@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
@@ -0,0 +1,572 @@
1
+ import ColumnCustomizationModal from "../../../../UI/Components/ModelTable/ColumnCustomizationModal";
2
+ import {
3
+ CustomizableColumn,
4
+ ModelTableColumn,
5
+ } from "../../../../UI/Components/ModelTable/ColumnPreference";
6
+ import FieldType from "../../../../UI/Components/Types/FieldType";
7
+ import Monitor from "../../../../Models/DatabaseModels/Monitor";
8
+ import getJestMockFunction, { MockFunction } from "../../../MockType";
9
+ import "@testing-library/jest-dom";
10
+ import {
11
+ RenderResult,
12
+ cleanup,
13
+ fireEvent,
14
+ render,
15
+ } from "@testing-library/react";
16
+ import React from "react";
17
+ import {
18
+ afterEach,
19
+ beforeEach,
20
+ describe,
21
+ expect,
22
+ jest,
23
+ test,
24
+ } from "@jest/globals";
25
+
26
+ /*
27
+ * The "Customize Columns" picker. Two invariants carry real weight here and
28
+ * are pinned below:
29
+ *
30
+ * 1. Nothing leaves the modal until Save. Cancel has to be a genuine escape
31
+ * hatch, so every checkbox and every reorder is staged in local state.
32
+ *
33
+ * 2. The viewer can never end up with zero columns. A table with no columns
34
+ * renders as an empty shell with no header row, and the only control that
35
+ * could undo that is the picker they just closed. Both the per-row
36
+ * checkbox and "Hide all" have to respect that.
37
+ *
38
+ * Drag-and-drop is deliberately not exercised: react-beautiful-dnd renders
39
+ * fine in jsdom but a synthetic drag cannot be driven through it. The Up/Down
40
+ * buttons exist precisely so that reordering is reachable without a pointer,
41
+ * which also makes it the reorder path these tests use.
42
+ */
43
+
44
+ type MakeEntryFunction = (data: {
45
+ id: string;
46
+ title: string;
47
+ isVisible: boolean;
48
+ }) => CustomizableColumn<Monitor>;
49
+
50
+ const makeEntry: MakeEntryFunction = (data: {
51
+ id: string;
52
+ title: string;
53
+ isVisible: boolean;
54
+ }): CustomizableColumn<Monitor> => {
55
+ const column: ModelTableColumn<Monitor> = {
56
+ field: { name: true },
57
+ title: data.title,
58
+ type: FieldType.Text,
59
+ };
60
+
61
+ return {
62
+ id: data.id,
63
+ column: column,
64
+ isVisible: data.isVisible,
65
+ isPinned: false,
66
+ };
67
+ };
68
+
69
+ type GetDefaultColumnsFunction = () => Array<CustomizableColumn<Monitor>>;
70
+
71
+ // Three on, one off - so the count line has something to say from the start.
72
+ const getDefaultColumns: GetDefaultColumnsFunction = (): Array<
73
+ CustomizableColumn<Monitor>
74
+ > => {
75
+ return [
76
+ makeEntry({ id: "name", title: "Monitor Name", isVisible: true }),
77
+ makeEntry({
78
+ id: "currentMonitorStatus",
79
+ title: "Status",
80
+ isVisible: true,
81
+ }),
82
+ makeEntry({ id: "description", title: "Description", isVisible: true }),
83
+ makeEntry({ id: "createdAt", title: "Created At", isVisible: false }),
84
+ ];
85
+ };
86
+
87
+ interface RenderedModal {
88
+ view: RenderResult;
89
+ onSave: MockFunction;
90
+ onClose: MockFunction;
91
+ onReset: MockFunction;
92
+ }
93
+
94
+ type RenderModalFunction = (data?: {
95
+ columns?: Array<CustomizableColumn<Monitor>> | undefined;
96
+ isDefaultLayout?: boolean | undefined;
97
+ title?: string | undefined;
98
+ }) => RenderedModal;
99
+
100
+ const renderModal: RenderModalFunction = (data?: {
101
+ columns?: Array<CustomizableColumn<Monitor>> | undefined;
102
+ isDefaultLayout?: boolean | undefined;
103
+ title?: string | undefined;
104
+ }): RenderedModal => {
105
+ const onSave: MockFunction = getJestMockFunction();
106
+ const onClose: MockFunction = getJestMockFunction();
107
+ const onReset: MockFunction = getJestMockFunction();
108
+
109
+ const view: RenderResult = render(
110
+ <ColumnCustomizationModal<Monitor>
111
+ columns={data?.columns || getDefaultColumns()}
112
+ onSave={onSave}
113
+ onClose={onClose}
114
+ onReset={onReset}
115
+ isDefaultLayout={data?.isDefaultLayout}
116
+ title={data?.title}
117
+ />,
118
+ );
119
+
120
+ return { view, onSave, onClose, onReset };
121
+ };
122
+
123
+ type GetSavedFunction = (
124
+ onSave: MockFunction,
125
+ ) => Array<CustomizableColumn<Monitor>>;
126
+
127
+ const getSaved: GetSavedFunction = (
128
+ onSave: MockFunction,
129
+ ): Array<CustomizableColumn<Monitor>> => {
130
+ return onSave.mock.calls[0]![0] as Array<CustomizableColumn<Monitor>>;
131
+ };
132
+
133
+ type GetSavedIdsFunction = (onSave: MockFunction) => Array<string>;
134
+
135
+ const getSavedIds: GetSavedIdsFunction = (
136
+ onSave: MockFunction,
137
+ ): Array<string> => {
138
+ return getSaved(onSave).map((entry: CustomizableColumn<Monitor>) => {
139
+ return entry.id;
140
+ });
141
+ };
142
+
143
+ type TypeSearchFunction = (view: RenderResult, text: string) => void;
144
+
145
+ const typeSearch: TypeSearchFunction = (
146
+ view: RenderResult,
147
+ text: string,
148
+ ): void => {
149
+ fireEvent.change(view.getByTestId("column-customization-search"), {
150
+ target: { value: text },
151
+ });
152
+ };
153
+
154
+ describe("ColumnCustomizationModal", () => {
155
+ beforeEach(() => {
156
+ /*
157
+ * The whole Common suite runs --runInBand, so storage written by an
158
+ * earlier file is still around. Nothing here reads it, but leaving it
159
+ * behind is how the next test starts flaking.
160
+ */
161
+ window.localStorage.clear();
162
+ });
163
+
164
+ afterEach(() => {
165
+ cleanup();
166
+ jest.restoreAllMocks();
167
+ });
168
+
169
+ test("renders one row per column, with the titles visible", () => {
170
+ const { view }: RenderedModal = renderModal();
171
+
172
+ expect(view.getByTestId("column-customization-modal")).toBeInTheDocument();
173
+ expect(view.getAllByTestId(/^column-toggle-/)).toHaveLength(4);
174
+
175
+ expect(view.getByText("Monitor Name")).toBeInTheDocument();
176
+ expect(view.getByText("Status")).toBeInTheDocument();
177
+ expect(view.getByText("Description")).toBeInTheDocument();
178
+ expect(view.getByText("Created At")).toBeInTheDocument();
179
+
180
+ expect(view.getByTestId("column-toggle-name")).toBeChecked();
181
+ expect(view.getByTestId("column-toggle-createdAt")).not.toBeChecked();
182
+ });
183
+
184
+ test("counts the visible columns and keeps the count in step with the checkboxes", () => {
185
+ const { view }: RenderedModal = renderModal();
186
+
187
+ expect(view.getByTestId("column-customization-count")).toHaveTextContent(
188
+ "3 of 4 columns shown",
189
+ );
190
+
191
+ fireEvent.click(view.getByTestId("column-toggle-createdAt"));
192
+
193
+ expect(view.getByTestId("column-customization-count")).toHaveTextContent(
194
+ "4 of 4 columns shown",
195
+ );
196
+
197
+ fireEvent.click(view.getByTestId("column-toggle-description"));
198
+
199
+ expect(view.getByTestId("column-customization-count")).toHaveTextContent(
200
+ "3 of 4 columns shown",
201
+ );
202
+ });
203
+
204
+ test("stages changes locally: nothing is handed back before Save", () => {
205
+ const { view, onSave }: RenderedModal = renderModal();
206
+
207
+ fireEvent.click(view.getByTestId("column-toggle-description"));
208
+
209
+ expect(onSave).not.toHaveBeenCalled();
210
+ });
211
+
212
+ test("Cancel discards the staged changes", () => {
213
+ const { view, onSave, onClose }: RenderedModal = renderModal();
214
+
215
+ fireEvent.click(view.getByTestId("column-toggle-description"));
216
+ fireEvent.click(view.getByTestId("modal-footer-close-button"));
217
+
218
+ // The caller is told to close and is told nothing else - the edit is gone.
219
+ expect(onClose).toHaveBeenCalledTimes(1);
220
+ expect(onSave).not.toHaveBeenCalled();
221
+ });
222
+
223
+ test("Save hands back every entry with its new isVisible flag", () => {
224
+ const { view, onSave }: RenderedModal = renderModal();
225
+
226
+ fireEvent.click(view.getByTestId("column-toggle-description"));
227
+ fireEvent.click(view.getByTestId("column-toggle-createdAt"));
228
+ fireEvent.click(view.getByTestId("modal-footer-submit-button"));
229
+
230
+ expect(onSave).toHaveBeenCalledTimes(1);
231
+
232
+ /*
233
+ * Hidden columns are still in the list. The caller needs the full set to
234
+ * build the stored layout - "hidden" is not the complement of "order".
235
+ */
236
+ expect(
237
+ getSaved(onSave).map((entry: CustomizableColumn<Monitor>) => {
238
+ return { id: entry.id, isVisible: entry.isVisible };
239
+ }),
240
+ ).toEqual([
241
+ { id: "name", isVisible: true },
242
+ { id: "currentMonitorStatus", isVisible: true },
243
+ { id: "description", isVisible: false },
244
+ { id: "createdAt", isVisible: true },
245
+ ]);
246
+ });
247
+
248
+ test("the last visible column cannot be switched off", () => {
249
+ const { view, onSave }: RenderedModal = renderModal({
250
+ columns: [
251
+ makeEntry({ id: "name", title: "Monitor Name", isVisible: true }),
252
+ makeEntry({
253
+ id: "description",
254
+ title: "Description",
255
+ isVisible: false,
256
+ }),
257
+ makeEntry({ id: "createdAt", title: "Created At", isVisible: false }),
258
+ ],
259
+ });
260
+
261
+ const onlyVisible: HTMLElement = view.getByTestId("column-toggle-name");
262
+
263
+ // First line of defence: the viewer cannot reach the control at all.
264
+ expect(onlyVisible).toBeDisabled();
265
+
266
+ /*
267
+ * Second line of defence: even if a change does arrive - a stray
268
+ * programmatic event, a future restyle that drops `disabled` - the state
269
+ * update refuses rather than leaving the table with no columns to render.
270
+ */
271
+ fireEvent.click(onlyVisible);
272
+ fireEvent.change(onlyVisible, { target: { checked: false } });
273
+
274
+ expect(view.getByTestId("column-customization-count")).toHaveTextContent(
275
+ "1 of 3 columns shown",
276
+ );
277
+
278
+ fireEvent.click(view.getByTestId("modal-footer-submit-button"));
279
+
280
+ expect(
281
+ getSaved(onSave).filter((entry: CustomizableColumn<Monitor>) => {
282
+ return entry.isVisible;
283
+ }),
284
+ ).toHaveLength(1);
285
+ });
286
+
287
+ test("switching the second-to-last column off locks the survivor", () => {
288
+ const { view }: RenderedModal = renderModal({
289
+ columns: [
290
+ makeEntry({ id: "name", title: "Monitor Name", isVisible: true }),
291
+ makeEntry({ id: "description", title: "Description", isVisible: true }),
292
+ ],
293
+ });
294
+
295
+ expect(view.getByTestId("column-toggle-name")).not.toBeDisabled();
296
+
297
+ fireEvent.click(view.getByTestId("column-toggle-description"));
298
+
299
+ expect(view.getByTestId("column-customization-count")).toHaveTextContent(
300
+ "1 of 2 columns shown",
301
+ );
302
+ expect(view.getByTestId("column-toggle-name")).toBeDisabled();
303
+ });
304
+
305
+ test("Down moves a column later and Save reports the new order", () => {
306
+ const { view, onSave }: RenderedModal = renderModal();
307
+
308
+ fireEvent.click(view.getByTestId("column-move-down-name"));
309
+ fireEvent.click(view.getByTestId("modal-footer-submit-button"));
310
+
311
+ expect(getSavedIds(onSave)).toEqual([
312
+ "currentMonitorStatus",
313
+ "name",
314
+ "description",
315
+ "createdAt",
316
+ ]);
317
+ });
318
+
319
+ test("Up moves a column earlier and Save reports the new order", () => {
320
+ const { view, onSave }: RenderedModal = renderModal();
321
+
322
+ fireEvent.click(view.getByTestId("column-move-up-createdAt"));
323
+ fireEvent.click(view.getByTestId("column-move-up-createdAt"));
324
+ fireEvent.click(view.getByTestId("modal-footer-submit-button"));
325
+
326
+ expect(getSavedIds(onSave)).toEqual([
327
+ "name",
328
+ "createdAt",
329
+ "currentMonitorStatus",
330
+ "description",
331
+ ]);
332
+ });
333
+
334
+ test("reordering does not disturb the visibility flags", () => {
335
+ const { view, onSave }: RenderedModal = renderModal();
336
+
337
+ fireEvent.click(view.getByTestId("column-move-up-createdAt"));
338
+ fireEvent.click(view.getByTestId("modal-footer-submit-button"));
339
+
340
+ expect(
341
+ getSaved(onSave).map((entry: CustomizableColumn<Monitor>) => {
342
+ return { id: entry.id, isVisible: entry.isVisible };
343
+ }),
344
+ ).toEqual([
345
+ { id: "name", isVisible: true },
346
+ { id: "currentMonitorStatus", isVisible: true },
347
+ { id: "createdAt", isVisible: false },
348
+ { id: "description", isVisible: true },
349
+ ]);
350
+ });
351
+
352
+ test("Up is dead on the first row and Down on the last, and that follows the move", () => {
353
+ const { view }: RenderedModal = renderModal();
354
+
355
+ expect(view.getByTestId("column-move-up-name")).toBeDisabled();
356
+ expect(view.getByTestId("column-move-down-name")).not.toBeDisabled();
357
+ expect(view.getByTestId("column-move-down-createdAt")).toBeDisabled();
358
+ expect(view.getByTestId("column-move-up-createdAt")).not.toBeDisabled();
359
+
360
+ fireEvent.click(view.getByTestId("column-move-down-name"));
361
+
362
+ // "name" is now second, so both of its buttons are live and Status leads.
363
+ expect(view.getByTestId("column-move-up-name")).not.toBeDisabled();
364
+ expect(
365
+ view.getByTestId("column-move-up-currentMonitorStatus"),
366
+ ).toBeDisabled();
367
+ });
368
+
369
+ test("Show all turns every column on", () => {
370
+ const { view, onSave }: RenderedModal = renderModal();
371
+
372
+ fireEvent.click(view.getByTestId("column-customization-show-all"));
373
+
374
+ expect(view.getByTestId("column-customization-count")).toHaveTextContent(
375
+ "4 of 4 columns shown",
376
+ );
377
+
378
+ fireEvent.click(view.getByTestId("modal-footer-submit-button"));
379
+
380
+ expect(
381
+ getSaved(onSave).every((entry: CustomizableColumn<Monitor>) => {
382
+ return entry.isVisible;
383
+ }),
384
+ ).toBe(true);
385
+ });
386
+
387
+ test("Hide all leaves exactly one column standing - the first", () => {
388
+ const { view, onSave }: RenderedModal = renderModal();
389
+
390
+ fireEvent.click(view.getByTestId("column-customization-hide-all"));
391
+
392
+ /*
393
+ * Not zero: the leftmost column is kept because it is normally the one
394
+ * that identifies the row, and because a table with no columns cannot be
395
+ * recovered from.
396
+ */
397
+ expect(view.getByTestId("column-customization-count")).toHaveTextContent(
398
+ "1 of 4 columns shown",
399
+ );
400
+ expect(view.getByTestId("column-toggle-name")).toBeDisabled();
401
+
402
+ fireEvent.click(view.getByTestId("modal-footer-submit-button"));
403
+
404
+ expect(
405
+ getSaved(onSave)
406
+ .filter((entry: CustomizableColumn<Monitor>) => {
407
+ return entry.isVisible;
408
+ })
409
+ .map((entry: CustomizableColumn<Monitor>) => {
410
+ return entry.id;
411
+ }),
412
+ ).toEqual(["name"]);
413
+ });
414
+
415
+ test("Hide all keeps the first column even after the list has been reordered", () => {
416
+ const { view, onSave }: RenderedModal = renderModal();
417
+
418
+ fireEvent.click(view.getByTestId("column-move-up-createdAt"));
419
+ fireEvent.click(view.getByTestId("column-move-up-createdAt"));
420
+ fireEvent.click(view.getByTestId("column-move-up-createdAt"));
421
+ fireEvent.click(view.getByTestId("column-customization-hide-all"));
422
+ fireEvent.click(view.getByTestId("modal-footer-submit-button"));
423
+
424
+ // "createdAt" is now the leftmost column, so it is the one that survives.
425
+ expect(
426
+ getSaved(onSave)
427
+ .filter((entry: CustomizableColumn<Monitor>) => {
428
+ return entry.isVisible;
429
+ })
430
+ .map((entry: CustomizableColumn<Monitor>) => {
431
+ return entry.id;
432
+ }),
433
+ ).toEqual(["createdAt"]);
434
+ });
435
+
436
+ test("search filters the list by title", () => {
437
+ const { view }: RenderedModal = renderModal();
438
+
439
+ typeSearch(view, "desc");
440
+
441
+ expect(view.getAllByTestId(/^column-toggle-/)).toHaveLength(1);
442
+ expect(view.getByTestId("column-toggle-description")).toBeInTheDocument();
443
+ expect(view.queryByTestId("column-toggle-name")).not.toBeInTheDocument();
444
+ });
445
+
446
+ test("search is case-insensitive and ignores surrounding whitespace", () => {
447
+ const { view }: RenderedModal = renderModal();
448
+
449
+ typeSearch(view, " STATUS ");
450
+
451
+ expect(view.getAllByTestId(/^column-toggle-/)).toHaveLength(1);
452
+ expect(
453
+ view.getByTestId("column-toggle-currentMonitorStatus"),
454
+ ).toBeInTheDocument();
455
+ });
456
+
457
+ test("search says so when nothing matches", () => {
458
+ const { view }: RenderedModal = renderModal();
459
+
460
+ typeSearch(view, "no-such-column");
461
+
462
+ expect(view.queryAllByTestId(/^column-toggle-/)).toHaveLength(0);
463
+ expect(
464
+ view.getByTestId("column-customization-no-results"),
465
+ ).toHaveTextContent('No columns match "no-such-column".');
466
+ });
467
+
468
+ test("the move buttons are inert while a search is active", () => {
469
+ const { view }: RenderedModal = renderModal();
470
+
471
+ typeSearch(view, "e");
472
+
473
+ /*
474
+ * A filtered list renumbers the rows, so "move down" would land the column
475
+ * at a position that only means something inside the filter. Rather than
476
+ * guess what the viewer meant, reordering is switched off until the search
477
+ * is cleared.
478
+ */
479
+ expect(view.getByTestId("column-move-up-description")).toBeDisabled();
480
+ expect(view.getByTestId("column-move-down-description")).toBeDisabled();
481
+ expect(view.getByTestId("column-move-up-name")).toBeDisabled();
482
+ expect(view.getByTestId("column-move-down-name")).toBeDisabled();
483
+ });
484
+
485
+ test("clearing the search restores the full list and the move buttons", () => {
486
+ const { view, onSave }: RenderedModal = renderModal();
487
+
488
+ typeSearch(view, "desc");
489
+ expect(view.getAllByTestId(/^column-toggle-/)).toHaveLength(1);
490
+
491
+ typeSearch(view, "");
492
+
493
+ expect(view.getAllByTestId(/^column-toggle-/)).toHaveLength(4);
494
+ expect(view.getByTestId("column-move-down-name")).not.toBeDisabled();
495
+ expect(view.getByTestId("column-move-up-description")).not.toBeDisabled();
496
+
497
+ // And reordering works again once the buttons come back.
498
+ fireEvent.click(view.getByTestId("column-move-down-name"));
499
+ fireEvent.click(view.getByTestId("modal-footer-submit-button"));
500
+
501
+ expect(getSavedIds(onSave)).toEqual([
502
+ "currentMonitorStatus",
503
+ "name",
504
+ "description",
505
+ "createdAt",
506
+ ]);
507
+ });
508
+
509
+ test("a change made before searching survives the search", () => {
510
+ const { view, onSave }: RenderedModal = renderModal();
511
+
512
+ fireEvent.click(view.getByTestId("column-toggle-description"));
513
+ typeSearch(view, "created");
514
+ fireEvent.click(view.getByTestId("column-toggle-createdAt"));
515
+ typeSearch(view, "");
516
+ fireEvent.click(view.getByTestId("modal-footer-submit-button"));
517
+
518
+ expect(
519
+ getSaved(onSave).map((entry: CustomizableColumn<Monitor>) => {
520
+ return { id: entry.id, isVisible: entry.isVisible };
521
+ }),
522
+ ).toEqual([
523
+ { id: "name", isVisible: true },
524
+ { id: "currentMonitorStatus", isVisible: true },
525
+ { id: "description", isVisible: false },
526
+ { id: "createdAt", isVisible: true },
527
+ ]);
528
+ });
529
+
530
+ test("Reset is absent while the layout is still the one the table ships", () => {
531
+ const { view }: RenderedModal = renderModal({ isDefaultLayout: true });
532
+
533
+ // Nothing to reset to, so offering the button would only be confusing.
534
+ expect(
535
+ view.queryByTestId("column-customization-reset"),
536
+ ).not.toBeInTheDocument();
537
+ });
538
+
539
+ test("Reset appears once the layout has been customized and calls back", () => {
540
+ const { view, onReset, onSave }: RenderedModal = renderModal({
541
+ isDefaultLayout: false,
542
+ });
543
+
544
+ const reset: HTMLElement = view.getByTestId("column-customization-reset");
545
+
546
+ expect(reset).toBeInTheDocument();
547
+
548
+ fireEvent.click(reset);
549
+
550
+ // Reset is the caller's business: it drops the stored layout, not a draft.
551
+ expect(onReset).toHaveBeenCalledTimes(1);
552
+ expect(onSave).not.toHaveBeenCalled();
553
+ });
554
+
555
+ test("uses a custom title when one is given", () => {
556
+ const { view }: RenderedModal = renderModal({
557
+ title: "Pick your columns",
558
+ });
559
+
560
+ expect(view.getByTestId("modal-title")).toHaveTextContent(
561
+ "Pick your columns",
562
+ );
563
+ });
564
+
565
+ test("falls back to the default title", () => {
566
+ const { view }: RenderedModal = renderModal();
567
+
568
+ expect(view.getByTestId("modal-title")).toHaveTextContent(
569
+ "Customize Columns",
570
+ );
571
+ });
572
+ });