@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,539 @@
1
+ import "@testing-library/jest-dom";
2
+ import { afterEach, describe, expect, jest, test } from "@jest/globals";
3
+ import {
4
+ cleanup,
5
+ fireEvent,
6
+ render,
7
+ screen,
8
+ waitFor,
9
+ } from "@testing-library/react";
10
+ import * as React from "react";
11
+ import getJestMockFunction, { MockFunction } from "../../MockType";
12
+
13
+ /*
14
+ * A dashboard variable has two faces. The control in the toolbar tells the
15
+ * user what the board is scoped to; DashboardVariableInterpolation decides
16
+ * what the widgets actually query. They live in different files, and the
17
+ * only bug they can produce together is disagreement — a control reading
18
+ * "All" over widgets that are quietly filtered.
19
+ *
20
+ * That is exactly what shipped: an empty multi-select fell through to the
21
+ * variable's Default, so the popover's own Clear button applied a filter
22
+ * the popover then described as "All". The contract that closes it:
23
+ *
24
+ * - A multi-select is its `selectedValues` and nothing else. Empty is
25
+ * "All". `defaultValue` is a single-select concept.
26
+ * - A single-select is `selectedValue ?? defaultValue`. The empty string
27
+ * is the "All" option — a real choice — not an absent one, so `||`
28
+ * would be wrong on both sides of the contract.
29
+ *
30
+ * Every assertion below drives the real components: the rendered control is
31
+ * read for what the user sees, and the same variable is pushed through the
32
+ * real interpolation for what the server would be asked. Agreement between
33
+ * those two is the invariant, not either one alone.
34
+ */
35
+
36
+ const getTelemetryAttributeValuesMock: MockFunction = getJestMockFunction();
37
+
38
+ /*
39
+ * The toolbar selector fetches attribute values on mount for
40
+ * TelemetryAttribute variables. The arrow wrapper is load bearing:
41
+ * jest.mock is hoisted above the compiled requires, so the mock variable
42
+ * above is still unassigned when the factory runs.
43
+ */
44
+ jest.mock(
45
+ "../../../../App/FeatureSet/Dashboard/src/Components/Metrics/Utils/Metrics",
46
+ () => {
47
+ return {
48
+ __esModule: true,
49
+ default: {
50
+ getTelemetryAttributeValues: (...args: Array<any>) => {
51
+ return getTelemetryAttributeValuesMock(...args);
52
+ },
53
+ },
54
+ };
55
+ },
56
+ );
57
+
58
+ // The public selector reaches the anonymous dashboard API for the same list.
59
+ jest.mock("../../../../App/FeatureSet/PublicDashboard/src/Utils/API", () => {
60
+ return {
61
+ __esModule: true,
62
+ default: {
63
+ post: () => {
64
+ return Promise.resolve({ data: { values: [] } });
65
+ },
66
+ },
67
+ };
68
+ });
69
+
70
+ jest.mock("../../../../App/FeatureSet/PublicDashboard/src/Utils/Config", () => {
71
+ return {
72
+ __esModule: true,
73
+ PUBLIC_DASHBOARD_API_URL: {
74
+ toString: () => {
75
+ return "https://localhost/api/public-dashboard";
76
+ },
77
+ },
78
+ };
79
+ });
80
+
81
+ import DashboardVariableSelector, {
82
+ VariableValueChange,
83
+ } from "../../../../App/FeatureSet/Dashboard/src/Components/Dashboard/Toolbar/DashboardVariableSelector";
84
+ import DashboardVariablesModal from "../../../../App/FeatureSet/Dashboard/src/Components/Dashboard/Toolbar/DashboardVariablesModal";
85
+ import PublicDashboardVariableSelector from "../../../../App/FeatureSet/PublicDashboard/src/Pages/DashboardView/DashboardVariableSelector";
86
+ import DashboardVariable, {
87
+ DashboardVariableType,
88
+ } from "../../../Types/Dashboard/DashboardVariable";
89
+ import ObjectID from "../../../Types/ObjectID";
90
+ import DashboardVariableInterpolation from "../../../Utils/Dashboard/VariableInterpolation";
91
+
92
+ const ATTRIBUTE_KEY: string = "k8s.cluster.name";
93
+
94
+ function makeVariable(
95
+ overrides: Partial<DashboardVariable>,
96
+ ): DashboardVariable {
97
+ return {
98
+ id: "var-1",
99
+ name: "cluster",
100
+ label: "Cluster",
101
+ /*
102
+ * CustomList keeps the option list synchronous. The multi-select and
103
+ * single-select branches of the selector are shared by both variable
104
+ * types — only where the options come from differs — so the contract
105
+ * is testable without an async fetch in the middle of it. The
106
+ * TelemetryAttribute path is covered separately below.
107
+ */
108
+ type: DashboardVariableType.CustomList,
109
+ customListValues: "eu-1,us-1,ap-1",
110
+ ...overrides,
111
+ } as DashboardVariable;
112
+ }
113
+
114
+ interface RecordedChange {
115
+ variableId: string;
116
+ change: VariableValueChange;
117
+ }
118
+
119
+ function renderToolbar(variable: DashboardVariable): Array<RecordedChange> {
120
+ const changes: Array<RecordedChange> = [];
121
+ render(
122
+ React.createElement(DashboardVariableSelector, {
123
+ variables: [variable],
124
+ onVariableValueChange: (
125
+ variableId: string,
126
+ change: VariableValueChange,
127
+ ): void => {
128
+ changes.push({ variableId: variableId, change: change });
129
+ },
130
+ }),
131
+ );
132
+ return changes;
133
+ }
134
+
135
+ /** The multi-select popover's trigger — the only button the toolbar draws. */
136
+ function popoverButton(): HTMLButtonElement {
137
+ return screen.getByTitle("Cluster") as HTMLButtonElement;
138
+ }
139
+
140
+ function openPopover(): void {
141
+ fireEvent.click(popoverButton());
142
+ }
143
+
144
+ function isUnfiltered(variable: DashboardVariable): boolean {
145
+ return (
146
+ DashboardVariableInterpolation.resolveValue(variable) === undefined &&
147
+ DashboardVariableInterpolation.applyToAttributes(
148
+ { [ATTRIBUTE_KEY]: "already-here" },
149
+ [
150
+ {
151
+ ...variable,
152
+ type: DashboardVariableType.TelemetryAttribute,
153
+ attributeKey: ATTRIBUTE_KEY,
154
+ },
155
+ ],
156
+ )[ATTRIBUTE_KEY] === undefined
157
+ );
158
+ }
159
+
160
+ afterEach(() => {
161
+ cleanup();
162
+ getTelemetryAttributeValuesMock.mockReset();
163
+ });
164
+
165
+ describe("dashboard variable All contract", () => {
166
+ describe("a multi-select shows All exactly when it filters nothing", () => {
167
+ /*
168
+ * The regression, stated as the user meets it: a Default is set, the
169
+ * popover says "All", and the widgets must be unscoped. Before the fix
170
+ * the label said "All" and the query said "prod".
171
+ */
172
+ test("an untouched multi-select with a Default reads All and filters nothing", () => {
173
+ const variable: DashboardVariable = makeVariable({
174
+ isMultiSelect: true,
175
+ defaultValue: "prod",
176
+ });
177
+
178
+ renderToolbar(variable);
179
+
180
+ expect(popoverButton()).toHaveTextContent("All");
181
+ expect(isUnfiltered(variable)).toBe(true);
182
+ });
183
+
184
+ test("a cleared multi-select with a Default reads All and filters nothing", () => {
185
+ const variable: DashboardVariable = makeVariable({
186
+ isMultiSelect: true,
187
+ selectedValues: [],
188
+ defaultValue: "prod",
189
+ });
190
+
191
+ renderToolbar(variable);
192
+
193
+ expect(popoverButton()).toHaveTextContent("All");
194
+ expect(isUnfiltered(variable)).toBe(true);
195
+ });
196
+
197
+ /*
198
+ * A variable that was single-select before the author ticked "Allow
199
+ * multi-select" still carries the scalar it was left on. Neither face
200
+ * of the variable may resurrect it.
201
+ */
202
+ test("a stale scalar under a multi-select changes neither face", () => {
203
+ const variable: DashboardVariable = makeVariable({
204
+ isMultiSelect: true,
205
+ selectedValues: [],
206
+ selectedValue: "stale",
207
+ defaultValue: "prod",
208
+ });
209
+
210
+ renderToolbar(variable);
211
+
212
+ expect(popoverButton()).toHaveTextContent("All");
213
+ expect(isUnfiltered(variable)).toBe(true);
214
+ });
215
+
216
+ test("one pick names itself on the button and filters", () => {
217
+ const variable: DashboardVariable = makeVariable({
218
+ isMultiSelect: true,
219
+ selectedValues: ["eu-1"],
220
+ defaultValue: "prod",
221
+ });
222
+
223
+ renderToolbar(variable);
224
+
225
+ expect(popoverButton()).toHaveTextContent("eu-1");
226
+ expect(isUnfiltered(variable)).toBe(false);
227
+ });
228
+
229
+ test("several picks are counted on the button and filter", () => {
230
+ const variable: DashboardVariable = makeVariable({
231
+ isMultiSelect: true,
232
+ selectedValues: ["eu-1", "us-1"],
233
+ });
234
+
235
+ renderToolbar(variable);
236
+
237
+ expect(popoverButton()).toHaveTextContent("2 selected");
238
+ expect(isUnfiltered(variable)).toBe(false);
239
+ });
240
+ });
241
+
242
+ describe("the popover writes back what the contract reads", () => {
243
+ test("Clear emits an empty list, which is the All state", () => {
244
+ const variable: DashboardVariable = makeVariable({
245
+ isMultiSelect: true,
246
+ selectedValues: ["eu-1"],
247
+ defaultValue: "prod",
248
+ });
249
+
250
+ const changes: Array<RecordedChange> = renderToolbar(variable);
251
+ openPopover();
252
+ fireEvent.click(screen.getByText("Clear"));
253
+
254
+ expect(changes).toHaveLength(1);
255
+ expect(changes[0]?.change).toEqual({ selectedValues: [] });
256
+
257
+ // And what it wrote is a variable that filters nothing.
258
+ const afterClear: DashboardVariable = {
259
+ ...variable,
260
+ selectedValues: changes[0]?.change.selectedValues,
261
+ };
262
+ expect(isUnfiltered(afterClear)).toBe(true);
263
+ });
264
+
265
+ test("Clear is unavailable when there is nothing to clear", () => {
266
+ renderToolbar(
267
+ makeVariable({
268
+ isMultiSelect: true,
269
+ selectedValues: [],
270
+ defaultValue: "prod",
271
+ }),
272
+ );
273
+ openPopover();
274
+
275
+ expect(screen.getByText("Clear")).toBeDisabled();
276
+ });
277
+
278
+ test("ticking an option emits it and lands on a filtering variable", () => {
279
+ const variable: DashboardVariable = makeVariable({
280
+ isMultiSelect: true,
281
+ selectedValues: [],
282
+ defaultValue: "prod",
283
+ });
284
+
285
+ const changes: Array<RecordedChange> = renderToolbar(variable);
286
+ openPopover();
287
+ fireEvent.click(screen.getByLabelText("us-1"));
288
+
289
+ expect(changes[0]?.change).toEqual({ selectedValues: ["us-1"] });
290
+ expect(isUnfiltered({ ...variable, selectedValues: ["us-1"] })).toBe(
291
+ false,
292
+ );
293
+ });
294
+
295
+ test("unticking the last option returns to the All state", () => {
296
+ const variable: DashboardVariable = makeVariable({
297
+ isMultiSelect: true,
298
+ selectedValues: ["us-1"],
299
+ defaultValue: "prod",
300
+ });
301
+
302
+ const changes: Array<RecordedChange> = renderToolbar(variable);
303
+ openPopover();
304
+ fireEvent.click(screen.getByLabelText("us-1"));
305
+
306
+ expect(changes[0]?.change).toEqual({ selectedValues: [] });
307
+ expect(isUnfiltered({ ...variable, selectedValues: [] })).toBe(true);
308
+ });
309
+
310
+ /*
311
+ * The popover never sends a scalar, so nothing downstream can mistake
312
+ * a multi-select for one.
313
+ */
314
+ test("the popover never writes selectedValue", () => {
315
+ const changes: Array<RecordedChange> = renderToolbar(
316
+ makeVariable({
317
+ isMultiSelect: true,
318
+ selectedValues: ["eu-1"],
319
+ defaultValue: "prod",
320
+ }),
321
+ );
322
+ openPopover();
323
+ fireEvent.click(screen.getByText("Clear"));
324
+ fireEvent.click(screen.getByLabelText("ap-1"));
325
+
326
+ expect(changes.length).toBeGreaterThan(0);
327
+ for (const recorded of changes) {
328
+ expect(recorded.change.selectedValue).toBeUndefined();
329
+ expect(recorded.change.selectedValues).toBeDefined();
330
+ }
331
+ });
332
+ });
333
+
334
+ describe("a single-select keeps its Default but not over an explicit All", () => {
335
+ test("an untouched single-select shows its Default and filters on it", () => {
336
+ const variable: DashboardVariable = makeVariable({
337
+ defaultValue: "eu-1",
338
+ });
339
+
340
+ renderToolbar(variable);
341
+
342
+ expect(screen.getByRole("combobox")).toHaveValue("eu-1");
343
+ expect(isUnfiltered(variable)).toBe(false);
344
+ });
345
+
346
+ /*
347
+ * The single-select twin of the same bug: "" is the "All" option's
348
+ * value, and `||` treats it as absent — so the control snapped back to
349
+ * the Default while the widgets stayed unfiltered. `??` keeps them
350
+ * agreeing.
351
+ */
352
+ test("choosing All holds on All rather than snapping to the Default", () => {
353
+ const variable: DashboardVariable = makeVariable({
354
+ selectedValue: "",
355
+ defaultValue: "eu-1",
356
+ });
357
+
358
+ renderToolbar(variable);
359
+
360
+ expect(screen.getByRole("combobox")).toHaveValue("");
361
+ expect(isUnfiltered(variable)).toBe(true);
362
+ });
363
+
364
+ test("choosing All emits an empty scalar", () => {
365
+ const changes: Array<RecordedChange> = renderToolbar(
366
+ makeVariable({ selectedValue: "eu-1", defaultValue: "eu-1" }),
367
+ );
368
+
369
+ fireEvent.change(screen.getByRole("combobox"), {
370
+ target: { value: "" },
371
+ });
372
+
373
+ expect(changes[0]?.change).toEqual({ selectedValue: "" });
374
+ });
375
+
376
+ test("a picked value wins over the Default", () => {
377
+ const variable: DashboardVariable = makeVariable({
378
+ selectedValue: "us-1",
379
+ defaultValue: "eu-1",
380
+ });
381
+
382
+ renderToolbar(variable);
383
+
384
+ expect(screen.getByRole("combobox")).toHaveValue("us-1");
385
+ expect(DashboardVariableInterpolation.resolveValue(variable)).toEqual({
386
+ scalar: "us-1",
387
+ });
388
+ });
389
+
390
+ test("a cleared text variable stays cleared", () => {
391
+ const variable: DashboardVariable = makeVariable({
392
+ type: DashboardVariableType.TextInput,
393
+ customListValues: undefined,
394
+ selectedValue: "",
395
+ defaultValue: "eu-1",
396
+ });
397
+
398
+ renderToolbar(variable);
399
+
400
+ expect(screen.getByRole("textbox")).toHaveValue("");
401
+ expect(isUnfiltered(variable)).toBe(true);
402
+ });
403
+ });
404
+
405
+ describe("a TelemetryAttribute multi-select follows the same rule", () => {
406
+ test("it reads All once its options arrive, Default or not", async () => {
407
+ getTelemetryAttributeValuesMock.mockReturnValue(
408
+ Promise.resolve(["eu-1", "us-1"]),
409
+ );
410
+
411
+ const variable: DashboardVariable = makeVariable({
412
+ type: DashboardVariableType.TelemetryAttribute,
413
+ customListValues: undefined,
414
+ attributeKey: ATTRIBUTE_KEY,
415
+ isMultiSelect: true,
416
+ selectedValues: [],
417
+ defaultValue: "prod",
418
+ });
419
+
420
+ renderToolbar(variable);
421
+
422
+ /*
423
+ * The button reads "Loading…" until the attribute values land. It
424
+ * must settle on "All" — never on the Default — once they do.
425
+ */
426
+ expect(popoverButton()).toHaveTextContent("Loading…");
427
+ await waitFor(() => {
428
+ expect(popoverButton()).toHaveTextContent("All");
429
+ });
430
+ expect(popoverButton()).not.toBeDisabled();
431
+ expect(isUnfiltered(variable)).toBe(true);
432
+ });
433
+ });
434
+
435
+ describe("the public dashboard selector follows the same rule", () => {
436
+ function renderPublic(variable: DashboardVariable): Array<string> {
437
+ const values: Array<string> = [];
438
+ render(
439
+ React.createElement(PublicDashboardVariableSelector, {
440
+ variables: [variable],
441
+ dashboardId: new ObjectID("11111111-1111-4111-8111-111111111111"),
442
+ onVariableValueChange: (_id: string, value: string): void => {
443
+ values.push(value);
444
+ },
445
+ }),
446
+ );
447
+ return values;
448
+ }
449
+
450
+ test("choosing All holds on All rather than snapping to the Default", () => {
451
+ const variable: DashboardVariable = makeVariable({
452
+ selectedValue: "",
453
+ defaultValue: "eu-1",
454
+ });
455
+
456
+ renderPublic(variable);
457
+
458
+ expect(screen.getByRole("combobox")).toHaveValue("");
459
+ expect(isUnfiltered(variable)).toBe(true);
460
+ });
461
+
462
+ test("an untouched variable still shows its Default", () => {
463
+ renderPublic(makeVariable({ defaultValue: "eu-1" }));
464
+
465
+ expect(screen.getByRole("combobox")).toHaveValue("eu-1");
466
+ });
467
+ });
468
+
469
+ /*
470
+ * The Default input sits directly beside the "Allow multi-select"
471
+ * checkbox in the editor, which is how an author sets a default that a
472
+ * multi-select can never honour. It has to stop accepting one rather
473
+ * than accept it and ignore it.
474
+ */
475
+ describe("the editor does not offer a Default a multi-select ignores", () => {
476
+ function renderModal(variable: DashboardVariable): void {
477
+ render(
478
+ React.createElement(DashboardVariablesModal, {
479
+ variables: [variable],
480
+ telemetryAttributeOptions: [],
481
+ onClose: (): void => {},
482
+ onSave: (): void => {},
483
+ }),
484
+ );
485
+ }
486
+
487
+ function defaultInput(): HTMLInputElement {
488
+ return screen.getByPlaceholderText(
489
+ /^\(none\)$|^All$/,
490
+ ) as HTMLInputElement;
491
+ }
492
+
493
+ test("the Default input is disabled for a multi-select", () => {
494
+ renderModal(
495
+ makeVariable({
496
+ type: DashboardVariableType.TelemetryAttribute,
497
+ customListValues: undefined,
498
+ attributeKey: ATTRIBUTE_KEY,
499
+ isMultiSelect: true,
500
+ defaultValue: "prod",
501
+ }),
502
+ );
503
+
504
+ expect(defaultInput()).toBeDisabled();
505
+ // The stored value survives so unticking the box restores it.
506
+ expect(defaultInput()).toHaveValue("prod");
507
+ });
508
+
509
+ test("the Default input is editable for a single-select", () => {
510
+ renderModal(
511
+ makeVariable({
512
+ type: DashboardVariableType.TelemetryAttribute,
513
+ customListValues: undefined,
514
+ attributeKey: ATTRIBUTE_KEY,
515
+ defaultValue: "prod",
516
+ }),
517
+ );
518
+
519
+ expect(defaultInput()).toBeEnabled();
520
+ });
521
+
522
+ test("ticking Allow multi-select disables the Default there and then", () => {
523
+ renderModal(
524
+ makeVariable({
525
+ type: DashboardVariableType.TelemetryAttribute,
526
+ customListValues: undefined,
527
+ attributeKey: ATTRIBUTE_KEY,
528
+ defaultValue: "prod",
529
+ }),
530
+ );
531
+
532
+ expect(defaultInput()).toBeEnabled();
533
+
534
+ fireEvent.click(screen.getByLabelText(/Allow multi-select/));
535
+
536
+ expect(defaultInput()).toBeDisabled();
537
+ });
538
+ });
539
+ });