@oneuptime/common 12.0.11 → 12.0.13

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 (251) hide show
  1. package/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.ts +32 -5
  2. package/Models/DatabaseModels/NetworkDevice.ts +64 -0
  3. package/Models/DatabaseModels/StatusPage.ts +59 -0
  4. package/Models/DatabaseModels/StatusPageOidc.ts +2 -0
  5. package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +19 -2
  6. package/Server/API/AIChatAPI.ts +55 -56
  7. package/Server/API/CommonAPI.ts +89 -0
  8. package/Server/API/MicrosoftTeamsAPI.ts +20 -9
  9. package/Server/API/SlackAPI.ts +13 -10
  10. package/Server/API/StatusPageAPI.ts +2197 -2128
  11. package/Server/API/TelemetryAPI.ts +72 -3
  12. package/Server/Infrastructure/Postgres/SchemaMigrations/1787500000000-AddEnableSearchEngineIndexingToStatusPage.ts +30 -0
  13. package/Server/Infrastructure/Postgres/SchemaMigrations/1787600000000-AddNetworkDeviceReachabilityColumns.ts +47 -0
  14. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
  15. package/Server/Middleware/UserAuthorization.ts +11 -2
  16. package/Server/Services/ApiKeyPermissionService.ts +116 -2
  17. package/Server/Services/DatabaseService.ts +17 -6
  18. package/Server/Services/LogAggregationService.ts +34 -0
  19. package/Server/Services/LogService.ts +21 -0
  20. package/Server/Services/NetworkSiteService.ts +12 -0
  21. package/Server/Services/SpanService.ts +21 -0
  22. package/Server/Services/TraceAggregationService.ts +15 -0
  23. package/Server/Services/WorkspaceNotificationRuleService.ts +172 -220
  24. package/Server/Types/AnalyticsDatabase/ModelPermission.ts +9 -0
  25. package/Server/Types/Database/Permissions/AccessControlPermission.ts +47 -16
  26. package/Server/Types/Workflow/Components/Conditions/IfElse.ts +9 -0
  27. package/Server/Types/Workflow/Components/JavaScript.ts +9 -0
  28. package/Server/Utils/APIKey/AccessPermission.ts +16 -40
  29. package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +144 -0
  30. package/Server/Utils/LogRedaction.ts +576 -0
  31. package/Server/Utils/Logger.ts +123 -46
  32. package/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.ts +94 -23
  33. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +12 -0
  34. package/Server/Utils/Monitor/MonitorResource.ts +29 -9
  35. package/Server/Utils/Monitor/NetworkInventoryUtil.ts +28 -7
  36. package/Server/Utils/SessionReplay/SessionReplayGateCacheStore.ts +56 -10
  37. package/Server/Utils/StartServer.ts +30 -9
  38. package/Server/Utils/StatusPageSearchEngineIndexing.ts +33 -0
  39. package/Server/Utils/Telemetry/ResourceEntityFilter.ts +441 -0
  40. package/Server/Utils/VM/VMRunner.ts +693 -874
  41. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +488 -46
  42. package/Tests/App/Dashboard/MonitorTypePicker.test.tsx +300 -0
  43. package/Tests/App/StatusPage/StatusPageIndexPageRobotsMeta.test.ts +130 -0
  44. package/Tests/Models/DatabaseModels/DatabaseBaseModelToJSONObjectCache.test.ts +180 -0
  45. package/Tests/Models/StatusPageEnableSearchEngineIndexing.test.ts +157 -0
  46. package/Tests/Server/API/AIChatCancelAndFeedback.test.ts +23 -1
  47. package/Tests/Server/API/AIChatRouteAuthorization.test.ts +785 -0
  48. package/Tests/Server/API/BaseAPIApiKeyAuth.test.ts +21 -8
  49. package/Tests/Server/API/CommonAPIAuthGuard.test.ts +290 -0
  50. package/Tests/Server/API/MicrosoftTeamsManifest.test.ts +7 -1
  51. package/Tests/Server/API/StatusPageOverviewCache.test.ts +474 -0
  52. package/Tests/Server/API/StatusPageSeoSearchEngineIndexing.test.ts +189 -0
  53. package/Tests/Server/Infrastructure/InMemoryTTLCache.test.ts +158 -0
  54. package/Tests/Server/Infrastructure/Postgres/DeviceRoleAndDeclaredLinkParentMigration.test.ts +9 -60
  55. package/Tests/Server/Middleware/ProjectAuthorizationApiKeyMiddleware.test.ts +24 -15
  56. package/Tests/Server/Middleware/UserAuthorization.test.ts +79 -0
  57. package/Tests/Server/Services/AddNetworkDeviceReachabilityColumnsMigration.test.ts +332 -0
  58. package/Tests/Server/Services/ApiKeyPermissionService.test.ts +347 -0
  59. package/Tests/Server/Services/DatabaseServiceUpdateDebugLogging.test.ts +282 -0
  60. package/Tests/Server/Services/NetworkSiteService.test.ts +56 -2
  61. package/Tests/Server/Services/TelemetryResourceFacetFilters.test.ts +267 -0
  62. package/Tests/Server/Services/WorkspaceNotificationRuleTestRuleChannels.test.ts +702 -0
  63. package/Tests/Server/Types/Database/Permissions/AccessControlPermission.test.ts +165 -0
  64. package/Tests/Server/Types/Workflow/Components/CustomCodeScriptError.test.ts +121 -0
  65. package/Tests/Server/Utils/APIKey/AccessPermission.test.ts +48 -36
  66. package/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.ts +213 -0
  67. package/Tests/Server/Utils/LogRedaction.test.ts +415 -0
  68. package/Tests/Server/Utils/LoggerCredentialLeak.test.ts +245 -0
  69. package/Tests/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.test.ts +374 -4
  70. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorJavascriptExpression.test.ts +92 -0
  71. package/Tests/Server/Utils/Monitor/MonitorResourceIngestedStepSelection.test.ts +455 -0
  72. package/Tests/Server/Utils/Monitor/NetworkDeviceReachabilityRoundTrip.test.ts +369 -0
  73. package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +86 -8
  74. package/Tests/Server/Utils/PrivacyFilterUtil.test.ts +64 -0
  75. package/Tests/Server/Utils/SessionReplay/SessionReplayGateCacheStore.test.ts +207 -0
  76. package/Tests/Server/Utils/StartServerBodyVerify.test.ts +335 -0
  77. package/Tests/Server/Utils/StatusPageSearchEngineIndexing.test.ts +60 -0
  78. package/Tests/Server/Utils/Telemetry/ResourceEntityFilter.test.ts +435 -0
  79. package/Tests/Server/Utils/VM/VMRunnerIsolation.test.ts +385 -0
  80. package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +3 -0
  81. package/Tests/Server/Utils/Workspace/MicrosoftTeamsChannelSend.test.ts +607 -62
  82. package/Tests/Server/Utils/Workspace/MicrosoftTeamsInstalledTeamIdSpace.test.ts +778 -0
  83. package/Tests/Server/Utils/Workspace/MicrosoftTeamsTeamInstalls.test.ts +44 -10
  84. package/Tests/Types/API/HostnameFromAuthority.test.ts +164 -0
  85. package/Tests/Types/Database/AccessControl/ColumnAccessControlCache.test.ts +344 -0
  86. package/Tests/Types/Database/DatabasePropertyFindOperator.test.ts +518 -0
  87. package/Tests/Types/Database/TableColumnMetadataCache.test.ts +286 -0
  88. package/Tests/Types/Monitor/MonitorStep.test.ts +100 -0
  89. package/Tests/Types/Monitor/MonitorTypeKeywords.test.ts +360 -0
  90. package/Tests/Types/StatusPage/SearchEngineIndexing.test.ts +86 -0
  91. package/Tests/Types/Telemetry/ResourceEntityFacet.test.ts +254 -0
  92. package/Tests/UI/Components/CardSelect.test.tsx +1021 -0
  93. package/Tests/UI/Components/MasterPage.test.tsx +36 -1
  94. package/Tests/Utils/Monitor/MonitorMetricType.test.ts +66 -1
  95. package/Tests/Utils/Monitor/NetworkTopologyUtil.test.ts +115 -6
  96. package/Tests/Utils/NetworkDevice/DeviceReachabilityUtil.test.ts +610 -0
  97. package/Tests/Utils/NetworkSite/SiteStatusRollupUtil.test.ts +114 -45
  98. package/Types/API/Hostname.ts +79 -0
  99. package/Types/Database/AccessControl/ColumnAccessControl.ts +33 -11
  100. package/Types/Database/AccessControl/ColumnBillingAccessControl.ts +33 -11
  101. package/Types/Database/DatabaseProperty.ts +38 -0
  102. package/Types/Database/TableColumn.ts +34 -7
  103. package/Types/Events/Recurring.ts +16 -1
  104. package/Types/Monitor/CustomCodeMonitor/CustomCodeMonitorResponse.ts +14 -2
  105. package/Types/Monitor/MonitorStep.ts +13 -1
  106. package/Types/Monitor/MonitorType.ts +345 -40
  107. package/Types/Monitor/SSLMonitor/SslMonitorResponse.ts +43 -0
  108. package/Types/StatusPage/SearchEngineIndexing.ts +61 -0
  109. package/Types/Telemetry/ResourceEntityFacet.ts +211 -0
  110. package/UI/Components/CardSelect/CardSelect.tsx +714 -105
  111. package/UI/Components/EmptyState/EmptyState.tsx +8 -1
  112. package/UI/Components/Footer/Footer.tsx +32 -6
  113. package/UI/Components/Forms/Fields/FormField.tsx +3 -0
  114. package/UI/Components/Forms/Types/Field.ts +8 -0
  115. package/UI/Components/Loader/PageLoader.tsx +29 -8
  116. package/UI/Components/LogsViewer/components/LogsAnalyticsView.tsx +26 -4
  117. package/UI/Components/Markdown.tsx/LazyMarkdownViewer.tsx +17 -1
  118. package/UI/Components/MasterPage/MasterPage.tsx +24 -11
  119. package/Utils/Monitor/MonitorMetricType.ts +16 -1
  120. package/Utils/Monitor/NetworkTopologyUtil.ts +60 -8
  121. package/Utils/NetworkDevice/DeviceReachabilityUtil.ts +262 -0
  122. package/Utils/NetworkSite/SiteStatusRollupUtil.ts +41 -24
  123. package/Utils/Telemetry/CrossSignalScope.ts +75 -4
  124. package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js +20 -4
  125. package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js.map +1 -1
  126. package/build/dist/Models/DatabaseModels/NetworkDevice.js +66 -0
  127. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
  128. package/build/dist/Models/DatabaseModels/StatusPage.js +60 -0
  129. package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
  130. package/build/dist/Models/DatabaseModels/StatusPageOidc.js +2 -0
  131. package/build/dist/Models/DatabaseModels/StatusPageOidc.js.map +1 -1
  132. package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
  133. package/build/dist/Server/API/AIChatAPI.js +48 -35
  134. package/build/dist/Server/API/AIChatAPI.js.map +1 -1
  135. package/build/dist/Server/API/CommonAPI.js +59 -0
  136. package/build/dist/Server/API/CommonAPI.js.map +1 -1
  137. package/build/dist/Server/API/MicrosoftTeamsAPI.js +20 -6
  138. package/build/dist/Server/API/MicrosoftTeamsAPI.js.map +1 -1
  139. package/build/dist/Server/API/SlackAPI.js +13 -10
  140. package/build/dist/Server/API/SlackAPI.js.map +1 -1
  141. package/build/dist/Server/API/StatusPageAPI.js +745 -673
  142. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  143. package/build/dist/Server/API/TelemetryAPI.js +34 -3
  144. package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
  145. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787500000000-AddEnableSearchEngineIndexingToStatusPage.js +23 -0
  146. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787500000000-AddEnableSearchEngineIndexingToStatusPage.js.map +1 -0
  147. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787600000000-AddNetworkDeviceReachabilityColumns.js +34 -0
  148. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787600000000-AddNetworkDeviceReachabilityColumns.js.map +1 -0
  149. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +4 -0
  150. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  151. package/build/dist/Server/Middleware/UserAuthorization.js +6 -2
  152. package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
  153. package/build/dist/Server/Services/ApiKeyPermissionService.js +90 -1
  154. package/build/dist/Server/Services/ApiKeyPermissionService.js.map +1 -1
  155. package/build/dist/Server/Services/DatabaseService.js +15 -6
  156. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  157. package/build/dist/Server/Services/LogAggregationService.js +2 -0
  158. package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
  159. package/build/dist/Server/Services/LogService.js +16 -0
  160. package/build/dist/Server/Services/LogService.js.map +1 -1
  161. package/build/dist/Server/Services/NetworkSiteService.js +12 -0
  162. package/build/dist/Server/Services/NetworkSiteService.js.map +1 -1
  163. package/build/dist/Server/Services/SpanService.js +16 -0
  164. package/build/dist/Server/Services/SpanService.js.map +1 -1
  165. package/build/dist/Server/Services/TraceAggregationService.js +2 -0
  166. package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
  167. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +137 -164
  168. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
  169. package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js +9 -0
  170. package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js.map +1 -1
  171. package/build/dist/Server/Types/Database/Permissions/AccessControlPermission.js +21 -13
  172. package/build/dist/Server/Types/Database/Permissions/AccessControlPermission.js.map +1 -1
  173. package/build/dist/Server/Types/Workflow/Components/Conditions/IfElse.js +8 -0
  174. package/build/dist/Server/Types/Workflow/Components/Conditions/IfElse.js.map +1 -1
  175. package/build/dist/Server/Types/Workflow/Components/JavaScript.js +8 -0
  176. package/build/dist/Server/Types/Workflow/Components/JavaScript.js.map +1 -1
  177. package/build/dist/Server/Utils/APIKey/AccessPermission.js +9 -32
  178. package/build/dist/Server/Utils/APIKey/AccessPermission.js.map +1 -1
  179. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +87 -0
  180. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
  181. package/build/dist/Server/Utils/LogRedaction.js +449 -0
  182. package/build/dist/Server/Utils/LogRedaction.js.map +1 -0
  183. package/build/dist/Server/Utils/Logger.js +98 -45
  184. package/build/dist/Server/Utils/Logger.js.map +1 -1
  185. package/build/dist/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.js +65 -13
  186. package/build/dist/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.js.map +1 -1
  187. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +12 -1
  188. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  189. package/build/dist/Server/Utils/Monitor/MonitorResource.js +20 -3
  190. package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
  191. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +27 -7
  192. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
  193. package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCacheStore.js +29 -10
  194. package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCacheStore.js.map +1 -1
  195. package/build/dist/Server/Utils/StartServer.js +10 -7
  196. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  197. package/build/dist/Server/Utils/StatusPageSearchEngineIndexing.js +24 -0
  198. package/build/dist/Server/Utils/StatusPageSearchEngineIndexing.js.map +1 -0
  199. package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js +311 -0
  200. package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js.map +1 -0
  201. package/build/dist/Server/Utils/VM/VMRunner.js +402 -525
  202. package/build/dist/Server/Utils/VM/VMRunner.js.map +1 -1
  203. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +366 -37
  204. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  205. package/build/dist/Types/API/Hostname.js +63 -0
  206. package/build/dist/Types/API/Hostname.js.map +1 -1
  207. package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js +20 -6
  208. package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js.map +1 -1
  209. package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js +20 -6
  210. package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js.map +1 -1
  211. package/build/dist/Types/Database/DatabaseProperty.js +38 -0
  212. package/build/dist/Types/Database/DatabaseProperty.js.map +1 -1
  213. package/build/dist/Types/Database/TableColumn.js +24 -6
  214. package/build/dist/Types/Database/TableColumn.js.map +1 -1
  215. package/build/dist/Types/Events/Recurring.js +13 -1
  216. package/build/dist/Types/Events/Recurring.js.map +1 -1
  217. package/build/dist/Types/Monitor/MonitorStep.js +9 -1
  218. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  219. package/build/dist/Types/Monitor/MonitorType.js +330 -31
  220. package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
  221. package/build/dist/Types/StatusPage/SearchEngineIndexing.js +55 -0
  222. package/build/dist/Types/StatusPage/SearchEngineIndexing.js.map +1 -0
  223. package/build/dist/Types/Telemetry/ResourceEntityFacet.js +156 -0
  224. package/build/dist/Types/Telemetry/ResourceEntityFacet.js.map +1 -0
  225. package/build/dist/UI/Components/CardSelect/CardSelect.js +360 -40
  226. package/build/dist/UI/Components/CardSelect/CardSelect.js.map +1 -1
  227. package/build/dist/UI/Components/EmptyState/EmptyState.js +1 -1
  228. package/build/dist/UI/Components/EmptyState/EmptyState.js.map +1 -1
  229. package/build/dist/UI/Components/Footer/Footer.js +7 -4
  230. package/build/dist/UI/Components/Footer/Footer.js.map +1 -1
  231. package/build/dist/UI/Components/Forms/Fields/FormField.js +1 -1
  232. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  233. package/build/dist/UI/Components/Loader/PageLoader.js +15 -5
  234. package/build/dist/UI/Components/Loader/PageLoader.js.map +1 -1
  235. package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js +16 -3
  236. package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js.map +1 -1
  237. package/build/dist/UI/Components/Markdown.tsx/LazyMarkdownViewer.js +13 -1
  238. package/build/dist/UI/Components/Markdown.tsx/LazyMarkdownViewer.js.map +1 -1
  239. package/build/dist/UI/Components/MasterPage/MasterPage.js +10 -2
  240. package/build/dist/UI/Components/MasterPage/MasterPage.js.map +1 -1
  241. package/build/dist/Utils/Monitor/MonitorMetricType.js +13 -1
  242. package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
  243. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +34 -7
  244. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
  245. package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js +177 -0
  246. package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js.map +1 -0
  247. package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js +23 -27
  248. package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js.map +1 -1
  249. package/build/dist/Utils/Telemetry/CrossSignalScope.js +44 -4
  250. package/build/dist/Utils/Telemetry/CrossSignalScope.js.map +1 -1
  251. package/package.json +1 -1
@@ -54,9 +54,44 @@ describe("MasterPage", () => {
54
54
  });
55
55
 
56
56
  it("should render correctly with makeTopSectionUnstick", () => {
57
- render(<MasterPage {...defaultProps} makeTopSectionUnstick />);
57
+ render(
58
+ <MasterPage
59
+ {...defaultProps}
60
+ header={<div>Header</div>}
61
+ makeTopSectionUnstick
62
+ />,
63
+ );
58
64
 
59
65
  const topSection: HTMLElement = screen.getByRole("banner").parentElement!;
60
66
  expect(topSection).not.toHaveClass("sticky");
61
67
  });
68
+
69
+ it("should render the top section when it has a header or a navbar", () => {
70
+ const { rerender } = render(
71
+ <MasterPage {...defaultProps} header={<div>Header</div>} />,
72
+ );
73
+ expect(screen.getByRole("banner")).toBeInTheDocument();
74
+
75
+ rerender(<MasterPage {...defaultProps} navBar={<div>NavBar</div>} />);
76
+ expect(screen.getByRole("banner")).toBeInTheDocument();
77
+ });
78
+
79
+ /*
80
+ * The status page renders its own header and navbar inside children and
81
+ * passes neither prop. Rendering the top section anyway left an empty white
82
+ * bar with a drop shadow above the content.
83
+ */
84
+ it("should not render an empty top section when it has neither", () => {
85
+ render(<MasterPage {...defaultProps} />);
86
+
87
+ expect(screen.queryByRole("banner")).not.toBeInTheDocument();
88
+ });
89
+
90
+ it("should not render the top section when its only header is hidden", () => {
91
+ render(
92
+ <MasterPage {...defaultProps} header={<div>Header</div>} hideHeader />,
93
+ );
94
+
95
+ expect(screen.queryByRole("banner")).not.toBeInTheDocument();
96
+ });
62
97
  });
@@ -1,7 +1,9 @@
1
1
  import AggregationType from "../../../Types/BaseDatabase/AggregationType";
2
2
  import { CheckOn } from "../../../Types/Monitor/CriteriaFilter";
3
3
  import MonitorMetricType from "../../../Types/Monitor/MonitorMetricType";
4
- import MonitorType from "../../../Types/Monitor/MonitorType";
4
+ import MonitorType, {
5
+ MonitorTypeHelper,
6
+ } from "../../../Types/Monitor/MonitorType";
5
7
  import MonitorMetricTypeUtil, {
6
8
  MonitorMetricCategory,
7
9
  } from "../../../Utils/Monitor/MonitorMetricType";
@@ -333,3 +335,66 @@ describe("invariant: every displayed metric resolves its metadata", () => {
333
335
  }
334
336
  });
335
337
  });
338
+
339
+ /*
340
+ * Regression suite for https://github.com/OneUptime/oneuptime/issues/3225.
341
+ *
342
+ * SSLCertificate was missing from getMonitorMetricTypesByMonitorType, so it
343
+ * fell through to `return []`. getMonitorMetricCategoriesByMonitorType
344
+ * short-circuits on an empty metric list and the dashboard hides the whole
345
+ * Monitor Metrics tab when there are no categories - so an SSL monitor
346
+ * showed no charts at all, even though IsOnline rows were being written to
347
+ * ClickHouse on every single check. An operator therefore had no way to see
348
+ * that their monitor was running, which is a large part of why the issue was
349
+ * reported as "the monitor never executes".
350
+ *
351
+ * The invariant test above cannot catch this: it iterates the metrics a type
352
+ * already lists, so an empty list passes vacuously.
353
+ */
354
+ describe("SSL Certificate monitor metrics (issue #3225)", () => {
355
+ test("SSLCertificate reports IsOnline and ResponseTime", () => {
356
+ const metrics: Array<MonitorMetricType> =
357
+ MonitorMetricTypeUtil.getMonitorMetricTypesByMonitorType(
358
+ MonitorType.SSLCertificate,
359
+ );
360
+
361
+ expect(metrics).toContain(MonitorMetricType.IsOnline);
362
+ expect(metrics).toContain(MonitorMetricType.ResponseTime);
363
+ });
364
+
365
+ test("SSLCertificate produces at least one display category", () => {
366
+ const categories: Array<MonitorMetricCategory> =
367
+ MonitorMetricTypeUtil.getMonitorMetricCategoriesByMonitorType(
368
+ MonitorType.SSLCertificate,
369
+ );
370
+
371
+ // An empty list is what made the dashboard hide the metrics tab.
372
+ expect(categories.length).toBeGreaterThan(0);
373
+ });
374
+ });
375
+
376
+ describe("invariant: every probeable monitor type displays some metric", () => {
377
+ test("no probeable type falls through to an empty metric list", () => {
378
+ const typesWithoutMetrics: Array<MonitorType> = [];
379
+
380
+ for (const monitorType of ALL_MONITOR_TYPES) {
381
+ if (!MonitorTypeHelper.isProbableMonitor(monitorType)) {
382
+ continue;
383
+ }
384
+
385
+ const metrics: Array<MonitorMetricType> =
386
+ MonitorMetricTypeUtil.getMonitorMetricTypesByMonitorType(monitorType);
387
+
388
+ if (metrics.length === 0) {
389
+ typesWithoutMetrics.push(monitorType);
390
+ }
391
+ }
392
+
393
+ /*
394
+ * Asserting on the collected list rather than per-type so a failure
395
+ * names every offender at once - this is the structural hole that let
396
+ * SSLCertificate ship with no charts.
397
+ */
398
+ expect(typesWithoutMetrics).toEqual([]);
399
+ });
400
+ });
@@ -13,6 +13,12 @@ describe("NetworkTopologyUtil.buildTopology", () => {
13
13
  const now: Date = new Date("2026-07-22T12:00:00Z");
14
14
  const fresh: Date = new Date("2026-07-22T11:55:00Z");
15
15
  const stale: Date = new Date("2026-07-22T11:30:00Z");
16
+ /*
17
+ * Past the shared staleness window (an hour at the default interval), so
18
+ * "we have stopped polling this entirely" rather than "the probe is a bit
19
+ * behind" — the distinction issue #3220 turned on.
20
+ */
21
+ const outOfContact: Date = new Date("2026-07-22T09:00:00Z");
16
22
 
17
23
  const makeDevice: (
18
24
  id: string,
@@ -155,12 +161,24 @@ describe("NetworkTopologyUtil.buildTopology", () => {
155
161
  expect(nodeById(result, "d3")!.status).toBe("up");
156
162
  });
157
163
 
158
- it("derives device status from lastSeenAt freshness", () => {
164
+ it("derives device status from the outcome of the last poll", () => {
159
165
  const result: TopologyBuildResult = NetworkTopologyUtil.buildTopology(
160
166
  [
161
- makeDevice("d1", "fresh-device", { lastSeenAt: fresh }),
162
- makeDevice("d2", "stale-device", { lastSeenAt: stale }),
163
- makeDevice("d3", "never-seen", { lastSeenAt: undefined }),
167
+ makeDevice("d1", "answered", {
168
+ isReachable: true,
169
+ lastPolledAt: fresh,
170
+ lastSeenAt: fresh,
171
+ }),
172
+ makeDevice("d2", "did-not-answer", {
173
+ isReachable: false,
174
+ lastPolledAt: fresh,
175
+ lastSeenAt: outOfContact,
176
+ }),
177
+ makeDevice("d3", "never-polled", {
178
+ isReachable: undefined,
179
+ lastPolledAt: undefined,
180
+ lastSeenAt: undefined,
181
+ }),
164
182
  ],
165
183
  now,
166
184
  );
@@ -170,6 +188,75 @@ describe("NetworkTopologyUtil.buildTopology", () => {
170
188
  expect(nodeById(result, "d3")!.status).toBe("unknown");
171
189
  });
172
190
 
191
+ /*
192
+ * Issue #3220: the map drew a whole fleet red because its probe could
193
+ * not get round every device inside the old fixed 15-minute freshness
194
+ * window. A device that answered its last poll is up on the map however
195
+ * far behind the schedule has fallen.
196
+ */
197
+ it("issue #3220: a device that answered 30 minutes ago is still up on the map", () => {
198
+ const result: TopologyBuildResult = NetworkTopologyUtil.buildTopology(
199
+ [
200
+ makeDevice("d1", "behind-schedule", {
201
+ isReachable: true,
202
+ lastPolledAt: stale,
203
+ lastSeenAt: stale,
204
+ }),
205
+ ],
206
+ now,
207
+ );
208
+
209
+ expect(nodeById(result, "d1")!.status).toBe("up");
210
+ });
211
+
212
+ /*
213
+ * A device nothing has polled for hours keeps its last known colour
214
+ * rather than being drawn as an outage. Repainting a whole map red
215
+ * because its probe stopped is the false-positive storm this change
216
+ * exists to remove; the staleness signal belongs on the device page,
217
+ * not in the graph's only three colours.
218
+ */
219
+ it("a device nothing has polled for hours keeps its last known colour", () => {
220
+ const result: TopologyBuildResult = NetworkTopologyUtil.buildTopology(
221
+ [
222
+ makeDevice("d1", "out-of-contact", {
223
+ isReachable: true,
224
+ lastPolledAt: outOfContact,
225
+ lastSeenAt: outOfContact,
226
+ }),
227
+ makeDevice("d2", "out-of-contact-and-failing", {
228
+ isReachable: false,
229
+ lastPolledAt: outOfContact,
230
+ lastSeenAt: outOfContact,
231
+ }),
232
+ ],
233
+ now,
234
+ );
235
+
236
+ expect(nodeById(result, "d1")!.status).toBe("up");
237
+ expect(nodeById(result, "d2")!.status).toBe("down");
238
+ });
239
+
240
+ /*
241
+ * Rows written before the reachability columns existed carry only
242
+ * lastSeenAt; the map must keep drawing them from that until their next
243
+ * walk fills the rest in.
244
+ */
245
+ it("falls back to lastSeenAt for rows with no recorded poll outcome", () => {
246
+ const result: TopologyBuildResult = NetworkTopologyUtil.buildTopology(
247
+ [
248
+ makeDevice("d1", "legacy-fresh", { lastSeenAt: fresh }),
249
+ makeDevice("d2", "legacy-out-of-contact", {
250
+ lastSeenAt: outOfContact,
251
+ }),
252
+ ],
253
+ now,
254
+ );
255
+
256
+ expect(nodeById(result, "d1")!.status).toBe("up");
257
+ expect(nodeById(result, "d2")!.status).toBe("down");
258
+ });
259
+
173
260
  it("merges the same link reported from both ends by both protocols", () => {
174
261
  const result: TopologyBuildResult = NetworkTopologyUtil.buildTopology(
175
262
  [
@@ -762,7 +849,13 @@ describe("NetworkTopologyUtil.buildTopology", () => {
762
849
  expect(nodeById(result, "endpoint:ep-4")!.name).toBe("aa:00:00:00:00:04");
763
850
  });
764
851
 
765
- it("derives endpoint status from lastSeenAt with the same freshness rule", () => {
852
+ /*
853
+ * Endpoints are ARP/FDB-learned hosts with no poll of their own, so
854
+ * freshness really is all there is. The window is the shared staleness
855
+ * one (an hour) rather than the old 15 minutes, so a host behind a
856
+ * switch its probe polls slowly does not blink out between walks.
857
+ */
858
+ it("derives endpoint status from lastSeenAt freshness", () => {
766
859
  const result: TopologyBuildResult = NetworkTopologyUtil.buildTopology(
767
860
  [makeDevice("d1", "edge-1")],
768
861
  now,
@@ -774,7 +867,7 @@ describe("NetworkTopologyUtil.buildTopology", () => {
774
867
  }),
775
868
  makeEndpoint("ep-2", "aa:00:00:00:00:02", {
776
869
  attachedNetworkDeviceId: "d1",
777
- lastSeenAt: stale,
870
+ lastSeenAt: outOfContact,
778
871
  }),
779
872
  makeEndpoint("ep-3", "aa:00:00:00:00:03", {
780
873
  attachedNetworkDeviceId: "d1",
@@ -788,6 +881,22 @@ describe("NetworkTopologyUtil.buildTopology", () => {
788
881
  expect(nodeById(result, "endpoint:ep-3")!.status).toBe("unknown");
789
882
  });
790
883
 
884
+ it("an endpoint seen half an hour ago is still up, not blinked out", () => {
885
+ const result: TopologyBuildResult = NetworkTopologyUtil.buildTopology(
886
+ [makeDevice("d1", "edge-1")],
887
+ now,
888
+ [],
889
+ [
890
+ makeEndpoint("ep-1", "aa:00:00:00:00:01", {
891
+ attachedNetworkDeviceId: "d1",
892
+ lastSeenAt: stale,
893
+ }),
894
+ ],
895
+ );
896
+
897
+ expect(nodeById(result, "endpoint:ep-1")!.status).toBe("up");
898
+ });
899
+
791
900
  it("labels the port from the interface row, then falls back to if<index>", () => {
792
901
  const interfaces: Array<TopologyInterfaceInput> = [
793
902
  { networkDeviceId: "d1", interfaceIndex: 9, name: "Fa0/9" },