@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
@@ -11,6 +11,13 @@ export interface ComponentProps {
11
11
  id: string;
12
12
  iconClassName?: string;
13
13
  showSolidBackground?: boolean | undefined;
14
+ /*
15
+ * Vertical padding. The default is 13rem top and bottom, which suits a
16
+ * full-page dashboard empty state but swamps a short page. Override it
17
+ * rather than changing the default — several call sites cancel the 13rem
18
+ * with negative margins and would overlap their neighbours if it shrank.
19
+ */
20
+ paddingClassName?: string | undefined;
14
21
  }
15
22
 
16
23
  const EmptyState: FunctionComponent<ComponentProps> = (
@@ -21,7 +28,7 @@ const EmptyState: FunctionComponent<ComponentProps> = (
21
28
  <React.Fragment>
22
29
  <div
23
30
  id={props.id}
24
- className={`flex pt-52 pb-52 ${
31
+ className={`flex ${props.paddingClassName || "pt-52 pb-52"} ${
25
32
  props.showSolidBackground ? "bg-white rounded shadow" : ""
26
33
  }`}
27
34
  >
@@ -16,6 +16,18 @@ export interface ComponentProps {
16
16
  links: Array<FooterLink>;
17
17
  style?: React.CSSProperties | undefined;
18
18
  className?: string | undefined;
19
+ /*
20
+ * Classes for the inner row. The default adds its own horizontal padding,
21
+ * which double-indents the footer inside a layout that is already padded —
22
+ * the status page, for one. Override it to align the footer with the content
23
+ * above it.
24
+ */
25
+ innerClassName?: string | undefined;
26
+ /*
27
+ * Classes for the copyright block. The default hides it between md and lg,
28
+ * which is not something every layout wants.
29
+ */
30
+ copyrightClassName?: string | undefined;
19
31
  }
20
32
 
21
33
  const Footer: FunctionComponent<ComponentProps> = (
@@ -29,7 +41,12 @@ const Footer: FunctionComponent<ComponentProps> = (
29
41
  }
30
42
  style={props.style}
31
43
  >
32
- <div className="mx-auto w-full py-6 px-6 md:flex md:items-center md:justify-between lg:px-8">
44
+ <div
45
+ className={
46
+ props.innerClassName ||
47
+ "mx-auto w-full py-6 px-6 md:flex md:items-center md:justify-between lg:px-8"
48
+ }
49
+ >
33
50
  {/* Mobile: Stack links vertically, Desktop: Horizontal layout */}
34
51
  <div className="flex flex-col space-y-3 md:flex-row md:justify-center md:items-center md:space-y-0 md:space-x-8 md:order-2">
35
52
  {props.links &&
@@ -63,14 +80,23 @@ const Footer: FunctionComponent<ComponentProps> = (
63
80
  );
64
81
  })}
65
82
  </div>
66
- {/* Copyright: Show on mobile, hide on larger screens unless specified */}
67
- <div className="mt-5 md:order-1 md:mt-0 block md:hidden lg:block">
68
- {props.copyright && (
83
+ {/*
84
+ * Guard the wrapper, not just the <p>: with no copyright configured
85
+ * the empty div still contributed its mt-5, leaving a dead gap under
86
+ * the links.
87
+ */}
88
+ {props.copyright && (
89
+ <div
90
+ className={
91
+ props.copyrightClassName ||
92
+ "mt-5 md:order-1 md:mt-0 block md:hidden lg:block"
93
+ }
94
+ >
69
95
  <p className="text-center text-sm text-gray-500">
70
96
  &copy; {props.copyright}
71
97
  </p>
72
- )}
73
- </div>
98
+ </div>
99
+ )}
74
100
  </div>
75
101
  </footer>
76
102
  </React.Fragment>
@@ -521,6 +521,9 @@ const FormField: <T extends GenericObject>(
521
521
  tabIndex={0}
522
522
  dataTestId={props.field.dataTestId}
523
523
  singleColumn={props.field.cardSelectSingleColumn}
524
+ searchable={props.field.cardSelectSearchable}
525
+ searchPlaceholder={props.field.cardSelectSearchPlaceholder}
526
+ collapsibleGroups={props.field.cardSelectCollapsibleGroups}
524
527
  onChange={(value: string) => {
525
528
  onChange(value);
526
529
  props.setFieldValue(props.fieldName, value);
@@ -58,6 +58,14 @@ export default interface Field<TEntity> {
58
58
  | Array<CardSelectOption | CardSelectOptionGroup>
59
59
  | undefined;
60
60
  cardSelectSingleColumn?: boolean | undefined;
61
+ /*
62
+ * Give the card picker a search box and collapse its groups behind their
63
+ * headers. Both are opt in: a picker with a handful of cards reads fine as
64
+ * a plain grid, and turning them on there would only add chrome.
65
+ */
66
+ cardSelectSearchable?: boolean | undefined;
67
+ cardSelectSearchPlaceholder?: string | undefined;
68
+ cardSelectCollapsibleGroups?: boolean | undefined;
61
69
  fetchDropdownOptions?:
62
70
  | ((
63
71
  item: FormValues<TEntity>,
@@ -1,22 +1,43 @@
1
1
  import Loader, { LoaderType } from "./Loader";
2
- import { VeryLightGray } from "../../../Types/BrandColors";
2
+ import { Gray500 } from "../../../Types/BrandColors";
3
3
  import React, { FunctionComponent, ReactElement } from "react";
4
4
 
5
5
  export interface ComponentProps {
6
6
  isVisible: boolean;
7
+ /*
8
+ * Lets a full-page caller reserve height (e.g. "min-h-[60vh]") without
9
+ * changing the footprint of the many inline, in-card call sites that rely on
10
+ * the default spacing.
11
+ */
12
+ className?: string | undefined;
7
13
  }
8
14
 
9
15
  const PageLoader: FunctionComponent<ComponentProps> = (
10
16
  props: ComponentProps,
11
17
  ): ReactElement => {
12
- if (props.isVisible) {
13
- return (
14
- <div className="m-auto w-full text-center w-max mt-52 align-middle flex items-center">
15
- <Loader loaderType={LoaderType.Bar} color={VeryLightGray} size={200} />
16
- </div>
17
- );
18
+ if (!props.isVisible) {
19
+ return <></>;
18
20
  }
19
- return <></>;
21
+
22
+ /*
23
+ * The bar used to be VeryLightGray (#c2c2c2) on white — about 1.7:1, which
24
+ * reads as a blank page rather than a loading one. Gray500 is visible without
25
+ * being loud.
26
+ *
27
+ * "w-full" and "w-max" were both set here, so which one applied came down to
28
+ * the order Tailwind happened to emit them in. The loader is centred by the
29
+ * flex row inside <Loader>, so full width is the one that was wanted.
30
+ */
31
+ return (
32
+ <div
33
+ className={
34
+ props.className ||
35
+ "m-auto mt-52 flex w-full items-center justify-center"
36
+ }
37
+ >
38
+ <Loader loaderType={LoaderType.Bar} color={Gray500} size={200} />
39
+ </div>
40
+ );
20
41
  };
21
42
 
22
43
  export default PageLoader;
@@ -26,6 +26,11 @@ import URL from "../../../../Types/API/URL";
26
26
  import HTTPResponse from "../../../../Types/API/HTTPResponse";
27
27
  import HTTPErrorResponse from "../../../../Types/API/HTTPErrorResponse";
28
28
  import { JSONObject } from "../../../../Types/JSON";
29
+ import {
30
+ ResourceEntityFacetSelections,
31
+ collectResourceEntityFacetSelections,
32
+ collectServiceFacetSelections,
33
+ } from "../../../../Types/Telemetry/ResourceEntityFacet";
29
34
  import { APP_API_URL } from "../../../Config";
30
35
  import ModelAPI from "../../../Utils/ModelAPI/ModelAPI";
31
36
  import ComponentLoader from "../../ComponentLoader/ComponentLoader";
@@ -381,12 +386,29 @@ const LogsAnalyticsView: FunctionComponent<LogsAnalyticsViewProps> = (
381
386
  Array.from(severityValues);
382
387
  }
383
388
 
384
- const serviceFilterValues: Set<string> | undefined =
385
- props.appliedFacetFilters.get("primaryEntityId");
389
+ const serviceFilterValues: Array<string> =
390
+ collectServiceFacetSelections(props.appliedFacetFilters.entries());
386
391
 
387
- if (serviceFilterValues && serviceFilterValues.size > 0) {
392
+ if (serviceFilterValues.length > 0) {
388
393
  (requestData as Record<string, unknown>)["serviceIds"] =
389
- Array.from(serviceFilterValues);
394
+ serviceFilterValues;
395
+ }
396
+
397
+ /*
398
+ * Host / docker / podman / Kubernetes chips ride their own field —
399
+ * their ids are not `primaryEntityId` values for telemetry that
400
+ * carries a service.name, so the server resolves them to the
401
+ * resource's entity key. Without this the analytics tab silently
402
+ * ignored a cluster the sidebar was filtering by.
403
+ */
404
+ const resourceFilters: ResourceEntityFacetSelections =
405
+ collectResourceEntityFacetSelections(
406
+ props.appliedFacetFilters.entries(),
407
+ );
408
+
409
+ if (Object.keys(resourceFilters).length > 0) {
410
+ (requestData as Record<string, unknown>)["resourceFilters"] =
411
+ resourceFilters;
390
412
  }
391
413
 
392
414
  const traceFilterValues: Set<string> | undefined =
@@ -15,7 +15,23 @@ const LazyMarkdownViewer: FunctionComponent<ComponentProps> = (
15
15
  props: ComponentProps,
16
16
  ): JSX.Element => {
17
17
  return (
18
- <Suspense fallback={<div>Loading...</div>}>
18
+ <Suspense
19
+ fallback={
20
+ /*
21
+ * A bare "Loading..." string here painted raw English text in the
22
+ * middle of the page, then swapped it for content of a different
23
+ * height. Reserve roughly the space two lines of prose take instead.
24
+ *
25
+ * Spans rather than divs: callers such as EventItem render this inside
26
+ * a <p>, where block elements are invalid nesting.
27
+ */
28
+ <span role="status" aria-live="polite" className="block space-y-2">
29
+ <span className="block h-4 w-3/4 animate-pulse rounded bg-gray-100" />
30
+ <span className="block h-4 w-1/2 animate-pulse rounded bg-gray-100" />
31
+ <span className="sr-only">Loading content</span>
32
+ </span>
33
+ }
34
+ >
19
35
  <MarkdownViewer {...props} />
20
36
  </Suspense>
21
37
  );
@@ -30,6 +30,16 @@ const MasterPage: FunctionComponent<ComponentProps> = (
30
30
  const topSectionRef: React.RefObject<HTMLDivElement> =
31
31
  React.useRef<HTMLDivElement>(null);
32
32
 
33
+ /*
34
+ * The status page supplies neither header nor navbar — it renders its own
35
+ * inside children. Rendering TopSection anyway left an empty white bar with a
36
+ * drop shadow above the content, so only render it when it has something in
37
+ * it.
38
+ */
39
+ const hasTopSection: boolean = Boolean(
40
+ (!props.hideHeader && props.header) || props.navBar,
41
+ );
42
+
33
43
  /*
34
44
  * Publish the sticky top section's height as --app-header-height so anything
35
45
  * that sticks underneath it (the side menu, for example) can offset itself by
@@ -89,6 +99,7 @@ const MasterPage: FunctionComponent<ComponentProps> = (
89
99
  props.isLoading,
90
100
  props.error,
91
101
  props.disableMainContentWrapper,
102
+ hasTopSection,
92
103
  isOnline,
93
104
  ]);
94
105
 
@@ -125,17 +136,19 @@ const MasterPage: FunctionComponent<ComponentProps> = (
125
136
  Skip to main content
126
137
  </a>
127
138
  )}
128
- <div
129
- ref={topSectionRef}
130
- className={props.makeTopSectionUnstick ? "" : "sticky top-0 z-10"}
131
- >
132
- <TopSection
133
- hideHeader={props.hideHeader}
134
- className={props.topSectionClassName}
135
- header={props.header}
136
- navbar={props.navBar}
137
- />
138
- </div>
139
+ {hasTopSection && (
140
+ <div
141
+ ref={topSectionRef}
142
+ className={props.makeTopSectionUnstick ? "" : "sticky top-0 z-10"}
143
+ >
144
+ <TopSection
145
+ hideHeader={props.hideHeader}
146
+ className={props.topSectionClassName}
147
+ header={props.header}
148
+ navbar={props.navBar}
149
+ />
150
+ </div>
151
+ )}
139
152
 
140
153
  {props.disableMainContentWrapper ? (
141
154
  props.children
@@ -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
 
6
8
  /*
7
9
  * Groups of metrics rendered as separate cards on the monitor metrics page.
@@ -238,11 +240,24 @@ class MonitorMetricTypeUtil {
238
240
  monitorType === MonitorType.DNSSEC ||
239
241
  monitorType === MonitorType.Domain ||
240
242
  monitorType === MonitorType.SQLQuery ||
243
+ monitorType === MonitorType.SSLCertificate ||
241
244
  monitorType === MonitorType.ExternalStatusPage
242
245
  ) {
243
246
  return [MonitorMetricType.IsOnline, MonitorMetricType.ResponseTime];
244
247
  }
245
248
 
249
+ /*
250
+ * Any other type the probe actually checks still writes IsOnline and
251
+ * ResponseTime rows, so default to showing them rather than to an empty
252
+ * list. Falling through to [] hides the Monitor Metrics tab entirely -
253
+ * SSL Certificate monitors were missing from the list above and so had
254
+ * no metrics tab at all, which left an operator with no way to see that
255
+ * their monitor was running.
256
+ */
257
+ if (MonitorTypeHelper.isProbableMonitor(monitorType)) {
258
+ return [MonitorMetricType.IsOnline, MonitorMetricType.ResponseTime];
259
+ }
260
+
246
261
  return [];
247
262
  }
248
263
 
@@ -13,13 +13,27 @@ import {
13
13
  classifyEndpointRole,
14
14
  resolveDeviceRole,
15
15
  } from "./NetworkDeviceRoleUtil";
16
+ import DeviceReachabilityUtil, {
17
+ NetworkDeviceReachability,
18
+ } from "../NetworkDevice/DeviceReachabilityUtil";
16
19
 
17
20
  export interface TopologyDeviceInput {
18
21
  id: string;
19
22
  name: string;
20
23
  hostname?: string | undefined;
21
24
  sysName?: string | undefined;
25
+ /*
26
+ * Reachability inputs, all three of them. `isReachable` is the outcome of
27
+ * the last poll and is what actually decides up/down; `lastPolledAt` and
28
+ * `pollingIntervalInMinutes` only size the "we have stopped polling
29
+ * entirely" backstop. Passing lastSeenAt alone still works (that is the
30
+ * legacy path for rows written before the columns existed) but re-creates
31
+ * the bug where a fleet the probe cannot keep up with draws all-red.
32
+ */
33
+ isReachable?: boolean | undefined;
34
+ lastPolledAt?: Date | undefined;
22
35
  lastSeenAt?: Date | undefined;
36
+ pollingIntervalInMinutes?: number | undefined;
23
37
  interfacesUp?: number | undefined;
24
38
  interfacesDown?: number | undefined;
25
39
  vendor?: string | undefined;
@@ -232,12 +246,17 @@ interface ResolvedClaim {
232
246
  */
233
247
  const IPV4_PATTERN: RegExp = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
234
248
 
235
- // A device not seen within this window is treated as not currently up.
236
- const FRESH_WINDOW_MS: number = 15 * 60 * 1000;
237
-
238
249
  // Endpoint nodes rendered per graph; the slice is deterministic (by MAC).
239
250
  const ENDPOINT_RENDER_CAP: number = 2000;
240
251
 
252
+ /*
253
+ * How long an ARP/FDB-learned endpoint keeps its "up" colour after the last
254
+ * walk that saw it. Taken from the shared device rule at its default
255
+ * interval so the map's two node kinds age out on comparable timescales.
256
+ */
257
+ const ENDPOINT_FRESH_WINDOW_MS: number =
258
+ DeviceReachabilityUtil.getStaleWindowInMinutes(undefined) * 60 * 1000;
259
+
241
260
  export default class NetworkTopologyUtil {
242
261
  /*
243
262
  * Builds the topology graph from every device in a project. Nodes are the
@@ -1305,10 +1324,17 @@ export default class NetworkTopologyUtil {
1305
1324
  if (device.monitorStatus) {
1306
1325
  return device.monitorStatus;
1307
1326
  }
1308
- return NetworkTopologyUtil.statusFromLastSeen(device.lastSeenAt, now);
1327
+ return NetworkTopologyUtil.statusFromPoll(device, now);
1309
1328
  }
1310
1329
 
1311
- // The shared freshness rule: seen within the window = up, stale = down.
1330
+ /*
1331
+ * Endpoints (ARP/FDB-learned hosts) have no poll of their own: they are
1332
+ * re-learned from whichever device's tables they appear in, so freshness
1333
+ * really is all there is to go on. The window is the shared default
1334
+ * staleness window rather than the old fixed 15 minutes, so a host on a
1335
+ * switch its probe polls slowly does not blink out of the map between
1336
+ * walks.
1337
+ */
1312
1338
  private static statusFromLastSeen(
1313
1339
  lastSeenAt: Date | undefined,
1314
1340
  now: Date,
@@ -1316,10 +1342,36 @@ export default class NetworkTopologyUtil {
1316
1342
  if (!lastSeenAt) {
1317
1343
  return "unknown";
1318
1344
  }
1345
+
1319
1346
  const ageMs: number = now.getTime() - new Date(lastSeenAt).getTime();
1320
- if (ageMs > FRESH_WINDOW_MS) {
1321
- return "down";
1347
+
1348
+ return ageMs > ENDPOINT_FRESH_WINDOW_MS ? "down" : "up";
1349
+ }
1350
+
1351
+ /*
1352
+ * The shared reachability rule (DeviceReachabilityUtil), mapped onto the
1353
+ * graph's three node states. "Pending" — never polled — is the graph's
1354
+ * "unknown", which is what keeps a device nothing walks from being drawn
1355
+ * as a failure.
1356
+ */
1357
+ private static statusFromPoll(
1358
+ device: TopologyDeviceInput,
1359
+ now: Date,
1360
+ ): NetworkTopologyNodeStatus {
1361
+ const status: NetworkDeviceReachability = DeviceReachabilityUtil.getStatus(
1362
+ {
1363
+ isReachable: device.isReachable,
1364
+ lastPolledAt: device.lastPolledAt,
1365
+ lastSeenAt: device.lastSeenAt,
1366
+ pollingIntervalInMinutes: device.pollingIntervalInMinutes,
1367
+ },
1368
+ now,
1369
+ );
1370
+
1371
+ if (status === NetworkDeviceReachability.Pending) {
1372
+ return "unknown";
1322
1373
  }
1323
- return "up";
1374
+
1375
+ return status === NetworkDeviceReachability.Up ? "up" : "down";
1324
1376
  }
1325
1377
  }