@oneuptime/common 12.0.6 → 12.0.7

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 (424) hide show
  1. package/Models/DatabaseModels/AIInsight.ts +1 -1
  2. package/Models/DatabaseModels/DatabaseBaseModel/FileModel.ts +2 -3
  3. package/Models/DatabaseModels/DeletedProject.ts +595 -0
  4. package/Models/DatabaseModels/Index.ts +2 -0
  5. package/Models/DatabaseModels/Monitor.ts +111 -0
  6. package/Models/DatabaseModels/Project.ts +3 -3
  7. package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +19 -1
  8. package/Server/API/FileAPI.ts +15 -2
  9. package/Server/API/MicrosoftTeamsAPI.ts +6 -1
  10. package/Server/API/ProjectAPI.ts +214 -0
  11. package/Server/API/StatusPageAPI.ts +39 -6
  12. package/Server/Infrastructure/Postgres/SchemaMigrations/1786446545142-MigrationName.ts +50 -0
  13. package/Server/Infrastructure/Postgres/SchemaMigrations/1786449497966-AddMonitorDependency.ts +67 -0
  14. package/Server/Infrastructure/Postgres/SchemaMigrations/1786461136170-AddDeletedProjectTable.ts +39 -0
  15. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
  16. package/Server/Services/AIAgentService.ts +20 -0
  17. package/Server/Services/DashboardDomainService.ts +73 -28
  18. package/Server/Services/DatabaseService.ts +1 -0
  19. package/Server/Services/DeletedProjectService.ts +138 -0
  20. package/Server/Services/FileService.ts +61 -0
  21. package/Server/Services/IncidentEpisodePublicNoteService.ts +18 -0
  22. package/Server/Services/IncidentPublicNoteService.ts +18 -0
  23. package/Server/Services/Index.ts +2 -0
  24. package/Server/Services/MonitorService.ts +311 -0
  25. package/Server/Services/ProbeService.ts +20 -0
  26. package/Server/Services/ProjectService.ts +297 -1
  27. package/Server/Services/PushNotificationService.ts +71 -0
  28. package/Server/Services/ScheduledMaintenancePublicNoteService.ts +18 -0
  29. package/Server/Services/StatusPageAnnouncementService.ts +53 -0
  30. package/Server/Services/StatusPageDomainService.ts +73 -28
  31. package/Server/Services/TeamMemberService.ts +117 -12
  32. package/Server/Services/TelemetryIngestionKeyService.ts +1 -0
  33. package/Server/Services/UserWebhookService.ts +34 -109
  34. package/Server/Services/WorkspaceNotificationRuleService.ts +69 -0
  35. package/Server/Services/WorkspaceProjectAuthTokenService.ts +37 -1
  36. package/Server/Types/Database/DeleteById.ts +2 -0
  37. package/Server/Types/Database/DeleteOneBy.ts +6 -0
  38. package/Server/Types/Domain.ts +41 -0
  39. package/Server/Types/Workflow/Components/API/Delete.ts +2 -1
  40. package/Server/Types/Workflow/Components/API/Get.ts +2 -1
  41. package/Server/Types/Workflow/Components/API/Patch.ts +2 -1
  42. package/Server/Types/Workflow/Components/API/Post.ts +2 -1
  43. package/Server/Types/Workflow/Components/API/Put.ts +2 -1
  44. package/Server/Types/Workflow/Components/API/Utils.ts +41 -2
  45. package/Server/Types/Workflow/Components/BaseModel/CreateManyBaseModel.ts +25 -19
  46. package/Server/Types/Workflow/Components/BaseModel/CreateOneBaseModel.ts +6 -5
  47. package/Server/Types/Workflow/Components/BaseModel/DeleteManyBaseModel.ts +32 -14
  48. package/Server/Types/Workflow/Components/BaseModel/DeleteOneBaseModel.ts +31 -13
  49. package/Server/Types/Workflow/Components/BaseModel/FindManyBaseModel.ts +29 -20
  50. package/Server/Types/Workflow/Components/BaseModel/FindOneBaseModel.ts +28 -21
  51. package/Server/Types/Workflow/Components/BaseModel/LogComponentError.ts +89 -0
  52. package/Server/Types/Workflow/Components/BaseModel/ModelArguments.ts +208 -0
  53. package/Server/Types/Workflow/Components/BaseModel/OnTriggerBaseModel.ts +11 -0
  54. package/Server/Types/Workflow/Components/BaseModel/UpdateManyBaseModel.ts +41 -18
  55. package/Server/Types/Workflow/Components/BaseModel/UpdateOneBaseModel.ts +45 -19
  56. package/Server/Types/Workflow/Components/Discord/SendMessageToChannel.ts +16 -9
  57. package/Server/Types/Workflow/Components/IncomingWebhookUtils.ts +66 -0
  58. package/Server/Types/Workflow/Components/MicrosoftTeams/SendMessageToChannel.ts +15 -9
  59. package/Server/Types/Workflow/Components/Slack/SendMessageToChannel.ts +17 -0
  60. package/Server/Utils/AI/Chat/ObservabilityChatPrompt.ts +1 -1
  61. package/Server/Utils/AI/CodeFix/CodeAgentWorkspaceGuard.ts +171 -0
  62. package/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.ts +3 -3
  63. package/Server/Utils/AI/SRE/Insights/FixRouting.ts +3 -2
  64. package/Server/Utils/AI/SRE/TelemetryImprovementTaskTrigger.ts +1 -1
  65. package/Server/Utils/AI/Toolbox/CodeWriteTools.ts +6 -6
  66. package/Server/Utils/CodeRepository/GitHub/GitHub.ts +43 -5
  67. package/Server/Utils/DataSource/EgressGuard.ts +176 -16
  68. package/Server/Utils/DataSource/HttpFetch.ts +6 -45
  69. package/Server/Utils/Execute.ts +8 -0
  70. package/Server/Utils/InlineImageAccessTokenSync.ts +23 -0
  71. package/Server/Utils/LLM/LLMService.ts +57 -12
  72. package/Server/Utils/Monitor/MonitorAlert.ts +40 -0
  73. package/Server/Utils/Monitor/MonitorDependencySuppression.ts +192 -0
  74. package/Server/Utils/Monitor/MonitorIncident.ts +40 -0
  75. package/Server/Utils/Monitor/MonitorResource.ts +36 -0
  76. package/Server/Utils/Response.ts +142 -6
  77. package/Server/Utils/SSRFProtection.ts +273 -60
  78. package/Server/Utils/StartServer.ts +8 -0
  79. package/Server/Utils/VM/VMRunner.ts +88 -1
  80. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +555 -49
  81. package/Server/Utils/Workspace/Slack/Slack.ts +25 -2
  82. package/Server/Utils/Workspace/WorkspaceBase.ts +6 -0
  83. package/Tests/App/Dashboard/DangerZone.test.tsx +334 -0
  84. package/Tests/App/Dashboard/DashboardVariableAllContract.test.tsx +539 -0
  85. package/Tests/App/Dashboard/DashboardVariableSelector.test.tsx +678 -0
  86. package/Tests/App/Dashboard/DashboardVariablesDiscard.test.tsx +706 -0
  87. package/Tests/App/Dashboard/DashboardVariablesModal.test.tsx +508 -0
  88. package/Tests/App/PublicDashboard/DashboardVariableSelector.test.tsx +470 -0
  89. package/Tests/App/StatusPage/StatusPageDetailPagesNotFound.test.tsx +308 -0
  90. package/Tests/Models/DatabaseModels/DeletedProjectModel.test.ts +251 -0
  91. package/Tests/Models/DatabaseModels/SavedViewJSONColumnTuples.test.ts +115 -0
  92. package/Tests/Server/API/FileAPIAccessControl.test.ts +316 -0
  93. package/Tests/Server/API/ProjectAPI.test.ts +299 -1
  94. package/Tests/Server/API/ProjectAPIAdjustBalance.test.ts +459 -0
  95. package/Tests/Server/API/ProjectAPIAdjustBalanceBillingDisabled.test.ts +177 -0
  96. package/Tests/Server/Services/DatabaseServiceDeletionReason.test.ts +123 -0
  97. package/Tests/Server/Services/DeletedProjectService.test.ts +415 -0
  98. package/Tests/Server/Services/DeletedProjectServiceSelfHosted.test.ts +70 -0
  99. package/Tests/Server/Services/DomainSubdomainHooks.test.ts +94 -0
  100. package/Tests/Server/Services/FileIsPublicBooleanMigration.test.ts +244 -0
  101. package/Tests/Server/Services/FileServiceMimeType.test.ts +89 -0
  102. package/Tests/Server/Services/MonitorServiceDependencyValidation.test.ts +702 -0
  103. package/Tests/Server/Services/ProjectServiceAdjustBalance.test.ts +615 -0
  104. package/Tests/Server/Services/ProjectServiceDeleteAudit.test.ts +406 -0
  105. package/Tests/Server/Services/PublishTimeImageVisibility.test.ts +450 -0
  106. package/Tests/Server/Services/TeamMemberAutoAcceptInvitation.test.ts +669 -0
  107. package/Tests/Server/Services/UserWebhookSSRF.test.ts +174 -0
  108. package/Tests/Server/Services/WebPushEndpointAllowlist.test.ts +133 -0
  109. package/Tests/Server/Services/WorkspaceProjectAuthTokenRepoint.test.ts +618 -0
  110. package/Tests/Server/Types/Workflow/Components/ApiComponentErrorPort.test.ts +26 -1
  111. package/Tests/Server/Types/Workflow/Components/ApiComponentSsrf.test.ts +215 -0
  112. package/Tests/Server/Types/Workflow/Components/BaseModelDatabaseComponents.test.ts +742 -0
  113. package/Tests/Server/Types/Workflow/Components/ChatWebhookComponents.test.ts +256 -0
  114. package/Tests/Server/Types/Workflow/Components/ModelArguments.test.ts +371 -0
  115. package/Tests/Server/Utils/AI/CodeAgentCommandGuard.test.ts +204 -0
  116. package/Tests/Server/Utils/AI/CodeAgentWriteLimits.test.ts +213 -0
  117. package/Tests/Server/Utils/AI/CodeWriteTools.test.ts +52 -5
  118. package/Tests/Server/Utils/AI/LLMServiceBaseUrl.test.ts +3 -0
  119. package/Tests/Server/Utils/AI/LLMServiceEgressGuard.test.ts +315 -0
  120. package/Tests/Server/Utils/AI/LLMServiceModelCompatibility.test.ts +3 -0
  121. package/Tests/Server/Utils/AI/LLMServiceRequestPolicy.test.ts +17 -5
  122. package/Tests/Server/Utils/AI/LLMServiceToolCalling.test.ts +14 -1
  123. package/Tests/Server/Utils/AI/ObservabilityChatPrompt.test.ts +35 -0
  124. package/Tests/Server/Utils/AI/StubLLMEgressGuard.ts +25 -0
  125. package/Tests/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.test.ts +62 -7
  126. package/Tests/Server/Utils/DataSource/EgressGuard.test.ts +69 -0
  127. package/Tests/Server/Utils/DataSource/EgressGuardPinning.test.ts +330 -0
  128. package/Tests/Server/Utils/GitHubCreatePullRequestWithToken.test.ts +393 -0
  129. package/Tests/Server/Utils/InlineImageAccessTokenSync.test.ts +202 -0
  130. package/Tests/Server/Utils/Monitor/MonitorDependencySuppression.test.ts +811 -0
  131. package/Tests/Server/Utils/Monitor/MonitorDependencySuppressionCreatorSkip.test.ts +604 -0
  132. package/Tests/Server/Utils/ResponseSendFileResponse.test.ts +192 -0
  133. package/Tests/Server/Utils/SSRFProtectionBypasses.test.ts +406 -0
  134. package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +194 -0
  135. package/Tests/Server/Utils/Workspace/MicrosoftTeamsChannelSend.test.ts +1169 -0
  136. package/Tests/Server/Utils/Workspace/MicrosoftTeamsChannelsList.test.ts +2 -0
  137. package/Tests/Server/Utils/Workspace/MicrosoftTeamsTeamInstalls.test.ts +1605 -0
  138. package/Tests/Server/Utils/Workspace/MicrosoftTeamsTenantResolution.test.ts +1218 -0
  139. package/Tests/Types/AI/AIChatMessageStatus.test.ts +79 -0
  140. package/Tests/Types/AI/AIInsightStatus.test.ts +40 -0
  141. package/Tests/Types/API/HostnameAuthorityParsing.test.ts +157 -0
  142. package/Tests/Types/Dashboard/DashboardTemplateInvariants.test.ts +27 -0
  143. package/Tests/Types/DataSource/DataSourceLimits.test.ts +71 -0
  144. package/Tests/Types/DataSource/DataSourceType.test.ts +181 -0
  145. package/Tests/Types/DomainSubdomainValidation.test.ts +90 -0
  146. package/Tests/Types/JSONFunctions.test.ts +252 -1
  147. package/Tests/Types/Monitor/SnmpMonitor/SnmpAuthProtocol.test.ts +61 -0
  148. package/Tests/Types/Monitor/SnmpMonitor/SnmpPrivProtocol.test.ts +62 -0
  149. package/Tests/Types/Monitor/SnmpMonitor/SnmpSecurityLevel.test.ts +68 -0
  150. package/Tests/Types/Monitor/SnmpMonitor/SnmpVersion.test.ts +51 -0
  151. package/Tests/UI/Components/404.test.tsx +1 -1
  152. package/Tests/UI/Components/Alert.test.tsx +1 -1
  153. package/Tests/UI/Components/Badge.test.tsx +1 -1
  154. package/Tests/UI/Components/BasicForm.test.tsx +39 -10
  155. package/Tests/UI/Components/Button.test.tsx +1 -1
  156. package/Tests/UI/Components/Card.test.tsx +1 -1
  157. package/Tests/UI/Components/Charts/AxisTickColor.test.tsx +1 -1
  158. package/Tests/UI/Components/ColorViewer.test.tsx +1 -1
  159. package/Tests/UI/Components/ComponentsModal.test.tsx +7 -1
  160. package/Tests/UI/Components/DictionaryOfStrings.test.tsx +1 -1
  161. package/Tests/UI/Components/Dropdown.test.tsx +1 -1
  162. package/Tests/UI/Components/FilePicker.test.tsx +1 -1
  163. package/Tests/UI/Components/HiddenText.test.tsx +1 -1
  164. package/Tests/UI/Components/Input.test.tsx +1 -1
  165. package/Tests/UI/Components/Loader.test.tsx +1 -1
  166. package/Tests/UI/Components/LogTimeRangePicker.test.tsx +1 -1
  167. package/Tests/UI/Components/MasterPage.test.tsx +1 -1
  168. package/Tests/UI/Components/ModalPortalDismissal.test.tsx +489 -0
  169. package/Tests/UI/Components/ModelDelete.test.tsx +214 -0
  170. package/Tests/UI/Components/ModelTable/BaseModelTableBulkSelectAll.test.tsx +1 -1
  171. package/Tests/UI/Components/ModelTable/BaseModelTableColumnCustomization.test.tsx +1 -1
  172. package/Tests/UI/Components/ModelTable/BaseModelTableSearchLabels.test.tsx +1 -1
  173. package/Tests/UI/Components/ModelTable/BaseModelTableUrlState.test.tsx +1 -1
  174. package/Tests/UI/Components/ModelTable/CustomFieldColumns.test.tsx +1 -1
  175. package/Tests/UI/Components/NavBar.test.tsx +1 -1
  176. package/Tests/UI/Components/OperatorSelectorKeyboard.test.tsx +1 -1
  177. package/Tests/UI/Components/Pagination.test.tsx +1 -1
  178. package/Tests/UI/Components/Pill.test.tsx +1 -1
  179. package/Tests/UI/Components/Probe.test.tsx +1 -1
  180. package/Tests/UI/Components/ProgressBar.test.tsx +1 -1
  181. package/Tests/UI/Components/RadioButtons.test.tsx +1 -1
  182. package/Tests/UI/Components/SideMenuItem.test.tsx +1 -1
  183. package/Tests/UI/Components/SideOver.test.tsx +500 -6
  184. package/Tests/UI/Components/Tabs.test.tsx +1 -1
  185. package/Tests/UI/Components/TelemetrySearchBar.test.tsx +1 -1
  186. package/Tests/UI/Components/TelemetryTimeRangePicker.test.tsx +1 -1
  187. package/Tests/UI/Components/TextArea.test.tsx +1 -1
  188. package/Tests/UI/Components/Toast.test.tsx +1 -1
  189. package/Tests/UI/Components/Toggle.test.tsx +1 -1
  190. package/Tests/UI/Components/TopSection.test.tsx +1 -1
  191. package/Tests/UI/Components/UseLiveLogsRefresh.test.tsx +1 -1
  192. package/Tests/UI/Rum/ReplayScrubber.test.tsx +1 -1
  193. package/Tests/UI/Rum/ReplayStage.test.tsx +1 -1
  194. package/Tests/UI/Telemetry/TelemetrySnapshotWindowAlert.test.tsx +1 -1
  195. package/Tests/UI/Utils/LocalStorageArrayRoundTrip.test.ts +72 -0
  196. package/Tests/Utils/Dashboard/HtmlWidgetDocument.test.ts +19 -2
  197. package/Tests/Utils/Dashboard/ModelQueryVariableInterpolation.test.ts +44 -0
  198. package/Tests/Utils/Dashboard/VariableInterpolation.test.ts +288 -5
  199. package/Tests/Utils/Dashboard/VariableUrlState.test.ts +42 -0
  200. package/Tests/Utils/DataSource/DataSourceQueryText.test.ts +27 -0
  201. package/Tests/Utils/LegacySerializedArray.test.ts +139 -0
  202. package/Tests/Utils/Monitor/MonitorDependencyRule.test.ts +190 -0
  203. package/Tests/Utils/Realtime.test.ts +78 -0
  204. package/Tests/Utils/Telemetry/SavedViewFilters.test.ts +246 -0
  205. package/Tests/__mocks__/i18next-browser-languagedetector.js +21 -0
  206. package/Types/AI/FixPullRequestCiStatus.ts +1 -1
  207. package/Types/AI/FixVerificationStatus.ts +2 -2
  208. package/Types/API/Hostname.ts +92 -4
  209. package/Types/API/URL.ts +43 -25
  210. package/Types/Billing/BalanceAdjustmentType.ts +14 -0
  211. package/Types/Billing/ProjectBalanceType.ts +13 -0
  212. package/Types/Domain.ts +26 -0
  213. package/Types/File/MimeType.ts +11 -0
  214. package/Types/JSONFunctions.ts +15 -0
  215. package/Types/Telemetry/TelemetrySavedViewState.ts +9 -1
  216. package/Types/Workflow/Components/BaseModel.ts +92 -28
  217. package/Typings/Index.d.ts +12 -0
  218. package/UI/Components/GanttChart/ChartContainer.tsx +4 -3
  219. package/UI/Components/Modal/ConfirmModal.tsx +10 -5
  220. package/UI/Components/Modal/Modal.tsx +27 -47
  221. package/UI/Components/ModelDelete/ModelDelete.tsx +23 -6
  222. package/UI/Components/SideOver/SideOver.tsx +195 -68
  223. package/UI/Utils/PageScrollLock.ts +66 -0
  224. package/Utils/Dashboard/HtmlWidgetDocument.ts +4 -2
  225. package/Utils/Dashboard/VariableInterpolation.ts +19 -1
  226. package/Utils/LegacySerializedArray.ts +60 -0
  227. package/Utils/Monitor/MonitorDependencyRule.ts +88 -0
  228. package/Utils/Telemetry/SavedViewFilters.ts +88 -0
  229. package/build/dist/Models/DatabaseModels/AIInsight.js +1 -1
  230. package/build/dist/Models/DatabaseModels/AIInsight.js.map +1 -1
  231. package/build/dist/Models/DatabaseModels/DatabaseBaseModel/FileModel.js +2 -3
  232. package/build/dist/Models/DatabaseModels/DatabaseBaseModel/FileModel.js.map +1 -1
  233. package/build/dist/Models/DatabaseModels/DeletedProject.js +640 -0
  234. package/build/dist/Models/DatabaseModels/DeletedProject.js.map +1 -0
  235. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  236. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  237. package/build/dist/Models/DatabaseModels/Monitor.js +106 -0
  238. package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
  239. package/build/dist/Models/DatabaseModels/Project.js +3 -3
  240. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  241. package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
  242. package/build/dist/Server/API/FileAPI.js +14 -2
  243. package/build/dist/Server/API/FileAPI.js.map +1 -1
  244. package/build/dist/Server/API/MicrosoftTeamsAPI.js +6 -1
  245. package/build/dist/Server/API/MicrosoftTeamsAPI.js.map +1 -1
  246. package/build/dist/Server/API/ProjectAPI.js +157 -4
  247. package/build/dist/Server/API/ProjectAPI.js.map +1 -1
  248. package/build/dist/Server/API/StatusPageAPI.js +27 -3
  249. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  250. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786446545142-MigrationName.js +34 -0
  251. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786446545142-MigrationName.js.map +1 -0
  252. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786449497966-AddMonitorDependency.js +30 -0
  253. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786449497966-AddMonitorDependency.js.map +1 -0
  254. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786461136170-AddDeletedProjectTable.js +20 -0
  255. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786461136170-AddDeletedProjectTable.js.map +1 -0
  256. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
  257. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  258. package/build/dist/Server/Services/AIAgentService.js +17 -0
  259. package/build/dist/Server/Services/AIAgentService.js.map +1 -1
  260. package/build/dist/Server/Services/DashboardDomainService.js +55 -18
  261. package/build/dist/Server/Services/DashboardDomainService.js.map +1 -1
  262. package/build/dist/Server/Services/DatabaseService.js +1 -0
  263. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  264. package/build/dist/Server/Services/DeletedProjectService.js +124 -0
  265. package/build/dist/Server/Services/DeletedProjectService.js.map +1 -0
  266. package/build/dist/Server/Services/FileService.js +52 -0
  267. package/build/dist/Server/Services/FileService.js.map +1 -1
  268. package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js +10 -1
  269. package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js.map +1 -1
  270. package/build/dist/Server/Services/IncidentPublicNoteService.js +10 -1
  271. package/build/dist/Server/Services/IncidentPublicNoteService.js.map +1 -1
  272. package/build/dist/Server/Services/Index.js +2 -0
  273. package/build/dist/Server/Services/Index.js.map +1 -1
  274. package/build/dist/Server/Services/MonitorService.js +232 -0
  275. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  276. package/build/dist/Server/Services/ProbeService.js +17 -0
  277. package/build/dist/Server/Services/ProbeService.js.map +1 -1
  278. package/build/dist/Server/Services/ProjectService.js +228 -6
  279. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  280. package/build/dist/Server/Services/PushNotificationService.js +56 -0
  281. package/build/dist/Server/Services/PushNotificationService.js.map +1 -1
  282. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js +10 -1
  283. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js.map +1 -1
  284. package/build/dist/Server/Services/StatusPageAnnouncementService.js +54 -0
  285. package/build/dist/Server/Services/StatusPageAnnouncementService.js.map +1 -1
  286. package/build/dist/Server/Services/StatusPageDomainService.js +55 -18
  287. package/build/dist/Server/Services/StatusPageDomainService.js.map +1 -1
  288. package/build/dist/Server/Services/TeamMemberService.js +97 -6
  289. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  290. package/build/dist/Server/Services/TelemetryIngestionKeyService.js +1 -0
  291. package/build/dist/Server/Services/TelemetryIngestionKeyService.js.map +1 -1
  292. package/build/dist/Server/Services/UserWebhookService.js +31 -87
  293. package/build/dist/Server/Services/UserWebhookService.js.map +1 -1
  294. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +65 -0
  295. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
  296. package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js +23 -0
  297. package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js.map +1 -1
  298. package/build/dist/Server/Types/Domain.js +37 -0
  299. package/build/dist/Server/Types/Domain.js.map +1 -1
  300. package/build/dist/Server/Types/Workflow/Components/API/Delete.js +2 -1
  301. package/build/dist/Server/Types/Workflow/Components/API/Delete.js.map +1 -1
  302. package/build/dist/Server/Types/Workflow/Components/API/Get.js +2 -1
  303. package/build/dist/Server/Types/Workflow/Components/API/Get.js.map +1 -1
  304. package/build/dist/Server/Types/Workflow/Components/API/Patch.js +2 -1
  305. package/build/dist/Server/Types/Workflow/Components/API/Patch.js.map +1 -1
  306. package/build/dist/Server/Types/Workflow/Components/API/Post.js +2 -1
  307. package/build/dist/Server/Types/Workflow/Components/API/Post.js.map +1 -1
  308. package/build/dist/Server/Types/Workflow/Components/API/Put.js +2 -1
  309. package/build/dist/Server/Types/Workflow/Components/API/Put.js.map +1 -1
  310. package/build/dist/Server/Types/Workflow/Components/API/Utils.js +35 -2
  311. package/build/dist/Server/Types/Workflow/Components/API/Utils.js.map +1 -1
  312. package/build/dist/Server/Types/Workflow/Components/BaseModel/CreateManyBaseModel.js +15 -11
  313. package/build/dist/Server/Types/Workflow/Components/BaseModel/CreateManyBaseModel.js.map +1 -1
  314. package/build/dist/Server/Types/Workflow/Components/BaseModel/CreateOneBaseModel.js +2 -3
  315. package/build/dist/Server/Types/Workflow/Components/BaseModel/CreateOneBaseModel.js.map +1 -1
  316. package/build/dist/Server/Types/Workflow/Components/BaseModel/DeleteManyBaseModel.js +21 -10
  317. package/build/dist/Server/Types/Workflow/Components/BaseModel/DeleteManyBaseModel.js.map +1 -1
  318. package/build/dist/Server/Types/Workflow/Components/BaseModel/DeleteOneBaseModel.js +21 -10
  319. package/build/dist/Server/Types/Workflow/Components/BaseModel/DeleteOneBaseModel.js.map +1 -1
  320. package/build/dist/Server/Types/Workflow/Components/BaseModel/FindManyBaseModel.js +18 -13
  321. package/build/dist/Server/Types/Workflow/Components/BaseModel/FindManyBaseModel.js.map +1 -1
  322. package/build/dist/Server/Types/Workflow/Components/BaseModel/FindOneBaseModel.js +18 -13
  323. package/build/dist/Server/Types/Workflow/Components/BaseModel/FindOneBaseModel.js.map +1 -1
  324. package/build/dist/Server/Types/Workflow/Components/BaseModel/LogComponentError.js +43 -0
  325. package/build/dist/Server/Types/Workflow/Components/BaseModel/LogComponentError.js.map +1 -0
  326. package/build/dist/Server/Types/Workflow/Components/BaseModel/ModelArguments.js +116 -0
  327. package/build/dist/Server/Types/Workflow/Components/BaseModel/ModelArguments.js.map +1 -0
  328. package/build/dist/Server/Types/Workflow/Components/BaseModel/OnTriggerBaseModel.js +7 -0
  329. package/build/dist/Server/Types/Workflow/Components/BaseModel/OnTriggerBaseModel.js.map +1 -1
  330. package/build/dist/Server/Types/Workflow/Components/BaseModel/UpdateManyBaseModel.js +24 -13
  331. package/build/dist/Server/Types/Workflow/Components/BaseModel/UpdateManyBaseModel.js.map +1 -1
  332. package/build/dist/Server/Types/Workflow/Components/BaseModel/UpdateOneBaseModel.js +27 -13
  333. package/build/dist/Server/Types/Workflow/Components/BaseModel/UpdateOneBaseModel.js.map +1 -1
  334. package/build/dist/Server/Types/Workflow/Components/Discord/SendMessageToChannel.js +14 -6
  335. package/build/dist/Server/Types/Workflow/Components/Discord/SendMessageToChannel.js.map +1 -1
  336. package/build/dist/Server/Types/Workflow/Components/IncomingWebhookUtils.js +42 -0
  337. package/build/dist/Server/Types/Workflow/Components/IncomingWebhookUtils.js.map +1 -0
  338. package/build/dist/Server/Types/Workflow/Components/MicrosoftTeams/SendMessageToChannel.js +15 -6
  339. package/build/dist/Server/Types/Workflow/Components/MicrosoftTeams/SendMessageToChannel.js.map +1 -1
  340. package/build/dist/Server/Types/Workflow/Components/Slack/SendMessageToChannel.js +10 -2
  341. package/build/dist/Server/Types/Workflow/Components/Slack/SendMessageToChannel.js.map +1 -1
  342. package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js +1 -1
  343. package/build/dist/Server/Utils/AI/CodeFix/CodeAgentWorkspaceGuard.js +141 -0
  344. package/build/dist/Server/Utils/AI/CodeFix/CodeAgentWorkspaceGuard.js.map +1 -1
  345. package/build/dist/Server/Utils/AI/SRE/Insights/FixRouting.js.map +1 -1
  346. package/build/dist/Server/Utils/AI/SRE/TelemetryImprovementTaskTrigger.js +1 -1
  347. package/build/dist/Server/Utils/AI/Toolbox/CodeWriteTools.js +6 -6
  348. package/build/dist/Server/Utils/AI/Toolbox/CodeWriteTools.js.map +1 -1
  349. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js +39 -5
  350. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js.map +1 -1
  351. package/build/dist/Server/Utils/DataSource/EgressGuard.js +94 -10
  352. package/build/dist/Server/Utils/DataSource/EgressGuard.js.map +1 -1
  353. package/build/dist/Server/Utils/DataSource/HttpFetch.js +1 -19
  354. package/build/dist/Server/Utils/DataSource/HttpFetch.js.map +1 -1
  355. package/build/dist/Server/Utils/Execute.js +2 -2
  356. package/build/dist/Server/Utils/Execute.js.map +1 -1
  357. package/build/dist/Server/Utils/InlineImageAccessTokenSync.js +13 -0
  358. package/build/dist/Server/Utils/InlineImageAccessTokenSync.js.map +1 -1
  359. package/build/dist/Server/Utils/LLM/LLMService.js +43 -12
  360. package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
  361. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +44 -24
  362. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  363. package/build/dist/Server/Utils/Monitor/MonitorDependencySuppression.js +158 -0
  364. package/build/dist/Server/Utils/Monitor/MonitorDependencySuppression.js.map +1 -0
  365. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +50 -30
  366. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  367. package/build/dist/Server/Utils/Monitor/MonitorResource.js +32 -0
  368. package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
  369. package/build/dist/Server/Utils/Response.js +112 -5
  370. package/build/dist/Server/Utils/Response.js.map +1 -1
  371. package/build/dist/Server/Utils/SSRFProtection.js +219 -53
  372. package/build/dist/Server/Utils/SSRFProtection.js.map +1 -1
  373. package/build/dist/Server/Utils/StartServer.js +7 -0
  374. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  375. package/build/dist/Server/Utils/VM/VMRunner.js +73 -1
  376. package/build/dist/Server/Utils/VM/VMRunner.js.map +1 -1
  377. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +445 -43
  378. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  379. package/build/dist/Server/Utils/Workspace/Slack/Slack.js +18 -1
  380. package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
  381. package/build/dist/Server/Utils/Workspace/WorkspaceBase.js.map +1 -1
  382. package/build/dist/Types/AI/FixPullRequestCiStatus.js +1 -1
  383. package/build/dist/Types/AI/FixVerificationStatus.js +2 -2
  384. package/build/dist/Types/API/Hostname.js +73 -4
  385. package/build/dist/Types/API/Hostname.js.map +1 -1
  386. package/build/dist/Types/API/URL.js +42 -24
  387. package/build/dist/Types/API/URL.js.map +1 -1
  388. package/build/dist/Types/Billing/BalanceAdjustmentType.js +15 -0
  389. package/build/dist/Types/Billing/BalanceAdjustmentType.js.map +1 -0
  390. package/build/dist/Types/Billing/ProjectBalanceType.js +14 -0
  391. package/build/dist/Types/Billing/ProjectBalanceType.js.map +1 -0
  392. package/build/dist/Types/Domain.js +22 -0
  393. package/build/dist/Types/Domain.js.map +1 -1
  394. package/build/dist/Types/File/MimeType.js +11 -0
  395. package/build/dist/Types/File/MimeType.js.map +1 -1
  396. package/build/dist/Types/JSONFunctions.js +14 -0
  397. package/build/dist/Types/JSONFunctions.js.map +1 -1
  398. package/build/dist/Types/Workflow/Components/BaseModel.js +83 -28
  399. package/build/dist/Types/Workflow/Components/BaseModel.js.map +1 -1
  400. package/build/dist/UI/Components/GanttChart/ChartContainer.js +4 -3
  401. package/build/dist/UI/Components/GanttChart/ChartContainer.js.map +1 -1
  402. package/build/dist/UI/Components/Modal/ConfirmModal.js +3 -1
  403. package/build/dist/UI/Components/Modal/ConfirmModal.js.map +1 -1
  404. package/build/dist/UI/Components/Modal/Modal.js +24 -34
  405. package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
  406. package/build/dist/UI/Components/ModelDelete/ModelDelete.js +11 -6
  407. package/build/dist/UI/Components/ModelDelete/ModelDelete.js.map +1 -1
  408. package/build/dist/UI/Components/SideOver/SideOver.js +105 -30
  409. package/build/dist/UI/Components/SideOver/SideOver.js.map +1 -1
  410. package/build/dist/UI/Utils/PageScrollLock.js +52 -0
  411. package/build/dist/UI/Utils/PageScrollLock.js.map +1 -0
  412. package/build/dist/Utils/Dashboard/HtmlWidgetDocument.js +4 -2
  413. package/build/dist/Utils/Dashboard/HtmlWidgetDocument.js.map +1 -1
  414. package/build/dist/Utils/Dashboard/VariableInterpolation.js +19 -1
  415. package/build/dist/Utils/Dashboard/VariableInterpolation.js.map +1 -1
  416. package/build/dist/Utils/LegacySerializedArray.js +51 -0
  417. package/build/dist/Utils/LegacySerializedArray.js.map +1 -0
  418. package/build/dist/Utils/Monitor/MonitorDependencyRule.js +47 -0
  419. package/build/dist/Utils/Monitor/MonitorDependencyRule.js.map +1 -0
  420. package/build/dist/Utils/Telemetry/SavedViewFilters.js +52 -0
  421. package/build/dist/Utils/Telemetry/SavedViewFilters.js.map +1 -0
  422. package/jest.config.json +3 -0
  423. package/package.json +1 -1
  424. package/tsconfig.json +3 -1
@@ -0,0 +1,72 @@
1
+ import LocalStorage from "../../../UI/Utils/LocalStorage";
2
+ import { readLegacySerializedArray } from "../../../Utils/LegacySerializedArray";
3
+ import { beforeEach, describe, expect, test } from "@jest/globals";
4
+
5
+ /*
6
+ * LocalStorage.setItem hands the caller's value straight to
7
+ * JSONFunctions.serializeValue rather than wrapping it in an object first, so
8
+ * a TOP-LEVEL array took the same broken path as a nested one and came back as
9
+ * { "0": ..., "1": ... }. This is not the saved-view case: the array is flat.
10
+ *
11
+ * It shipped. The logs explorer stores its selected columns here, read back
12
+ * behind an Array.isArray guard, so the corruption showed up as the column
13
+ * picker silently resetting to defaults on every reload — no error anywhere.
14
+ */
15
+
16
+ describe("LocalStorage round-trips arrays", () => {
17
+ beforeEach(() => {
18
+ localStorage.clear();
19
+ });
20
+
21
+ test("A flat string array comes back as an array", () => {
22
+ LocalStorage.setItem("columns", ["time", "body", "severityText"]);
23
+
24
+ const restored: unknown = LocalStorage.getItem("columns");
25
+
26
+ expect(Array.isArray(restored)).toBe(true);
27
+ expect(restored).toEqual(["time", "body", "severityText"]);
28
+ });
29
+
30
+ test("The stored JSON is an array, not a numeric-keyed object", () => {
31
+ LocalStorage.setItem("columns", ["time", "body"]);
32
+
33
+ expect(localStorage.getItem("columns")).toBe('["time","body"]');
34
+ });
35
+
36
+ test("An empty array round-trips", () => {
37
+ LocalStorage.setItem("columns", []);
38
+
39
+ expect(LocalStorage.getItem("columns")).toEqual([]);
40
+ });
41
+
42
+ test("An array of numbers round-trips", () => {
43
+ LocalStorage.setItem("sizes", [10, 25, 50]);
44
+
45
+ expect(LocalStorage.getItem("sizes")).toEqual([10, 25, 50]);
46
+ });
47
+
48
+ test("An array nested inside a stored object round-trips", () => {
49
+ LocalStorage.setItem("state", { columns: ["time"], filters: [["a", "b"]] });
50
+
51
+ expect(LocalStorage.getItem("state")).toEqual({
52
+ columns: ["time"],
53
+ filters: [["a", "b"]],
54
+ });
55
+ });
56
+
57
+ test("A plain object is still stored as an object", () => {
58
+ LocalStorage.setItem("prefs", { pageSize: 50 });
59
+
60
+ expect(LocalStorage.getItem("prefs")).toEqual({ pageSize: 50 });
61
+ });
62
+
63
+ test("A value written by the old serializer still reads back as a list", () => {
64
+ // What a pre-fix build left in the browser.
65
+ localStorage.setItem("columns", '{"0":"time","1":"body"}');
66
+
67
+ const restored: unknown = LocalStorage.getItem("columns");
68
+
69
+ expect(Array.isArray(restored)).toBe(false);
70
+ expect(readLegacySerializedArray(restored)).toEqual(["time", "body"]);
71
+ });
72
+ });
@@ -216,7 +216,12 @@ describe("HtmlWidgetDocument", () => {
216
216
  ).toEqual({ clusters: "eu-1,us-1" });
217
217
  });
218
218
 
219
- it("falls back to the default when a multi-select has no picks", () => {
219
+ /*
220
+ * A multi-select with no picks is "All", and the default does not
221
+ * override it — same rule the chart widgets follow. The author sees
222
+ * an empty string, which is what "no scope" looks like in a template.
223
+ */
224
+ it("renders an empty string when a multi-select has no picks", () => {
220
225
  expect(
221
226
  HtmlWidgetDocument.resolveVariables([
222
227
  makeVariable({
@@ -226,7 +231,19 @@ describe("HtmlWidgetDocument", () => {
226
231
  defaultValue: "eu-1",
227
232
  }),
228
233
  ]),
229
- ).toEqual({ clusters: "eu-1" });
234
+ ).toEqual({ clusters: "" });
235
+ });
236
+
237
+ it("renders an empty string for an untouched multi-select with a default", () => {
238
+ expect(
239
+ HtmlWidgetDocument.resolveVariables([
240
+ makeVariable({
241
+ name: "clusters",
242
+ isMultiSelect: true,
243
+ defaultValue: "eu-1",
244
+ }),
245
+ ]),
246
+ ).toEqual({ clusters: "" });
230
247
  });
231
248
 
232
249
  it("maps an unset variable to an empty string rather than dropping it", () => {
@@ -105,6 +105,50 @@ describe("DashboardModelQueryInterpolation.applyToQuery - writing predicates", (
105
105
  expect((result["hostname"] as Includes).values).toEqual(["web1", "web2"]);
106
106
  });
107
107
 
108
+ /*
109
+ * Resource list widgets share DashboardVariableInterpolation.resolveValue
110
+ * with the metric widgets, so they inherit the "All" rule: an empty
111
+ * multi-select filters nothing, and the variable's single-select Default
112
+ * does not stand in for the picks the user did not make.
113
+ */
114
+ test("an empty multi-select writes no predicate, Default or not", () => {
115
+ const query: Record<string, unknown> = { kind: "Container" };
116
+ const result: Record<string, unknown> =
117
+ DashboardModelQueryInterpolation.applyToQuery(
118
+ query,
119
+ [
120
+ attrVariable("host.name", {
121
+ isMultiSelect: true,
122
+ selectedValues: [],
123
+ defaultValue: "web1",
124
+ }),
125
+ ],
126
+ MAP,
127
+ );
128
+
129
+ expect(result).toBe(query);
130
+ expect(result["hostname"]).toBeUndefined();
131
+ });
132
+
133
+ test("a cleared multi-select removes a prior filter on that column", () => {
134
+ const query: Record<string, unknown> = { hostname: "web1", kind: "Pod" };
135
+ const result: Record<string, unknown> =
136
+ DashboardModelQueryInterpolation.applyToQuery(
137
+ query,
138
+ [
139
+ attrVariable("host.name", {
140
+ isMultiSelect: true,
141
+ selectedValues: [],
142
+ defaultValue: "web1",
143
+ }),
144
+ ],
145
+ MAP,
146
+ );
147
+
148
+ expect(result).toEqual({ kind: "Pod" });
149
+ expect(query).toEqual({ hostname: "web1", kind: "Pod" }); // input untouched
150
+ });
151
+
108
152
  test("maps two variables onto their respective columns", () => {
109
153
  const result: Record<string, unknown> =
110
154
  DashboardModelQueryInterpolation.applyToQuery(
@@ -2,6 +2,7 @@ import Includes from "../../../Types/BaseDatabase/Includes";
2
2
  import DashboardVariable, {
3
3
  DashboardVariableType,
4
4
  } from "../../../Types/Dashboard/DashboardVariable";
5
+ import MetricQueryConfigData from "../../../Types/Metrics/MetricQueryConfigData";
5
6
  import DashboardVariableInterpolation from "../../../Utils/Dashboard/VariableInterpolation";
6
7
 
7
8
  function makeVariable(
@@ -15,6 +16,24 @@ function makeVariable(
15
16
  } as DashboardVariable;
16
17
  }
17
18
 
19
+ function makeQueryConfig(
20
+ attributes: Record<string, unknown> | undefined,
21
+ ): MetricQueryConfigData {
22
+ return {
23
+ metricQueryData: {
24
+ filterData: attributes === undefined ? {} : { attributes },
25
+ },
26
+ } as unknown as MetricQueryConfigData;
27
+ }
28
+
29
+ function attributesOf(
30
+ config: MetricQueryConfigData,
31
+ ): Record<string, unknown> | undefined {
32
+ return config.metricQueryData.filterData.attributes as unknown as
33
+ | Record<string, unknown>
34
+ | undefined;
35
+ }
36
+
18
37
  describe("DashboardVariableInterpolation", () => {
19
38
  describe("resolveValue", () => {
20
39
  test("returns scalar for a single-select with selectedValue", () => {
@@ -76,14 +95,117 @@ describe("DashboardVariableInterpolation", () => {
76
95
  });
77
96
  });
78
97
 
79
- test("multi-select with no picks falls through to scalar default", () => {
98
+ /*
99
+ * The contract for multi-select, and the reason it is not simply
100
+ * "reuse the single-select fallback": the selector renders "All"
101
+ * whenever `selectedValues` is empty and has no way to render
102
+ * anything else. If an empty list resolved to `defaultValue`, every
103
+ * multi-select variable with a Default would filter its widgets from
104
+ * behind a control that says the widgets are unfiltered — and the
105
+ * popover's own Clear button is the fastest way to get there.
106
+ */
107
+ describe("an empty multi-select means All", () => {
108
+ test("ignores defaultValue when the list is empty", () => {
109
+ const variable: DashboardVariable = makeVariable({
110
+ isMultiSelect: true,
111
+ selectedValues: [],
112
+ defaultValue: "d",
113
+ });
114
+ expect(
115
+ DashboardVariableInterpolation.resolveValue(variable),
116
+ ).toBeUndefined();
117
+ });
118
+
119
+ test("ignores defaultValue when the list is unset", () => {
120
+ const variable: DashboardVariable = makeVariable({
121
+ isMultiSelect: true,
122
+ defaultValue: "d",
123
+ });
124
+ expect(
125
+ DashboardVariableInterpolation.resolveValue(variable),
126
+ ).toBeUndefined();
127
+ });
128
+
129
+ test("ignores defaultValue when every pick is blank", () => {
130
+ const variable: DashboardVariable = makeVariable({
131
+ isMultiSelect: true,
132
+ selectedValues: ["", ""],
133
+ defaultValue: "d",
134
+ });
135
+ expect(
136
+ DashboardVariableInterpolation.resolveValue(variable),
137
+ ).toBeUndefined();
138
+ });
139
+
140
+ /*
141
+ * A variable that was single-select before the author ticked
142
+ * "Allow multi-select" still carries the scalar it was left on.
143
+ * The multi list is the only source of truth once the flag is set,
144
+ * so that stale scalar must not resurface as a filter.
145
+ */
146
+ test("ignores a stale selectedValue left over from single-select", () => {
147
+ const variable: DashboardVariable = makeVariable({
148
+ isMultiSelect: true,
149
+ selectedValues: [],
150
+ selectedValue: "stale",
151
+ defaultValue: "d",
152
+ });
153
+ expect(
154
+ DashboardVariableInterpolation.resolveValue(variable),
155
+ ).toBeUndefined();
156
+ });
157
+
158
+ test("still resolves once the user picks something", () => {
159
+ const variable: DashboardVariable = makeVariable({
160
+ isMultiSelect: true,
161
+ selectedValues: ["a"],
162
+ defaultValue: "d",
163
+ });
164
+ expect(DashboardVariableInterpolation.resolveValue(variable)).toEqual({
165
+ multi: ["a"],
166
+ });
167
+ });
168
+ });
169
+
170
+ /*
171
+ * The mirror of the rule above on the single-select side. "" is the
172
+ * value of the selector's "All" option — a real choice — so it must
173
+ * not fall back to the default. `??` draws that line; `||` would not.
174
+ */
175
+ test("an explicit empty scalar is All, not a fallback to the default", () => {
80
176
  const variable: DashboardVariable = makeVariable({
81
- isMultiSelect: true,
82
- selectedValues: [],
83
- defaultValue: "d",
177
+ selectedValue: "",
178
+ defaultValue: "staging",
179
+ });
180
+ expect(
181
+ DashboardVariableInterpolation.resolveValue(variable),
182
+ ).toBeUndefined();
183
+ });
184
+
185
+ test("defaultValue still applies to a single-select that is untouched", () => {
186
+ expect(
187
+ DashboardVariableInterpolation.resolveValue(
188
+ makeVariable({ defaultValue: "staging", isMultiSelect: false }),
189
+ ),
190
+ ).toEqual({ scalar: "staging" });
191
+ });
192
+
193
+ test("an empty defaultValue is not a filter", () => {
194
+ expect(
195
+ DashboardVariableInterpolation.resolveValue(
196
+ makeVariable({ defaultValue: "" }),
197
+ ),
198
+ ).toBeUndefined();
199
+ });
200
+
201
+ test("selectedValues on a single-select variable is ignored", () => {
202
+ const variable: DashboardVariable = makeVariable({
203
+ isMultiSelect: false,
204
+ selectedValues: ["a", "b"],
205
+ selectedValue: "prod",
84
206
  });
85
207
  expect(DashboardVariableInterpolation.resolveValue(variable)).toEqual({
86
- scalar: "d",
208
+ scalar: "prod",
87
209
  });
88
210
  });
89
211
  });
@@ -178,6 +300,74 @@ describe("DashboardVariableInterpolation", () => {
178
300
  expect(result).toEqual({ "k8s.cluster.name": "prod" });
179
301
  });
180
302
 
303
+ /*
304
+ * The user-visible bug this contract exists for: the popover reads
305
+ * "All" the moment the last pick is removed, so the widget has to be
306
+ * unfiltered at that moment too — including dropping the widget's own
307
+ * base filter on that key, exactly as an "All" single-select does.
308
+ */
309
+ test("a cleared multi-select with a default removes the filter", () => {
310
+ const variable: DashboardVariable = makeVariable({
311
+ attributeKey: "k8s.cluster.name",
312
+ isMultiSelect: true,
313
+ selectedValues: [],
314
+ defaultValue: "prod",
315
+ });
316
+ const result: Record<string, unknown> =
317
+ DashboardVariableInterpolation.applyToAttributes(
318
+ { "k8s.cluster.name": "staging", other: "keep" },
319
+ [variable],
320
+ );
321
+ expect(result).toEqual({ other: "keep" });
322
+ });
323
+
324
+ test("a cleared multi-select with a default adds nothing", () => {
325
+ const attrs: Record<string, unknown> = { other: "keep" };
326
+ const variable: DashboardVariable = makeVariable({
327
+ attributeKey: "k8s.cluster.name",
328
+ isMultiSelect: true,
329
+ selectedValues: [],
330
+ defaultValue: "prod",
331
+ });
332
+ const result: Record<string, unknown> =
333
+ DashboardVariableInterpolation.applyToAttributes(attrs, [variable]);
334
+ expect(result).toBe(attrs);
335
+ expect(result["k8s.cluster.name"]).toBeUndefined();
336
+ });
337
+
338
+ test("an untouched multi-select with a default adds nothing", () => {
339
+ const attrs: Record<string, unknown> = {};
340
+ const variable: DashboardVariable = makeVariable({
341
+ attributeKey: "k8s.cluster.name",
342
+ isMultiSelect: true,
343
+ defaultValue: "prod",
344
+ });
345
+ expect(
346
+ DashboardVariableInterpolation.applyToAttributes(attrs, [variable]),
347
+ ).toBe(attrs);
348
+ });
349
+
350
+ test("clearing one multi-select does not disturb another variable", () => {
351
+ const cleared: DashboardVariable = makeVariable({
352
+ id: "v1",
353
+ attributeKey: "cluster",
354
+ isMultiSelect: true,
355
+ selectedValues: [],
356
+ defaultValue: "prod",
357
+ });
358
+ const picked: DashboardVariable = makeVariable({
359
+ id: "v2",
360
+ attributeKey: "namespace",
361
+ selectedValue: "default",
362
+ });
363
+ const result: Record<string, unknown> =
364
+ DashboardVariableInterpolation.applyToAttributes(
365
+ { cluster: "staging" },
366
+ [cleared, picked],
367
+ );
368
+ expect(result).toEqual({ namespace: "default" });
369
+ });
370
+
181
371
  test("applies multiple variables at once", () => {
182
372
  const v1: DashboardVariable = makeVariable({
183
373
  id: "v1",
@@ -194,4 +384,97 @@ describe("DashboardVariableInterpolation", () => {
194
384
  expect(result).toEqual({ cluster: "prod", namespace: "default" });
195
385
  });
196
386
  });
387
+
388
+ /*
389
+ * Metric charts and gauges go through the query-config wrapper rather
390
+ * than calling applyToAttributes directly, so the "All" contract is
391
+ * pinned at that level too — this is the path a user actually watches
392
+ * change when they clear the popover.
393
+ */
394
+ describe("applyToQueryConfig", () => {
395
+ test("injects an Includes for a multi-select with picks", () => {
396
+ const config: MetricQueryConfigData = makeQueryConfig({});
397
+ const result: MetricQueryConfigData =
398
+ DashboardVariableInterpolation.applyToQueryConfig(config, [
399
+ makeVariable({
400
+ attributeKey: "k8s.cluster.name",
401
+ isMultiSelect: true,
402
+ selectedValues: ["eu-1", "us-1"],
403
+ }),
404
+ ]);
405
+ const value: unknown = attributesOf(result)?.["k8s.cluster.name"];
406
+ expect(value).toBeInstanceOf(Includes);
407
+ expect((value as Includes).values).toEqual(["eu-1", "us-1"]);
408
+ });
409
+
410
+ test("a cleared multi-select with a default leaves the query unfiltered", () => {
411
+ const config: MetricQueryConfigData = makeQueryConfig({
412
+ "k8s.cluster.name": "prod",
413
+ });
414
+ const result: MetricQueryConfigData =
415
+ DashboardVariableInterpolation.applyToQueryConfig(config, [
416
+ makeVariable({
417
+ attributeKey: "k8s.cluster.name",
418
+ isMultiSelect: true,
419
+ selectedValues: [],
420
+ defaultValue: "prod",
421
+ }),
422
+ ]);
423
+ expect(attributesOf(result)).toEqual({});
424
+ });
425
+
426
+ test("returns the same config reference when nothing changes", () => {
427
+ const config: MetricQueryConfigData = makeQueryConfig({});
428
+ expect(
429
+ DashboardVariableInterpolation.applyToQueryConfig(config, [
430
+ makeVariable({
431
+ attributeKey: "k8s.cluster.name",
432
+ isMultiSelect: true,
433
+ selectedValues: [],
434
+ defaultValue: "prod",
435
+ }),
436
+ ]),
437
+ ).toBe(config);
438
+ expect(
439
+ DashboardVariableInterpolation.applyToQueryConfig(config, []),
440
+ ).toBe(config);
441
+ expect(
442
+ DashboardVariableInterpolation.applyToQueryConfig(config, undefined),
443
+ ).toBe(config);
444
+ });
445
+
446
+ test("leaves a config with no filterData alone", () => {
447
+ const config: MetricQueryConfigData = {
448
+ metricQueryData: {},
449
+ } as unknown as MetricQueryConfigData;
450
+ expect(
451
+ DashboardVariableInterpolation.applyToQueryConfig(config, [
452
+ makeVariable({
453
+ attributeKey: "k8s.cluster.name",
454
+ selectedValue: "prod",
455
+ }),
456
+ ]),
457
+ ).toBe(config);
458
+ });
459
+
460
+ test("applyToQueryConfigs maps every config", () => {
461
+ const configs: Array<MetricQueryConfigData> = [
462
+ makeQueryConfig({ "k8s.cluster.name": "prod" }),
463
+ makeQueryConfig({ "k8s.cluster.name": "prod", keep: "me" }),
464
+ ];
465
+ const result: Array<MetricQueryConfigData> =
466
+ DashboardVariableInterpolation.applyToQueryConfigs(configs, [
467
+ makeVariable({
468
+ attributeKey: "k8s.cluster.name",
469
+ isMultiSelect: true,
470
+ selectedValues: [],
471
+ defaultValue: "prod",
472
+ }),
473
+ ]);
474
+ expect(attributesOf(result[0] as MetricQueryConfigData)).toEqual({});
475
+ expect(attributesOf(result[1] as MetricQueryConfigData)).toEqual({
476
+ keep: "me",
477
+ });
478
+ });
479
+ });
197
480
  });
@@ -4,6 +4,7 @@ import DashboardVariableUrlState, {
4
4
  import DashboardVariable, {
5
5
  DashboardVariableType,
6
6
  } from "../../../Types/Dashboard/DashboardVariable";
7
+ import DashboardVariableInterpolation from "../../../Utils/Dashboard/VariableInterpolation";
7
8
 
8
9
  function makeVariable(data: Partial<DashboardVariable>): DashboardVariable {
9
10
  return {
@@ -147,6 +148,47 @@ describe("DashboardVariableUrlState", () => {
147
148
  expect(applied[0]?.selectedValue).toBe("prod");
148
149
  expect(applied[1]?.selectedValues).toEqual(["us", "eu"]);
149
150
  });
151
+
152
+ /*
153
+ * "All" is the absence of a var- param — writeToBrowserUrl emits
154
+ * nothing for an empty selection, so a reload cannot tell "cleared"
155
+ * from "never touched" and must treat both as All. That only holds
156
+ * because resolveValue ignores defaultValue for a multi-select; if it
157
+ * fell back, a viewer who cleared the popover would silently get the
158
+ * author's Default back on every refresh and on every shared link.
159
+ */
160
+ test("a cleared multi-select survives a url round trip as All", () => {
161
+ window.history.replaceState({}, "", "/dashboard");
162
+ DashboardVariableUrlState.writeToBrowserUrl([
163
+ makeVariable({
164
+ name: "region",
165
+ isMultiSelect: true,
166
+ selectedValues: [],
167
+ defaultValue: "us",
168
+ }),
169
+ ]);
170
+
171
+ expect(window.location.search).toBe("");
172
+
173
+ const applied: Array<DashboardVariable> =
174
+ DashboardVariableUrlState.applyUrlToVariables(
175
+ [
176
+ makeVariable({
177
+ name: "region",
178
+ isMultiSelect: true,
179
+ defaultValue: "us",
180
+ }),
181
+ ],
182
+ DashboardVariableUrlState.parseFromSearch(window.location.search),
183
+ );
184
+
185
+ expect(applied[0]?.selectedValues).toBeUndefined();
186
+ expect(
187
+ DashboardVariableInterpolation.resolveValue(
188
+ applied[0] as DashboardVariable,
189
+ ),
190
+ ).toBeUndefined();
191
+ });
150
192
  });
151
193
 
152
194
  describe("writeToBrowserUrl", () => {
@@ -52,6 +52,33 @@ describe("DataSourceQueryText.applyVariables", () => {
52
52
  expect(result).toBe("default-cluster");
53
53
  });
54
54
 
55
+ /*
56
+ * An empty multi-select is "All", so it resolves to nothing and the token
57
+ * is left standing — the connector then names the unbound variable
58
+ * instead of silently querying the author's Default, which is a
59
+ * single-select concept the picks were never seeded from.
60
+ */
61
+ test("an empty multi-select leaves the token untouched, Default or not", () => {
62
+ const result: string = DataSourceQueryText.applyVariables(
63
+ 'up{cluster=~"{{cluster}}"}',
64
+ [
65
+ makeVariable({
66
+ isMultiSelect: true,
67
+ selectedValues: [],
68
+ defaultValue: "prod",
69
+ }),
70
+ ],
71
+ );
72
+ expect(result).toBe('up{cluster=~"{{cluster}}"}');
73
+ });
74
+
75
+ test("an untouched multi-select leaves the token untouched too", () => {
76
+ const result: string = DataSourceQueryText.applyVariables("{{cluster}}", [
77
+ makeVariable({ isMultiSelect: true, defaultValue: "prod" }),
78
+ ]);
79
+ expect(result).toBe("{{cluster}}");
80
+ });
81
+
55
82
  test("leaves the token untouched when the variable is unresolved", () => {
56
83
  const result: string = DataSourceQueryText.applyVariables("{{cluster}}", [
57
84
  makeVariable({}),