@oneuptime/common 12.0.5 → 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 (528) hide show
  1. package/Models/DatabaseModels/AIRun.ts +33 -0
  2. package/Models/DatabaseModels/DataSource.ts +744 -0
  3. package/Models/DatabaseModels/Index.ts +3 -0
  4. package/Models/DatabaseModels/ProjectCallSMSConfig.ts +10 -2
  5. package/Models/DatabaseModels/User.ts +2 -0
  6. package/Models/DatabaseModels/UserOnCallLog.ts +2 -0
  7. package/Models/DatabaseModels/UserOnCallLogTimeline.ts +2 -0
  8. package/Models/DatabaseModels/UserSession.ts +2 -0
  9. package/Models/DatabaseModels/UserTotpAuth.ts +6 -4
  10. package/Models/DatabaseModels/UserWebAuthn.ts +5 -3
  11. package/Server/API/AIInsightAPI.ts +47 -4
  12. package/Server/API/AIInvestigationAPI.ts +25 -0
  13. package/Server/API/DashboardAPI.ts +176 -492
  14. package/Server/API/DataSourceAPI.ts +268 -0
  15. package/Server/API/StatusPageAPI.ts +11 -1
  16. package/Server/API/UserAPI.ts +119 -0
  17. package/Server/Infrastructure/ClickhouseConfig.ts +59 -0
  18. package/Server/Infrastructure/Postgres/SchemaMigrations/1786303472848-AddDataSourceTable.ts +39 -0
  19. package/Server/Infrastructure/Postgres/SchemaMigrations/1786600000000-AddInvestigationAnalysisTldr.ts +24 -0
  20. package/Server/Infrastructure/Postgres/SchemaMigrations/1786700000000-DropProjectCallSMSConfigCredentialUniques.ts +76 -0
  21. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
  22. package/Server/Infrastructure/Queue.ts +26 -0
  23. package/Server/Infrastructure/QueueWorker.ts +17 -0
  24. package/Server/Middleware/TelemetryIngest.ts +8 -3
  25. package/Server/Services/AIInsightService.ts +132 -12
  26. package/Server/Services/AIRunService.ts +34 -0
  27. package/Server/Services/AIService.ts +17 -2
  28. package/Server/Services/AlertService.ts +38 -32
  29. package/Server/Services/AnalyticsDatabaseService.ts +8 -4
  30. package/Server/Services/DataSourceService.ts +200 -0
  31. package/Server/Services/HostService.ts +92 -0
  32. package/Server/Services/IncidentService.ts +45 -0
  33. package/Server/Services/Index.ts +2 -0
  34. package/Server/Services/MonitorService.ts +49 -0
  35. package/Server/Services/MonitorStatusService.ts +166 -0
  36. package/Server/Services/OpenTelemetryIngestService.ts +255 -184
  37. package/Server/Services/RumSessionPinService.ts +7 -21
  38. package/Server/Services/StatusPageSubscriberService.ts +13 -0
  39. package/Server/Services/UserService.ts +280 -9
  40. package/Server/Static/Vendor/README.md +62 -0
  41. package/Server/Static/Vendor/fonts/InterVariable.woff2 +0 -0
  42. package/Server/Static/Vendor/highlight/highlight.min.js +1244 -0
  43. package/Server/Static/Vendor/highlight/languages/apache.min.js +15 -0
  44. package/Server/Static/Vendor/highlight/languages/bash.min.js +21 -0
  45. package/Server/Static/Vendor/highlight/languages/c.min.js +41 -0
  46. package/Server/Static/Vendor/highlight/languages/cpp.min.js +47 -0
  47. package/Server/Static/Vendor/highlight/languages/csharp.min.js +49 -0
  48. package/Server/Static/Vendor/highlight/languages/css.min.js +31 -0
  49. package/Server/Static/Vendor/highlight/languages/diff.min.js +9 -0
  50. package/Server/Static/Vendor/highlight/languages/dns.min.js +11 -0
  51. package/Server/Static/Vendor/highlight/languages/dockerfile.min.js +8 -0
  52. package/Server/Static/Vendor/highlight/languages/go.min.js +20 -0
  53. package/Server/Static/Vendor/highlight/languages/graphql.min.js +12 -0
  54. package/Server/Static/Vendor/highlight/languages/http.min.js +14 -0
  55. package/Server/Static/Vendor/highlight/languages/ini.min.js +15 -0
  56. package/Server/Static/Vendor/highlight/languages/java.min.js +38 -0
  57. package/Server/Static/Vendor/highlight/languages/javascript.min.js +81 -0
  58. package/Server/Static/Vendor/highlight/languages/json.min.js +8 -0
  59. package/Server/Static/Vendor/highlight/languages/kotlin.min.js +46 -0
  60. package/Server/Static/Vendor/highlight/languages/lua.min.js +15 -0
  61. package/Server/Static/Vendor/highlight/languages/makefile.min.js +14 -0
  62. package/Server/Static/Vendor/highlight/languages/nginx.min.js +21 -0
  63. package/Server/Static/Vendor/highlight/languages/perl.min.js +41 -0
  64. package/Server/Static/Vendor/highlight/languages/php.min.js +59 -0
  65. package/Server/Static/Vendor/highlight/languages/powershell.min.js +39 -0
  66. package/Server/Static/Vendor/highlight/languages/python.min.js +42 -0
  67. package/Server/Static/Vendor/highlight/languages/r.min.js +26 -0
  68. package/Server/Static/Vendor/highlight/languages/ruby.min.js +54 -0
  69. package/Server/Static/Vendor/highlight/languages/rust.min.js +27 -0
  70. package/Server/Static/Vendor/highlight/languages/scala.min.js +28 -0
  71. package/Server/Static/Vendor/highlight/languages/sql.min.js +21 -0
  72. package/Server/Static/Vendor/highlight/languages/swift.min.js +68 -0
  73. package/Server/Static/Vendor/highlight/languages/typescript.min.js +99 -0
  74. package/Server/Static/Vendor/highlight/languages/xml.min.js +29 -0
  75. package/Server/Static/Vendor/highlight/languages/yaml.min.js +28 -0
  76. package/Server/Static/Vendor/highlight/styles/github-dark.min.css +10 -0
  77. package/Server/Static/Vendor/highlight/styles/vs2015.min.css +1 -0
  78. package/Server/Static/Vendor/tailwind/tailwind-3.4.5.js +21028 -0
  79. package/Server/Types/Database/Permissions/BasePermission.ts +7 -0
  80. package/Server/Types/Database/Permissions/DeletePermission.ts +2 -0
  81. package/Server/Types/Database/Permissions/ReadPermission.ts +3 -0
  82. package/Server/Types/Database/Permissions/TenantPermission.ts +101 -16
  83. package/Server/Utils/AI/CodeFix/FixRunBudget.ts +2 -2
  84. package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +90 -11
  85. package/Server/Utils/AI/SRE/AlertInvestigationRunner.ts +1 -0
  86. package/Server/Utils/AI/SRE/IncidentInvestigationRunner.ts +1 -0
  87. package/Server/Utils/AI/SRE/Insights/Detectors/ExceptionIdentity.ts +125 -0
  88. package/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.ts +25 -15
  89. package/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.ts +256 -57
  90. package/Server/Utils/AI/SRE/Insights/InsightStore.ts +76 -18
  91. package/Server/Utils/AI/SRE/InvestigationTldr.ts +352 -0
  92. package/Server/Utils/AnalyticsDatabase/InsertDedupContext.ts +7 -2
  93. package/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.ts +1793 -0
  94. package/Server/Utils/Dashboard/PublicDashboardViewConfig.ts +65 -0
  95. package/Server/Utils/DataSource/ConnectorRegistry.ts +53 -0
  96. package/Server/Utils/DataSource/Connectors/ClickHouseConnector.ts +338 -0
  97. package/Server/Utils/DataSource/Connectors/ElasticsearchConnector.ts +717 -0
  98. package/Server/Utils/DataSource/Connectors/LokiConnector.ts +606 -0
  99. package/Server/Utils/DataSource/Connectors/MySqlConnector.ts +307 -0
  100. package/Server/Utils/DataSource/Connectors/PostgresConnector.ts +260 -0
  101. package/Server/Utils/DataSource/Connectors/PrometheusConnector.ts +555 -0
  102. package/Server/Utils/DataSource/Connectors/RestApiConnector.ts +597 -0
  103. package/Server/Utils/DataSource/Connectors/SqlServerConnector.ts +318 -0
  104. package/Server/Utils/DataSource/EgressGuard.ts +446 -0
  105. package/Server/Utils/DataSource/HttpFetch.ts +221 -0
  106. package/Server/Utils/DataSource/SqlQueryGuard.ts +383 -0
  107. package/Server/Utils/DataSource/SqlResultShaper.ts +372 -0
  108. package/Server/Utils/DataSource/Types.ts +93 -0
  109. package/Server/Utils/Database/PostgresErrorTranslator.ts +172 -17
  110. package/Server/Utils/InProcessMemo.ts +141 -0
  111. package/Server/Utils/InstanceHealth/TelemetryIngestion.ts +628 -0
  112. package/Server/Utils/Monitor/MonitorMetricUtil.ts +58 -0
  113. package/Server/Utils/Monitor/MonitorResource.ts +14 -0
  114. package/Server/Utils/Response.ts +12 -1
  115. package/Server/Utils/SSRFProtection.ts +237 -0
  116. package/Server/Utils/StartServer.ts +8 -0
  117. package/Server/Utils/StatusPageSubscriberWebhook.ts +30 -0
  118. package/Server/Utils/Telemetry/CaptureSpan.ts +30 -18
  119. package/Server/Utils/Telemetry/IngestionTimestamp.ts +75 -0
  120. package/Server/Utils/Telemetry/ResourceHeartbeat.ts +99 -7
  121. package/Server/Utils/Telemetry/Telemetry.ts +112 -1
  122. package/Server/Utils/Telemetry.ts +104 -3
  123. package/Server/Utils/VendorAssets.ts +165 -0
  124. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +28 -5
  125. package/Server/Utils/Workspace/Slack/Slack.ts +5 -0
  126. package/Server/Views/Partials/Head.ejs +21 -7
  127. package/Tests/App/AdminDashboard/AdminProjectsIdFilter.test.tsx +207 -0
  128. package/Tests/App/AdminDashboard/AdminUsersIdFilter.test.tsx +216 -0
  129. package/Tests/App/Dashboard/AIInsightViewActions.test.tsx +422 -0
  130. package/Tests/App/Dashboard/AddWidgetModal.test.tsx +10 -3
  131. package/Tests/App/Dashboard/AlertsSideMenu.test.tsx +387 -0
  132. package/Tests/App/Dashboard/ChatActivityFeed.test.tsx +199 -0
  133. package/Tests/App/Dashboard/DataSourceChartSyntheticConfig.test.tsx +736 -0
  134. package/Tests/App/Dashboard/DataSourceQueryEditor.test.tsx +868 -0
  135. package/Tests/App/Dashboard/DataSourceWidgetCatalog.test.ts +440 -0
  136. package/Tests/App/Dashboard/DataSourceWidgetFetching.test.tsx +2109 -0
  137. package/Tests/App/Dashboard/DataSourceWidgetViews.test.tsx +726 -0
  138. package/Tests/App/Dashboard/IncidentsSideMenu.test.tsx +447 -0
  139. package/Tests/App/Dashboard/InvestigationPanel.test.tsx +514 -3
  140. package/Tests/App/Dashboard/ProductMenuBreadcrumbs.test.tsx +391 -0
  141. package/Tests/App/Dashboard/ScheduledMaintenanceSideMenu.test.tsx +326 -0
  142. package/Tests/App/Dashboard/SideMenuHarness.tsx +187 -0
  143. package/Tests/App/Dashboard/WidgetCatalog.test.ts +6 -1
  144. package/Tests/App/StatusPage/StatusPageResourceExplorer.test.tsx +1858 -0
  145. package/Tests/Models/DatabaseModels/DataSourceModelSecrets.test.ts +70 -0
  146. package/Tests/Server/API/AIInvestigationAPI.test.ts +187 -0
  147. package/Tests/Server/API/DashboardPublicDataSourceStrip.test.ts +686 -0
  148. package/Tests/Server/API/DashboardPublicResourceListAPI.test.ts +585 -823
  149. package/Tests/Server/API/DataSourceAPIRoutes.test.ts +486 -0
  150. package/Tests/Server/API/StatusPageSubscriberOwnership.test.ts +291 -0
  151. package/Tests/Server/API/UserAuthenticationAPI.test.ts +641 -0
  152. package/Tests/Server/Infrastructure/ClickhouseKeepAliveOptions.test.ts +441 -0
  153. package/Tests/Server/Middleware/TelemetryIngestTokenLog.test.ts +140 -0
  154. package/Tests/Server/Services/AIInsightService.test.ts +266 -11
  155. package/Tests/Server/Services/AIRunAnalysisTldrPersistence.test.ts +160 -0
  156. package/Tests/Server/Services/AIServiceDailyBudget.test.ts +4 -0
  157. package/Tests/Server/Services/AlertMetricResourceAttributes.test.ts +352 -0
  158. package/Tests/Server/Services/DataSourceServiceSettings.test.ts +244 -0
  159. package/Tests/Server/Services/HostServiceFindOrCreateMemo.test.ts +397 -0
  160. package/Tests/Server/Services/HostServiceUpdateLastSeen.test.ts +41 -2
  161. package/Tests/Server/Services/IncidentMetricResourceAttributes.test.ts +408 -0
  162. package/Tests/Server/Services/MonitorStatusServiceDeleteReferenceCleanup.test.ts +351 -0
  163. package/Tests/Server/Services/MonitorStatusServiceValidation.test.ts +171 -0
  164. package/Tests/Server/Services/OpenTelemetryResourceRetentionMemo.test.ts +398 -0
  165. package/Tests/Server/Services/OpenTelemetryServiceResolutionCache.test.ts +19 -0
  166. package/Tests/Server/Services/ProjectCallSMSConfigCredentialUniqueness.test.ts +305 -0
  167. package/Tests/Server/Services/ResourceUpdateLastSeenLivenessFallback.test.ts +36 -1
  168. package/Tests/Server/Services/RumSessionPinUniqueViolationRecovery.test.ts +163 -0
  169. package/Tests/Server/Services/UserAuthenticationService.test.ts +973 -0
  170. package/Tests/Server/Types/Database/ObjectIdColumnQuery.test.ts +262 -0
  171. package/Tests/Server/Types/Database/Permissions/TenantPermission.test.ts +358 -0
  172. package/Tests/Server/Utils/AI/FixRunBudget.test.ts +2 -2
  173. package/Tests/Server/Utils/AI/Insights/ExceptionSpikeDetector.test.ts +6 -1
  174. package/Tests/Server/Utils/AI/Insights/InsightStore.test.ts +121 -4
  175. package/Tests/Server/Utils/AI/Insights/NewExceptionDetector.test.ts +361 -10
  176. package/Tests/Server/Utils/AI/InvestigationSettlement.test.ts +292 -0
  177. package/Tests/Server/Utils/AI/InvestigationTldr.test.ts +623 -0
  178. package/Tests/Server/Utils/AI/InvestigationTldrWiring.test.ts +98 -0
  179. package/Tests/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.test.ts +857 -0
  180. package/Tests/Server/Utils/Dashboard/PublicDashboardViewConfig.test.ts +480 -0
  181. package/Tests/Server/Utils/DataSource/ClickHouseConnector.test.ts +759 -0
  182. package/Tests/Server/Utils/DataSource/ConnectorRegistry.test.ts +37 -0
  183. package/Tests/Server/Utils/DataSource/EgressGuard.test.ts +645 -0
  184. package/Tests/Server/Utils/DataSource/ElasticsearchConnector.test.ts +1206 -0
  185. package/Tests/Server/Utils/DataSource/HttpFetch.test.ts +616 -0
  186. package/Tests/Server/Utils/DataSource/LokiConnector.test.ts +970 -0
  187. package/Tests/Server/Utils/DataSource/MySqlConnector.test.ts +935 -0
  188. package/Tests/Server/Utils/DataSource/PostgresConnector.test.ts +854 -0
  189. package/Tests/Server/Utils/DataSource/PrometheusConnector.test.ts +881 -0
  190. package/Tests/Server/Utils/DataSource/RestApiConnector.test.ts +1020 -0
  191. package/Tests/Server/Utils/DataSource/SqlQueryGuard.test.ts +425 -0
  192. package/Tests/Server/Utils/DataSource/SqlResultShaper.test.ts +555 -0
  193. package/Tests/Server/Utils/DataSource/SqlServerConnector.test.ts +934 -0
  194. package/Tests/Server/Utils/Database/PostgresErrorTranslator.test.ts +228 -7
  195. package/Tests/Server/Utils/InProcessMemo.test.ts +292 -0
  196. package/Tests/Server/Utils/InstanceHealth/TelemetryIngestion.test.ts +960 -0
  197. package/Tests/Server/Utils/MicrosoftTeamsWebhookUrlValidation.test.ts +103 -0
  198. package/Tests/Server/Utils/Monitor/MonitorMetricResourceAttributes.test.ts +336 -0
  199. package/Tests/Server/Utils/OfflineAssetHygiene.test.ts +521 -0
  200. package/Tests/Server/Utils/ResponseRenderAnalytics.test.ts +143 -0
  201. package/Tests/Server/Utils/SSRFProtection.test.ts +193 -0
  202. package/Tests/Server/Utils/StatusPageSubscriberWebhook.test.ts +101 -0
  203. package/Tests/Server/Utils/TailwindBuildCopy.test.ts +225 -0
  204. package/Tests/Server/Utils/Telemetry/ResourceHeartbeatL1Memo.test.ts +355 -0
  205. package/Tests/Server/Utils/Telemetry/TelemetryFanInWriter.test.ts +128 -0
  206. package/Tests/Server/Utils/Telemetry/TelemetryUtilAttributeKeys.test.ts +381 -0
  207. package/Tests/Server/Utils/Telemetry.test.ts +87 -0
  208. package/Tests/Server/Utils/VendorAssetIntegrity.test.ts +343 -0
  209. package/Tests/Server/Utils/VendorAssets.test.ts +671 -0
  210. package/Tests/Server/Views/OfflineRender.test.ts +297 -0
  211. package/Tests/Types/Dashboard/DataSourceComponentTypes.test.ts +618 -0
  212. package/Tests/Types/DateClickhouseFormat.test.ts +192 -0
  213. package/Tests/Types/Password.test.ts +363 -0
  214. package/Tests/UI/Components/ConfirmModal.test.tsx +7 -0
  215. package/Tests/UI/Components/ErrorBoundary.test.tsx +53 -0
  216. package/Tests/UI/Components/Modal.test.tsx +281 -1
  217. package/Tests/UI/Components/ObjectIdFilterPipeline.test.tsx +396 -0
  218. package/Tests/UI/Components/StatusPage/ResourceGroupNavigator.test.tsx +1147 -0
  219. package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +116 -1
  220. package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +2 -0
  221. package/Tests/Utils/Analytics.test.ts +23 -0
  222. package/Tests/Utils/Dashboard/Components/DashboardDataSourceComponents.test.ts +640 -0
  223. package/Tests/Utils/DataSource/DataSourceQueryText.test.ts +138 -0
  224. package/Tests/Utils/DataSource/DataSourceValueReducer.test.ts +526 -0
  225. package/Tests/Utils/Metrics/MetricResourceAttributeUtil.test.ts +691 -0
  226. package/Tests/Utils/StatusPage/GroupHierarchyView.test.ts +1452 -0
  227. package/Tests/Utils/StatusPage/ResourceExplorer.test.ts +931 -0
  228. package/Tests/Utils/Telemetry/CaptureSpanExportGating.test.ts +288 -0
  229. package/Tests/Utils/Telemetry/IngestionTimestamp.test.ts +170 -0
  230. package/Types/AI/AIInsightEvidence.ts +6 -0
  231. package/Types/Analytics/RevenueEvent.ts +31 -0
  232. package/Types/Dashboard/DashboardComponentType.ts +31 -0
  233. package/Types/Dashboard/DashboardComponents/DashboardDataSourceChartComponent.ts +27 -0
  234. package/Types/Dashboard/DashboardComponents/DashboardDataSourceGaugeComponent.ts +32 -0
  235. package/Types/Dashboard/DashboardComponents/DashboardDataSourceTableComponent.ts +30 -0
  236. package/Types/Dashboard/DashboardComponents/DashboardDataSourceValueComponent.ts +55 -0
  237. package/Types/DataSource/DataSourceLimits.ts +62 -0
  238. package/Types/DataSource/DataSourceQueryConfig.ts +41 -0
  239. package/Types/DataSource/DataSourceTableResult.ts +38 -0
  240. package/Types/DataSource/DataSourceType.ts +213 -0
  241. package/Types/Date.ts +43 -3
  242. package/Types/Password.ts +64 -0
  243. package/Types/Permission.ts +46 -0
  244. package/Types/UserAuthenticationStatus.ts +34 -0
  245. package/UI/Components/Button/Button.tsx +1 -1
  246. package/UI/Components/ErrorBoundary.tsx +459 -108
  247. package/UI/Components/Icon/Icon.tsx +10 -9
  248. package/UI/Components/Modal/ConfirmModal.tsx +6 -1
  249. package/UI/Components/Modal/Modal.tsx +267 -35
  250. package/UI/Components/Modal/ModalFooter.tsx +6 -1
  251. package/UI/Components/MoreMenu/MoreMenu.tsx +19 -4
  252. package/UI/Components/MoreMenu/MoreMenuItem.tsx +6 -1
  253. package/UI/Components/StatusPage/ResourceGrid.tsx +314 -0
  254. package/UI/Components/StatusPage/ResourceGroupNavigator.tsx +808 -0
  255. package/UI/Components/StatusPage/ResourceList.tsx +570 -0
  256. package/UI/Styles/Theme.css +18 -0
  257. package/UI/Utils/API/RequestOptions.ts +7 -0
  258. package/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.ts +1 -0
  259. package/UI/Utils/ModelAPI/ModelAPI.ts +1 -0
  260. package/UI/Utils/TestDataSource.ts +61 -0
  261. package/UI/esbuild-config.js +45 -0
  262. package/Utils/Analytics.ts +15 -0
  263. package/Utils/Dashboard/Components/DashboardDataSourceChartComponent.ts +88 -0
  264. package/Utils/Dashboard/Components/DashboardDataSourceGaugeComponent.ts +123 -0
  265. package/Utils/Dashboard/Components/DashboardDataSourceShared.ts +16 -0
  266. package/Utils/Dashboard/Components/DashboardDataSourceTableComponent.ts +72 -0
  267. package/Utils/Dashboard/Components/DashboardDataSourceValueComponent.ts +126 -0
  268. package/Utils/Dashboard/Components/Index.ts +28 -0
  269. package/Utils/DataSource/DataSourceQueryText.ts +94 -0
  270. package/Utils/DataSource/DataSourceValueReducer.ts +156 -0
  271. package/Utils/Metrics/MetricResourceAttributeUtil.ts +380 -0
  272. package/Utils/NetworkDiscovery/ScanTargetUtil.ts +8 -6
  273. package/Utils/StatusPage/GroupHierarchyView.ts +931 -0
  274. package/Utils/StatusPage/ResourceExplorer.ts +853 -0
  275. package/build/dist/Models/DatabaseModels/AIRun.js +34 -0
  276. package/build/dist/Models/DatabaseModels/AIRun.js.map +1 -1
  277. package/build/dist/Models/DatabaseModels/DataSource.js +774 -0
  278. package/build/dist/Models/DatabaseModels/DataSource.js.map +1 -0
  279. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  280. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  281. package/build/dist/Models/DatabaseModels/ProjectCallSMSConfig.js +14 -4
  282. package/build/dist/Models/DatabaseModels/ProjectCallSMSConfig.js.map +1 -1
  283. package/build/dist/Models/DatabaseModels/User.js +2 -0
  284. package/build/dist/Models/DatabaseModels/User.js.map +1 -1
  285. package/build/dist/Models/DatabaseModels/UserOnCallLog.js +2 -0
  286. package/build/dist/Models/DatabaseModels/UserOnCallLog.js.map +1 -1
  287. package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js +2 -0
  288. package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js.map +1 -1
  289. package/build/dist/Models/DatabaseModels/UserSession.js +2 -0
  290. package/build/dist/Models/DatabaseModels/UserSession.js.map +1 -1
  291. package/build/dist/Models/DatabaseModels/UserTotpAuth.js +6 -4
  292. package/build/dist/Models/DatabaseModels/UserTotpAuth.js.map +1 -1
  293. package/build/dist/Models/DatabaseModels/UserWebAuthn.js +5 -3
  294. package/build/dist/Models/DatabaseModels/UserWebAuthn.js.map +1 -1
  295. package/build/dist/Server/API/AIInsightAPI.js +34 -4
  296. package/build/dist/Server/API/AIInsightAPI.js.map +1 -1
  297. package/build/dist/Server/API/AIInvestigationAPI.js +23 -0
  298. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  299. package/build/dist/Server/API/DashboardAPI.js +119 -433
  300. package/build/dist/Server/API/DashboardAPI.js.map +1 -1
  301. package/build/dist/Server/API/DataSourceAPI.js +173 -0
  302. package/build/dist/Server/API/DataSourceAPI.js.map +1 -0
  303. package/build/dist/Server/API/StatusPageAPI.js +11 -1
  304. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  305. package/build/dist/Server/API/UserAPI.js +94 -2
  306. package/build/dist/Server/API/UserAPI.js.map +1 -1
  307. package/build/dist/Server/Infrastructure/ClickhouseConfig.js +49 -0
  308. package/build/dist/Server/Infrastructure/ClickhouseConfig.js.map +1 -1
  309. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786303472848-AddDataSourceTable.js +20 -0
  310. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786303472848-AddDataSourceTable.js.map +1 -0
  311. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786600000000-AddInvestigationAnalysisTldr.js +19 -0
  312. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786600000000-AddInvestigationAnalysisTldr.js.map +1 -0
  313. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786700000000-DropProjectCallSMSConfigCredentialUniques.js +64 -0
  314. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786700000000-DropProjectCallSMSConfigCredentialUniques.js.map +1 -0
  315. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
  316. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  317. package/build/dist/Server/Infrastructure/Queue.js +27 -0
  318. package/build/dist/Server/Infrastructure/Queue.js.map +1 -1
  319. package/build/dist/Server/Infrastructure/QueueWorker.js +13 -0
  320. package/build/dist/Server/Infrastructure/QueueWorker.js.map +1 -1
  321. package/build/dist/Server/Middleware/TelemetryIngest.js +8 -3
  322. package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
  323. package/build/dist/Server/Services/AIInsightService.js +110 -10
  324. package/build/dist/Server/Services/AIInsightService.js.map +1 -1
  325. package/build/dist/Server/Services/AIRunService.js +34 -0
  326. package/build/dist/Server/Services/AIRunService.js.map +1 -1
  327. package/build/dist/Server/Services/AIService.js +16 -2
  328. package/build/dist/Server/Services/AIService.js.map +1 -1
  329. package/build/dist/Server/Services/AlertService.js +28 -35
  330. package/build/dist/Server/Services/AlertService.js.map +1 -1
  331. package/build/dist/Server/Services/AnalyticsDatabaseService.js +8 -4
  332. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  333. package/build/dist/Server/Services/DataSourceService.js +159 -0
  334. package/build/dist/Server/Services/DataSourceService.js.map +1 -0
  335. package/build/dist/Server/Services/HostService.js +74 -0
  336. package/build/dist/Server/Services/HostService.js.map +1 -1
  337. package/build/dist/Server/Services/IncidentService.js +35 -24
  338. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  339. package/build/dist/Server/Services/Index.js +2 -0
  340. package/build/dist/Server/Services/Index.js.map +1 -1
  341. package/build/dist/Server/Services/MonitorService.js +45 -0
  342. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  343. package/build/dist/Server/Services/MonitorStatusService.js +129 -0
  344. package/build/dist/Server/Services/MonitorStatusService.js.map +1 -1
  345. package/build/dist/Server/Services/OpenTelemetryIngestService.js +222 -159
  346. package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
  347. package/build/dist/Server/Services/RumSessionPinService.js +7 -15
  348. package/build/dist/Server/Services/RumSessionPinService.js.map +1 -1
  349. package/build/dist/Server/Services/StatusPageSubscriberService.js +10 -0
  350. package/build/dist/Server/Services/StatusPageSubscriberService.js.map +1 -1
  351. package/build/dist/Server/Services/UserService.js +241 -10
  352. package/build/dist/Server/Services/UserService.js.map +1 -1
  353. package/build/dist/Server/Types/Database/Permissions/BasePermission.js +6 -0
  354. package/build/dist/Server/Types/Database/Permissions/BasePermission.js.map +1 -1
  355. package/build/dist/Server/Types/Database/Permissions/DeletePermission.js +1 -0
  356. package/build/dist/Server/Types/Database/Permissions/DeletePermission.js.map +1 -1
  357. package/build/dist/Server/Types/Database/Permissions/ReadPermission.js +2 -0
  358. package/build/dist/Server/Types/Database/Permissions/ReadPermission.js.map +1 -1
  359. package/build/dist/Server/Types/Database/Permissions/TenantPermission.js +68 -12
  360. package/build/dist/Server/Types/Database/Permissions/TenantPermission.js.map +1 -1
  361. package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js +2 -2
  362. package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js.map +1 -1
  363. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +68 -8
  364. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
  365. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js +1 -0
  366. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -1
  367. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js +1 -0
  368. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js.map +1 -1
  369. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionIdentity.js +97 -0
  370. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionIdentity.js.map +1 -0
  371. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js +17 -15
  372. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js.map +1 -1
  373. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js +178 -54
  374. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js.map +1 -1
  375. package/build/dist/Server/Utils/AI/SRE/Insights/InsightStore.js +65 -16
  376. package/build/dist/Server/Utils/AI/SRE/Insights/InsightStore.js.map +1 -1
  377. package/build/dist/Server/Utils/AI/SRE/InvestigationTldr.js +303 -0
  378. package/build/dist/Server/Utils/AI/SRE/InvestigationTldr.js.map +1 -0
  379. package/build/dist/Server/Utils/AnalyticsDatabase/InsertDedupContext.js.map +1 -1
  380. package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js +1261 -0
  381. package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js.map +1 -0
  382. package/build/dist/Server/Utils/Dashboard/PublicDashboardViewConfig.js +47 -0
  383. package/build/dist/Server/Utils/Dashboard/PublicDashboardViewConfig.js.map +1 -0
  384. package/build/dist/Server/Utils/DataSource/ConnectorRegistry.js +42 -0
  385. package/build/dist/Server/Utils/DataSource/ConnectorRegistry.js.map +1 -0
  386. package/build/dist/Server/Utils/DataSource/Connectors/ClickHouseConnector.js +187 -0
  387. package/build/dist/Server/Utils/DataSource/Connectors/ClickHouseConnector.js.map +1 -0
  388. package/build/dist/Server/Utils/DataSource/Connectors/ElasticsearchConnector.js +493 -0
  389. package/build/dist/Server/Utils/DataSource/Connectors/ElasticsearchConnector.js.map +1 -0
  390. package/build/dist/Server/Utils/DataSource/Connectors/LokiConnector.js +399 -0
  391. package/build/dist/Server/Utils/DataSource/Connectors/LokiConnector.js.map +1 -0
  392. package/build/dist/Server/Utils/DataSource/Connectors/MySqlConnector.js +195 -0
  393. package/build/dist/Server/Utils/DataSource/Connectors/MySqlConnector.js.map +1 -0
  394. package/build/dist/Server/Utils/DataSource/Connectors/PostgresConnector.js +149 -0
  395. package/build/dist/Server/Utils/DataSource/Connectors/PostgresConnector.js.map +1 -0
  396. package/build/dist/Server/Utils/DataSource/Connectors/PrometheusConnector.js +362 -0
  397. package/build/dist/Server/Utils/DataSource/Connectors/PrometheusConnector.js.map +1 -0
  398. package/build/dist/Server/Utils/DataSource/Connectors/RestApiConnector.js +342 -0
  399. package/build/dist/Server/Utils/DataSource/Connectors/RestApiConnector.js.map +1 -0
  400. package/build/dist/Server/Utils/DataSource/Connectors/SqlServerConnector.js +186 -0
  401. package/build/dist/Server/Utils/DataSource/Connectors/SqlServerConnector.js.map +1 -0
  402. package/build/dist/Server/Utils/DataSource/EgressGuard.js +305 -0
  403. package/build/dist/Server/Utils/DataSource/EgressGuard.js.map +1 -0
  404. package/build/dist/Server/Utils/DataSource/HttpFetch.js +134 -0
  405. package/build/dist/Server/Utils/DataSource/HttpFetch.js.map +1 -0
  406. package/build/dist/Server/Utils/DataSource/SqlQueryGuard.js +331 -0
  407. package/build/dist/Server/Utils/DataSource/SqlQueryGuard.js.map +1 -0
  408. package/build/dist/Server/Utils/DataSource/SqlResultShaper.js +280 -0
  409. package/build/dist/Server/Utils/DataSource/SqlResultShaper.js.map +1 -0
  410. package/build/dist/Server/Utils/DataSource/Types.js +2 -0
  411. package/build/dist/Server/Utils/DataSource/Types.js.map +1 -0
  412. package/build/dist/Server/Utils/Database/PostgresErrorTranslator.js +103 -9
  413. package/build/dist/Server/Utils/Database/PostgresErrorTranslator.js.map +1 -1
  414. package/build/dist/Server/Utils/InProcessMemo.js +113 -0
  415. package/build/dist/Server/Utils/InProcessMemo.js.map +1 -0
  416. package/build/dist/Server/Utils/InstanceHealth/TelemetryIngestion.js +406 -0
  417. package/build/dist/Server/Utils/InstanceHealth/TelemetryIngestion.js.map +1 -0
  418. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +34 -0
  419. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
  420. package/build/dist/Server/Utils/Monitor/MonitorResource.js +14 -0
  421. package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
  422. package/build/dist/Server/Utils/Response.js +9 -1
  423. package/build/dist/Server/Utils/Response.js.map +1 -1
  424. package/build/dist/Server/Utils/SSRFProtection.js +192 -0
  425. package/build/dist/Server/Utils/SSRFProtection.js.map +1 -0
  426. package/build/dist/Server/Utils/StartServer.js +7 -0
  427. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  428. package/build/dist/Server/Utils/StatusPageSubscriberWebhook.js +24 -0
  429. package/build/dist/Server/Utils/StatusPageSubscriberWebhook.js.map +1 -1
  430. package/build/dist/Server/Utils/Telemetry/CaptureSpan.js +25 -11
  431. package/build/dist/Server/Utils/Telemetry/CaptureSpan.js.map +1 -1
  432. package/build/dist/Server/Utils/Telemetry/IngestionTimestamp.js +32 -0
  433. package/build/dist/Server/Utils/Telemetry/IngestionTimestamp.js.map +1 -0
  434. package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js +92 -5
  435. package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js.map +1 -1
  436. package/build/dist/Server/Utils/Telemetry/Telemetry.js +92 -6
  437. package/build/dist/Server/Utils/Telemetry/Telemetry.js.map +1 -1
  438. package/build/dist/Server/Utils/Telemetry.js +93 -6
  439. package/build/dist/Server/Utils/Telemetry.js.map +1 -1
  440. package/build/dist/Server/Utils/VendorAssets.js +121 -0
  441. package/build/dist/Server/Utils/VendorAssets.js.map +1 -0
  442. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +25 -4
  443. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  444. package/build/dist/Server/Utils/Workspace/Slack/Slack.js +5 -0
  445. package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
  446. package/build/dist/Types/Analytics/RevenueEvent.js +26 -0
  447. package/build/dist/Types/Analytics/RevenueEvent.js.map +1 -0
  448. package/build/dist/Types/Dashboard/DashboardComponentType.js +27 -0
  449. package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
  450. package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceChartComponent.js +2 -0
  451. package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceChartComponent.js.map +1 -0
  452. package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceGaugeComponent.js +2 -0
  453. package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceGaugeComponent.js.map +1 -0
  454. package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceTableComponent.js +2 -0
  455. package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceTableComponent.js.map +1 -0
  456. package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceValueComponent.js +16 -0
  457. package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceValueComponent.js.map +1 -0
  458. package/build/dist/Types/DataSource/DataSourceLimits.js +47 -0
  459. package/build/dist/Types/DataSource/DataSourceLimits.js.map +1 -0
  460. package/build/dist/Types/DataSource/DataSourceQueryConfig.js +10 -0
  461. package/build/dist/Types/DataSource/DataSourceQueryConfig.js.map +1 -0
  462. package/build/dist/Types/DataSource/DataSourceTableResult.js +14 -0
  463. package/build/dist/Types/DataSource/DataSourceTableResult.js.map +1 -0
  464. package/build/dist/Types/DataSource/DataSourceType.js +183 -0
  465. package/build/dist/Types/DataSource/DataSourceType.js.map +1 -0
  466. package/build/dist/Types/Date.js +38 -3
  467. package/build/dist/Types/Date.js.map +1 -1
  468. package/build/dist/Types/Password.js +56 -0
  469. package/build/dist/Types/Password.js.map +1 -0
  470. package/build/dist/Types/Permission.js +42 -0
  471. package/build/dist/Types/Permission.js.map +1 -1
  472. package/build/dist/Types/UserAuthenticationStatus.js +2 -0
  473. package/build/dist/Types/UserAuthenticationStatus.js.map +1 -0
  474. package/build/dist/UI/Components/ErrorBoundary.js +388 -72
  475. package/build/dist/UI/Components/ErrorBoundary.js.map +1 -1
  476. package/build/dist/UI/Components/Icon/Icon.js +10 -4
  477. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  478. package/build/dist/UI/Components/Modal/ConfirmModal.js +1 -1
  479. package/build/dist/UI/Components/Modal/ConfirmModal.js.map +1 -1
  480. package/build/dist/UI/Components/Modal/Modal.js +178 -19
  481. package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
  482. package/build/dist/UI/Components/Modal/ModalFooter.js +3 -1
  483. package/build/dist/UI/Components/Modal/ModalFooter.js.map +1 -1
  484. package/build/dist/UI/Components/MoreMenu/MoreMenu.js +9 -6
  485. package/build/dist/UI/Components/MoreMenu/MoreMenu.js.map +1 -1
  486. package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js +7 -1
  487. package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js.map +1 -1
  488. package/build/dist/UI/Components/StatusPage/ResourceGrid.js +119 -0
  489. package/build/dist/UI/Components/StatusPage/ResourceGrid.js.map +1 -0
  490. package/build/dist/UI/Components/StatusPage/ResourceGroupNavigator.js +354 -0
  491. package/build/dist/UI/Components/StatusPage/ResourceGroupNavigator.js.map +1 -0
  492. package/build/dist/UI/Components/StatusPage/ResourceList.js +203 -0
  493. package/build/dist/UI/Components/StatusPage/ResourceList.js.map +1 -0
  494. package/build/dist/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.js +1 -6
  495. package/build/dist/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.js.map +1 -1
  496. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js +3 -8
  497. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js.map +1 -1
  498. package/build/dist/UI/Utils/TestDataSource.js +39 -0
  499. package/build/dist/UI/Utils/TestDataSource.js.map +1 -0
  500. package/build/dist/Utils/Analytics.js +4 -0
  501. package/build/dist/Utils/Analytics.js.map +1 -1
  502. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceChartComponent.js +79 -0
  503. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceChartComponent.js.map +1 -0
  504. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceGaugeComponent.js +111 -0
  505. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceGaugeComponent.js.map +1 -0
  506. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceShared.js +15 -0
  507. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceShared.js.map +1 -0
  508. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceTableComponent.js +62 -0
  509. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceTableComponent.js.map +1 -0
  510. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceValueComponent.js +112 -0
  511. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceValueComponent.js.map +1 -0
  512. package/build/dist/Utils/Dashboard/Components/Index.js +16 -0
  513. package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
  514. package/build/dist/Utils/DataSource/DataSourceQueryText.js +64 -0
  515. package/build/dist/Utils/DataSource/DataSourceQueryText.js.map +1 -0
  516. package/build/dist/Utils/DataSource/DataSourceValueReducer.js +124 -0
  517. package/build/dist/Utils/DataSource/DataSourceValueReducer.js.map +1 -0
  518. package/build/dist/Utils/Metrics/MetricResourceAttributeUtil.js +281 -0
  519. package/build/dist/Utils/Metrics/MetricResourceAttributeUtil.js.map +1 -0
  520. package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js +8 -6
  521. package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js.map +1 -1
  522. package/build/dist/Utils/StatusPage/GroupHierarchyView.js +560 -0
  523. package/build/dist/Utils/StatusPage/GroupHierarchyView.js.map +1 -0
  524. package/build/dist/Utils/StatusPage/ResourceExplorer.js +519 -0
  525. package/build/dist/Utils/StatusPage/ResourceExplorer.js.map +1 -0
  526. package/jest.config.json +1 -0
  527. package/package.json +5 -1
  528. package/tsconfig.json +12 -10
@@ -0,0 +1,736 @@
1
+ import "@testing-library/jest-dom";
2
+ import {
3
+ beforeEach,
4
+ afterEach,
5
+ describe,
6
+ expect,
7
+ jest,
8
+ test,
9
+ } from "@jest/globals";
10
+ import { cleanup, render, screen, waitFor } from "@testing-library/react";
11
+ import * as React from "react";
12
+ import getJestMockFunction, { MockFunction } from "../../MockType";
13
+
14
+ /*
15
+ * The Data Source chart widget does not draw anything itself — it builds a
16
+ * SYNTHETIC MetricViewData and hands it to the same MetricCharts layer the
17
+ * OneUptime-metrics chart uses. That translation object is the entire
18
+ * contract between an external system (PromQL / SQL / LogQL / ES DSL / REST)
19
+ * and a chart layer that otherwise assumes it is looking at OneUptime
20
+ * metrics, so every field of it is behaviour:
21
+ *
22
+ * - `filterData` staying EMPTY is what stops MetricCharts recognising the
23
+ * config as a real metric query and firing metric-exemplar fetches
24
+ * against OneUptime for data that never came from OneUptime;
25
+ * - `groupByAttributeKeys` is what makes the chart split series on each
26
+ * point's `attributes`, and must be undefined rather than [] when there
27
+ * is nothing to group on — an empty array reads as "group by nothing",
28
+ * which is a different chart;
29
+ * - the legend field and the `getSeries` hook are mutually exclusive
30
+ * halves of one decision: a static string names the whole query, a
31
+ * "{{label}}" template has to be resolved per series instead.
32
+ *
33
+ * Nothing here renders a real chart. MetricCharts is stubbed to record its
34
+ * props, because what this component is responsible for is what it ASKS the
35
+ * chart layer to do, not what recharts eventually paints in jsdom.
36
+ */
37
+
38
+ const fetchTimeSeriesMock: MockFunction = getJestMockFunction();
39
+ const getAttributeKeysMock: MockFunction = getJestMockFunction();
40
+ const metricChartsRenderMock: MockFunction = getJestMockFunction();
41
+
42
+ /*
43
+ * The arrow wrappers are load bearing: jest.mock is hoisted above the
44
+ * compiled requires, so the mock variables above are still unassigned when
45
+ * the factory runs. Dereferencing them lazily, at call time, is what makes
46
+ * this work.
47
+ *
48
+ * getAttributeKeys is a BARE stub returning whatever the test set — it is
49
+ * deliberately not a second implementation of the real key-union logic,
50
+ * because the component's only job with it is to forward the value through
51
+ * to groupByAttributeKeys. Re-deriving the keys in the mock would mean the
52
+ * assertions were checking the mock against itself.
53
+ */
54
+ jest.mock(
55
+ "../../../../App/FeatureSet/Dashboard/src/Utils/DataSourceQuery",
56
+ () => {
57
+ return {
58
+ __esModule: true,
59
+ default: {
60
+ fetchTimeSeries: (...args: Array<any>) => {
61
+ return fetchTimeSeriesMock(...args);
62
+ },
63
+ fetchTable: () => {
64
+ throw new Error("The chart widget must not use the table endpoint.");
65
+ },
66
+ getAttributeKeys: (...args: Array<any>) => {
67
+ return getAttributeKeysMock(...args);
68
+ },
69
+ },
70
+ };
71
+ },
72
+ );
73
+
74
+ jest.mock(
75
+ "../../../../App/FeatureSet/Dashboard/src/Components/Metrics/MetricCharts",
76
+ () => {
77
+ return {
78
+ __esModule: true,
79
+ default: (props: MetricChartsStubProps): React.ReactElement => {
80
+ metricChartsRenderMock(props);
81
+ return React.createElement(
82
+ "div",
83
+ { "data-testid": "metric-charts" },
84
+ `results:${props.metricResults.length} configs:${props.metricViewData.queryConfigs.length}`,
85
+ );
86
+ },
87
+ };
88
+ },
89
+ );
90
+
91
+ import DashboardDataSourceChartComponentElement from "../../../../App/FeatureSet/Dashboard/src/Components/Dashboard/Components/DashboardDataSourceChartComponent";
92
+ import { DashboardBaseComponentProps } from "../../../../App/FeatureSet/Dashboard/src/Components/Dashboard/Components/DashboardBaseComponent";
93
+ import { setPublicDashboardContext } from "../../../../App/FeatureSet/Dashboard/src/Components/Dashboard/Utils/PublicDashboardContext";
94
+ import AggregatedModel from "../../../Types/BaseDatabase/AggregatedModel";
95
+ import AggregatedResult from "../../../Types/BaseDatabase/AggregatedResult";
96
+ import InBetween from "../../../Types/BaseDatabase/InBetween";
97
+ import DashboardChartType from "../../../Types/Dashboard/Chart/ChartType";
98
+ import DashboardComponentType from "../../../Types/Dashboard/DashboardComponentType";
99
+ import DashboardDataSourceChartComponent from "../../../Types/Dashboard/DashboardComponents/DashboardDataSourceChartComponent";
100
+ import DashboardViewConfig from "../../../Types/Dashboard/DashboardViewConfig";
101
+ import DataSourceQueryConfig from "../../../Types/DataSource/DataSourceQueryConfig";
102
+ import { ObjectType } from "../../../Types/JSON";
103
+ import MetricQueryConfigData, {
104
+ ChartSeries,
105
+ MetricChartType,
106
+ } from "../../../Types/Metrics/MetricQueryConfigData";
107
+ import MetricViewData from "../../../Types/Metrics/MetricViewData";
108
+ import ObjectID from "../../../Types/ObjectID";
109
+ import RangeStartAndEndDateTime from "../../../Types/Time/RangeStartAndEndDateTime";
110
+ import TimeRange from "../../../Types/Time/TimeRange";
111
+
112
+ interface MetricChartsStubProps {
113
+ metricResults: Array<AggregatedResult>;
114
+ metricViewData: MetricViewData;
115
+ hideCard?: boolean | undefined;
116
+ topNOverrideScope?: string | undefined;
117
+ }
118
+
119
+ /** One recorded call into the data source query client. */
120
+ interface DataSourceFetchArgs {
121
+ queryConfig: DataSourceQueryConfig;
122
+ startDate: Date;
123
+ endDate: Date;
124
+ }
125
+
126
+ const COMPONENT_ID: ObjectID = new ObjectID(
127
+ "11111111-1111-4111-8111-111111111111",
128
+ );
129
+
130
+ const START_DATE: Date = new Date("2026-08-10T09:00:00.000Z");
131
+ const END_DATE: Date = new Date("2026-08-10T10:00:00.000Z");
132
+
133
+ /*
134
+ * A CUSTOM range pins the window to fixed instants — a relative range would
135
+ * resolve against the wall clock and make the window assertions untestable.
136
+ */
137
+ const DASHBOARD_RANGE: RangeStartAndEndDateTime = {
138
+ range: TimeRange.CUSTOM,
139
+ startAndEndDate: new InBetween<Date>(START_DATE, END_DATE),
140
+ };
141
+
142
+ const DASHBOARD_VIEW_CONFIG: DashboardViewConfig = {
143
+ _type: ObjectType.DashboardViewConfig,
144
+ components: [],
145
+ heightInDashboardUnits: 60,
146
+ };
147
+
148
+ /*
149
+ * A value nothing in the component could invent on its own. If it shows up
150
+ * in groupByAttributeKeys, the component forwarded what getAttributeKeys
151
+ * returned rather than deriving anything itself.
152
+ */
153
+ const SENTINEL_ATTRIBUTE_KEYS: Array<string> = [
154
+ "sentinel.attribute.one",
155
+ "sentinel.attribute.two",
156
+ ];
157
+
158
+ type BuildBasePropsFunction = (
159
+ overrides?: Partial<DashboardBaseComponentProps>,
160
+ ) => DashboardBaseComponentProps;
161
+
162
+ const buildBaseProps: BuildBasePropsFunction = (
163
+ overrides: Partial<DashboardBaseComponentProps> = {},
164
+ ): DashboardBaseComponentProps => {
165
+ return {
166
+ componentId: COMPONENT_ID,
167
+ isEditMode: false,
168
+ isSelected: false,
169
+ key: "data-source-chart-widget",
170
+ onComponentUpdate: (): void => {
171
+ // The chart widget never writes back through this.
172
+ },
173
+ totalCurrentDashboardWidthInPx: 1200,
174
+ dashboardCanvasTopInPx: 0,
175
+ dashboardCanvasLeftInPx: 0,
176
+ dashboardCanvasWidthInPx: 1200,
177
+ dashboardCanvasHeightInPx: 800,
178
+ dashboardComponentHeightInPx: 320,
179
+ dashboardComponentWidthInPx: 480,
180
+ dashboardViewConfig: DASHBOARD_VIEW_CONFIG,
181
+ dashboardStartAndEndDate: DASHBOARD_RANGE,
182
+ metricTypes: [],
183
+ refreshTick: 0,
184
+ variables: undefined,
185
+ ...overrides,
186
+ };
187
+ };
188
+
189
+ type BuildPointFunction = (
190
+ value: number,
191
+ timestamp: string,
192
+ attributes?: Record<string, string>,
193
+ ) => AggregatedModel;
194
+
195
+ const buildPoint: BuildPointFunction = (
196
+ value: number,
197
+ timestamp: string,
198
+ attributes?: Record<string, string>,
199
+ ): AggregatedModel => {
200
+ return {
201
+ timestamp: new Date(timestamp),
202
+ value: value,
203
+ ...(attributes ? { attributes: attributes } : {}),
204
+ } as AggregatedModel;
205
+ };
206
+
207
+ type BuildSeriesFunction = (points: Array<AggregatedModel>) => AggregatedResult;
208
+
209
+ const buildSeries: BuildSeriesFunction = (
210
+ points: Array<AggregatedModel>,
211
+ ): AggregatedResult => {
212
+ return {
213
+ data: points,
214
+ truncated: false,
215
+ };
216
+ };
217
+
218
+ type RenderChartFunction = (
219
+ args: DashboardDataSourceChartComponent["arguments"],
220
+ overrides?: Partial<DashboardBaseComponentProps>,
221
+ ) => void;
222
+
223
+ const renderChartWidget: RenderChartFunction = (
224
+ args: DashboardDataSourceChartComponent["arguments"],
225
+ overrides: Partial<DashboardBaseComponentProps> = {},
226
+ ): void => {
227
+ const component: DashboardDataSourceChartComponent = {
228
+ _type: ObjectType.DashboardComponent,
229
+ componentId: COMPONENT_ID,
230
+ componentType: DashboardComponentType.DataSourceChart,
231
+ topInDashboardUnits: 0,
232
+ leftInDashboardUnits: 0,
233
+ widthInDashboardUnits: 8,
234
+ heightInDashboardUnits: 6,
235
+ minWidthInDashboardUnits: 4,
236
+ minHeightInDashboardUnits: 3,
237
+ arguments: args,
238
+ };
239
+
240
+ render(
241
+ <DashboardDataSourceChartComponentElement
242
+ {...buildBaseProps(overrides)}
243
+ component={component}
244
+ />,
245
+ );
246
+ };
247
+
248
+ /** The props of the most recent MetricCharts render. */
249
+ type GetLastChartPropsFunction = () => MetricChartsStubProps;
250
+
251
+ const getLastChartProps: GetLastChartPropsFunction =
252
+ (): MetricChartsStubProps => {
253
+ const calls: Array<Array<unknown>> = metricChartsRenderMock.mock.calls;
254
+
255
+ if (calls.length === 0) {
256
+ throw new Error("MetricCharts was never rendered.");
257
+ }
258
+
259
+ return calls[calls.length - 1]![0] as MetricChartsStubProps;
260
+ };
261
+
262
+ /*
263
+ * Render, wait for the fetch to settle and the chart layer to be handed its
264
+ * synthetic view data, then return that view data.
265
+ */
266
+ type RenderAndGetConfigsFunction = (
267
+ args: DashboardDataSourceChartComponent["arguments"],
268
+ ) => Promise<Array<MetricQueryConfigData>>;
269
+
270
+ const renderAndGetConfigs: RenderAndGetConfigsFunction = async (
271
+ args: DashboardDataSourceChartComponent["arguments"],
272
+ ): Promise<Array<MetricQueryConfigData>> => {
273
+ renderChartWidget(args);
274
+
275
+ await waitFor((): void => {
276
+ expect(screen.getByTestId("metric-charts")).toBeInTheDocument();
277
+ });
278
+
279
+ return getLastChartProps().metricViewData.queryConfigs;
280
+ };
281
+
282
+ const PROM_QUERY: DataSourceQueryConfig = {
283
+ id: "q1",
284
+ dataSourceId: "ds-prom",
285
+ query: "up",
286
+ };
287
+
288
+ beforeEach((): void => {
289
+ jest.clearAllMocks();
290
+ fetchTimeSeriesMock.mockResolvedValue(
291
+ buildSeries([buildPoint(1, "2026-08-10T09:15:00.000Z")]),
292
+ );
293
+ getAttributeKeysMock.mockReturnValue([]);
294
+ });
295
+
296
+ afterEach((): void => {
297
+ cleanup();
298
+ setPublicDashboardContext(null);
299
+ });
300
+
301
+ describe("Data Source chart synthetic MetricViewData", () => {
302
+ describe("the synthetic config exposes no OneUptime metric surface", () => {
303
+ /*
304
+ * The one clause that keeps the chart layer from treating an external
305
+ * query as a metric query. MetricCharts branches on filterData to decide
306
+ * whether it can fetch exemplars/metadata for the named metric; a
307
+ * populated filterData here means requests to OneUptime for a series
308
+ * that came out of somebody's Prometheus.
309
+ */
310
+ test("filterData is empty, so no metric-exemplar fetch can be keyed off it", async () => {
311
+ const configs: Array<MetricQueryConfigData> = await renderAndGetConfigs({
312
+ queries: [PROM_QUERY],
313
+ });
314
+
315
+ expect(configs).toHaveLength(1);
316
+ expect(configs[0]!.metricQueryData.filterData).toEqual({});
317
+ // toEqual treats an explicit `undefined` key as absent; this does not.
318
+ expect(Object.keys(configs[0]!.metricQueryData.filterData)).toHaveLength(
319
+ 0,
320
+ );
321
+ });
322
+
323
+ test("filterData stays empty for every query, not just the first", async () => {
324
+ const configs: Array<MetricQueryConfigData> = await renderAndGetConfigs({
325
+ queries: [
326
+ PROM_QUERY,
327
+ { id: "q2", dataSourceId: "ds-pg", query: "select 1" },
328
+ ],
329
+ });
330
+
331
+ expect(configs).toHaveLength(2);
332
+ for (const config of configs) {
333
+ expect(Object.keys(config.metricQueryData.filterData)).toHaveLength(0);
334
+ }
335
+ });
336
+
337
+ test("no formula configs are synthesised for external data", async () => {
338
+ await renderAndGetConfigs({ queries: [PROM_QUERY] });
339
+
340
+ expect(getLastChartProps().metricViewData.formulaConfigs).toEqual([]);
341
+ });
342
+ });
343
+
344
+ describe("groupByAttributeKeys is the forwarded attribute-key list", () => {
345
+ test("whatever getAttributeKeys returns is passed straight through", async () => {
346
+ getAttributeKeysMock.mockReturnValue(SENTINEL_ATTRIBUTE_KEYS);
347
+
348
+ const configs: Array<MetricQueryConfigData> = await renderAndGetConfigs({
349
+ queries: [PROM_QUERY],
350
+ });
351
+
352
+ expect(configs[0]!.metricQueryData.groupByAttributeKeys).toEqual(
353
+ SENTINEL_ATTRIBUTE_KEYS,
354
+ );
355
+ });
356
+
357
+ test("getAttributeKeys is asked about the result, not the query", async () => {
358
+ const result: AggregatedResult = buildSeries([
359
+ buildPoint(5, "2026-08-10T09:15:00.000Z", { instance: "a:9090" }),
360
+ ]);
361
+ fetchTimeSeriesMock.mockResolvedValue(result);
362
+
363
+ await renderAndGetConfigs({ queries: [PROM_QUERY] });
364
+
365
+ const lastCall: Array<unknown> =
366
+ getAttributeKeysMock.mock.calls[
367
+ getAttributeKeysMock.mock.calls.length - 1
368
+ ]!;
369
+ expect(lastCall[0]).toBe(result);
370
+ });
371
+
372
+ /*
373
+ * `[]` and `undefined` are NOT the same instruction to the chart layer:
374
+ * an empty array is a group-by with no keys, undefined is "do not group
375
+ * at all". A result with no attributes must produce the second.
376
+ */
377
+ test("no attributes means undefined, never an empty array", async () => {
378
+ getAttributeKeysMock.mockReturnValue([]);
379
+
380
+ const configs: Array<MetricQueryConfigData> = await renderAndGetConfigs({
381
+ queries: [PROM_QUERY],
382
+ });
383
+
384
+ expect(configs[0]!.metricQueryData.groupByAttributeKeys).toBeUndefined();
385
+ expect(configs[0]!.metricQueryData.groupByAttributeKeys).not.toEqual([]);
386
+ });
387
+ });
388
+
389
+ describe("the legend field is a three-way decision", () => {
390
+ test("no legend falls back to a positional Query N name", async () => {
391
+ const configs: Array<MetricQueryConfigData> = await renderAndGetConfigs({
392
+ queries: [
393
+ { id: "q1", dataSourceId: "ds-prom", query: "up" },
394
+ { id: "q2", dataSourceId: "ds-pg", query: "select 1" },
395
+ ],
396
+ });
397
+
398
+ expect(
399
+ configs.map((config: MetricQueryConfigData): string | undefined => {
400
+ return config.metricAliasData?.legend;
401
+ }),
402
+ ).toEqual(["Query 1", "Query 2"]);
403
+ });
404
+
405
+ test("a literal legend is used verbatim", async () => {
406
+ const configs: Array<MetricQueryConfigData> = await renderAndGetConfigs({
407
+ queries: [
408
+ { id: "q1", dataSourceId: "ds-prom", query: "up", legend: "errors" },
409
+ ],
410
+ });
411
+
412
+ expect(configs[0]!.metricAliasData?.legend).toBe("errors");
413
+ });
414
+
415
+ /*
416
+ * A template cannot name the whole query — it names each series
417
+ * separately, which only getSeries can do. Leaving the literal
418
+ * "{{instance}}" in the legend would put the raw template in the chart
419
+ * legend for every series.
420
+ */
421
+ test("a templated legend clears the static legend entirely", async () => {
422
+ const configs: Array<MetricQueryConfigData> = await renderAndGetConfigs({
423
+ queries: [
424
+ {
425
+ id: "q1",
426
+ dataSourceId: "ds-prom",
427
+ query: "up",
428
+ legend: "{{instance}}",
429
+ },
430
+ ],
431
+ });
432
+
433
+ expect(configs[0]!.metricAliasData?.legend).toBeUndefined();
434
+ });
435
+
436
+ test("a templated legend does not fall back to Query N either", async () => {
437
+ const configs: Array<MetricQueryConfigData> = await renderAndGetConfigs({
438
+ queries: [
439
+ {
440
+ id: "q1",
441
+ dataSourceId: "ds-prom",
442
+ query: "up",
443
+ legend: "{{instance}} ({{job}})",
444
+ },
445
+ ],
446
+ });
447
+
448
+ expect(configs[0]!.metricAliasData?.legend).not.toBe("Query 1");
449
+ expect(configs[0]!.metricAliasData?.legend).toBeUndefined();
450
+ });
451
+
452
+ test("each query decides for itself, in its own position", async () => {
453
+ const configs: Array<MetricQueryConfigData> = await renderAndGetConfigs({
454
+ queries: [
455
+ {
456
+ id: "q1",
457
+ dataSourceId: "ds-prom",
458
+ query: "up",
459
+ legend: "{{instance}}",
460
+ },
461
+ { id: "q2", dataSourceId: "ds-pg", query: "select 1" },
462
+ {
463
+ id: "q3",
464
+ dataSourceId: "ds-prom",
465
+ query: "rate(x[5m])",
466
+ legend: "errors",
467
+ },
468
+ ],
469
+ });
470
+
471
+ expect(
472
+ configs.map((config: MetricQueryConfigData): string | undefined => {
473
+ return config.metricAliasData?.legend;
474
+ }),
475
+ ).toEqual([undefined, "Query 2", "errors"]);
476
+ });
477
+ });
478
+
479
+ describe("the getSeries hook exists only for templated legends", () => {
480
+ type GetSeriesForFunction = (
481
+ legend: string | undefined,
482
+ ) => Promise<MetricQueryConfigData["getSeries"]>;
483
+
484
+ const getSeriesFor: GetSeriesForFunction = async (
485
+ legend: string | undefined,
486
+ ): Promise<MetricQueryConfigData["getSeries"]> => {
487
+ const configs: Array<MetricQueryConfigData> = await renderAndGetConfigs({
488
+ queries: [
489
+ {
490
+ id: "q1",
491
+ dataSourceId: "ds-prom",
492
+ query: "up",
493
+ ...(legend === undefined ? {} : { legend: legend }),
494
+ },
495
+ ],
496
+ });
497
+
498
+ return configs[0]!.getSeries;
499
+ };
500
+
501
+ test("a templated legend installs the hook", async () => {
502
+ expect(await getSeriesFor("{{instance}}")).toBeDefined();
503
+ });
504
+
505
+ test("a literal legend installs no hook", async () => {
506
+ expect(await getSeriesFor("errors")).toBeUndefined();
507
+ });
508
+
509
+ test("no legend at all installs no hook", async () => {
510
+ expect(await getSeriesFor(undefined)).toBeUndefined();
511
+ });
512
+
513
+ test("the hook names a series from that point's attributes", async () => {
514
+ const getSeries: MetricQueryConfigData["getSeries"] =
515
+ await getSeriesFor("{{instance}}");
516
+
517
+ const series: ChartSeries = getSeries!({
518
+ attributes: { instance: "a:9090" },
519
+ } as unknown as AggregatedModel);
520
+
521
+ expect(series).toEqual({ title: "a:9090" });
522
+ });
523
+
524
+ /*
525
+ * A point that carries no attributes at all still has to get a name —
526
+ * an empty title collapses every such series into one nameless entry.
527
+ */
528
+ test("a point with empty attributes renders the unset marker", async () => {
529
+ const getSeries: MetricQueryConfigData["getSeries"] =
530
+ await getSeriesFor("{{instance}}");
531
+
532
+ expect(
533
+ getSeries!({ attributes: {} } as unknown as AggregatedModel),
534
+ ).toEqual({ title: "(unset)" });
535
+ });
536
+
537
+ test("a point with no attributes object at all renders the unset marker", async () => {
538
+ const getSeries: MetricQueryConfigData["getSeries"] =
539
+ await getSeriesFor("{{instance}}");
540
+
541
+ expect(getSeries!(buildPoint(1, "2026-08-10T09:15:00.000Z"))).toEqual({
542
+ title: "(unset)",
543
+ });
544
+ });
545
+
546
+ test("the hook resolves every placeholder in a multi-token template", async () => {
547
+ const getSeries: MetricQueryConfigData["getSeries"] = await getSeriesFor(
548
+ "{{instance}} ({{job}})",
549
+ );
550
+
551
+ expect(
552
+ getSeries!({
553
+ attributes: { instance: "a:9090", job: "api" },
554
+ } as unknown as AggregatedModel),
555
+ ).toEqual({ title: "a:9090 (api)" });
556
+ });
557
+ });
558
+
559
+ describe("the widget's chart type maps onto the chart layer's", () => {
560
+ interface ChartTypeCase {
561
+ label: string;
562
+ dashboardChartType: DashboardChartType | undefined;
563
+ expectedMetricChartType: MetricChartType;
564
+ }
565
+
566
+ const CHART_TYPE_CASES: Array<ChartTypeCase> = [
567
+ {
568
+ label: "Bar",
569
+ dashboardChartType: DashboardChartType.Bar,
570
+ expectedMetricChartType: MetricChartType.BAR,
571
+ },
572
+ {
573
+ label: "Area",
574
+ dashboardChartType: DashboardChartType.Area,
575
+ expectedMetricChartType: MetricChartType.AREA,
576
+ },
577
+ /*
578
+ * StackedArea is a one-line branch that shares its return with Area.
579
+ * Drop it from the condition and the widget silently draws lines.
580
+ */
581
+ {
582
+ label: "Stacked Area",
583
+ dashboardChartType: DashboardChartType.StackedArea,
584
+ expectedMetricChartType: MetricChartType.AREA,
585
+ },
586
+ {
587
+ label: "Line",
588
+ dashboardChartType: DashboardChartType.Line,
589
+ expectedMetricChartType: MetricChartType.LINE,
590
+ },
591
+ {
592
+ label: "an unset chart type",
593
+ dashboardChartType: undefined,
594
+ expectedMetricChartType: MetricChartType.LINE,
595
+ },
596
+ ];
597
+
598
+ for (const chartTypeCase of CHART_TYPE_CASES) {
599
+ test(`${chartTypeCase.label} becomes ${chartTypeCase.expectedMetricChartType}`, async () => {
600
+ const configs: Array<MetricQueryConfigData> = await renderAndGetConfigs(
601
+ {
602
+ queries: [PROM_QUERY],
603
+ ...(chartTypeCase.dashboardChartType === undefined
604
+ ? {}
605
+ : { chartType: chartTypeCase.dashboardChartType }),
606
+ },
607
+ );
608
+
609
+ expect(configs[0]!.chartType).toBe(
610
+ chartTypeCase.expectedMetricChartType,
611
+ );
612
+ });
613
+ }
614
+
615
+ test("the chart type is applied to every query, not only the first", async () => {
616
+ const configs: Array<MetricQueryConfigData> = await renderAndGetConfigs({
617
+ queries: [
618
+ PROM_QUERY,
619
+ { id: "q2", dataSourceId: "ds-pg", query: "select 1" },
620
+ ],
621
+ chartType: DashboardChartType.Bar,
622
+ });
623
+
624
+ expect(
625
+ configs.map(
626
+ (config: MetricQueryConfigData): MetricChartType | undefined => {
627
+ return config.chartType;
628
+ },
629
+ ),
630
+ ).toEqual([MetricChartType.BAR, MetricChartType.BAR]);
631
+ });
632
+ });
633
+
634
+ describe("config identity and index alignment", () => {
635
+ /*
636
+ * Chart layers key per-chart UI state (hidden series, Top-N, sort) on
637
+ * config.id. Older persisted widgets predate the stored id, so the
638
+ * synthetic config has to invent a stable one rather than leave it
639
+ * undefined and let two charts share state.
640
+ */
641
+ test("a stored query with no id gets a positional fallback id", async () => {
642
+ const configs: Array<MetricQueryConfigData> = await renderAndGetConfigs({
643
+ queries: [
644
+ { dataSourceId: "ds-prom", query: "up" },
645
+ { id: "q-b", dataSourceId: "ds-pg", query: "select 1" },
646
+ { dataSourceId: "ds-prom", query: "rate(x[5m])" },
647
+ ],
648
+ });
649
+
650
+ expect(
651
+ configs.map((config: MetricQueryConfigData): string | undefined => {
652
+ return config.id;
653
+ }),
654
+ ).toEqual(["data-source-query-0", "q-b", "data-source-query-2"]);
655
+ });
656
+
657
+ test("the fallback id counts configured queries, skipping half-filled cards", async () => {
658
+ const configs: Array<MetricQueryConfigData> = await renderAndGetConfigs({
659
+ queries: [
660
+ // Source picked, query still empty — the user is mid-edit.
661
+ { dataSourceId: "ds-prom", query: " " },
662
+ { dataSourceId: "ds-pg", query: "select 1" },
663
+ ],
664
+ });
665
+
666
+ expect(configs).toHaveLength(1);
667
+ expect(configs[0]!.id).toBe("data-source-query-0");
668
+ });
669
+
670
+ /*
671
+ * The synthetic configs and the results array are read together by the
672
+ * chart layer, position by position. If they ever drift, query 1's
673
+ * legend ends up over query 2's data.
674
+ */
675
+ test("each configured query gets one config, paired with its own result", async () => {
676
+ fetchTimeSeriesMock.mockImplementation(
677
+ (args: DataSourceFetchArgs): Promise<AggregatedResult> => {
678
+ return Promise.resolve(
679
+ buildSeries([
680
+ buildPoint(1, "2026-08-10T09:15:00.000Z", {
681
+ query: args.queryConfig.query,
682
+ }),
683
+ ]),
684
+ );
685
+ },
686
+ );
687
+
688
+ const configs: Array<MetricQueryConfigData> = await renderAndGetConfigs({
689
+ queries: [
690
+ { id: "q1", dataSourceId: "ds-prom", query: "up" },
691
+ // Never configured — must not consume a position.
692
+ { id: "q2", dataSourceId: "", query: "select 1" },
693
+ { id: "q3", dataSourceId: "ds-pg", query: "select count(*) from t" },
694
+ ],
695
+ });
696
+
697
+ const lastProps: MetricChartsStubProps = getLastChartProps();
698
+
699
+ expect(configs).toHaveLength(2);
700
+ expect(lastProps.metricResults).toHaveLength(2);
701
+ expect(
702
+ configs.map((config: MetricQueryConfigData): string | undefined => {
703
+ return config.id;
704
+ }),
705
+ ).toEqual(["q1", "q3"]);
706
+
707
+ /*
708
+ * Identity, not shape: config[i] was built from result[i], which is
709
+ * the only thing that proves the pairing.
710
+ */
711
+ const attributeKeyArguments: Array<unknown> =
712
+ getAttributeKeysMock.mock.calls
713
+ .slice(-2)
714
+ .map((call: Array<unknown>): unknown => {
715
+ return call[0];
716
+ });
717
+
718
+ expect(attributeKeyArguments[0]).toBe(lastProps.metricResults[0]);
719
+ expect(attributeKeyArguments[1]).toBe(lastProps.metricResults[1]);
720
+ expect(
721
+ (
722
+ lastProps.metricResults[0]!.data[0] as unknown as {
723
+ attributes: Record<string, string>;
724
+ }
725
+ ).attributes["query"],
726
+ ).toBe("up");
727
+ expect(
728
+ (
729
+ lastProps.metricResults[1]!.data[0] as unknown as {
730
+ attributes: Record<string, string>;
731
+ }
732
+ ).attributes["query"],
733
+ ).toBe("select count(*) from t");
734
+ });
735
+ });
736
+ });