@oneuptime/common 11.7.1 → 11.7.3

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 (285) hide show
  1. package/Models/AnalyticsModels/KubernetesCostAllocation.ts +103 -0
  2. package/Models/DatabaseModels/DashboardDomain.ts +1 -0
  3. package/Models/DatabaseModels/Incident.ts +2 -0
  4. package/Models/DatabaseModels/IncidentEpisode.ts +1 -0
  5. package/Models/DatabaseModels/IncidentEpisodePublicNote.ts +1 -0
  6. package/Models/DatabaseModels/IncidentEpisodeStateTimeline.ts +1 -0
  7. package/Models/DatabaseModels/IncidentPublicNote.ts +1 -0
  8. package/Models/DatabaseModels/IncidentStateTimeline.ts +1 -0
  9. package/Models/DatabaseModels/Monitor.ts +1 -0
  10. package/Models/DatabaseModels/MonitorStatusTimeline.ts +1 -0
  11. package/Models/DatabaseModels/NetworkSite.ts +1 -0
  12. package/Models/DatabaseModels/NetworkSiteStatusTimeline.ts +1 -0
  13. package/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.ts +1 -0
  14. package/Models/DatabaseModels/OnCallDutyPolicySchedule.ts +2 -0
  15. package/Models/DatabaseModels/Probe.ts +13 -13
  16. package/Models/DatabaseModels/ScheduledMaintenance.ts +1 -0
  17. package/Models/DatabaseModels/ScheduledMaintenancePublicNote.ts +1 -0
  18. package/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.ts +1 -0
  19. package/Models/DatabaseModels/ScheduledMaintenanceTemplate.ts +1 -0
  20. package/Models/DatabaseModels/StatusPage.ts +1 -0
  21. package/Models/DatabaseModels/StatusPageAnnouncement.ts +1 -0
  22. package/Models/DatabaseModels/StatusPageDomain.ts +1 -0
  23. package/Models/DatabaseModels/TableView.ts +40 -0
  24. package/Models/DatabaseModels/WorkspaceNotificationSummary.ts +1 -0
  25. package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +11 -0
  26. package/Server/API/BaseAPI.ts +17 -1
  27. package/Server/API/CommonAPI.ts +32 -0
  28. package/Server/API/MicrosoftTeamsAPI.ts +99 -2
  29. package/Server/API/ProbeAPI.ts +2 -0
  30. package/Server/API/SlackAPI.ts +62 -0
  31. package/Server/API/StatusPageAPI.ts +157 -192
  32. package/Server/Infrastructure/Postgres/SchemaMigrations/1785140242697-AddHotQueryIndexes.ts +89 -0
  33. package/Server/Infrastructure/Postgres/SchemaMigrations/1785148065137-AddHotQueryIndexesSecondPass.ts +61 -0
  34. package/Server/Infrastructure/Postgres/SchemaMigrations/1785240000000-RepairCrossProjectMonitorStatusReferences.ts +280 -0
  35. package/Server/Infrastructure/Postgres/SchemaMigrations/1785241000000-AddColumnsToTableView.ts +13 -0
  36. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
  37. package/Server/Services/DatabaseService.ts +11 -3
  38. package/Server/Services/MonitorGroupService.ts +145 -0
  39. package/Server/Services/MonitorService.ts +231 -30
  40. package/Server/Services/ProbeService.ts +319 -16
  41. package/Server/Services/StatusPageService.ts +72 -42
  42. package/Server/Services/WorkspaceNotificationRuleService.ts +232 -2
  43. package/Server/Utils/Database/PostgresErrorTranslator.ts +131 -0
  44. package/Server/Utils/Monitor/MonitorResource.ts +88 -35
  45. package/Server/Utils/Monitor/MonitorStatusTimeline.ts +21 -1
  46. package/Server/Utils/Monitor/MonitorStepsProjectValidator.ts +158 -0
  47. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +706 -6
  48. package/Tests/Models/AnalyticsModels/KubernetesCostAllocation.test.ts +16 -0
  49. package/Tests/Models/DatabaseModels/ProbeColumnAccessControl.test.ts +103 -0
  50. package/Tests/Server/API/BaseAPIUpdateNoOp.test.ts +135 -0
  51. package/Tests/Server/API/CommonAPIAuthGuard.test.ts +317 -0
  52. package/Tests/Server/API/MicrosoftTeamsManifest.test.ts +228 -0
  53. package/Tests/Server/API/ProbeAPI.test.ts +6 -0
  54. package/Tests/Server/API/ZZVerifyChatsAuth.test.ts +167 -0
  55. package/Tests/Server/Services/AddHotQueryIndexesMigration.test.ts +255 -0
  56. package/Tests/Server/Services/AddHotQueryIndexesSecondPassMigration.test.ts +258 -0
  57. package/Tests/Server/Services/DatabaseServiceSanitizeUpdateData.test.ts +1 -1
  58. package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +121 -0
  59. package/Tests/Server/Services/HeartbeatWriteFastPathSafety.test.ts +200 -0
  60. package/Tests/Server/Services/HookFreeWriteSafetySecondPass.test.ts +181 -0
  61. package/Tests/Server/Services/MonitorGroupServiceBatchedStatuses.test.ts +513 -0
  62. package/Tests/Server/Services/MonitorResourceProbeAgreementReuse.test.ts +492 -0
  63. package/Tests/Server/Services/MonitorServiceProbeSelection.test.ts +401 -0
  64. package/Tests/Server/Services/MonitorStatusTimelineFastPath.test.ts +453 -0
  65. package/Tests/Server/Services/ProbeAuthKeyCacheAndHeartbeat.test.ts +679 -0
  66. package/Tests/Server/Services/ServiceLevelObjectiveService.test.ts +3 -3
  67. package/Tests/Server/Services/StatusPageDomainResolutionCache.test.ts +245 -0
  68. package/Tests/Server/Services/StatusPageOverviewTimelineWindow.test.ts +283 -0
  69. package/Tests/Server/Services/StatusPageServiceMcp.test.ts +17 -1
  70. package/Tests/Server/Services/StatusPageServiceMonitorGroupBatching.test.ts +331 -0
  71. package/Tests/Server/Services/UserOnCallLogClaimNotificationRule.test.ts +12 -12
  72. package/Tests/Server/Services/WorkspaceNotificationRuleChats.test.ts +1390 -0
  73. package/Tests/Server/Utils/AI/Insights/InsightFixRouting.test.ts +4 -4
  74. package/Tests/Server/Utils/AI/Insights/InsightScanner.test.ts +2 -2
  75. package/Tests/Server/Utils/AI/Insights/InsightStore.test.ts +1 -3
  76. package/Tests/Server/Utils/AI/Insights/InsightStoreHardening.test.ts +1 -3
  77. package/Tests/Server/Utils/AI/Insights/InsightTriage.test.ts +1 -1
  78. package/Tests/Server/Utils/AI/Insights/InsightTriageRunner.test.ts +5 -5
  79. package/Tests/Server/Utils/Alert/AlertPrivacyFilter.test.ts +187 -0
  80. package/Tests/Server/Utils/AlertEpisode/AlertEpisodePrivacyFilter.test.ts +170 -0
  81. package/Tests/Server/Utils/Database/PostgresErrorTranslator.test.ts +125 -0
  82. package/Tests/Server/Utils/Incident/IncidentPrivacyFilter.test.ts +264 -0
  83. package/Tests/Server/Utils/IncidentEpisode/IncidentEpisodePrivacyFilter.test.ts +175 -0
  84. package/Tests/Server/Utils/Monitor/MonitorStepsProjectValidator.test.ts +181 -0
  85. package/Tests/Server/Utils/Monitor/NetworkDeviceWalkUtil.test.ts +1 -1
  86. package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +2 -2
  87. package/Tests/Server/Utils/Workspace/MicrosoftTeamsChannelsList.test.ts +341 -0
  88. package/Tests/Server/Utils/Workspace/MicrosoftTeamsChats.test.ts +2175 -0
  89. package/Tests/Server/Utils/Workspace/SlackChannelsList.test.ts +585 -0
  90. package/Tests/Types/Billing/MeteredPlan.test.ts +46 -0
  91. package/Tests/Types/JSONFunctions.test.ts +103 -1
  92. package/Tests/Types/Workspace/NotificationRules/NotificationRuleCondition.test.ts +219 -1
  93. package/Tests/UI/Components/BulkUpdateForm.test.tsx +174 -0
  94. package/Tests/UI/Components/CardModelDetailEdit.test.tsx +315 -0
  95. package/Tests/UI/Components/ModelDetailSelect.test.tsx +229 -0
  96. package/Tests/UI/Components/ModelTable/BaseModelTableBulkSelectAll.test.tsx +1258 -0
  97. package/Tests/UI/Components/ModelTable/BaseModelTableColumnCustomization.test.tsx +679 -0
  98. package/Tests/UI/Components/ModelTable/ColumnCustomizationModal.test.tsx +572 -0
  99. package/Tests/UI/Components/ModelTable/ColumnPreference.test.ts +1678 -0
  100. package/Tests/UI/Components/ModelTable/CustomFieldColumns.test.tsx +1094 -0
  101. package/Tests/UI/Components/ModelTableExportFromColumns.test.ts +153 -0
  102. package/Tests/UI/Components/MonacoLoader.test.ts +67 -0
  103. package/Tests/UI/Components/MonacoRuntime.test.ts +121 -0
  104. package/Tests/UI/Components/TableBulkCsvExport.test.tsx +212 -3
  105. package/Tests/UI/Utils/Project.test.ts +809 -0
  106. package/Tests/UI/Utils/TableColumnsToCsv.test.ts +360 -0
  107. package/Tests/Utils/Alerts/AlertMetricType.test.ts +143 -0
  108. package/Tests/Utils/Dashboard/VariableUrlState.test.ts +219 -0
  109. package/Tests/Utils/Incident/IncidentMetricType.test.ts +174 -0
  110. package/Tests/Utils/Monitor/MonitorProbeSelectionUtil.test.ts +145 -0
  111. package/Tests/Utils/StatusPage/ResourceUptime.test.ts +263 -0
  112. package/Tests/Utils/UserPreferences.test.ts +563 -0
  113. package/Types/JSONFunctions.ts +7 -2
  114. package/Types/Kubernetes/KubernetesCostIngest.ts +37 -1
  115. package/Types/Workspace/NotificationRules/BaseNotificationRule.ts +4 -0
  116. package/Types/Workspace/NotificationRules/NotificationRuleCondition.ts +25 -10
  117. package/Types/Workspace/WorkspaceMessagePayload.ts +1 -0
  118. package/UI/Components/BulkUpdate/BulkUpdateForm.tsx +63 -8
  119. package/UI/Components/CodeEditor/CodeEditor.tsx +3 -0
  120. package/UI/Components/CodeEditor/MonacoLoader.ts +36 -0
  121. package/UI/Components/Forms/ModelForm.tsx +41 -18
  122. package/UI/Components/MasterPage/MasterPage.tsx +65 -0
  123. package/UI/Components/ModelDetail/CardModelDetail.tsx +23 -1
  124. package/UI/Components/ModelDetail/ModelDetail.tsx +46 -1
  125. package/UI/Components/ModelTable/BaseModelTable.tsx +687 -34
  126. package/UI/Components/ModelTable/Column.ts +29 -0
  127. package/UI/Components/ModelTable/ColumnCustomizationModal.tsx +420 -0
  128. package/UI/Components/ModelTable/ColumnPreference.ts +482 -0
  129. package/UI/Components/ModelTable/CustomFieldColumns.tsx +326 -0
  130. package/UI/Components/ModelTable/ExportFromColumns.ts +57 -0
  131. package/UI/Components/ModelTable/TableView.tsx +24 -2
  132. package/UI/Components/ModelTable/useCustomFieldColumns.ts +150 -0
  133. package/UI/Components/Navbar/NavBar.tsx +66 -1
  134. package/UI/Components/SideMenu/SideMenu.tsx +24 -4
  135. package/UI/Components/Table/Table.tsx +66 -14
  136. package/UI/Components/Table/TableRow.tsx +180 -175
  137. package/UI/Components/Table/Types/Column.ts +20 -0
  138. package/UI/Utils/Project.ts +214 -18
  139. package/UI/Utils/TableColumnsToCsv.ts +86 -6
  140. package/UI/esbuild-config.js +34 -0
  141. package/Utils/Monitor/MonitorProbeSelectionUtil.ts +72 -0
  142. package/Utils/UserPreferences.ts +53 -0
  143. package/build/dist/Models/AnalyticsModels/KubernetesCostAllocation.js +86 -0
  144. package/build/dist/Models/AnalyticsModels/KubernetesCostAllocation.js.map +1 -1
  145. package/build/dist/Models/DatabaseModels/DashboardDomain.js +1 -0
  146. package/build/dist/Models/DatabaseModels/DashboardDomain.js.map +1 -1
  147. package/build/dist/Models/DatabaseModels/Incident.js +2 -0
  148. package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
  149. package/build/dist/Models/DatabaseModels/IncidentEpisode.js +1 -0
  150. package/build/dist/Models/DatabaseModels/IncidentEpisode.js.map +1 -1
  151. package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js +1 -0
  152. package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js.map +1 -1
  153. package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js +1 -0
  154. package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js.map +1 -1
  155. package/build/dist/Models/DatabaseModels/IncidentPublicNote.js +1 -0
  156. package/build/dist/Models/DatabaseModels/IncidentPublicNote.js.map +1 -1
  157. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js +1 -0
  158. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js.map +1 -1
  159. package/build/dist/Models/DatabaseModels/Monitor.js +1 -0
  160. package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
  161. package/build/dist/Models/DatabaseModels/MonitorStatusTimeline.js +1 -0
  162. package/build/dist/Models/DatabaseModels/MonitorStatusTimeline.js.map +1 -1
  163. package/build/dist/Models/DatabaseModels/NetworkSite.js +1 -0
  164. package/build/dist/Models/DatabaseModels/NetworkSite.js.map +1 -1
  165. package/build/dist/Models/DatabaseModels/NetworkSiteStatusTimeline.js +1 -0
  166. package/build/dist/Models/DatabaseModels/NetworkSiteStatusTimeline.js.map +1 -1
  167. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.js +1 -0
  168. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.js.map +1 -1
  169. package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js +2 -0
  170. package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js.map +1 -1
  171. package/build/dist/Models/DatabaseModels/Probe.js +13 -13
  172. package/build/dist/Models/DatabaseModels/Probe.js.map +1 -1
  173. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js +1 -0
  174. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js.map +1 -1
  175. package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js +1 -0
  176. package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js.map +1 -1
  177. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js +1 -0
  178. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js.map +1 -1
  179. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplate.js +1 -0
  180. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplate.js.map +1 -1
  181. package/build/dist/Models/DatabaseModels/StatusPage.js +1 -0
  182. package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
  183. package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js +1 -0
  184. package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js.map +1 -1
  185. package/build/dist/Models/DatabaseModels/StatusPageDomain.js +1 -0
  186. package/build/dist/Models/DatabaseModels/StatusPageDomain.js.map +1 -1
  187. package/build/dist/Models/DatabaseModels/TableView.js +40 -0
  188. package/build/dist/Models/DatabaseModels/TableView.js.map +1 -1
  189. package/build/dist/Models/DatabaseModels/WorkspaceNotificationSummary.js +1 -0
  190. package/build/dist/Models/DatabaseModels/WorkspaceNotificationSummary.js.map +1 -1
  191. package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
  192. package/build/dist/Server/API/BaseAPI.js +12 -1
  193. package/build/dist/Server/API/BaseAPI.js.map +1 -1
  194. package/build/dist/Server/API/CommonAPI.js +21 -0
  195. package/build/dist/Server/API/CommonAPI.js.map +1 -1
  196. package/build/dist/Server/API/MicrosoftTeamsAPI.js +72 -2
  197. package/build/dist/Server/API/MicrosoftTeamsAPI.js.map +1 -1
  198. package/build/dist/Server/API/ProbeAPI.js +2 -0
  199. package/build/dist/Server/API/ProbeAPI.js.map +1 -1
  200. package/build/dist/Server/API/SlackAPI.js +44 -0
  201. package/build/dist/Server/API/SlackAPI.js.map +1 -1
  202. package/build/dist/Server/API/StatusPageAPI.js +98 -152
  203. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  204. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785140242697-AddHotQueryIndexes.js +36 -0
  205. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785140242697-AddHotQueryIndexes.js.map +1 -0
  206. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785148065137-AddHotQueryIndexesSecondPass.js +26 -0
  207. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785148065137-AddHotQueryIndexesSecondPass.js.map +1 -0
  208. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785240000000-RepairCrossProjectMonitorStatusReferences.js +254 -0
  209. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785240000000-RepairCrossProjectMonitorStatusReferences.js.map +1 -0
  210. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785241000000-AddColumnsToTableView.js +12 -0
  211. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785241000000-AddColumnsToTableView.js.map +1 -0
  212. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
  213. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  214. package/build/dist/Server/Services/DatabaseService.js +10 -2
  215. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  216. package/build/dist/Server/Services/MonitorGroupService.js +118 -0
  217. package/build/dist/Server/Services/MonitorGroupService.js.map +1 -1
  218. package/build/dist/Server/Services/MonitorService.js +198 -24
  219. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  220. package/build/dist/Server/Services/ProbeService.js +238 -9
  221. package/build/dist/Server/Services/ProbeService.js.map +1 -1
  222. package/build/dist/Server/Services/StatusPageService.js +46 -39
  223. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  224. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +178 -3
  225. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
  226. package/build/dist/Server/Utils/Database/PostgresErrorTranslator.js +80 -0
  227. package/build/dist/Server/Utils/Database/PostgresErrorTranslator.js.map +1 -0
  228. package/build/dist/Server/Utils/Monitor/MonitorResource.js +67 -29
  229. package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
  230. package/build/dist/Server/Utils/Monitor/MonitorStatusTimeline.js +31 -14
  231. package/build/dist/Server/Utils/Monitor/MonitorStatusTimeline.js.map +1 -1
  232. package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js +117 -0
  233. package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js.map +1 -0
  234. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +549 -7
  235. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  236. package/build/dist/Types/JSONFunctions.js +8 -3
  237. package/build/dist/Types/JSONFunctions.js.map +1 -1
  238. package/build/dist/Types/Kubernetes/KubernetesCostIngest.js.map +1 -1
  239. package/build/dist/Types/Workspace/NotificationRules/NotificationRuleCondition.js +17 -7
  240. package/build/dist/Types/Workspace/NotificationRules/NotificationRuleCondition.js.map +1 -1
  241. package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js +37 -11
  242. package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js.map +1 -1
  243. package/build/dist/UI/Components/CodeEditor/CodeEditor.js +2 -0
  244. package/build/dist/UI/Components/CodeEditor/CodeEditor.js.map +1 -1
  245. package/build/dist/UI/Components/CodeEditor/MonacoLoader.js +34 -0
  246. package/build/dist/UI/Components/CodeEditor/MonacoLoader.js.map +1 -0
  247. package/build/dist/UI/Components/Forms/ModelForm.js +37 -17
  248. package/build/dist/UI/Components/Forms/ModelForm.js.map +1 -1
  249. package/build/dist/UI/Components/MasterPage/MasterPage.js +50 -1
  250. package/build/dist/UI/Components/MasterPage/MasterPage.js.map +1 -1
  251. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js +22 -1
  252. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js.map +1 -1
  253. package/build/dist/UI/Components/ModelDetail/ModelDetail.js +31 -1
  254. package/build/dist/UI/Components/ModelDetail/ModelDetail.js.map +1 -1
  255. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +472 -27
  256. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  257. package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js +189 -0
  258. package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js.map +1 -0
  259. package/build/dist/UI/Components/ModelTable/ColumnPreference.js +258 -0
  260. package/build/dist/UI/Components/ModelTable/ColumnPreference.js.map +1 -0
  261. package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js +168 -0
  262. package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js.map +1 -0
  263. package/build/dist/UI/Components/ModelTable/ExportFromColumns.js +30 -0
  264. package/build/dist/UI/Components/ModelTable/ExportFromColumns.js.map +1 -0
  265. package/build/dist/UI/Components/ModelTable/TableView.js +13 -2
  266. package/build/dist/UI/Components/ModelTable/TableView.js.map +1 -1
  267. package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js +84 -0
  268. package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js.map +1 -0
  269. package/build/dist/UI/Components/Navbar/NavBar.js +39 -1
  270. package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
  271. package/build/dist/UI/Components/SideMenu/SideMenu.js +15 -5
  272. package/build/dist/UI/Components/SideMenu/SideMenu.js.map +1 -1
  273. package/build/dist/UI/Components/Table/Table.js +46 -13
  274. package/build/dist/UI/Components/Table/Table.js.map +1 -1
  275. package/build/dist/UI/Components/Table/TableRow.js +11 -6
  276. package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
  277. package/build/dist/UI/Utils/Project.js +161 -15
  278. package/build/dist/UI/Utils/Project.js.map +1 -1
  279. package/build/dist/UI/Utils/TableColumnsToCsv.js +67 -6
  280. package/build/dist/UI/Utils/TableColumnsToCsv.js.map +1 -1
  281. package/build/dist/Utils/Monitor/MonitorProbeSelectionUtil.js +52 -0
  282. package/build/dist/Utils/Monitor/MonitorProbeSelectionUtil.js.map +1 -0
  283. package/build/dist/Utils/UserPreferences.js +33 -0
  284. package/build/dist/Utils/UserPreferences.js.map +1 -1
  285. package/package.json +4 -3
@@ -9,7 +9,7 @@ import ScheduledMaintenanceState from "../../../Models/DatabaseModels/ScheduledM
9
9
  import { DropdownOption } from "../../../UI/Components/Dropdown/Dropdown";
10
10
  import DropdownUtil from "../../../UI/Utils/Dropdown";
11
11
  import MonitorType from "../../Monitor/MonitorType";
12
- import WorkspaceType from "../WorkspaceType";
12
+ import WorkspaceType, { getWorkspaceTypeDisplayName } from "../WorkspaceType";
13
13
  import NotificationRuleEventType from "./EventType";
14
14
  import IncidentNotificationRule from "./NotificationRuleTypes/IncidentNotificationRule";
15
15
 
@@ -108,32 +108,47 @@ export class NotificationRuleConditionUtil {
108
108
  eventType === NotificationRuleEventType.IncidentEpisode ||
109
109
  eventType === NotificationRuleEventType.ScheduledMaintenance
110
110
  ) {
111
- // either create slack channel or select existing one should be active.
111
+ // either create a channel, post to an existing channel, or post to a chat.
112
+
113
+ const workspaceDisplayName: string =
114
+ getWorkspaceTypeDisplayName(workspaceType);
112
115
 
113
116
  if (
114
117
  !notificationRule.shouldCreateNewChannel &&
115
- !notificationRule.shouldPostToExistingChannel
118
+ !notificationRule.shouldPostToExistingChannel &&
119
+ !notificationRule.shouldPostToExistingChat
116
120
  ) {
117
- return (
118
- "Please select either create slack channel or post to existing " +
119
- workspaceType +
120
- " channel"
121
- );
121
+ return workspaceType === WorkspaceType.MicrosoftTeams
122
+ ? `Please select a destination: create a ${workspaceDisplayName} channel, post to an existing ${workspaceDisplayName} channel, or post to an existing ${workspaceDisplayName} chat`
123
+ : `Please select a destination: create a ${workspaceDisplayName} channel or post to an existing ${workspaceDisplayName} channel`;
122
124
  }
123
125
 
124
126
  if (notificationRule.shouldPostToExistingChannel) {
125
127
  if (!notificationRule.existingChannelNames?.trim()) {
126
- return "Existing " + workspaceType + " channel name is required";
128
+ return (
129
+ "Existing " + workspaceDisplayName + " channel name is required"
130
+ );
127
131
  }
128
132
  }
129
133
 
130
134
  if (notificationRule.shouldCreateNewChannel) {
131
135
  if (!notificationRule.newChannelTemplateName?.trim()) {
132
- return "New " + workspaceType + " channel name is required";
136
+ return "New " + workspaceDisplayName + " channel name is required";
133
137
  }
134
138
  }
135
139
  }
136
140
 
141
+ if (notificationRule.shouldPostToExistingChat) {
142
+ if (
143
+ !notificationRule.existingChatIds ||
144
+ notificationRule.existingChatIds.length === 0
145
+ ) {
146
+ const workspaceDisplayName: string =
147
+ getWorkspaceTypeDisplayName(workspaceType);
148
+ return `Please select at least one ${workspaceDisplayName} chat to post to. If no chats are listed, add the OneUptime app to a chat in ${workspaceDisplayName} first.`;
149
+ }
150
+ }
151
+
137
152
  return null;
138
153
  }
139
154
 
@@ -106,4 +106,5 @@ export default interface WorkspaceMessagePayload {
106
106
  messageBlocks: Array<WorkspaceMessageBlock>; // Message to add to blocks.
107
107
  workspaceType: WorkspaceType;
108
108
  teamId?: string | undefined; // Team ID for Microsoft Teams
109
+ chatIds?: Array<string> | undefined; // Microsoft Teams chat ids (group / personal chats) to send message to.
109
110
  }
@@ -67,6 +67,21 @@ export interface ComponentProps<T extends GenericObject> {
67
67
  onActionStart?: (() => void) | undefined;
68
68
  onActionEnd?: (() => void) | undefined;
69
69
  itemToString?: ((item: T) => string) | undefined;
70
+ /*
71
+ * Selecting everything is a multi-request fetch that can fail. Surfacing it
72
+ * here - next to the button the user pressed - keeps the message alive; the
73
+ * table body's own error is wiped by the next refresh.
74
+ */
75
+ errorMessage?: string | undefined;
76
+ isSelectingAllItems?: boolean | undefined;
77
+ /*
78
+ * Set when the selection hit the per-selection ceiling and there are more
79
+ * matching rows than were selected. `totalMatchingItemsCount` is how many
80
+ * rows actually matched, so the warning can name real numbers instead of
81
+ * inferring truncation from the selected count.
82
+ */
83
+ isSelectionTruncated?: boolean | undefined;
84
+ totalMatchingItemsCount?: number | undefined;
70
85
  }
71
86
 
72
87
  const isDangerStyle: (style: ButtonStyleType) => boolean = (
@@ -317,9 +332,16 @@ const BulkUpdateForm: <T extends GenericObject>(
317
332
  menuChildren.push(renderMenuItem(button, safeButtons.length + index));
318
333
  });
319
334
 
320
- const showLimitWarning: boolean =
321
- props.isAllItemsSelected &&
322
- props.selectedItems.length === LIMIT_PER_PROJECT;
335
+ /*
336
+ * Driven by what the fetch actually reported rather than by
337
+ * `selectedItems.length === LIMIT_PER_PROJECT`, which both cried wolf on a
338
+ * project holding exactly the ceiling and stayed silent whenever a partial
339
+ * selection came back one row short of it.
340
+ */
341
+ const showLimitWarning: boolean = Boolean(props.isSelectionTruncated);
342
+
343
+ const totalMatchingItemsCount: number =
344
+ props.totalMatchingItemsCount || props.selectedItems.length;
323
345
 
324
346
  return (
325
347
  <div>
@@ -345,13 +367,33 @@ const BulkUpdateForm: <T extends GenericObject>(
345
367
  {!props.isAllItemsSelected && (
346
368
  <button
347
369
  type="button"
370
+ disabled={props.isSelectingAllItems}
348
371
  onClick={() => {
372
+ if (props.isSelectingAllItems) {
373
+ // the fetch is paged, so it must not be re-entrant.
374
+ return;
375
+ }
349
376
  props.onSelectAllClick();
350
377
  }}
351
- className="inline-flex items-center gap-1.5 rounded-lg border border-gray-300 bg-white px-3 py-1.5 text-sm font-medium text-gray-700 shadow-sm hover:bg-indigo-50 hover:border-indigo-300 hover:text-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 transition-all duration-150 cursor-pointer select-none"
378
+ className={`inline-flex items-center gap-1.5 rounded-lg border border-gray-300 bg-white px-3 py-1.5 text-sm font-medium text-gray-700 shadow-sm focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 transition-all duration-150 select-none ${
379
+ props.isSelectingAllItems
380
+ ? "opacity-50 cursor-not-allowed"
381
+ : "cursor-pointer hover:bg-indigo-50 hover:border-indigo-300 hover:text-indigo-700"
382
+ }`}
352
383
  >
353
- <Icon icon={IconProp.CheckCircle} className="h-3.5 w-3.5" />
354
- <span>Select All {props.pluralLabel}</span>
384
+ <Icon
385
+ icon={
386
+ props.isSelectingAllItems
387
+ ? IconProp.Spinner
388
+ : IconProp.CheckCircle
389
+ }
390
+ className="h-3.5 w-3.5"
391
+ />
392
+ <span>
393
+ {props.isSelectingAllItems
394
+ ? `Selecting All ${props.pluralLabel}...`
395
+ : `Select All ${props.pluralLabel}`}
396
+ </span>
355
397
  </button>
356
398
  )}
357
399
 
@@ -393,8 +435,21 @@ const BulkUpdateForm: <T extends GenericObject>(
393
435
 
394
436
  {showLimitWarning && (
395
437
  <div className="mt-2 text-xs text-gray-500">
396
- You can only select {LIMIT_PER_PROJECT} {props.pluralLabel} at a
397
- time. This is for performance reasons.
438
+ Selected {props.selectedItems.length.toLocaleString()} of{" "}
439
+ {totalMatchingItemsCount.toLocaleString()} matching{" "}
440
+ {props.pluralLabel}. You can only select{" "}
441
+ {LIMIT_PER_PROJECT.toLocaleString()} {props.pluralLabel} at a
442
+ time, for performance reasons, so bulk actions will apply to the
443
+ selected {props.selectedItems.length.toLocaleString()} only.
444
+ </div>
445
+ )}
446
+
447
+ {props.errorMessage && (
448
+ <div
449
+ role="alert"
450
+ className="mt-2 rounded-lg bg-red-50 p-3 text-sm text-red-800"
451
+ >
452
+ {props.errorMessage}
398
453
  </div>
399
454
  )}
400
455
  </div>
@@ -1,4 +1,5 @@
1
1
  import Editor from "@monaco-editor/react";
2
+ import configureMonacoLoader from "./MonacoLoader";
2
3
  import CodeType from "../../../Types/Code/CodeType";
3
4
  import MarkdownUtil from "../../Utils/Markdown";
4
5
  import { Theme, useTheme } from "../../Utils/Theme";
@@ -10,6 +11,8 @@ import React, {
10
11
  useState,
11
12
  } from "react";
12
13
 
14
+ configureMonacoLoader();
15
+
13
16
  export interface ComponentProps {
14
17
  initialValue?: undefined | string;
15
18
  onClick?: undefined | (() => void);
@@ -0,0 +1,36 @@
1
+ import { loader } from "@monaco-editor/react";
2
+
3
+ /**
4
+ * Points Monaco at the copy of its runtime that ships with the app.
5
+ *
6
+ * @monaco-editor/loader otherwise fetches it from cdn.jsdelivr.net at runtime,
7
+ * which never resolves on an air-gapped install and leaves every code editor
8
+ * stuck on "Loading...". The path is baked in by the build, which is the only
9
+ * place that knows where this service is mounted.
10
+ *
11
+ * The path has to be absolute. Monaco loads its language services in a worker
12
+ * spun up from a blob: URL, and a blob worker has no base to resolve a
13
+ * root-relative path against - it fetches "/dashboard/assets/monaco/vs/..." and
14
+ * throws "Failed to parse URL". The editor still renders, so the only visible
15
+ * symptom is that JSON/TypeScript validation and IntelliSense quietly stop
16
+ * working. The CDN default never hit this because it was already absolute.
17
+ *
18
+ * The monaco-editor version in Common/package.json is pinned exactly, because
19
+ * the loader resolves init() with whatever the AMD module `vs/editor/editor.main`
20
+ * exports and that shape is not stable across releases - 0.53 and 0.54 nest the
21
+ * API under `exports.m`, which leaves `monaco.editor` undefined and makes every
22
+ * editor throw instead of mount. MonacoRuntime.test.ts guards the pin.
23
+ */
24
+ export default function configureMonacoLoader(): void {
25
+ const assetPath: string | undefined = process.env["MONACO_ASSET_PATH"];
26
+
27
+ if (!assetPath) {
28
+ return;
29
+ }
30
+
31
+ loader.config({
32
+ paths: {
33
+ vs: new URL(assetPath, window.location.origin).href,
34
+ },
35
+ });
36
+ }
@@ -641,27 +641,50 @@ const ModelForm: <TBaseModel extends BaseModel>(
641
641
  return fields;
642
642
  };
643
643
 
644
+ /*
645
+ * Keyed on the id (as a string - ObjectID identity changes every render)
646
+ * so a form that mounts before its id is known still fetches once it
647
+ * arrives. It used to run only on mount, which left an Update form showing
648
+ * blank defaults: submitting that silently wrote empty values - and false
649
+ * for every Toggle, since BasicForm defaults untouched toggles to false -
650
+ * over the real record.
651
+ */
644
652
  useAsyncEffect(async () => {
645
- if (
646
- props.modelIdToEdit &&
647
- props.formType === FormType.Update &&
648
- !props.doNotFetchExistingModel
649
- ) {
650
- // get item.
651
- setLoading(true);
652
- setIsFetching(true);
653
- setError("");
654
- try {
655
- await fetchItem();
656
- } catch (err) {
657
- setError(API.getFriendlyMessage(err));
658
- props.onError?.(API.getFriendlyMessage(err));
659
- }
653
+ if (props.formType !== FormType.Update || props.doNotFetchExistingModel) {
654
+ return;
655
+ }
656
+
657
+ if (!props.modelIdToEdit) {
658
+ /*
659
+ * Without an id there is nothing to prefill and nothing to update, so
660
+ * say so rather than rendering an empty form that looks editable.
661
+ *
662
+ * Deliberately not props.onError: ModelFormModal unmounts the form on
663
+ * that, and this state is recoverable - the effect re-runs and clears
664
+ * the message as soon as the id arrives.
665
+ */
666
+ setError(
667
+ `Cannot edit this ${(
668
+ model.singularName || "item"
669
+ ).toLowerCase()} yet because it is still loading. Please try again in a moment.`,
670
+ );
671
+ return;
672
+ }
660
673
 
661
- setLoading(false);
662
- setIsFetching(false);
674
+ // get item.
675
+ setLoading(true);
676
+ setIsFetching(true);
677
+ setError("");
678
+ try {
679
+ await fetchItem();
680
+ } catch (err) {
681
+ setError(API.getFriendlyMessage(err));
682
+ props.onError?.(API.getFriendlyMessage(err));
663
683
  }
664
- }, []);
684
+
685
+ setLoading(false);
686
+ setIsFetching(false);
687
+ }, [props.modelIdToEdit?.toString()]);
665
688
 
666
689
  type GetMiscDataPropsFunction = (
667
690
  values: FormValues<JSONObject>,
@@ -27,6 +27,70 @@ const MasterPage: FunctionComponent<ComponentProps> = (
27
27
  props: ComponentProps,
28
28
  ): ReactElement => {
29
29
  const [isOnline, setIsOnline] = React.useState(true);
30
+ const topSectionRef: React.RefObject<HTMLDivElement> =
31
+ React.useRef<HTMLDivElement>(null);
32
+
33
+ /*
34
+ * Publish the sticky top section's height as --app-header-height so anything
35
+ * that sticks underneath it (the side menu, for example) can offset itself by
36
+ * the real header instead of guessing and ending up tucked behind it. The
37
+ * height is not a constant — it changes when the navbar is hidden, when the
38
+ * header wraps on narrow viewports and when top alerts appear — so keep it in
39
+ * sync rather than measuring once.
40
+ */
41
+ React.useLayoutEffect(() => {
42
+ const setHeaderHeight: (height: number) => void = (
43
+ height: number,
44
+ ): void => {
45
+ document.documentElement.style.setProperty(
46
+ "--app-header-height",
47
+ `${height}px`,
48
+ );
49
+ };
50
+
51
+ const element: HTMLDivElement | null = topSectionRef.current;
52
+
53
+ if (!element || props.makeTopSectionUnstick) {
54
+ // Nothing is overlaying the content, so no offset is needed.
55
+ setHeaderHeight(0);
56
+ return undefined;
57
+ }
58
+
59
+ const measure: () => void = (): void => {
60
+ setHeaderHeight(element.offsetHeight);
61
+ };
62
+
63
+ measure();
64
+
65
+ /*
66
+ * ResizeObserver is missing in jsdom and in older browsers, so fall back to
67
+ * resize events there — less precise, but the header only really changes
68
+ * height when the viewport does.
69
+ */
70
+ if (typeof ResizeObserver === "undefined") {
71
+ window.addEventListener("resize", measure);
72
+
73
+ return () => {
74
+ window.removeEventListener("resize", measure);
75
+ document.documentElement.style.removeProperty("--app-header-height");
76
+ };
77
+ }
78
+
79
+ const observer: ResizeObserver = new ResizeObserver(measure);
80
+ observer.observe(element);
81
+
82
+ return () => {
83
+ observer.disconnect();
84
+ document.documentElement.style.removeProperty("--app-header-height");
85
+ };
86
+ }, [
87
+ props.makeTopSectionUnstick,
88
+ props.hideHeader,
89
+ props.isLoading,
90
+ props.error,
91
+ props.disableMainContentWrapper,
92
+ isOnline,
93
+ ]);
30
94
 
31
95
  if (props.isLoading) {
32
96
  return (
@@ -62,6 +126,7 @@ const MasterPage: FunctionComponent<ComponentProps> = (
62
126
  </a>
63
127
  )}
64
128
  <div
129
+ ref={topSectionRef}
65
130
  className={props.makeTopSectionUnstick ? "" : "sticky top-0 z-10"}
66
131
  >
67
132
  <TopSection
@@ -12,6 +12,8 @@ import Fields from "../Forms/Types/Fields";
12
12
  import { FormStep } from "../Forms/Types/FormStep";
13
13
  import { ModalWidth } from "../Modal/Modal";
14
14
  import ModelFormModal from "../ModelFormModal/ModelFormModal";
15
+ import { ToastType } from "../Toast/Toast";
16
+ import { ShowToastNotification } from "../Toast/ToastInit";
15
17
  import ModelDetail, { ComponentProps as ModeDetailProps } from "./ModelDetail";
16
18
  import BaseModel from "../../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
17
19
  import IconProp from "../../../Types/Icon/IconProp";
@@ -165,6 +167,16 @@ const CardModelDetail: <TBaseModel extends BaseModel>(
165
167
  onSuccess={(item: TBaseModel) => {
166
168
  setShowModal(false);
167
169
  setRefresher(!refresher);
170
+ /*
171
+ * The modal just disappears otherwise, which reads as "nothing
172
+ * happened" - especially on cards that do not display every field
173
+ * the edit form exposes.
174
+ */
175
+ ShowToastNotification({
176
+ title: "Changes saved",
177
+ description: `${model.singularName || "Item"} updated successfully.`,
178
+ type: ToastType.SUCCESS,
179
+ });
168
180
  if (props.onSaveSuccess) {
169
181
  props.onSaveSuccess(item);
170
182
  }
@@ -180,7 +192,17 @@ const CardModelDetail: <TBaseModel extends BaseModel>(
180
192
  steps: props.formSteps || [],
181
193
  createOrUpdateApiUrl: props.createOrUpdateApiUrl,
182
194
  }}
183
- modelIdToEdit={item?.id || undefined}
195
+ /*
196
+ * Prefer the id the caller already handed us. Deriving it purely
197
+ * from the loaded item meant that opening the modal before (or
198
+ * without) a successful detail fetch produced an Update form with
199
+ * no id: ModelForm silently skipped its fetch, rendered defaults,
200
+ * and BasicForm coerced every untouched Toggle to false - so
201
+ * saving quietly wrote blank values over the real record.
202
+ */
203
+ modelIdToEdit={
204
+ props.modelDetailProps.modelId || item?.id || undefined
205
+ }
184
206
  />
185
207
  ) : (
186
208
  <></>
@@ -51,15 +51,55 @@ const ModelDetail: <TBaseModel extends BaseModel>(
51
51
  JSONObject | undefined
52
52
  >(undefined);
53
53
 
54
+ type HasPermissionToReadFieldFunction = (fieldName: string) => boolean;
55
+
56
+ /*
57
+ * The server rejects the WHOLE get-item request when the select names a
58
+ * single column the caller cannot read (SelectPermission.checkSelectPermission
59
+ * throws NotAuthorizedException), which blanks the entire card instead of
60
+ * hiding one row. setDetailFields() below already drops unreadable fields
61
+ * from the render, so the fetch has to drop them too - the same thing
62
+ * BaseModelTable does for its selectMoreFields.
63
+ */
64
+ const hasPermissionToReadField: HasPermissionToReadFieldFunction = (
65
+ fieldName: string,
66
+ ): boolean => {
67
+ if (User.isMasterAdmin()) {
68
+ return true;
69
+ }
70
+
71
+ const accessControl: Dictionary<ColumnAccessControl> =
72
+ new props.modelType().getColumnAccessControlForAllColumns() || {};
73
+
74
+ const fieldPermissions: Array<Permission> =
75
+ accessControl[fieldName]?.read || [];
76
+
77
+ return PermissionHelper.doesPermissionsIntersect(
78
+ PermissionUtil.getAllPermissions(),
79
+ fieldPermissions,
80
+ );
81
+ };
82
+
54
83
  type GetSelectFields = () => Select<TBaseModel>;
55
84
 
56
85
  const getSelectFields: GetSelectFields = (): Select<TBaseModel> => {
57
86
  const select: Select<TBaseModel> = {};
87
+
88
+ /*
89
+ * _id is never a declared field on most cards, but CardModelDetail needs
90
+ * it to know which record its edit modal is updating. It is exempt from
91
+ * select permission checks server-side, so it is always safe to ask for.
92
+ */
93
+ (select as Dictionary<boolean>)["_id"] = true;
94
+
58
95
  for (const field of props.fields) {
59
96
  if (!field.field) {
60
97
  continue;
61
98
  }
62
99
  for (const key of Object.keys(field.field)) {
100
+ if (!hasPermissionToReadField(key)) {
101
+ continue;
102
+ }
63
103
  select[key as keyof TBaseModel] = true;
64
104
  }
65
105
  }
@@ -70,7 +110,8 @@ const ModelDetail: <TBaseModel extends BaseModel>(
70
110
  typeof field === "string" &&
71
111
  field &&
72
112
  props.selectMoreFields &&
73
- (props.selectMoreFields as Select<TBaseModel>)[keyofField]
113
+ (props.selectMoreFields as Select<TBaseModel>)[keyofField] &&
114
+ hasPermissionToReadField(field)
74
115
  ) {
75
116
  select[keyofField] = props.selectMoreFields[keyofField] as JSONObject;
76
117
  }
@@ -91,6 +132,10 @@ const ModelDetail: <TBaseModel extends BaseModel>(
91
132
  continue;
92
133
  }
93
134
  for (const key of Object.keys(field.field)) {
135
+ if (!hasPermissionToReadField(key)) {
136
+ continue;
137
+ }
138
+
94
139
  if (model.isFileColumn(key)) {
95
140
  (relationSelect as JSONObject)[key] = {
96
141
  file: true,