@oneuptime/common 10.7.1 → 10.8.0

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 (262) hide show
  1. package/Models/DatabaseModels/CloudResource.ts +846 -0
  2. package/Models/DatabaseModels/CloudResourceInstance.ts +276 -0
  3. package/Models/DatabaseModels/CloudResourceLabelRule.ts +510 -0
  4. package/Models/DatabaseModels/CloudResourceOwnerRule.ts +592 -0
  5. package/Models/DatabaseModels/CloudResourceOwnerTeam.ts +487 -0
  6. package/Models/DatabaseModels/CloudResourceOwnerUser.ts +486 -0
  7. package/Models/DatabaseModels/Host.ts +209 -0
  8. package/Models/DatabaseModels/Index.ts +36 -0
  9. package/Models/DatabaseModels/RumApplication.ts +731 -0
  10. package/Models/DatabaseModels/RumApplicationClient.ts +229 -0
  11. package/Models/DatabaseModels/RumApplicationLabelRule.ts +510 -0
  12. package/Models/DatabaseModels/RumApplicationOwnerRule.ts +592 -0
  13. package/Models/DatabaseModels/RumApplicationOwnerTeam.ts +486 -0
  14. package/Models/DatabaseModels/RumApplicationOwnerUser.ts +485 -0
  15. package/Models/DatabaseModels/ServerlessFunction.ts +881 -0
  16. package/Models/DatabaseModels/ServerlessFunctionInstance.ts +212 -0
  17. package/Models/DatabaseModels/ServerlessFunctionLabelRule.ts +510 -0
  18. package/Models/DatabaseModels/ServerlessFunctionOwnerRule.ts +592 -0
  19. package/Models/DatabaseModels/ServerlessFunctionOwnerTeam.ts +487 -0
  20. package/Models/DatabaseModels/ServerlessFunctionOwnerUser.ts +486 -0
  21. package/Models/DatabaseModels/Service.ts +268 -0
  22. package/Models/DatabaseModels/TelemetryException.ts +15 -1
  23. package/Models/DatabaseModels/WorkflowLog.ts +52 -0
  24. package/Server/Infrastructure/Postgres/SchemaMigrations/1780931746908-AddResumeStateToWorkflowLog.ts +21 -0
  25. package/Server/Infrastructure/Postgres/SchemaMigrations/1780931863719-AddTelemetryResourceMetadataColumns.ts +108 -0
  26. package/Server/Infrastructure/Postgres/SchemaMigrations/1780933132562-AddServerlessFunctionTables.ts +205 -0
  27. package/Server/Infrastructure/Postgres/SchemaMigrations/1780935387827-AddCloudResourceTables.ts +195 -0
  28. package/Server/Infrastructure/Postgres/SchemaMigrations/1780936579718-AddRumApplicationTables.ts +202 -0
  29. package/Server/Infrastructure/Postgres/SchemaMigrations/1780938407319-AddServerlessFunctionRuleTables.ts +156 -0
  30. package/Server/Infrastructure/Postgres/SchemaMigrations/1780940721814-AddCloudResourceRuleTables.ts +149 -0
  31. package/Server/Infrastructure/Postgres/SchemaMigrations/1780940998002-AddRumApplicationRuleTables.ts +149 -0
  32. package/Server/Infrastructure/Postgres/SchemaMigrations/1780941762204-AddTelemetryResourceInventoryTables.ts +95 -0
  33. package/Server/Infrastructure/Postgres/SchemaMigrations/1780985763463-AddRumApplicationSdkLanguage.ts +25 -0
  34. package/Server/Infrastructure/Postgres/SchemaMigrations/1780987192743-RecastCloudResourcesByEnvironment.ts +30 -0
  35. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +22 -0
  36. package/Server/Infrastructure/Queue.ts +11 -0
  37. package/Server/Services/CloudResourceInstanceService.ts +76 -0
  38. package/Server/Services/CloudResourceLabelRuleEngineService.ts +175 -0
  39. package/Server/Services/CloudResourceLabelRuleService.ts +14 -0
  40. package/Server/Services/CloudResourceOwnerRuleEngineService.ts +192 -0
  41. package/Server/Services/CloudResourceOwnerRuleService.ts +14 -0
  42. package/Server/Services/CloudResourceOwnerTeamService.ts +10 -0
  43. package/Server/Services/CloudResourceOwnerUserService.ts +10 -0
  44. package/Server/Services/CloudResourceService.ts +342 -0
  45. package/Server/Services/ExceptionAggregationService.ts +3 -0
  46. package/Server/Services/HostService.ts +42 -0
  47. package/Server/Services/LogAggregationService.ts +3 -0
  48. package/Server/Services/MetricAggregationService.ts +3 -0
  49. package/Server/Services/OpenTelemetryIngestService.ts +148 -1
  50. package/Server/Services/RumApplicationClientService.ts +69 -0
  51. package/Server/Services/RumApplicationLabelRuleEngineService.ts +175 -0
  52. package/Server/Services/RumApplicationLabelRuleService.ts +14 -0
  53. package/Server/Services/RumApplicationOwnerRuleEngineService.ts +192 -0
  54. package/Server/Services/RumApplicationOwnerRuleService.ts +14 -0
  55. package/Server/Services/RumApplicationOwnerTeamService.ts +10 -0
  56. package/Server/Services/RumApplicationOwnerUserService.ts +10 -0
  57. package/Server/Services/RumApplicationService.ts +301 -0
  58. package/Server/Services/ServerlessFunctionInstanceService.ts +61 -0
  59. package/Server/Services/ServerlessFunctionLabelRuleEngineService.ts +182 -0
  60. package/Server/Services/ServerlessFunctionLabelRuleService.ts +14 -0
  61. package/Server/Services/ServerlessFunctionOwnerRuleEngineService.ts +199 -0
  62. package/Server/Services/ServerlessFunctionOwnerRuleService.ts +14 -0
  63. package/Server/Services/ServerlessFunctionOwnerTeamService.ts +10 -0
  64. package/Server/Services/ServerlessFunctionOwnerUserService.ts +10 -0
  65. package/Server/Services/ServerlessFunctionService.ts +351 -0
  66. package/Server/Services/ServiceService.ts +95 -8
  67. package/Server/Services/TraceAggregationService.ts +3 -0
  68. package/Server/Types/Database/Permissions/OwnerTableRegistry.ts +39 -0
  69. package/Server/Types/Workflow/ComponentCode.ts +9 -0
  70. package/Server/Types/Workflow/Components/Index.ts +2 -0
  71. package/Server/Types/Workflow/Components/Sleep.ts +105 -0
  72. package/Server/Types/Workflow/Workflow.ts +6 -0
  73. package/Server/Utils/Telemetry/ResourceFacetResolver.ts +150 -0
  74. package/Tests/Types/Monitor/KubernetesAlertTemplates.test.ts +193 -0
  75. package/Tests/UI/Components/DuplicateModel.test.tsx +2 -2
  76. package/Types/Monitor/KubernetesAlertTemplates.ts +239 -14
  77. package/Types/Permission.ts +692 -1
  78. package/Types/Telemetry/ServiceType.ts +3 -0
  79. package/Types/Workflow/ComponentID.ts +1 -0
  80. package/Types/Workflow/Components/Sleep.ts +71 -0
  81. package/Types/Workflow/Components.ts +2 -0
  82. package/Types/Workflow/WorkflowStatus.ts +1 -0
  83. package/UI/Components/BulkUpdate/BulkLabelActions.tsx +159 -32
  84. package/UI/Components/Navbar/NavBar.tsx +72 -123
  85. package/UI/Components/Navbar/NavBarMenuModal.tsx +642 -0
  86. package/UI/Components/Workflow/WorkflowStatus.tsx +3 -0
  87. package/build/dist/Models/DatabaseModels/CloudResource.js +871 -0
  88. package/build/dist/Models/DatabaseModels/CloudResource.js.map +1 -0
  89. package/build/dist/Models/DatabaseModels/CloudResourceInstance.js +300 -0
  90. package/build/dist/Models/DatabaseModels/CloudResourceInstance.js.map +1 -0
  91. package/build/dist/Models/DatabaseModels/CloudResourceLabelRule.js +520 -0
  92. package/build/dist/Models/DatabaseModels/CloudResourceLabelRule.js.map +1 -0
  93. package/build/dist/Models/DatabaseModels/CloudResourceOwnerRule.js +601 -0
  94. package/build/dist/Models/DatabaseModels/CloudResourceOwnerRule.js.map +1 -0
  95. package/build/dist/Models/DatabaseModels/CloudResourceOwnerTeam.js +503 -0
  96. package/build/dist/Models/DatabaseModels/CloudResourceOwnerTeam.js.map +1 -0
  97. package/build/dist/Models/DatabaseModels/CloudResourceOwnerUser.js +502 -0
  98. package/build/dist/Models/DatabaseModels/CloudResourceOwnerUser.js.map +1 -0
  99. package/build/dist/Models/DatabaseModels/Host.js +215 -0
  100. package/build/dist/Models/DatabaseModels/Host.js.map +1 -1
  101. package/build/dist/Models/DatabaseModels/Index.js +36 -0
  102. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  103. package/build/dist/Models/DatabaseModels/RumApplication.js +751 -0
  104. package/build/dist/Models/DatabaseModels/RumApplication.js.map +1 -0
  105. package/build/dist/Models/DatabaseModels/RumApplicationClient.js +252 -0
  106. package/build/dist/Models/DatabaseModels/RumApplicationClient.js.map +1 -0
  107. package/build/dist/Models/DatabaseModels/RumApplicationLabelRule.js +520 -0
  108. package/build/dist/Models/DatabaseModels/RumApplicationLabelRule.js.map +1 -0
  109. package/build/dist/Models/DatabaseModels/RumApplicationOwnerRule.js +601 -0
  110. package/build/dist/Models/DatabaseModels/RumApplicationOwnerRule.js.map +1 -0
  111. package/build/dist/Models/DatabaseModels/RumApplicationOwnerTeam.js +503 -0
  112. package/build/dist/Models/DatabaseModels/RumApplicationOwnerTeam.js.map +1 -0
  113. package/build/dist/Models/DatabaseModels/RumApplicationOwnerUser.js +502 -0
  114. package/build/dist/Models/DatabaseModels/RumApplicationOwnerUser.js.map +1 -0
  115. package/build/dist/Models/DatabaseModels/ServerlessFunction.js +908 -0
  116. package/build/dist/Models/DatabaseModels/ServerlessFunction.js.map +1 -0
  117. package/build/dist/Models/DatabaseModels/ServerlessFunctionInstance.js +234 -0
  118. package/build/dist/Models/DatabaseModels/ServerlessFunctionInstance.js.map +1 -0
  119. package/build/dist/Models/DatabaseModels/ServerlessFunctionLabelRule.js +520 -0
  120. package/build/dist/Models/DatabaseModels/ServerlessFunctionLabelRule.js.map +1 -0
  121. package/build/dist/Models/DatabaseModels/ServerlessFunctionOwnerRule.js +601 -0
  122. package/build/dist/Models/DatabaseModels/ServerlessFunctionOwnerRule.js.map +1 -0
  123. package/build/dist/Models/DatabaseModels/ServerlessFunctionOwnerTeam.js +503 -0
  124. package/build/dist/Models/DatabaseModels/ServerlessFunctionOwnerTeam.js.map +1 -0
  125. package/build/dist/Models/DatabaseModels/ServerlessFunctionOwnerUser.js +502 -0
  126. package/build/dist/Models/DatabaseModels/ServerlessFunctionOwnerUser.js.map +1 -0
  127. package/build/dist/Models/DatabaseModels/Service.js +276 -0
  128. package/build/dist/Models/DatabaseModels/Service.js.map +1 -1
  129. package/build/dist/Models/DatabaseModels/TelemetryException.js +12 -1
  130. package/build/dist/Models/DatabaseModels/TelemetryException.js.map +1 -1
  131. package/build/dist/Models/DatabaseModels/WorkflowLog.js +53 -0
  132. package/build/dist/Models/DatabaseModels/WorkflowLog.js.map +1 -1
  133. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780931746908-AddResumeStateToWorkflowLog.js +14 -0
  134. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780931746908-AddResumeStateToWorkflowLog.js.map +1 -0
  135. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780931863719-AddTelemetryResourceMetadataColumns.js +53 -0
  136. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780931863719-AddTelemetryResourceMetadataColumns.js.map +1 -0
  137. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780933132562-AddServerlessFunctionTables.js +82 -0
  138. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780933132562-AddServerlessFunctionTables.js.map +1 -0
  139. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780935387827-AddCloudResourceTables.js +82 -0
  140. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780935387827-AddCloudResourceTables.js.map +1 -0
  141. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780936579718-AddRumApplicationTables.js +83 -0
  142. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780936579718-AddRumApplicationTables.js.map +1 -0
  143. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780938407319-AddServerlessFunctionRuleTables.js +67 -0
  144. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780938407319-AddServerlessFunctionRuleTables.js.map +1 -0
  145. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780940721814-AddCloudResourceRuleTables.js +60 -0
  146. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780940721814-AddCloudResourceRuleTables.js.map +1 -0
  147. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780940998002-AddRumApplicationRuleTables.js +60 -0
  148. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780940998002-AddRumApplicationRuleTables.js.map +1 -0
  149. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780941762204-AddTelemetryResourceInventoryTables.js +45 -0
  150. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780941762204-AddTelemetryResourceInventoryTables.js.map +1 -0
  151. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780985763463-AddRumApplicationSdkLanguage.js +18 -0
  152. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780985763463-AddRumApplicationSdkLanguage.js.map +1 -0
  153. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780987192743-RecastCloudResourcesByEnvironment.js +27 -0
  154. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780987192743-RecastCloudResourcesByEnvironment.js.map +1 -0
  155. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +22 -0
  156. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  157. package/build/dist/Server/Infrastructure/Queue.js +3 -0
  158. package/build/dist/Server/Infrastructure/Queue.js.map +1 -1
  159. package/build/dist/Server/Services/CloudResourceInstanceService.js +76 -0
  160. package/build/dist/Server/Services/CloudResourceInstanceService.js.map +1 -0
  161. package/build/dist/Server/Services/CloudResourceLabelRuleEngineService.js +160 -0
  162. package/build/dist/Server/Services/CloudResourceLabelRuleEngineService.js.map +1 -0
  163. package/build/dist/Server/Services/CloudResourceLabelRuleService.js +13 -0
  164. package/build/dist/Server/Services/CloudResourceLabelRuleService.js.map +1 -0
  165. package/build/dist/Server/Services/CloudResourceOwnerRuleEngineService.js +179 -0
  166. package/build/dist/Server/Services/CloudResourceOwnerRuleEngineService.js.map +1 -0
  167. package/build/dist/Server/Services/CloudResourceOwnerRuleService.js +13 -0
  168. package/build/dist/Server/Services/CloudResourceOwnerRuleService.js.map +1 -0
  169. package/build/dist/Server/Services/CloudResourceOwnerTeamService.js +9 -0
  170. package/build/dist/Server/Services/CloudResourceOwnerTeamService.js.map +1 -0
  171. package/build/dist/Server/Services/CloudResourceOwnerUserService.js +9 -0
  172. package/build/dist/Server/Services/CloudResourceOwnerUserService.js.map +1 -0
  173. package/build/dist/Server/Services/CloudResourceService.js +287 -0
  174. package/build/dist/Server/Services/CloudResourceService.js.map +1 -0
  175. package/build/dist/Server/Services/ExceptionAggregationService.js +3 -0
  176. package/build/dist/Server/Services/ExceptionAggregationService.js.map +1 -1
  177. package/build/dist/Server/Services/HostService.js +29 -1
  178. package/build/dist/Server/Services/HostService.js.map +1 -1
  179. package/build/dist/Server/Services/LogAggregationService.js +3 -0
  180. package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
  181. package/build/dist/Server/Services/MetricAggregationService.js +3 -0
  182. package/build/dist/Server/Services/MetricAggregationService.js.map +1 -1
  183. package/build/dist/Server/Services/OpenTelemetryIngestService.js +98 -2
  184. package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
  185. package/build/dist/Server/Services/RumApplicationClientService.js +70 -0
  186. package/build/dist/Server/Services/RumApplicationClientService.js.map +1 -0
  187. package/build/dist/Server/Services/RumApplicationLabelRuleEngineService.js +160 -0
  188. package/build/dist/Server/Services/RumApplicationLabelRuleEngineService.js.map +1 -0
  189. package/build/dist/Server/Services/RumApplicationLabelRuleService.js +13 -0
  190. package/build/dist/Server/Services/RumApplicationLabelRuleService.js.map +1 -0
  191. package/build/dist/Server/Services/RumApplicationOwnerRuleEngineService.js +179 -0
  192. package/build/dist/Server/Services/RumApplicationOwnerRuleEngineService.js.map +1 -0
  193. package/build/dist/Server/Services/RumApplicationOwnerRuleService.js +13 -0
  194. package/build/dist/Server/Services/RumApplicationOwnerRuleService.js.map +1 -0
  195. package/build/dist/Server/Services/RumApplicationOwnerTeamService.js +9 -0
  196. package/build/dist/Server/Services/RumApplicationOwnerTeamService.js.map +1 -0
  197. package/build/dist/Server/Services/RumApplicationOwnerUserService.js +9 -0
  198. package/build/dist/Server/Services/RumApplicationOwnerUserService.js.map +1 -0
  199. package/build/dist/Server/Services/RumApplicationService.js +259 -0
  200. package/build/dist/Server/Services/RumApplicationService.js.map +1 -0
  201. package/build/dist/Server/Services/ServerlessFunctionInstanceService.js +64 -0
  202. package/build/dist/Server/Services/ServerlessFunctionInstanceService.js.map +1 -0
  203. package/build/dist/Server/Services/ServerlessFunctionLabelRuleEngineService.js +160 -0
  204. package/build/dist/Server/Services/ServerlessFunctionLabelRuleEngineService.js.map +1 -0
  205. package/build/dist/Server/Services/ServerlessFunctionLabelRuleService.js +13 -0
  206. package/build/dist/Server/Services/ServerlessFunctionLabelRuleService.js.map +1 -0
  207. package/build/dist/Server/Services/ServerlessFunctionOwnerRuleEngineService.js +179 -0
  208. package/build/dist/Server/Services/ServerlessFunctionOwnerRuleEngineService.js.map +1 -0
  209. package/build/dist/Server/Services/ServerlessFunctionOwnerRuleService.js +13 -0
  210. package/build/dist/Server/Services/ServerlessFunctionOwnerRuleService.js.map +1 -0
  211. package/build/dist/Server/Services/ServerlessFunctionOwnerTeamService.js +9 -0
  212. package/build/dist/Server/Services/ServerlessFunctionOwnerTeamService.js.map +1 -0
  213. package/build/dist/Server/Services/ServerlessFunctionOwnerUserService.js +9 -0
  214. package/build/dist/Server/Services/ServerlessFunctionOwnerUserService.js.map +1 -0
  215. package/build/dist/Server/Services/ServerlessFunctionService.js +299 -0
  216. package/build/dist/Server/Services/ServerlessFunctionService.js.map +1 -0
  217. package/build/dist/Server/Services/ServiceService.js +63 -7
  218. package/build/dist/Server/Services/ServiceService.js.map +1 -1
  219. package/build/dist/Server/Services/TraceAggregationService.js +3 -0
  220. package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
  221. package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js +39 -0
  222. package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js.map +1 -1
  223. package/build/dist/Server/Types/Workflow/ComponentCode.js.map +1 -1
  224. package/build/dist/Server/Types/Workflow/Components/Index.js +2 -0
  225. package/build/dist/Server/Types/Workflow/Components/Index.js.map +1 -1
  226. package/build/dist/Server/Types/Workflow/Components/Sleep.js +85 -0
  227. package/build/dist/Server/Types/Workflow/Components/Sleep.js.map +1 -0
  228. package/build/dist/Server/Utils/Telemetry/ResourceFacetResolver.js +90 -0
  229. package/build/dist/Server/Utils/Telemetry/ResourceFacetResolver.js.map +1 -1
  230. package/build/dist/Tests/Types/Monitor/KubernetesAlertTemplates.test.js +121 -0
  231. package/build/dist/Tests/Types/Monitor/KubernetesAlertTemplates.test.js.map +1 -0
  232. package/build/dist/Tests/UI/Components/DuplicateModel.test.js +2 -2
  233. package/build/dist/Tests/UI/Components/DuplicateModel.test.js.map +1 -1
  234. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js +210 -14
  235. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js.map +1 -1
  236. package/build/dist/Types/Permission.js +609 -1
  237. package/build/dist/Types/Permission.js.map +1 -1
  238. package/build/dist/Types/Telemetry/ServiceType.js +3 -0
  239. package/build/dist/Types/Telemetry/ServiceType.js.map +1 -1
  240. package/build/dist/Types/Workflow/ComponentID.js +1 -0
  241. package/build/dist/Types/Workflow/ComponentID.js.map +1 -1
  242. package/build/dist/Types/Workflow/Components/Sleep.js +64 -0
  243. package/build/dist/Types/Workflow/Components/Sleep.js.map +1 -0
  244. package/build/dist/Types/Workflow/Components.js +2 -0
  245. package/build/dist/Types/Workflow/Components.js.map +1 -1
  246. package/build/dist/Types/Workflow/WorkflowStatus.js +1 -0
  247. package/build/dist/Types/Workflow/WorkflowStatus.js.map +1 -1
  248. package/build/dist/UI/Components/BulkUpdate/BulkLabelActions.js +113 -19
  249. package/build/dist/UI/Components/BulkUpdate/BulkLabelActions.js.map +1 -1
  250. package/build/dist/UI/Components/Navbar/NavBar.js +34 -66
  251. package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
  252. package/build/dist/UI/Components/Navbar/NavBarMenuModal.js +412 -0
  253. package/build/dist/UI/Components/Navbar/NavBarMenuModal.js.map +1 -0
  254. package/build/dist/UI/Components/Workflow/WorkflowStatus.js +3 -0
  255. package/build/dist/UI/Components/Workflow/WorkflowStatus.js.map +1 -1
  256. package/package.json +1 -1
  257. package/UI/Components/Navbar/NavBarMenu.tsx +0 -183
  258. package/UI/Components/Navbar/NavBarMenuItem.tsx +0 -146
  259. package/build/dist/UI/Components/Navbar/NavBarMenu.js +0 -82
  260. package/build/dist/UI/Components/Navbar/NavBarMenu.js.map +0 -1
  261. package/build/dist/UI/Components/Navbar/NavBarMenuItem.js +0 -109
  262. package/build/dist/UI/Components/Navbar/NavBarMenuItem.js.map +0 -1
@@ -0,0 +1,642 @@
1
+ import Icon from "../Icon/Icon";
2
+ import Link from "../Link/Link";
3
+ import Navigation from "../../Utils/Navigation";
4
+ import IconProp from "../../../Types/Icon/IconProp";
5
+ import URL from "../../../Types/API/URL";
6
+ import type { MoreMenuItem } from "./NavBar";
7
+ import React, {
8
+ FunctionComponent,
9
+ ReactElement,
10
+ ReactNode,
11
+ useMemo,
12
+ useRef,
13
+ useState,
14
+ useEffect,
15
+ } from "react";
16
+
17
+ interface IconColorClasses {
18
+ bg: string;
19
+ ring: string;
20
+ text: string;
21
+ }
22
+
23
+ /*
24
+ * Icon color map carried over from the former NavBarMenuItem, extended with the
25
+ * few colors the dashboard items use (yellow/red/teal) plus a glyph text color
26
+ * so every product renders in its intended color. Unknown colors fall back to
27
+ * indigo.
28
+ */
29
+ const ICON_COLOR_CLASSES: Record<string, IconColorClasses> = {
30
+ purple: {
31
+ bg: "bg-purple-50",
32
+ ring: "ring-purple-200",
33
+ text: "text-purple-600",
34
+ },
35
+ blue: { bg: "bg-blue-50", ring: "ring-blue-200", text: "text-blue-600" },
36
+ gray: { bg: "bg-gray-100", ring: "ring-gray-300", text: "text-gray-600" },
37
+ amber: { bg: "bg-amber-50", ring: "ring-amber-200", text: "text-amber-600" },
38
+ green: { bg: "bg-green-50", ring: "ring-green-200", text: "text-green-600" },
39
+ cyan: { bg: "bg-cyan-50", ring: "ring-cyan-200", text: "text-cyan-600" },
40
+ slate: { bg: "bg-slate-100", ring: "ring-slate-300", text: "text-slate-600" },
41
+ indigo: {
42
+ bg: "bg-indigo-50",
43
+ ring: "ring-indigo-200",
44
+ text: "text-indigo-600",
45
+ },
46
+ rose: { bg: "bg-rose-50", ring: "ring-rose-200", text: "text-rose-600" },
47
+ violet: {
48
+ bg: "bg-violet-50",
49
+ ring: "ring-violet-200",
50
+ text: "text-violet-600",
51
+ },
52
+ orange: {
53
+ bg: "bg-orange-50",
54
+ ring: "ring-orange-200",
55
+ text: "text-orange-600",
56
+ },
57
+ stone: { bg: "bg-stone-100", ring: "ring-stone-300", text: "text-stone-600" },
58
+ sky: { bg: "bg-sky-50", ring: "ring-sky-200", text: "text-sky-600" },
59
+ emerald: {
60
+ bg: "bg-emerald-50",
61
+ ring: "ring-emerald-200",
62
+ text: "text-emerald-600",
63
+ },
64
+ yellow: {
65
+ bg: "bg-yellow-50",
66
+ ring: "ring-yellow-200",
67
+ text: "text-yellow-600",
68
+ },
69
+ red: { bg: "bg-red-50", ring: "ring-red-200", text: "text-red-600" },
70
+ teal: { bg: "bg-teal-50", ring: "ring-teal-200", text: "text-teal-600" },
71
+ };
72
+
73
+ // Persist the handful of most-recently opened products across sessions.
74
+ const RECENT_STORAGE_KEY: string = "oneuptime-navbar-recent-products";
75
+ const RECENT_LIMIT: number = 5;
76
+
77
+ const readRecentRoutes: () => string[] = (): string[] => {
78
+ try {
79
+ if (typeof window === "undefined" || !window.localStorage) {
80
+ return [];
81
+ }
82
+ const raw: string | null = window.localStorage.getItem(RECENT_STORAGE_KEY);
83
+ if (!raw) {
84
+ return [];
85
+ }
86
+ const parsed: unknown = JSON.parse(raw);
87
+ if (!Array.isArray(parsed)) {
88
+ return [];
89
+ }
90
+ return parsed.filter((value: unknown): value is string => {
91
+ return typeof value === "string";
92
+ });
93
+ } catch {
94
+ // Ignore storage access / parse errors (e.g. private mode, bad JSON).
95
+ return [];
96
+ }
97
+ };
98
+
99
+ const writeRecentRoute: (routeString: string) => void = (
100
+ routeString: string,
101
+ ): void => {
102
+ try {
103
+ if (typeof window === "undefined" || !window.localStorage) {
104
+ return;
105
+ }
106
+ const existing: string[] = readRecentRoutes().filter((route: string) => {
107
+ return route !== routeString;
108
+ });
109
+ const next: string[] = [routeString, ...existing].slice(0, RECENT_LIMIT);
110
+ window.localStorage.setItem(RECENT_STORAGE_KEY, JSON.stringify(next));
111
+ } catch {
112
+ // Ignore storage write errors (e.g. private mode, quota exceeded).
113
+ }
114
+ };
115
+
116
+ export interface ComponentProps {
117
+ items: MoreMenuItem[];
118
+ footer?:
119
+ | {
120
+ title: string;
121
+ description: string;
122
+ link: URL;
123
+ }
124
+ | undefined;
125
+ searchPlaceholder?: string | undefined;
126
+ noResultsText?: string | undefined;
127
+ keyboardHint?: string | undefined;
128
+ recentLabel?: string | undefined;
129
+ onClose: () => void;
130
+ }
131
+
132
+ interface IndexedItem {
133
+ item: MoreMenuItem;
134
+ flatIndex: number;
135
+ }
136
+
137
+ interface MenuGroup {
138
+ category: string;
139
+ items: IndexedItem[];
140
+ }
141
+
142
+ interface RawGroup {
143
+ category: string;
144
+ items: MoreMenuItem[];
145
+ }
146
+
147
+ const NavBarMenuModal: FunctionComponent<ComponentProps> = (
148
+ props: ComponentProps,
149
+ ): ReactElement => {
150
+ const [query, setQuery] = useState<string>("");
151
+ const [activeIndex, setActiveIndex] = useState<number>(0);
152
+ // Drives the open transition (fade + scale-in) on the first paint.
153
+ const [isShown, setIsShown] = useState<boolean>(false);
154
+ // Recently opened product routes, read once when the modal opens.
155
+ const [recentRoutes] = useState<string[]>(() => {
156
+ return readRecentRoutes();
157
+ });
158
+ const inputRef: React.RefObject<HTMLInputElement> =
159
+ useRef<HTMLInputElement>(null);
160
+ const cellRefs: React.MutableRefObject<Array<HTMLDivElement | null>> = useRef<
161
+ Array<HTMLDivElement | null>
162
+ >([]);
163
+
164
+ const recentLabel: string = props.recentLabel || "Recent";
165
+
166
+ // Show the OS-appropriate shortcut hint (⌘K on macOS, Ctrl K elsewhere).
167
+ const shortcutLabel: string = useMemo(() => {
168
+ if (typeof navigator === "undefined") {
169
+ return "⌘K";
170
+ }
171
+ const platform: string = (
172
+ navigator.platform ||
173
+ navigator.userAgent ||
174
+ ""
175
+ ).toLowerCase();
176
+ const isApplePlatform: boolean =
177
+ platform.includes("mac") ||
178
+ platform.includes("iphone") ||
179
+ platform.includes("ipad") ||
180
+ platform.includes("ipod");
181
+ return isApplePlatform ? "⌘K" : "Ctrl K";
182
+ }, []);
183
+
184
+ // Filter items by the search query (title + description + category).
185
+ const filteredItems: MoreMenuItem[] = useMemo(() => {
186
+ const normalizedQuery: string = query.trim().toLowerCase();
187
+ if (!normalizedQuery) {
188
+ return props.items;
189
+ }
190
+ return props.items.filter((item: MoreMenuItem) => {
191
+ const haystack: string = `${item.title} ${item.description} ${
192
+ item.category || ""
193
+ }`.toLowerCase();
194
+ return haystack.includes(normalizedQuery);
195
+ });
196
+ }, [props.items, query]);
197
+
198
+ /*
199
+ * The "Recent" row: resolve stored routes to current items, skip the page
200
+ * we're already on, and cap the count. Only shown while idle (no query).
201
+ */
202
+ const recentItems: MoreMenuItem[] = useMemo(() => {
203
+ if (recentRoutes.length === 0) {
204
+ return [];
205
+ }
206
+ const itemByRoute: Map<string, MoreMenuItem> = new Map();
207
+ props.items.forEach((item: MoreMenuItem) => {
208
+ itemByRoute.set(item.route.toString(), item);
209
+ });
210
+ const resolved: MoreMenuItem[] = [];
211
+ recentRoutes.forEach((route: string) => {
212
+ const item: MoreMenuItem | undefined = itemByRoute.get(route);
213
+ if (item && !Navigation.isStartWith(item.activeRoute || item.route)) {
214
+ resolved.push(item);
215
+ }
216
+ });
217
+ return resolved.slice(0, RECENT_LIMIT);
218
+ }, [recentRoutes, props.items]);
219
+
220
+ // Group filtered items by category, preserving first-seen order.
221
+ const categoryGroups: RawGroup[] = useMemo(() => {
222
+ const order: string[] = [];
223
+ const byCategory: Map<string, MoreMenuItem[]> = new Map();
224
+ filteredItems.forEach((item: MoreMenuItem) => {
225
+ const category: string = item.category || "Other";
226
+ if (!byCategory.has(category)) {
227
+ byCategory.set(category, []);
228
+ order.push(category);
229
+ }
230
+ byCategory.get(category)!.push(item);
231
+ });
232
+ return order.map((category: string) => {
233
+ return { category, items: byCategory.get(category)! };
234
+ });
235
+ }, [filteredItems]);
236
+
237
+ /*
238
+ * Final render order: a "Recent" group (idle only) followed by the category
239
+ * groups, with every item stamped with its index in the flattened order so
240
+ * keyboard navigation and cell refs stay in sync.
241
+ */
242
+ const displayGroups: MenuGroup[] = useMemo(() => {
243
+ const raw: RawGroup[] = [];
244
+ if (!query.trim() && recentItems.length > 0) {
245
+ raw.push({ category: recentLabel, items: recentItems });
246
+ }
247
+ raw.push(...categoryGroups);
248
+
249
+ let flatIndex: number = 0;
250
+ return raw.map((group: RawGroup) => {
251
+ const items: IndexedItem[] = group.items.map((item: MoreMenuItem) => {
252
+ const entry: IndexedItem = { item, flatIndex };
253
+ flatIndex++;
254
+ return entry;
255
+ });
256
+ return { category: group.category, items };
257
+ });
258
+ }, [query, recentItems, categoryGroups, recentLabel]);
259
+
260
+ // Flattened list in render order — used for keyboard navigation.
261
+ const flatItems: MoreMenuItem[] = useMemo(() => {
262
+ return displayGroups.reduce((acc: MoreMenuItem[], group: MenuGroup) => {
263
+ group.items.forEach((entry: IndexedItem) => {
264
+ acc.push(entry.item);
265
+ });
266
+ return acc;
267
+ }, []);
268
+ }, [displayGroups]);
269
+
270
+ // Index of the product matching the current page (the "you are here" item).
271
+ const currentFlatIndex: number = useMemo(() => {
272
+ return flatItems.findIndex((item: MoreMenuItem) => {
273
+ return Navigation.isStartWith(item.activeRoute || item.route);
274
+ });
275
+ }, [flatItems]);
276
+
277
+ // Play the open animation and focus the search box on mount.
278
+ useEffect(() => {
279
+ setIsShown(true);
280
+ inputRef.current?.focus();
281
+ }, []);
282
+
283
+ /*
284
+ * When idle, pre-select the current page so the modal opens "where you are";
285
+ * while searching, snap the selection to the first result.
286
+ */
287
+ useEffect(() => {
288
+ if (query) {
289
+ setActiveIndex(0);
290
+ return;
291
+ }
292
+ setActiveIndex(currentFlatIndex >= 0 ? currentFlatIndex : 0);
293
+ }, [query, currentFlatIndex]);
294
+
295
+ // Keep the active cell scrolled into view as the selection moves.
296
+ useEffect(() => {
297
+ cellRefs.current[activeIndex]?.scrollIntoView({ block: "nearest" });
298
+ }, [activeIndex]);
299
+
300
+ // Record a selection and close the modal.
301
+ const selectItem: (item: MoreMenuItem) => void = (
302
+ item: MoreMenuItem,
303
+ ): void => {
304
+ writeRecentRoute(item.route.toString());
305
+ props.onClose();
306
+ };
307
+
308
+ // Wrap the portions of text that match the query in a highlight.
309
+ const highlightMatch: (text: string) => ReactNode = (
310
+ text: string,
311
+ ): ReactNode => {
312
+ const needle: string = query.trim().toLowerCase();
313
+ if (!needle) {
314
+ return text;
315
+ }
316
+ const haystack: string = text.toLowerCase();
317
+ const parts: ReactNode[] = [];
318
+ let cursor: number = 0;
319
+ let matchAt: number = haystack.indexOf(needle, cursor);
320
+ let key: number = 0;
321
+ while (matchAt !== -1) {
322
+ if (matchAt > cursor) {
323
+ parts.push(text.slice(cursor, matchAt));
324
+ }
325
+ parts.push(
326
+ <mark
327
+ key={`m-${key}`}
328
+ className="rounded-sm bg-yellow-100 px-0.5 text-inherit"
329
+ >
330
+ {text.slice(matchAt, matchAt + needle.length)}
331
+ </mark>,
332
+ );
333
+ key++;
334
+ cursor = matchAt + needle.length;
335
+ matchAt = haystack.indexOf(needle, cursor);
336
+ }
337
+ if (cursor < text.length) {
338
+ parts.push(text.slice(cursor));
339
+ }
340
+ return parts;
341
+ };
342
+
343
+ const moveVertical: (direction: "up" | "down") => void = (
344
+ direction: "up" | "down",
345
+ ): void => {
346
+ const cells: Array<HTMLDivElement | null> = cellRefs.current;
347
+ const active: HTMLDivElement | null = cells[activeIndex] || null;
348
+ if (!active) {
349
+ return;
350
+ }
351
+ const activeRect: DOMRect = active.getBoundingClientRect();
352
+ const activeCenterX: number = activeRect.left + activeRect.width / 2;
353
+
354
+ // Find the nearest row in the requested direction.
355
+ let targetTop: number | null = null;
356
+ for (let i: number = 0; i < flatItems.length; i++) {
357
+ const cell: HTMLDivElement | null = cells[i] || null;
358
+ if (!cell) {
359
+ continue;
360
+ }
361
+ const top: number = cell.getBoundingClientRect().top;
362
+ if (direction === "down" && top > activeRect.top + 1) {
363
+ if (targetTop === null || top < targetTop) {
364
+ targetTop = top;
365
+ }
366
+ }
367
+ if (direction === "up" && top < activeRect.top - 1) {
368
+ if (targetTop === null || top > targetTop) {
369
+ targetTop = top;
370
+ }
371
+ }
372
+ }
373
+ if (targetTop === null) {
374
+ return;
375
+ }
376
+
377
+ // Within that row, pick the cell whose horizontal center is closest.
378
+ let bestIndex: number = activeIndex;
379
+ let bestDistance: number = Number.POSITIVE_INFINITY;
380
+ for (let i: number = 0; i < flatItems.length; i++) {
381
+ const cell: HTMLDivElement | null = cells[i] || null;
382
+ if (!cell) {
383
+ continue;
384
+ }
385
+ const rect: DOMRect = cell.getBoundingClientRect();
386
+ if (Math.abs(rect.top - targetTop) <= 1) {
387
+ const centerX: number = rect.left + rect.width / 2;
388
+ const distance: number = Math.abs(centerX - activeCenterX);
389
+ if (distance < bestDistance) {
390
+ bestDistance = distance;
391
+ bestIndex = i;
392
+ }
393
+ }
394
+ }
395
+ setActiveIndex(bestIndex);
396
+ };
397
+
398
+ const handleKeyDown: (
399
+ event: React.KeyboardEvent<HTMLInputElement>,
400
+ ) => void = (event: React.KeyboardEvent<HTMLInputElement>): void => {
401
+ if (event.key === "Escape") {
402
+ event.preventDefault();
403
+ props.onClose();
404
+ return;
405
+ }
406
+ if (flatItems.length === 0) {
407
+ return;
408
+ }
409
+ if (event.key === "ArrowRight") {
410
+ event.preventDefault();
411
+ setActiveIndex((index: number) => {
412
+ return Math.min(index + 1, flatItems.length - 1);
413
+ });
414
+ } else if (event.key === "ArrowLeft") {
415
+ event.preventDefault();
416
+ setActiveIndex((index: number) => {
417
+ return Math.max(index - 1, 0);
418
+ });
419
+ } else if (event.key === "ArrowDown") {
420
+ event.preventDefault();
421
+ moveVertical("down");
422
+ } else if (event.key === "ArrowUp") {
423
+ event.preventDefault();
424
+ moveVertical("up");
425
+ } else if (event.key === "Enter") {
426
+ event.preventDefault();
427
+ const item: MoreMenuItem | undefined = flatItems[activeIndex];
428
+ if (item) {
429
+ selectItem(item);
430
+ Navigation.navigate(item.route);
431
+ }
432
+ }
433
+ };
434
+
435
+ const keycapClass: string =
436
+ "inline-flex h-5 min-w-[1.25rem] items-center justify-center rounded border border-gray-200 bg-white px-1 text-[11px] font-medium text-gray-500 shadow-sm";
437
+
438
+ return (
439
+ <div
440
+ className="relative z-50"
441
+ role="dialog"
442
+ aria-modal="true"
443
+ aria-label="Products menu"
444
+ >
445
+ {/* Backdrop */}
446
+ <div
447
+ className={`fixed inset-0 bg-gray-900 bg-opacity-50 backdrop-blur-sm transition-opacity duration-200 ${
448
+ isShown ? "opacity-100" : "opacity-0"
449
+ }`}
450
+ />
451
+
452
+ {/* Scroll + click-away container */}
453
+ <div
454
+ className="fixed inset-0 z-50 overflow-y-auto"
455
+ onClick={props.onClose}
456
+ >
457
+ <div className="flex min-h-full items-start justify-center p-4 sm:p-6">
458
+ <div
459
+ className={`relative mt-[6vh] flex w-full max-w-4xl flex-col overflow-hidden rounded-2xl bg-white shadow-2xl ring-1 ring-black ring-opacity-5 transition-all duration-200 ease-out ${
460
+ isShown ? "scale-100 opacity-100" : "scale-95 opacity-0"
461
+ }`}
462
+ style={{ maxHeight: "80vh" }}
463
+ onClick={(event: React.MouseEvent<HTMLDivElement>) => {
464
+ event.stopPropagation();
465
+ }}
466
+ >
467
+ {/* Search header */}
468
+ <div className="flex items-center gap-3 border-b border-gray-100 px-4 py-3">
469
+ <Icon
470
+ icon={IconProp.Search}
471
+ className="h-5 w-5 flex-shrink-0 text-gray-400"
472
+ />
473
+ <input
474
+ ref={inputRef}
475
+ type="text"
476
+ role="combobox"
477
+ aria-expanded={true}
478
+ aria-controls="navbar-menu-listbox"
479
+ aria-activedescendant={
480
+ flatItems.length > 0
481
+ ? `navbar-menu-option-${activeIndex}`
482
+ : undefined
483
+ }
484
+ aria-label={props.searchPlaceholder || "Search products"}
485
+ value={query}
486
+ onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
487
+ setQuery(event.target.value);
488
+ }}
489
+ onKeyDown={handleKeyDown}
490
+ placeholder={props.searchPlaceholder || "Search…"}
491
+ className="flex-1 border-0 bg-transparent p-0 text-base text-gray-900 placeholder-gray-400 focus:outline-none focus:ring-0"
492
+ />
493
+ <kbd className="hidden items-center rounded border border-gray-200 bg-gray-50 px-1.5 py-0.5 text-xs font-medium text-gray-400 sm:inline-flex">
494
+ {shortcutLabel}
495
+ </kbd>
496
+ </div>
497
+
498
+ {/* Body */}
499
+ <div
500
+ id="navbar-menu-listbox"
501
+ role="listbox"
502
+ aria-label="Products"
503
+ className="flex-1 overflow-y-auto px-4 py-4"
504
+ >
505
+ {flatItems.length === 0 ? (
506
+ <div className="flex flex-col items-center justify-center py-16 text-center">
507
+ <Icon
508
+ icon={IconProp.Search}
509
+ className="mb-3 h-8 w-8 text-gray-300"
510
+ />
511
+ <p className="text-sm text-gray-500">
512
+ {props.noResultsText || "No results found."}
513
+ </p>
514
+ {query && (
515
+ <p className="mt-1 text-xs text-gray-400">
516
+ &ldquo;{query}&rdquo;
517
+ </p>
518
+ )}
519
+ </div>
520
+ ) : (
521
+ displayGroups.map((group: MenuGroup) => {
522
+ return (
523
+ <div key={group.category} className="mb-6 last:mb-1">
524
+ <h3 className="mb-2 px-1 text-xs font-semibold uppercase tracking-wider text-gray-500">
525
+ {group.category}
526
+ </h3>
527
+ <div className="grid grid-cols-2 gap-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5">
528
+ {group.items.map((entry: IndexedItem) => {
529
+ const item: MoreMenuItem = entry.item;
530
+ const flatIndex: number = entry.flatIndex;
531
+ const isActive: boolean = flatIndex === activeIndex;
532
+ const isCurrent: boolean =
533
+ flatIndex === currentFlatIndex;
534
+ const colors: IconColorClasses =
535
+ ICON_COLOR_CLASSES[item.iconColor || "indigo"] ||
536
+ ICON_COLOR_CLASSES["indigo"]!;
537
+ return (
538
+ <div
539
+ key={entry.flatIndex}
540
+ id={`navbar-menu-option-${flatIndex}`}
541
+ role="option"
542
+ aria-selected={isActive}
543
+ ref={(element: HTMLDivElement | null) => {
544
+ cellRefs.current[flatIndex] = element;
545
+ }}
546
+ onMouseEnter={() => {
547
+ setActiveIndex(flatIndex);
548
+ }}
549
+ className="relative"
550
+ >
551
+ {isCurrent && (
552
+ <span
553
+ aria-hidden="true"
554
+ className="absolute right-2 top-2 z-10 h-2 w-2 rounded-full bg-indigo-500 ring-2 ring-white"
555
+ />
556
+ )}
557
+ <Link
558
+ to={item.route}
559
+ onClick={() => {
560
+ selectItem(item);
561
+ }}
562
+ className={`group flex h-full flex-col items-center gap-2 rounded-xl p-3 text-center transition-all duration-150 ${
563
+ isActive
564
+ ? "scale-[1.03] bg-indigo-50 shadow-sm ring-2 ring-indigo-400"
565
+ : isCurrent
566
+ ? "bg-indigo-50/60 ring-1 ring-indigo-200 hover:bg-indigo-50"
567
+ : "hover:bg-gray-50"
568
+ }`}
569
+ >
570
+ <div
571
+ className={`flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-xl ${colors.bg} ring-1 ${colors.ring}`}
572
+ >
573
+ <Icon
574
+ icon={item.icon}
575
+ className={`h-6 w-6 transition-transform duration-150 group-hover:scale-110 ${colors.text}`}
576
+ />
577
+ </div>
578
+ <div className="w-full">
579
+ <p className="text-sm font-medium text-gray-900">
580
+ {highlightMatch(item.title)}
581
+ </p>
582
+ <p className="mt-0.5 text-xs leading-snug text-gray-500 line-clamp-2">
583
+ {highlightMatch(item.description)}
584
+ </p>
585
+ </div>
586
+ </Link>
587
+ </div>
588
+ );
589
+ })}
590
+ </div>
591
+ </div>
592
+ );
593
+ })
594
+ )}
595
+ </div>
596
+
597
+ {/* Footer */}
598
+ {props.footer && (
599
+ <div className="flex items-center justify-between gap-4 border-t border-gray-100 bg-gray-50 px-4 py-3">
600
+ <Link
601
+ to={props.footer.link}
602
+ openInNewTab={true}
603
+ className="group flex min-w-0 items-center gap-3"
604
+ >
605
+ <div className="flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg bg-gray-100 ring-1 ring-gray-200 transition-all group-hover:bg-gray-200">
606
+ <Icon
607
+ icon={IconProp.GitHub}
608
+ className="h-4 w-4 text-gray-700"
609
+ />
610
+ </div>
611
+ <div className="min-w-0 text-left">
612
+ <p className="truncate text-sm font-medium text-gray-900">
613
+ {props.footer.title}
614
+ </p>
615
+ <p className="truncate text-xs text-gray-500">
616
+ {props.footer.description}
617
+ </p>
618
+ </div>
619
+ </Link>
620
+ {props.keyboardHint && (
621
+ <div
622
+ aria-label={props.keyboardHint}
623
+ className="hidden flex-shrink-0 items-center gap-2 text-xs text-gray-400 md:flex"
624
+ >
625
+ <span className="flex items-center gap-1">
626
+ <kbd className={keycapClass}>↑</kbd>
627
+ <kbd className={keycapClass}>↓</kbd>
628
+ </span>
629
+ <kbd className={keycapClass}>↵</kbd>
630
+ <kbd className={keycapClass}>esc</kbd>
631
+ </div>
632
+ )}
633
+ </div>
634
+ )}
635
+ </div>
636
+ </div>
637
+ </div>
638
+ </div>
639
+ );
640
+ };
641
+
642
+ export default NavBarMenuModal;
@@ -19,6 +19,9 @@ const WorkflowStatusElement: FunctionComponent<ComponentProps> = (
19
19
  if (props.status === WorkflowStatus.Scheduled) {
20
20
  return <Pill color={Yellow} text="Scheduled" />;
21
21
  }
22
+ if (props.status === WorkflowStatus.Waiting) {
23
+ return <Pill color={Yellow} text="Waiting" />;
24
+ }
22
25
  if (props.status === WorkflowStatus.Error) {
23
26
  return <Pill color={Red} text="Error" />;
24
27
  }