@flamingo-stack/openframe-frontend-core 0.0.711 → 0.0.712

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 (523) hide show
  1. package/dist/chunk-2NASBO7O.js +1137 -0
  2. package/dist/{chunk-RQRX4YC3.cjs → chunk-2RKFMUNW.cjs} +46 -46
  3. package/dist/chunk-2Y7QZAB2.cjs +158 -0
  4. package/dist/chunk-34I6XI3N.js +136 -0
  5. package/dist/chunk-3K5ZLZE7.js +292 -0
  6. package/dist/chunk-3LU4UFPS.cjs +14 -0
  7. package/dist/{chunk-3UNL26CD.cjs → chunk-3RKBJT6K.cjs} +8 -6
  8. package/dist/{chunk-6GLQLTJI.js → chunk-3SEEGNRE.js} +35 -27
  9. package/dist/{chunk-FEMAJES4.cjs → chunk-3UAJLO5U.cjs} +41 -39
  10. package/dist/chunk-4HJRHEXD.cjs +1612 -0
  11. package/dist/{chunk-JPG7OHEG.js → chunk-4QFWGLZO.js} +1 -1
  12. package/dist/chunk-4R2L3DSA.js +14 -0
  13. package/dist/{chunk-2JTGK64G.js → chunk-4UYKNOZG.js} +12 -10
  14. package/dist/{chunk-TKZXHVBG.js → chunk-5SDELRH3.js} +5 -5
  15. package/dist/{chunk-Q6B35Y7O.js → chunk-5Y72YQEK.js} +22 -113
  16. package/dist/{chunk-KUC673HM.js → chunk-6T3BTD6Q.js} +204 -982
  17. package/dist/{chunk-F57ECE2I.js → chunk-6YPTUHM7.js} +4 -4
  18. package/dist/{chunk-WJUIXU6Y.js → chunk-7HNYYNKE.js} +28 -22
  19. package/dist/{chunk-P6G3JZNC.cjs → chunk-7NSU5EQD.cjs} +57 -148
  20. package/dist/chunk-AAYNCJMW.cjs +48 -0
  21. package/dist/{chunk-FXJ3WWUB.js → chunk-ADBE7QF3.js} +5 -252
  22. package/dist/chunk-AECTRMGQ.cjs +334 -0
  23. package/dist/chunk-AGVXKD4K.js +334 -0
  24. package/dist/chunk-AL2GUHAJ.cjs +18 -0
  25. package/dist/{chunk-WMX26HB5.js → chunk-APJZBDQN.js} +12 -12
  26. package/dist/chunk-AUMKE74M.cjs +16 -0
  27. package/dist/chunk-B4NCVYEQ.cjs +292 -0
  28. package/dist/{chunk-XWEBHS7O.cjs → chunk-BXSRTBLU.cjs} +82 -54
  29. package/dist/chunk-CMGFZHCN.js +233 -0
  30. package/dist/chunk-CMZ3QTFQ.js +1207 -0
  31. package/dist/chunk-CPA2CKRZ.cjs +125 -0
  32. package/dist/{chunk-G47AP6LX.cjs → chunk-CSCJU6YC.cjs} +35 -33
  33. package/dist/chunk-CYUUHFXL.js +41 -0
  34. package/dist/chunk-DC4RTYWK.cjs +1122 -0
  35. package/dist/{chunk-NF7GNGYG.js → chunk-DDWFCWOE.js} +5 -7
  36. package/dist/{chunk-K4PTDK34.js → chunk-EFNKS5W4.js} +322 -428
  37. package/dist/{chunk-QA6TROME.cjs → chunk-EOKSKJSS.cjs} +25 -83
  38. package/dist/{chunk-6NTPY5QA.cjs → chunk-ETYLOZOB.cjs} +978 -2413
  39. package/dist/chunk-F5BPGWGT.cjs +931 -0
  40. package/dist/{chunk-5HB7FLCV.js → chunk-FCAVAEHF.js} +8277 -9990
  41. package/dist/chunk-FFT56TYB.cjs +401 -0
  42. package/dist/chunk-FYEJTF5Y.js +125 -0
  43. package/dist/chunk-G3GRYDMS.js +16 -0
  44. package/dist/{chunk-VWFZRMQR.js → chunk-G3OMVCID.js} +13 -7
  45. package/dist/chunk-G6OHIX5C.cjs +100 -0
  46. package/dist/{chunk-UDFRUKLC.cjs → chunk-GEDY7HQI.cjs} +2 -2
  47. package/dist/chunk-GQ7JJUIT.cjs +1207 -0
  48. package/dist/chunk-H3PKYE4N.js +18 -0
  49. package/dist/{chunk-AGDVEUVL.js → chunk-H5R7U2D2.js} +206 -5
  50. package/dist/{chunk-7AM6C6XH.cjs → chunk-HETQETPV.cjs} +9641 -9678
  51. package/dist/{chunk-Y2GSOUCS.cjs → chunk-HWVUR735.cjs} +2 -2
  52. package/dist/chunk-II4QMH26.cjs +35 -0
  53. package/dist/chunk-ILNN6QRW.js +1612 -0
  54. package/dist/chunk-IYVFSLWJ.js +931 -0
  55. package/dist/{chunk-C4HRRB3V.cjs → chunk-JGCFRTND.cjs} +23 -17
  56. package/dist/chunk-JHQ334WS.js +655 -0
  57. package/dist/{chunk-WCVZCGK5.cjs → chunk-JO5TLJPM.cjs} +129 -907
  58. package/dist/{chunk-PRX7HVLE.cjs → chunk-JVCAK4W3.cjs} +210 -9
  59. package/dist/chunk-KBJJQFYU.js +1122 -0
  60. package/dist/chunk-KEKCQENI.js +48 -0
  61. package/dist/chunk-KHXZFLIN.cjs +41 -0
  62. package/dist/chunk-KT3U3ZRP.cjs +1137 -0
  63. package/dist/chunk-L2VUINHN.js +35 -0
  64. package/dist/{chunk-FYOKS5RI.cjs → chunk-L6ZQGWCX.cjs} +4521 -6234
  65. package/dist/{chunk-PLYEKV3N.cjs → chunk-MA4Q5RBP.cjs} +6 -6
  66. package/dist/{chunk-VMMHJFHG.js → chunk-N67XG5GY.js} +10 -8
  67. package/dist/chunk-NPAQSMRY.js +2087 -0
  68. package/dist/{chunk-IFWLJ66M.js → chunk-NQWJAOHO.js} +6 -4
  69. package/dist/{chunk-6K7QZDA6.cjs → chunk-OBZJICEA.cjs} +8 -8
  70. package/dist/{chunk-62KNLDXK.js → chunk-OPYODNV2.js} +3 -3
  71. package/dist/chunk-P3JMAMHP.js +401 -0
  72. package/dist/chunk-PPXR22YC.cjs +2087 -0
  73. package/dist/chunk-PSVSEN4J.cjs +655 -0
  74. package/dist/{chunk-EQWD4IJE.js → chunk-RBYVFPER.js} +74 -46
  75. package/dist/{chunk-SMAAV3HL.js → chunk-ROBQ5TR7.js} +10541 -10578
  76. package/dist/{chunk-K6Y5NX6L.cjs → chunk-T3CLXR43.cjs} +114 -220
  77. package/dist/{chunk-FI6GMDO7.js → chunk-TTVOLEUS.js} +3605 -5040
  78. package/dist/{chunk-LM7TXMLU.cjs → chunk-ULWVKHSI.cjs} +8 -255
  79. package/dist/{chunk-EX6GGCAC.cjs → chunk-UT3ODMBU.cjs} +15 -15
  80. package/dist/chunk-WANCBTUE.js +71 -0
  81. package/dist/{chunk-BIZNSF3U.cjs → chunk-WBNAEYTQ.cjs} +2 -51
  82. package/dist/chunk-WFPCCBOM.cjs +71 -0
  83. package/dist/chunk-WI6FHKD7.js +158 -0
  84. package/dist/chunk-WMNCVLES.js +100 -0
  85. package/dist/{chunk-UT4YHQZW.js → chunk-WSDT7LYL.js} +0 -49
  86. package/dist/chunk-WVOTC7HW.cjs +136 -0
  87. package/dist/{chunk-6AMIRXKM.cjs → chunk-WWJG4GVG.cjs} +93 -87
  88. package/dist/chunk-XXBLN4BP.cjs +233 -0
  89. package/dist/{chunk-4IBPRIQH.js → chunk-YBQQNDC7.js} +1 -1
  90. package/dist/{chunk-QGZPZ3RL.js → chunk-YBS5QGON.js} +70 -128
  91. package/dist/{chunk-CDM7OSFB.cjs → chunk-Z5SWJW5Q.cjs} +125 -117
  92. package/dist/{chunk-YD4LJZV4.cjs → chunk-ZX7SCPLO.cjs} +6 -8
  93. package/dist/cloud-tenants-KZUZGD4A.cjs +117 -0
  94. package/dist/cloud-tenants-OGLVVQ7X.js +117 -0
  95. package/dist/components/case-studies/index.cjs +45 -29
  96. package/dist/components/case-studies/index.js +32 -16
  97. package/dist/components/chat/ask-prompts.d.ts +64 -0
  98. package/dist/components/chat/ask-prompts.d.ts.map +1 -0
  99. package/dist/components/chat/entity-cards/case-study-card.d.ts +6 -3
  100. package/dist/components/chat/entity-cards/case-study-card.d.ts.map +1 -1
  101. package/dist/components/chat/index.cjs +27 -8
  102. package/dist/components/chat/index.d.ts +1 -0
  103. package/dist/components/chat/index.d.ts.map +1 -1
  104. package/dist/components/chat/index.js +57 -38
  105. package/dist/components/chat/quick-action-chip.d.ts +7 -3
  106. package/dist/components/chat/quick-action-chip.d.ts.map +1 -1
  107. package/dist/components/contact/index.cjs +29 -13
  108. package/dist/components/contact/index.js +28 -12
  109. package/dist/components/docs/index.cjs +33 -16
  110. package/dist/components/docs/index.js +33 -16
  111. package/dist/components/docs/use-scroll-spy.d.ts +23 -1
  112. package/dist/components/docs/use-scroll-spy.d.ts.map +1 -1
  113. package/dist/components/embeds/index.cjs +29 -13
  114. package/dist/components/embeds/index.js +28 -12
  115. package/dist/components/faq/faq-section.d.ts +8 -1
  116. package/dist/components/faq/faq-section.d.ts.map +1 -1
  117. package/dist/components/faq/index.cjs +30 -14
  118. package/dist/components/faq/index.js +29 -13
  119. package/dist/components/features/array-entry-manager.d.ts +5 -1
  120. package/dist/components/features/array-entry-manager.d.ts.map +1 -1
  121. package/dist/components/features/board/board.d.ts +2 -0
  122. package/dist/components/features/board/board.d.ts.map +1 -1
  123. package/dist/components/features/board/ticket-card.d.ts.map +1 -1
  124. package/dist/components/features/board/touch-board.d.ts +1 -1
  125. package/dist/components/features/board/touch-board.d.ts.map +1 -1
  126. package/dist/components/features/board/types.d.ts +3 -0
  127. package/dist/components/features/board/types.d.ts.map +1 -1
  128. package/dist/components/features/board/use-board-collapse.d.ts +6 -1
  129. package/dist/components/features/board/use-board-collapse.d.ts.map +1 -1
  130. package/dist/components/features/capability-explorer.d.ts +94 -0
  131. package/dist/components/features/capability-explorer.d.ts.map +1 -0
  132. package/dist/components/features/cloud-tenants/index.d.ts +14 -0
  133. package/dist/components/features/cloud-tenants/index.d.ts.map +1 -0
  134. package/dist/components/features/cloud-tenants/tenant-access-cell.d.ts +9 -0
  135. package/dist/components/features/cloud-tenants/tenant-access-cell.d.ts.map +1 -0
  136. package/dist/components/features/cloud-tenants/tenant-cell.d.ts +8 -0
  137. package/dist/components/features/cloud-tenants/tenant-cell.d.ts.map +1 -0
  138. package/dist/components/features/cloud-tenants/tenant-customer-cell.d.ts +9 -0
  139. package/dist/components/features/cloud-tenants/tenant-customer-cell.d.ts.map +1 -0
  140. package/dist/components/features/cloud-tenants/tenant-presentation.d.ts +42 -0
  141. package/dist/components/features/cloud-tenants/tenant-presentation.d.ts.map +1 -0
  142. package/dist/components/features/cloud-tenants/tenant-row.d.ts +22 -0
  143. package/dist/components/features/cloud-tenants/tenant-row.d.ts.map +1 -0
  144. package/dist/components/features/cloud-tenants/tenants-table-columns.d.ts +42 -0
  145. package/dist/components/features/cloud-tenants/tenants-table-columns.d.ts.map +1 -0
  146. package/dist/components/features/cloud-tenants/tenants-table-view.d.ts +26 -0
  147. package/dist/components/features/cloud-tenants/tenants-table-view.d.ts.map +1 -0
  148. package/dist/components/features/devices/device-last-online.d.ts +3 -0
  149. package/dist/components/features/devices/device-last-online.d.ts.map +1 -0
  150. package/dist/components/features/devices/device-name.d.ts +42 -0
  151. package/dist/components/features/devices/device-name.d.ts.map +1 -0
  152. package/dist/components/features/devices/device-selector/device-selection-mode-radio.d.ts +26 -0
  153. package/dist/components/features/devices/device-selector/device-selection-mode-radio.d.ts.map +1 -0
  154. package/dist/components/features/devices/device-selector/device-selector-skeleton.d.ts +25 -0
  155. package/dist/components/features/devices/device-selector/device-selector-skeleton.d.ts.map +1 -0
  156. package/dist/components/features/devices/device-selector/device-selector.d.ts +38 -0
  157. package/dist/components/features/devices/device-selector/device-selector.d.ts.map +1 -0
  158. package/dist/components/features/devices/device-selector/device-selector.types.d.ts +133 -0
  159. package/dist/components/features/devices/device-selector/device-selector.types.d.ts.map +1 -0
  160. package/dist/components/features/devices/device-selector/narrowing.d.ts +13 -0
  161. package/dist/components/features/devices/device-selector/narrowing.d.ts.map +1 -0
  162. package/dist/components/features/devices/device-selector/use-device-selector.d.ts +17 -0
  163. package/dist/components/features/devices/device-selector/use-device-selector.d.ts.map +1 -0
  164. package/dist/components/features/devices/device-status.d.ts +23 -0
  165. package/dist/components/features/devices/device-status.d.ts.map +1 -0
  166. package/dist/components/features/devices/device-statuses.d.ts +40 -0
  167. package/dist/components/features/devices/device-statuses.d.ts.map +1 -0
  168. package/dist/components/features/devices/device-tags-filter-button.d.ts +22 -0
  169. package/dist/components/features/devices/device-tags-filter-button.d.ts.map +1 -0
  170. package/dist/components/features/devices/device-type-icon.d.ts +11 -0
  171. package/dist/components/features/devices/device-type-icon.d.ts.map +1 -0
  172. package/dist/components/features/devices/device-type-tile.d.ts +9 -0
  173. package/dist/components/features/devices/device-type-tile.d.ts.map +1 -0
  174. package/dist/components/features/devices/devices-filter-toolbar.d.ts +46 -0
  175. package/dist/components/features/devices/devices-filter-toolbar.d.ts.map +1 -0
  176. package/dist/components/features/devices/devices-grid-filters.d.ts +25 -0
  177. package/dist/components/features/devices/devices-grid-filters.d.ts.map +1 -0
  178. package/dist/components/features/devices/devices-grid.d.ts +12 -0
  179. package/dist/components/features/devices/devices-grid.d.ts.map +1 -0
  180. package/dist/components/features/devices/devices-list.d.ts +131 -0
  181. package/dist/components/features/devices/devices-list.d.ts.map +1 -0
  182. package/dist/components/features/devices/devices-panel-header.d.ts +46 -0
  183. package/dist/components/features/devices/devices-panel-header.d.ts.map +1 -0
  184. package/dist/components/features/devices/devices-panel-view.d.ts +79 -0
  185. package/dist/components/features/devices/devices-panel-view.d.ts.map +1 -0
  186. package/dist/components/features/devices/devices-table-columns.d.ts +76 -0
  187. package/dist/components/features/devices/devices-table-columns.d.ts.map +1 -0
  188. package/dist/components/features/devices/devices-view-config.d.ts +25 -0
  189. package/dist/components/features/devices/devices-view-config.d.ts.map +1 -0
  190. package/dist/components/features/devices/index.d.ts +24 -0
  191. package/dist/components/features/devices/index.d.ts.map +1 -0
  192. package/dist/components/features/devices/types.d.ts +68 -0
  193. package/dist/components/features/devices/types.d.ts.map +1 -0
  194. package/dist/components/features/devices/use-tag-filter-modal.d.ts +50 -0
  195. package/dist/components/features/devices/use-tag-filter-modal.d.ts.map +1 -0
  196. package/dist/components/features/index.cjs +227 -12
  197. package/dist/components/features/index.d.ts +7 -0
  198. package/dist/components/features/index.d.ts.map +1 -1
  199. package/dist/components/features/index.js +266 -51
  200. package/dist/components/features/knowledge-base/index.d.ts +7 -0
  201. package/dist/components/features/knowledge-base/index.d.ts.map +1 -0
  202. package/dist/components/features/knowledge-base/knowledge-base-article-view.d.ts +44 -0
  203. package/dist/components/features/knowledge-base/knowledge-base-article-view.d.ts.map +1 -0
  204. package/dist/components/features/knowledge-base/knowledge-base-item-icon.d.ts +13 -0
  205. package/dist/components/features/knowledge-base/knowledge-base-item-icon.d.ts.map +1 -0
  206. package/dist/components/features/knowledge-base/knowledge-base-status.d.ts +8 -0
  207. package/dist/components/features/knowledge-base/knowledge-base-status.d.ts.map +1 -0
  208. package/dist/components/features/knowledge-base/knowledge-base-table.d.ts +52 -0
  209. package/dist/components/features/knowledge-base/knowledge-base-table.d.ts.map +1 -0
  210. package/dist/components/features/logs/index.d.ts +12 -0
  211. package/dist/components/features/logs/index.d.ts.map +1 -0
  212. package/dist/components/features/logs/log-drawer.d.ts +29 -0
  213. package/dist/components/features/logs/log-drawer.d.ts.map +1 -0
  214. package/dist/components/features/logs/log-source-labels.d.ts +11 -0
  215. package/dist/components/features/logs/log-source-labels.d.ts.map +1 -0
  216. package/dist/components/features/logs/logs-page-view.d.ts +32 -0
  217. package/dist/components/features/logs/logs-page-view.d.ts.map +1 -0
  218. package/dist/components/features/logs/logs-table-columns.d.ts +15 -0
  219. package/dist/components/features/logs/logs-table-columns.d.ts.map +1 -0
  220. package/dist/components/features/logs/logs-table-view.d.ts +64 -0
  221. package/dist/components/features/logs/logs-table-view.d.ts.map +1 -0
  222. package/dist/components/features/logs/types.d.ts +52 -0
  223. package/dist/components/features/logs/types.d.ts.map +1 -0
  224. package/dist/components/features/policies/compute-policy-summary.d.ts +37 -0
  225. package/dist/components/features/policies/compute-policy-summary.d.ts.map +1 -0
  226. package/dist/components/features/policies/index.d.ts +8 -0
  227. package/dist/components/features/policies/index.d.ts.map +1 -0
  228. package/dist/components/features/policies/policies-table.d.ts +34 -0
  229. package/dist/components/features/policies/policies-table.d.ts.map +1 -0
  230. package/dist/components/features/policies/policy-summary-cards.d.ts +17 -0
  231. package/dist/components/features/policies/policy-summary-cards.d.ts.map +1 -0
  232. package/dist/components/features/policies/policy-table-row.d.ts +37 -0
  233. package/dist/components/features/policies/policy-table-row.d.ts.map +1 -0
  234. package/dist/components/features/remote-session/index.d.ts +8 -0
  235. package/dist/components/features/remote-session/index.d.ts.map +1 -1
  236. package/dist/components/features/remote-session/remote-desktop-chat-message-row.d.ts +21 -0
  237. package/dist/components/features/remote-session/remote-desktop-chat-message-row.d.ts.map +1 -0
  238. package/dist/components/features/remote-session/remote-desktop-chat-panel.d.ts +31 -0
  239. package/dist/components/features/remote-session/remote-desktop-chat-panel.d.ts.map +1 -0
  240. package/dist/components/features/remote-session/remote-desktop-fullscreen-toolbar.d.ts +21 -0
  241. package/dist/components/features/remote-session/remote-desktop-fullscreen-toolbar.d.ts.map +1 -0
  242. package/dist/components/features/remote-session/remote-desktop-view.d.ts +50 -0
  243. package/dist/components/features/remote-session/remote-desktop-view.d.ts.map +1 -0
  244. package/dist/components/features/software/index.d.ts +8 -0
  245. package/dist/components/features/software/index.d.ts.map +1 -0
  246. package/dist/components/features/software/package-managers.d.ts +30 -0
  247. package/dist/components/features/software/package-managers.d.ts.map +1 -0
  248. package/dist/components/features/software/package-search-field-placeholder.d.ts +7 -0
  249. package/dist/components/features/software/package-search-field-placeholder.d.ts.map +1 -0
  250. package/dist/components/features/software/schedule-fields.d.ts +34 -0
  251. package/dist/components/features/software/schedule-fields.d.ts.map +1 -0
  252. package/dist/components/features/software/software-action-copy.d.ts +25 -0
  253. package/dist/components/features/software/software-action-copy.d.ts.map +1 -0
  254. package/dist/components/features/software/software-action-form.d.ts +71 -0
  255. package/dist/components/features/software/software-action-form.d.ts.map +1 -0
  256. package/dist/components/features/software/software-row-fields.d.ts +23 -0
  257. package/dist/components/features/software/software-row-fields.d.ts.map +1 -0
  258. package/dist/components/features/software/software-row.d.ts +18 -0
  259. package/dist/components/features/software/software-row.d.ts.map +1 -0
  260. package/dist/components/features/sortable-list/index.d.ts +1 -0
  261. package/dist/components/features/sortable-list/index.d.ts.map +1 -1
  262. package/dist/components/features/sortable-list/sortable-drag-handle.d.ts +21 -0
  263. package/dist/components/features/sortable-list/sortable-drag-handle.d.ts.map +1 -0
  264. package/dist/components/help-center-pages/index.cjs +133 -114
  265. package/dist/components/help-center-pages/index.js +58 -39
  266. package/dist/components/index.cjs +320 -82
  267. package/dist/components/index.js +451 -213
  268. package/dist/components/layout/page-heading.d.ts +12 -3
  269. package/dist/components/layout/page-heading.d.ts.map +1 -1
  270. package/dist/components/meeting-scheduler/index.cjs +120 -98
  271. package/dist/components/meeting-scheduler/index.js +50 -28
  272. package/dist/components/navigation/index.cjs +36 -17
  273. package/dist/components/navigation/index.d.ts +3 -0
  274. package/dist/components/navigation/index.d.ts.map +1 -1
  275. package/dist/components/navigation/index.js +36 -17
  276. package/dist/components/navigation/mingo-ai-button.d.ts +23 -10
  277. package/dist/components/navigation/mingo-ai-button.d.ts.map +1 -1
  278. package/dist/components/navigation/sticky-section-nav.d.ts +14 -1
  279. package/dist/components/navigation/sticky-section-nav.d.ts.map +1 -1
  280. package/dist/components/onboarding-guides/index.cjs +32 -16
  281. package/dist/components/onboarding-guides/index.js +31 -15
  282. package/dist/components/product-demo/cast.d.ts +58 -0
  283. package/dist/components/product-demo/cast.d.ts.map +1 -0
  284. package/dist/components/product-demo/fixtures/cloud-tenants.d.ts +10 -0
  285. package/dist/components/product-demo/fixtures/cloud-tenants.d.ts.map +1 -0
  286. package/dist/components/product-demo/fixtures/devices.d.ts +14 -0
  287. package/dist/components/product-demo/fixtures/devices.d.ts.map +1 -0
  288. package/dist/components/product-demo/fixtures/knowledge.d.ts +14 -0
  289. package/dist/components/product-demo/fixtures/knowledge.d.ts.map +1 -0
  290. package/dist/components/product-demo/fixtures/logs.d.ts +15 -0
  291. package/dist/components/product-demo/fixtures/logs.d.ts.map +1 -0
  292. package/dist/components/product-demo/fixtures/policies.d.ts +13 -0
  293. package/dist/components/product-demo/fixtures/policies.d.ts.map +1 -0
  294. package/dist/components/product-demo/fixtures/remote-session.d.ts +20 -0
  295. package/dist/components/product-demo/fixtures/remote-session.d.ts.map +1 -0
  296. package/dist/components/product-demo/fixtures/shared.d.ts +156 -0
  297. package/dist/components/product-demo/fixtures/shared.d.ts.map +1 -0
  298. package/dist/components/product-demo/fixtures/software-update.d.ts +19 -0
  299. package/dist/components/product-demo/fixtures/software-update.d.ts.map +1 -0
  300. package/dist/components/product-demo/fixtures/tickets-board.d.ts +8 -0
  301. package/dist/components/product-demo/fixtures/tickets-board.d.ts.map +1 -0
  302. package/dist/components/product-demo/index.cjs +112 -0
  303. package/dist/components/product-demo/index.d.ts +6 -0
  304. package/dist/components/product-demo/index.d.ts.map +1 -0
  305. package/dist/components/product-demo/index.js +112 -0
  306. package/dist/components/product-demo/product-screen.d.ts +22 -0
  307. package/dist/components/product-demo/product-screen.d.ts.map +1 -0
  308. package/dist/components/product-demo/registry.d.ts +13 -0
  309. package/dist/components/product-demo/registry.d.ts.map +1 -0
  310. package/dist/components/product-demo/screen-keys.cjs +25 -0
  311. package/dist/components/product-demo/screen-keys.d.ts +27 -0
  312. package/dist/components/product-demo/screen-keys.d.ts.map +1 -0
  313. package/dist/components/product-demo/screen-keys.js +20 -0
  314. package/dist/components/product-demo/screens/cloud-tenants.d.ts +8 -0
  315. package/dist/components/product-demo/screens/cloud-tenants.d.ts.map +1 -0
  316. package/dist/components/product-demo/screens/devices.d.ts +10 -0
  317. package/dist/components/product-demo/screens/devices.d.ts.map +1 -0
  318. package/dist/components/product-demo/screens/knowledge.d.ts +9 -0
  319. package/dist/components/product-demo/screens/knowledge.d.ts.map +1 -0
  320. package/dist/components/product-demo/screens/logs.d.ts +4 -0
  321. package/dist/components/product-demo/screens/logs.d.ts.map +1 -0
  322. package/dist/components/product-demo/screens/policies.d.ts +8 -0
  323. package/dist/components/product-demo/screens/policies.d.ts.map +1 -0
  324. package/dist/components/product-demo/screens/remote-desktop-picture.d.ts +11 -0
  325. package/dist/components/product-demo/screens/remote-desktop-picture.d.ts.map +1 -0
  326. package/dist/components/product-demo/screens/remote-session.d.ts +8 -0
  327. package/dist/components/product-demo/screens/remote-session.d.ts.map +1 -0
  328. package/dist/components/product-demo/screens/software-update.d.ts +12 -0
  329. package/dist/components/product-demo/screens/software-update.d.ts.map +1 -0
  330. package/dist/components/product-demo/screens/tickets-board.d.ts +4 -0
  331. package/dist/components/product-demo/screens/tickets-board.d.ts.map +1 -0
  332. package/dist/components/product-demo/types.d.ts +9 -0
  333. package/dist/components/product-demo/types.d.ts.map +1 -0
  334. package/dist/components/related-content/index.cjs +14 -8
  335. package/dist/components/related-content/index.js +13 -7
  336. package/dist/components/tickets/index.cjs +36 -20
  337. package/dist/components/tickets/index.js +35 -19
  338. package/dist/components/ui/file-manager/index.cjs +38 -34
  339. package/dist/components/ui/file-manager/index.js +8 -4
  340. package/dist/components/ui/index.cjs +57 -17
  341. package/dist/components/ui/index.d.ts +1 -0
  342. package/dist/components/ui/index.d.ts.map +1 -1
  343. package/dist/components/ui/index.js +141 -101
  344. package/dist/components/ui/product-screen-frame.d.ts +45 -0
  345. package/dist/components/ui/product-screen-frame.d.ts.map +1 -0
  346. package/dist/components/ui/radio-group.d.ts +5 -0
  347. package/dist/components/ui/radio-group.d.ts.map +1 -1
  348. package/dist/components/ui/snap-carousel.d.ts +11 -1
  349. package/dist/components/ui/snap-carousel.d.ts.map +1 -1
  350. package/dist/components/ui/tag.d.ts +1 -1
  351. package/dist/components/ui/tag.d.ts.map +1 -1
  352. package/dist/devices-LBMG42K6.js +81 -0
  353. package/dist/devices-YGYJIXQY.cjs +81 -0
  354. package/dist/hooks/index.cjs +17 -8
  355. package/dist/hooks/index.js +32 -23
  356. package/dist/hooks/ui/index.d.ts +1 -0
  357. package/dist/hooks/ui/index.d.ts.map +1 -1
  358. package/dist/hooks/ui/use-header-height.d.ts +12 -0
  359. package/dist/hooks/ui/use-header-height.d.ts.map +1 -1
  360. package/dist/hooks/ui/use-sticky-toolbar.d.ts +29 -0
  361. package/dist/hooks/ui/use-sticky-toolbar.d.ts.map +1 -0
  362. package/dist/hooks/use-location-hash.d.ts +2 -2
  363. package/dist/hooks/use-location-hash.d.ts.map +1 -1
  364. package/dist/hooks/use-scroll-to-hash.d.ts +7 -0
  365. package/dist/hooks/use-scroll-to-hash.d.ts.map +1 -1
  366. package/dist/index.cjs +276 -25
  367. package/dist/index.js +729 -478
  368. package/dist/knowledge-H5BIWJVI.js +108 -0
  369. package/dist/knowledge-KTCVJIWN.cjs +108 -0
  370. package/dist/logs-DB5Z7M5Q.js +216 -0
  371. package/dist/logs-RVCC2UQW.cjs +216 -0
  372. package/dist/policies-EWUULFBR.js +121 -0
  373. package/dist/policies-HV4IQCBV.cjs +121 -0
  374. package/dist/remote-session-GSGZOFDX.js +196 -0
  375. package/dist/remote-session-R6VAFESR.cjs +196 -0
  376. package/dist/software-update-6PXKRKBT.js +179 -0
  377. package/dist/software-update-D4OVSWSG.cjs +179 -0
  378. package/dist/tickets-board-BHLPAVNJ.cjs +137 -0
  379. package/dist/tickets-board-PYDNELSK.js +137 -0
  380. package/dist/types/case-study.d.ts +15 -1
  381. package/dist/types/case-study.d.ts.map +1 -1
  382. package/dist/utils/date-utils.d.ts +5 -0
  383. package/dist/utils/date-utils.d.ts.map +1 -1
  384. package/dist/utils/index.cjs +45 -2
  385. package/dist/utils/index.d.ts +2 -1
  386. package/dist/utils/index.d.ts.map +1 -1
  387. package/dist/utils/index.js +41 -3
  388. package/dist/utils/open-in-new-tab.d.ts +7 -0
  389. package/dist/utils/open-in-new-tab.d.ts.map +1 -0
  390. package/dist/utils/same-page-hash-nav.d.ts +31 -0
  391. package/dist/utils/same-page-hash-nav.d.ts.map +1 -1
  392. package/dist/utils/scroll-into-view.d.ts +14 -1
  393. package/dist/utils/scroll-into-view.d.ts.map +1 -1
  394. package/package.json +13 -1
  395. package/src/components/chat/ask-prompts.tsx +226 -0
  396. package/src/components/chat/embeddable-chat.tsx +36 -2
  397. package/src/components/chat/entity-cards/case-study-card.tsx +122 -46
  398. package/src/components/chat/index.ts +1 -0
  399. package/src/components/chat/quick-action-chip.tsx +33 -9
  400. package/src/components/docs/use-scroll-spy.ts +93 -18
  401. package/src/components/faq/faq-section.tsx +82 -43
  402. package/src/components/features/array-entry-manager.tsx +10 -1
  403. package/src/components/features/board/board.tsx +4 -1
  404. package/src/components/features/board/ticket-card.tsx +11 -1
  405. package/src/components/features/board/touch-board.tsx +2 -1
  406. package/src/components/features/board/types.ts +3 -0
  407. package/src/components/features/board/use-board-collapse.ts +7 -2
  408. package/src/components/features/capability-explorer.tsx +412 -0
  409. package/src/components/features/cloud-tenants/index.ts +28 -0
  410. package/src/components/features/cloud-tenants/tenant-access-cell.tsx +24 -0
  411. package/src/components/features/cloud-tenants/tenant-cell.tsx +26 -0
  412. package/src/components/features/cloud-tenants/tenant-customer-cell.tsx +27 -0
  413. package/src/components/features/cloud-tenants/tenant-presentation.ts +111 -0
  414. package/src/components/features/cloud-tenants/tenant-row.ts +21 -0
  415. package/src/components/features/cloud-tenants/tenants-table-columns.ts +30 -0
  416. package/src/components/features/cloud-tenants/tenants-table-view.tsx +142 -0
  417. package/src/components/features/devices/device-last-online.ts +6 -0
  418. package/src/components/features/devices/device-name.ts +51 -0
  419. package/src/components/features/devices/device-selector/device-selection-mode-radio.tsx +107 -0
  420. package/src/components/features/devices/device-selector/device-selector-skeleton.tsx +32 -0
  421. package/src/components/features/devices/device-selector/device-selector.tsx +799 -0
  422. package/src/components/features/devices/device-selector/device-selector.types.ts +138 -0
  423. package/src/components/features/devices/device-selector/narrowing.ts +33 -0
  424. package/src/components/features/devices/device-selector/use-device-selector.ts +51 -0
  425. package/src/components/features/devices/device-status.ts +102 -0
  426. package/src/components/features/devices/device-statuses.ts +88 -0
  427. package/src/components/features/devices/device-tags-filter-button.tsx +49 -0
  428. package/src/components/features/devices/device-type-icon.tsx +29 -0
  429. package/src/components/features/devices/device-type-tile.tsx +17 -0
  430. package/src/components/features/devices/devices-filter-toolbar.tsx +114 -0
  431. package/src/components/features/devices/devices-grid-filters.tsx +99 -0
  432. package/src/components/features/devices/devices-grid.tsx +86 -0
  433. package/src/components/features/devices/devices-list.tsx +357 -0
  434. package/src/components/features/devices/devices-panel-header.tsx +97 -0
  435. package/src/components/features/devices/devices-panel-view.tsx +261 -0
  436. package/src/components/features/devices/devices-table-columns.tsx +356 -0
  437. package/src/components/features/devices/devices-view-config.tsx +38 -0
  438. package/src/components/features/devices/index.ts +89 -0
  439. package/src/components/features/devices/types.ts +74 -0
  440. package/src/components/features/devices/use-tag-filter-modal.ts +109 -0
  441. package/src/components/features/index.ts +9 -0
  442. package/src/components/features/knowledge-base/index.ts +19 -0
  443. package/src/components/features/knowledge-base/knowledge-base-article-view.tsx +134 -0
  444. package/src/components/features/knowledge-base/knowledge-base-item-icon.ts +14 -0
  445. package/src/components/features/knowledge-base/knowledge-base-status.ts +12 -0
  446. package/src/components/features/knowledge-base/knowledge-base-table.tsx +180 -0
  447. package/src/components/features/logs/index.ts +20 -0
  448. package/src/components/features/logs/log-drawer.tsx +138 -0
  449. package/src/components/features/logs/log-source-labels.ts +25 -0
  450. package/src/components/features/logs/logs-page-view.tsx +100 -0
  451. package/src/components/features/logs/logs-table-columns.ts +16 -0
  452. package/src/components/features/logs/logs-table-view.tsx +509 -0
  453. package/src/components/features/logs/types.ts +71 -0
  454. package/src/components/features/policies/compute-policy-summary.ts +115 -0
  455. package/src/components/features/policies/index.ts +14 -0
  456. package/src/components/features/policies/policies-table.tsx +235 -0
  457. package/src/components/features/policies/policy-summary-cards.tsx +69 -0
  458. package/src/components/features/policies/policy-table-row.ts +37 -0
  459. package/src/components/features/remote-session/index.ts +8 -0
  460. package/src/components/features/remote-session/remote-desktop-chat-message-row.tsx +56 -0
  461. package/src/components/features/remote-session/remote-desktop-chat-panel.tsx +102 -0
  462. package/src/components/features/remote-session/remote-desktop-fullscreen-toolbar.tsx +119 -0
  463. package/src/components/features/remote-session/remote-desktop-view.tsx +209 -0
  464. package/src/components/features/software/index.ts +39 -0
  465. package/src/components/features/software/package-managers.ts +54 -0
  466. package/src/components/features/software/package-search-field-placeholder.tsx +23 -0
  467. package/src/components/features/software/schedule-fields.tsx +105 -0
  468. package/src/components/features/software/software-action-copy.ts +70 -0
  469. package/src/components/features/software/software-action-form.tsx +199 -0
  470. package/src/components/features/software/software-row-fields.tsx +105 -0
  471. package/src/components/features/software/software-row.ts +22 -0
  472. package/src/components/features/sortable-list/index.ts +1 -0
  473. package/src/components/features/sortable-list/sortable-drag-handle.tsx +41 -0
  474. package/src/components/layout/page-heading.tsx +23 -6
  475. package/src/components/navigation/index.ts +5 -0
  476. package/src/components/navigation/mingo-ai-button.tsx +37 -13
  477. package/src/components/navigation/sticky-section-nav.tsx +99 -1
  478. package/src/components/product-demo/cast.tsx +78 -0
  479. package/src/components/product-demo/fixtures/cloud-tenants.ts +63 -0
  480. package/src/components/product-demo/fixtures/devices.ts +87 -0
  481. package/src/components/product-demo/fixtures/knowledge.ts +48 -0
  482. package/src/components/product-demo/fixtures/logs.ts +103 -0
  483. package/src/components/product-demo/fixtures/policies.ts +77 -0
  484. package/src/components/product-demo/fixtures/remote-session.ts +65 -0
  485. package/src/components/product-demo/fixtures/shared.ts +53 -0
  486. package/src/components/product-demo/fixtures/software-update.ts +63 -0
  487. package/src/components/product-demo/fixtures/tickets-board.ts +100 -0
  488. package/src/components/product-demo/index.ts +7 -0
  489. package/src/components/product-demo/product-screen.tsx +94 -0
  490. package/src/components/product-demo/registry.ts +20 -0
  491. package/src/components/product-demo/screen-keys.ts +31 -0
  492. package/src/components/product-demo/screens/cloud-tenants.tsx +23 -0
  493. package/src/components/product-demo/screens/devices.tsx +41 -0
  494. package/src/components/product-demo/screens/knowledge.tsx +27 -0
  495. package/src/components/product-demo/screens/logs.tsx +113 -0
  496. package/src/components/product-demo/screens/policies.tsx +29 -0
  497. package/src/components/product-demo/screens/remote-desktop-picture.tsx +118 -0
  498. package/src/components/product-demo/screens/remote-session.tsx +46 -0
  499. package/src/components/product-demo/screens/software-update.tsx +97 -0
  500. package/src/components/product-demo/screens/tickets-board.tsx +28 -0
  501. package/src/components/product-demo/types.ts +10 -0
  502. package/src/components/ui/index.ts +1 -0
  503. package/src/components/ui/product-screen-frame.tsx +136 -0
  504. package/src/components/ui/radio-group.tsx +16 -4
  505. package/src/components/ui/snap-carousel.tsx +26 -1
  506. package/src/components/ui/tag.tsx +5 -0
  507. package/src/hooks/ui/index.ts +1 -0
  508. package/src/hooks/ui/use-header-height.ts +51 -2
  509. package/src/hooks/ui/use-sticky-toolbar.ts +60 -0
  510. package/src/hooks/use-location-hash.ts +9 -5
  511. package/src/hooks/use-scroll-to-hash.ts +9 -1
  512. package/src/types/case-study.ts +21 -1
  513. package/src/utils/date-utils.ts +8 -1
  514. package/src/utils/index.ts +5 -0
  515. package/src/utils/open-in-new-tab.ts +12 -0
  516. package/src/utils/same-page-hash-nav.ts +57 -0
  517. package/src/utils/scroll-into-view.ts +21 -5
  518. package/dist/chunk-BM5MVGH3.cjs +0 -499
  519. package/dist/chunk-CUME3VTQ.js +0 -144
  520. package/dist/chunk-CZ7Y7UG4.js +0 -732
  521. package/dist/chunk-FLKJYMVB.js +0 -499
  522. package/dist/chunk-OF6GEI5A.cjs +0 -144
  523. package/dist/chunk-UVTD52MD.cjs +0 -732
@@ -0,0 +1,261 @@
1
+ 'use client';
2
+
3
+ import type { ReactNode, RefObject } from 'react';
4
+ import { cn } from '../../../utils/cn';
5
+ import { AlertTriangleIcon } from '../../icons-v2-generated';
6
+ import {
7
+ Alert,
8
+ type ColumnDef,
9
+ type ColumnFiltersState,
10
+ DataTable,
11
+ type OnChangeFn,
12
+ type PageActionButton,
13
+ PageLayout,
14
+ TabSelector,
15
+ } from '../../ui';
16
+ import { DevicesFilterToolbar, type DevicesFilterToolbarProps } from './devices-filter-toolbar';
17
+ import { DevicesGrid } from './devices-grid';
18
+ import { DevicesGridFilters } from './devices-grid-filters';
19
+ import { DEVICE_VIEW_MODE_ITEMS } from './devices-panel-header';
20
+ import { DevicesTableBody, type DeviceFilterColumn, getDeviceFilterColumns } from './devices-table-columns';
21
+ import type { DeviceFilters, DeviceRow } from './types';
22
+
23
+ export type DevicesViewMode = 'table' | 'grid';
24
+
25
+ const NO_FILTERS: Record<string, string[]> = {};
26
+ const NO_TAGS: never[] = [];
27
+ const NO_FILTER_GROUPS: never[] = [];
28
+ const noop = () => {};
29
+
30
+ /** A toolbar with nothing in it and nothing wired: what a loading panel and a picture draw. */
31
+ export const IDLE_DEVICES_TOOLBAR: DevicesFilterToolbarProps = {
32
+ searchValue: '',
33
+ onSearchChange: noop,
34
+ tags: NO_TAGS,
35
+ onTagRemove: noop,
36
+ onClearAll: noop,
37
+ onSubmit: noop,
38
+ onOpenFilterModal: noop,
39
+ isFilterModalOpen: false,
40
+ onCloseFilterModal: noop,
41
+ filterGroups: NO_FILTER_GROUPS,
42
+ onFilterChange: noop,
43
+ tagFilterKeys: NO_TAGS,
44
+ selectedTags: NO_TAGS,
45
+ onTagsChange: noop,
46
+ };
47
+
48
+ export interface DevicesPanelViewProps<T extends DeviceRow = DeviceRow> {
49
+ /** Page title shown in the PageLayout header. */
50
+ title?: string;
51
+ /** Back button rendered above the title (e.g. on the archive page). */
52
+ backButton?: { label?: string; onClick: () => void };
53
+ /** The PageLayout wrapper's className, already resolved by the caller. */
54
+ className?: string;
55
+ /**
56
+ * Drawn in place of the panel's own header (title, view switch, actions),
57
+ * for a host that brings its own, such as a page hero.
58
+ */
59
+ headerSlot?: ReactNode;
60
+
61
+ viewMode: DevicesViewMode;
62
+ onViewModeChange?: (mode: DevicesViewMode) => void;
63
+ /** Header buttons: see `buildDevicePanelActions`. */
64
+ actions?: PageActionButton[];
65
+
66
+ /** The rows to draw, already narrowed. The view never fetches and never filters. */
67
+ devices: T[];
68
+ /**
69
+ * The request has not answered: the header, the view switch and the toolbar
70
+ * are the real ones, locked, and only the rows are skeletons.
71
+ */
72
+ loading?: boolean;
73
+ /** The rows on screen answer the previous narrowing while the next loads: dimmed, not replaced. */
74
+ isNarrowing?: boolean;
75
+ /** Server-side total for the current narrowing. */
76
+ totalCount?: number;
77
+
78
+ /** Facets behind the column funnels and the grid's filter row, from the server. */
79
+ deviceFilters?: DeviceFilters | null;
80
+ /** The filter columns the grid row offers. Defaults to every column of `deviceFilters` not in `hideFilters`. */
81
+ filterColumns?: DeviceFilterColumn[];
82
+ /** Search box, tag chips and the tags modal. Omit for an idle toolbar. */
83
+ toolbar?: DevicesFilterToolbarProps;
84
+ /** The table's column funnels. */
85
+ columnFilters?: ColumnFiltersState;
86
+ onColumnFiltersChange?: OnChangeFn<ColumnFiltersState>;
87
+ /** The grid filter row's selection, keyed by column id, and its writer. */
88
+ gridFilters?: Record<string, string[]>;
89
+ onGridFiltersChange?: (filters: Record<string, string[]>) => void;
90
+
91
+ /** The row-actions column: see `getDeviceActionsColumn`. */
92
+ actionsColumn?: ColumnDef<T>;
93
+ /** Column ids to drop from the table (e.g. 'organization' when scoped to one customer). */
94
+ hideColumns?: string[];
95
+ /** Filter keys to drop from the funnels and the grid row; the column itself stays. */
96
+ hideFilters?: string[];
97
+ /** Message shown when the list is empty. */
98
+ emptyMessage?: string;
99
+ /** Drawn instead of the toolbar and the list: the pristine, genuinely empty panel. */
100
+ emptyState?: ReactNode;
101
+ /** The tenant has no customers yet: a banner says a device needs one. */
102
+ noOrganizations?: boolean;
103
+
104
+ hasNextPage?: boolean;
105
+ isFetchingNextPage?: boolean;
106
+ onLoadMore?: () => void;
107
+ /** The grid's infinite-scroll sentinel. */
108
+ gridSentinelRef?: RefObject<HTMLDivElement | null>;
109
+ }
110
+
111
+ /**
112
+ * The device list as a page: header with the table / grid switch and the
113
+ * actions, the search and tag toolbar, and the rows as a table or as cards.
114
+ *
115
+ * Everything it shows is a prop. The product's container owns the queries and
116
+ * the URL state and maps them here; a fixture passes plain rows. Its loading
117
+ * state is the same component with `loading`: the chrome is the real one,
118
+ * locked, so the page does not move when the rows land.
119
+ */
120
+ export function DevicesPanelView<T extends DeviceRow = DeviceRow>({
121
+ title = 'Devices',
122
+ backButton,
123
+ className = '',
124
+ headerSlot,
125
+ viewMode,
126
+ onViewModeChange,
127
+ actions,
128
+ devices,
129
+ loading = false,
130
+ isNarrowing = false,
131
+ totalCount,
132
+ deviceFilters = null,
133
+ filterColumns,
134
+ toolbar = IDLE_DEVICES_TOOLBAR,
135
+ columnFilters,
136
+ onColumnFiltersChange,
137
+ gridFilters = NO_FILTERS,
138
+ onGridFiltersChange = noop,
139
+ actionsColumn,
140
+ hideColumns,
141
+ hideFilters,
142
+ emptyMessage = 'No devices found. Try adjusting your search or filters.',
143
+ emptyState,
144
+ noOrganizations = false,
145
+ hasNextPage = false,
146
+ isFetchingNextPage = false,
147
+ onLoadMore = noop,
148
+ gridSentinelRef,
149
+ }: DevicesPanelViewProps<T>) {
150
+ const gridColumns =
151
+ filterColumns ?? getDeviceFilterColumns(deviceFilters).filter(column => !hideFilters?.includes(column.key));
152
+
153
+ const list = (
154
+ <>
155
+ <DevicesFilterToolbar {...toolbar} isLoading={loading} />
156
+ {viewMode === 'table' ? (
157
+ <DevicesTableBody
158
+ devices={devices}
159
+ isLoading={loading}
160
+ emptyMessage={loading ? '' : emptyMessage}
161
+ skeletonRows={10}
162
+ stickyHeaderOffset="top-[96px]"
163
+ deviceFilters={deviceFilters}
164
+ // Loading: the facets have not answered, which is not "this list has
165
+ // no facets". Without it the empty options read as final and each
166
+ // column's funnel is hidden, so the header grew them when the query
167
+ // landed. Loaded: the facets arrive with the rows, nothing is pending.
168
+ filtersPending={loading || undefined}
169
+ columnFilters={columnFilters}
170
+ onColumnFiltersChange={onColumnFiltersChange}
171
+ actionsColumn={actionsColumn}
172
+ hideColumns={hideColumns}
173
+ disableColumnFilters={hideFilters}
174
+ totalCount={loading ? undefined : totalCount}
175
+ footerSlot={
176
+ loading ? undefined : (
177
+ <DataTable.InfiniteFooter
178
+ hasNextPage={hasNextPage}
179
+ isFetchingNextPage={isFetchingNextPage}
180
+ onLoadMore={onLoadMore}
181
+ skeletonRows={2}
182
+ />
183
+ )
184
+ }
185
+ />
186
+ ) : (
187
+ <>
188
+ {/* Loading: the labels are static, so the row holds its height; the
189
+ count is the query's answer and its tail is absolutely positioned,
190
+ so leaving it out moves nothing. */}
191
+ <DevicesGridFilters
192
+ filterColumns={gridColumns}
193
+ currentFilters={gridFilters}
194
+ onFilterChange={onGridFiltersChange}
195
+ totalCount={loading ? undefined : totalCount}
196
+ isLoading={loading}
197
+ />
198
+ <DevicesGrid
199
+ devices={devices}
200
+ isLoading={loading}
201
+ hasNextPage={hasNextPage}
202
+ isFetchingNextPage={isFetchingNextPage}
203
+ sentinelRef={gridSentinelRef}
204
+ emptyMessage={loading ? '' : emptyMessage}
205
+ />
206
+ </>
207
+ )}
208
+ </>
209
+ );
210
+
211
+ return (
212
+ <PageLayout
213
+ title={title}
214
+ backButton={backButton}
215
+ showHeader={!headerSlot}
216
+ actionsVariant="icon-buttons"
217
+ className={className}
218
+ selector={
219
+ <TabSelector
220
+ value={viewMode}
221
+ onValueChange={value => onViewModeChange?.(value as DevicesViewMode)}
222
+ items={DEVICE_VIEW_MODE_ITEMS}
223
+ disabled={loading}
224
+ />
225
+ }
226
+ actions={actions}
227
+ contentClassName="flex flex-col"
228
+ >
229
+ {headerSlot}
230
+ {loading && (
231
+ <span role="status" className="sr-only">
232
+ Loading devices…
233
+ </span>
234
+ )}
235
+ {noOrganizations && !loading && (
236
+ // Core Alert restyled to the ODS warning tokens. The icon is wrapped in a
237
+ // span so Alert's `[&>svg]` absolute-positioning rules don't apply.
238
+ <Alert className="mb-[var(--spacing-system-l)] flex items-start gap-[var(--spacing-system-m)] rounded-[6px] border-0 bg-ods-warning-secondary text-ods-warning">
239
+ <span className="shrink-0">
240
+ <AlertTriangleIcon className="h-6 w-6" />
241
+ </span>
242
+ <p className="text-h3">Add a customer to connect a new device</p>
243
+ </Alert>
244
+ )}
245
+ {emptyState && !loading ? (
246
+ emptyState
247
+ ) : loading ? (
248
+ // `inert` rather than per-control `disabled`: the toolbar's search field
249
+ // and tag chips have no disabled state of their own, and a focusable
250
+ // input that silently drops what is typed into it is worse than one
251
+ // that cannot be reached at all.
252
+ <div inert>{list}</div>
253
+ ) : (
254
+ // Dimmed, not skeletoned, while a filter or search change resolves: the
255
+ // rows on screen are the previous answer and stay readable until the
256
+ // next one arrives.
257
+ <div className={cn(isNarrowing && 'opacity-60 transition-opacity')}>{list}</div>
258
+ )}
259
+ </PageLayout>
260
+ );
261
+ }
@@ -0,0 +1,356 @@
1
+ 'use client';
2
+
3
+ import type React from 'react';
4
+ import { type MouseEvent, type ReactNode, useMemo } from 'react';
5
+ import { formatDate, formatTime } from '../../../utils/format-date';
6
+ import { ArrowRightUpIcon } from '../../icons-v2-generated';
7
+ import {
8
+ Button,
9
+ type ColumnDef,
10
+ type ColumnFiltersState,
11
+ DataTable,
12
+ EntityImage,
13
+ type NoDataProps,
14
+ type OnChangeFn,
15
+ type Row,
16
+ Tag,
17
+ TruncateText,
18
+ useDataTable,
19
+ } from '../../ui';
20
+ import { OSTypeBadge } from '../os-type-badge';
21
+ import { getDeviceName } from './device-name';
22
+ import { getDeviceStatusConfig } from './device-status';
23
+ import { DEFAULT_VISIBLE_STATUSES } from './device-statuses';
24
+ import { DeviceTypeTile } from './device-type-tile';
25
+ import { useDeviceImageUrl, useDevicesViewConfig } from './devices-view-config';
26
+ import type { DeviceFilters, DeviceRow } from './types';
27
+
28
+ /** Date then time in the viewer's locale; the empty mark for an instant that does not parse. */
29
+ function formatDateTime(input: string): string {
30
+ const date = formatDate(input);
31
+ return date === '—' ? date : `${date} ${formatTime(input)}`;
32
+ }
33
+
34
+ /** Filter options by id, first one wins: the backend can repeat a customer. */
35
+ function uniqueById<T extends { id: string }>(options: T[]): T[] {
36
+ const seen = new Map<string, T>();
37
+ for (const option of options) {
38
+ if (!seen.has(option.id)) seen.set(option.id, option);
39
+ }
40
+ return Array.from(seen.values());
41
+ }
42
+
43
+ /**
44
+ * The row-actions column, declared here beside every other device column so the
45
+ * loaded table and its loading state can't disagree about the column set.
46
+ *
47
+ * `renderRowActions` is optional because a loading table has no rows to act on
48
+ *, omit it and the column keeps its width and alignment while drawing nothing,
49
+ * which is exactly what the skeleton needs. Leaving the column out instead
50
+ * shifted every other column, since it takes real width from them.
51
+ */
52
+ export function getDeviceActionsColumn<T extends DeviceRow = DeviceRow>(
53
+ renderRowActions?: (device: T) => React.ReactNode,
54
+ ): ColumnDef<T> {
55
+ return {
56
+ id: 'actions',
57
+ cell: renderRowActions
58
+ ? ({ row }: { row: Row<T> }) => (
59
+ <div data-no-row-click className="pointer-events-auto flex items-center justify-end gap-2">
60
+ {renderRowActions(row.original)}
61
+ </div>
62
+ )
63
+ : () => null,
64
+ enableSorting: false,
65
+ meta: { width: 'w-12 shrink-0 flex-none', align: 'right' },
66
+ };
67
+ }
68
+
69
+ /** Opens the device's page in a new tab. A button, because the row is itself a link and a link cannot hold a link. */
70
+ function OpenDeviceButton({ device }: { device: DeviceRow }) {
71
+ const { getDeviceHref } = useDevicesViewConfig();
72
+ const href = getDeviceHref?.(device);
73
+ const open = (event: MouseEvent) => {
74
+ event.preventDefault();
75
+ if (href) window.open(href, '_blank', 'noopener,noreferrer');
76
+ };
77
+ return (
78
+ <div data-no-row-click className="pointer-events-auto flex items-center justify-end">
79
+ <Button
80
+ onClick={open}
81
+ variant="outline"
82
+ size="icon"
83
+ leftIcon={<ArrowRightUpIcon className="h-5 w-5" />}
84
+ aria-label="Open in new tab"
85
+ className="bg-ods-card"
86
+ />
87
+ </div>
88
+ );
89
+ }
90
+
91
+ export function getDeviceOpenColumn<T extends DeviceRow = DeviceRow>(): ColumnDef<T> {
92
+ return {
93
+ id: 'open',
94
+ cell: ({ row }: { row: Row<T> }) => <OpenDeviceButton device={row.original} />,
95
+ enableSorting: false,
96
+ meta: { width: 'w-12 shrink-0 flex-none', hideAt: 'md', align: 'right' },
97
+ };
98
+ }
99
+
100
+ export interface DevicesTableBodyProps<T extends DeviceRow = DeviceRow> {
101
+ devices: T[];
102
+ isLoading?: boolean;
103
+ /**
104
+ * The empty state, as the design's `data-placeholder`: icon over a title over
105
+ * a description. Wins over `emptyMessage` when both are given.
106
+ */
107
+ emptyState?: NoDataProps;
108
+ /** @deprecated Single-line variant of {@link emptyState}, pass `emptyState` instead. */
109
+ emptyMessage?: string;
110
+ skeletonRows?: number;
111
+ stickyHeaderOffset?: string;
112
+ footerSlot?: ReactNode;
113
+ deviceFilters?: DeviceFilters | null;
114
+ columnFilters?: ColumnFiltersState;
115
+ onColumnFiltersChange?: OnChangeFn<ColumnFiltersState>;
116
+ /** Optional extra column inserted before the open-in-new-tab column (e.g. row actions on the dedicated page). */
117
+ actionsColumn?: ColumnDef<T>;
118
+ /** Column ids to drop from the base table columns (e.g. ['organization'] when scoped to a single org). */
119
+ hideColumns?: string[];
120
+ /** Column ids whose header filter is dropped while the column stays visible (e.g. ['status'] on the archive page). */
121
+ disableColumnFilters?: string[];
122
+ /** The facet query is still in flight, see `getDeviceTableColumns`. */
123
+ filtersPending?: boolean;
124
+ /** Server-side total (for paginated lists). Falls back to loaded-row count when omitted. */
125
+ totalCount?: number;
126
+ /**
127
+ * Render the column header. Default true.
128
+ *
129
+ * Pass `false` to drop it over a genuinely empty list, column labels above
130
+ * nothing are noise, and the empty message reads better without a row of
131
+ * headings it does not explain. Keep it `true` while loading (the skeleton
132
+ * rows are the content it belongs to) and whenever the emptiness is the RESULT
133
+ * of narrowing: the column funnels live in this header, so removing it would
134
+ * strip the only way to undo the filter that emptied the table.
135
+ */
136
+ showHeader?: boolean;
137
+ }
138
+
139
+ export function DevicesTableBody<T extends DeviceRow = DeviceRow>({
140
+ devices,
141
+ isLoading,
142
+ emptyState,
143
+ emptyMessage = 'No devices found.',
144
+ skeletonRows = 10,
145
+ stickyHeaderOffset,
146
+ footerSlot,
147
+ deviceFilters,
148
+ columnFilters,
149
+ onColumnFiltersChange,
150
+ actionsColumn,
151
+ hideColumns,
152
+ disableColumnFilters,
153
+ filtersPending,
154
+ totalCount,
155
+ showHeader = true,
156
+ }: DevicesTableBodyProps<T>) {
157
+ const { getDeviceHref } = useDevicesViewConfig();
158
+ const columns = useMemo<ColumnDef<T>[]>(() => {
159
+ const hidden = new Set(hideColumns ?? []);
160
+ const unfiltered = new Set(disableColumnFilters ?? []);
161
+ const base = getDeviceTableColumns<T>(deviceFilters ?? null, filtersPending)
162
+ .filter(c => !c.id || !hidden.has(c.id))
163
+ .map(c => (c.id && unfiltered.has(c.id) ? { ...c, meta: { ...c.meta, filter: undefined } } : c));
164
+ const open = getDeviceOpenColumn<T>();
165
+ return actionsColumn ? [...base, actionsColumn, open] : [...base, open];
166
+ }, [deviceFilters, filtersPending, actionsColumn, hideColumns, disableColumnFilters]);
167
+
168
+ const table = useDataTable<T>({
169
+ data: devices,
170
+ columns,
171
+ // `machineId` is EMPTY (not absent) while the agent is not connected: those rows key on their id.
172
+ getRowId: row => String(row.machineId || row.id),
173
+ enableSorting: false,
174
+ state: columnFilters !== undefined ? { columnFilters } : undefined,
175
+ onColumnFiltersChange,
176
+ });
177
+
178
+ return (
179
+ <DataTable table={table}>
180
+ {showHeader && (
181
+ <DataTable.Header
182
+ stickyHeader={!!stickyHeaderOffset}
183
+ stickyHeaderOffset={stickyHeaderOffset}
184
+ rightSlot={<DataTable.RowCount itemName="device" totalCount={totalCount} />}
185
+ />
186
+ )}
187
+ <DataTable.Body
188
+ loading={isLoading}
189
+ skeletonRows={skeletonRows}
190
+ emptyState={emptyState}
191
+ emptyMessage={emptyState ? undefined : emptyMessage}
192
+ rowClassName="mb-1"
193
+ rowHref={getDeviceHref}
194
+ />
195
+ {footerSlot}
196
+ </DataTable>
197
+ );
198
+ }
199
+
200
+ function OrganizationCell({ device }: { device: DeviceRow }) {
201
+ const fullImageUrl = useDeviceImageUrl(device.organizationImageUrl, device.organizationImageHash);
202
+
203
+ return (
204
+ <div className="flex items-center gap-3">
205
+ <EntityImage src={fullImageUrl} alt={device.organization || 'Customer'} className="size-12 content-md:size-12" />
206
+ <div className="flex min-w-0 flex-1 flex-col justify-center">
207
+ <span className="break-words text-ods-text-primary text-h4">{device.organization || ''}</span>
208
+ </div>
209
+ </div>
210
+ );
211
+ }
212
+
213
+ export interface DeviceFilterColumn {
214
+ key: string;
215
+ label: string;
216
+ filterable?: boolean;
217
+ filterOptions?: DeviceFilterOption[];
218
+ }
219
+
220
+ /** A device filter dropdown entry: `meta.filter.options` plus the facet count. */
221
+ export interface DeviceFilterOption {
222
+ id: string;
223
+ label: string;
224
+ value: string;
225
+ count?: number;
226
+ }
227
+
228
+ /** Status / OS / customer options, shared by the table headers and the grid row. */
229
+ function buildDeviceFilterOptions(deviceFilters?: DeviceFilters | null): {
230
+ status: DeviceFilterOption[];
231
+ os: DeviceFilterOption[];
232
+ organization: DeviceFilterOption[];
233
+ } {
234
+ // Show only DEFAULT_VISIBLE_STATUSES (DELETED and legacy ARCHIVED live on /devices/archive)
235
+ const status = (deviceFilters?.statuses ?? [])
236
+ .filter(s => (DEFAULT_VISIBLE_STATUSES as readonly string[]).includes(s.value))
237
+ .map(s => ({ id: s.value, label: getDeviceStatusConfig(s.value).label, value: s.value, count: s.count }));
238
+
239
+ const os = (deviceFilters?.osTypes ?? []).map(o => ({ id: o.value, label: o.value, value: o.value, count: o.count }));
240
+
241
+ const organization = uniqueById(
242
+ (deviceFilters?.organizationIds ?? []).map(org => ({
243
+ id: org.value,
244
+ label: org.label,
245
+ value: org.value,
246
+ count: org.count,
247
+ })),
248
+ );
249
+
250
+ return { status, os, organization };
251
+ }
252
+
253
+ // Filter column metadata used by the external filter modal (useTagFilterModal).
254
+ // Kept separate from the table ColumnDef because DataTable doesn't carry the
255
+ // filter metadata that the external mobile filter modal needs.
256
+ export function getDeviceFilterColumns(deviceFilters?: DeviceFilters | null): DeviceFilterColumn[] {
257
+ const options = buildDeviceFilterOptions(deviceFilters);
258
+ return [
259
+ {
260
+ key: 'device',
261
+ label: 'DEVICE',
262
+ },
263
+ { key: 'status', label: 'STATUS', filterable: true, filterOptions: options.status },
264
+ { key: 'os', label: 'OS', filterable: true, filterOptions: options.os },
265
+ { key: 'organization', label: 'CUSTOMER', filterable: true, filterOptions: options.organization },
266
+ ];
267
+ }
268
+
269
+ /**
270
+ * @param filtersPending The `deviceFilters` query is in flight, keeps the
271
+ * funnels drawn (inert) rather than growing them when it answers. Absent means
272
+ * these are the final options: an empty one then hides its funnel, which is what
273
+ * a list with no facet source of its own wants.
274
+ */
275
+ export function getDeviceTableColumns<T extends DeviceRow = DeviceRow>(
276
+ deviceFilters?: DeviceFilters | null,
277
+ filtersPending?: boolean,
278
+ ): ColumnDef<T>[] {
279
+ const {
280
+ status: statusFilterOptions,
281
+ os: osFilterOptions,
282
+ organization: orgFilterOptions,
283
+ } = buildDeviceFilterOptions(deviceFilters);
284
+
285
+ return [
286
+ {
287
+ accessorKey: 'device',
288
+ id: 'device',
289
+ header: 'DEVICE',
290
+ cell: ({ row }: { row: Row<T> }) => {
291
+ const device = row.original;
292
+ return (
293
+ <div className="relative box-border flex h-20 w-full shrink-0 content-stretch items-center justify-start gap-4 py-0">
294
+ <DeviceTypeTile type={device.type} />
295
+ <div className="min-w-0 flex-1">
296
+ <TruncateText>{getDeviceName(device)}</TruncateText>
297
+ </div>
298
+ </div>
299
+ );
300
+ },
301
+ meta: { width: 'flex-1 content-md:w-1/4' },
302
+ },
303
+ {
304
+ accessorKey: 'status',
305
+ id: 'status',
306
+ header: 'STATUS',
307
+ cell: ({ row }: { row: Row<T> }) => {
308
+ const device = row.original;
309
+ const statusConfig = getDeviceStatusConfig(device.status);
310
+ return (
311
+ <div className="flex shrink-0 flex-col items-start gap-1">
312
+ <div className="inline-flex">
313
+ <Tag label={statusConfig.label} variant={statusConfig.variant} />
314
+ </div>
315
+ <span className="hidden text-ods-text-secondary text-h6 content-md:flex">
316
+ {device.last_seen ? formatDateTime(device.last_seen) : 'Never'}
317
+ </span>
318
+ </div>
319
+ );
320
+ },
321
+ meta: {
322
+ width: 'w-auto shrink-0 content-md:w-1/5',
323
+ // Declared unconditionally, empty options and all. `meta.filter` is what
324
+ // keeps a header cell visible below `lg`, so dropping it until the
325
+ // options query resolves made every header on a tablet disappear on
326
+ // reload, and reserving the funnel from the start keeps the label from
327
+ // shifting when they arrive. The dropdown stays shut while it is empty.
328
+ filter: { options: statusFilterOptions, pending: filtersPending },
329
+ },
330
+ },
331
+ {
332
+ accessorKey: 'os',
333
+ id: 'os',
334
+ header: 'OS',
335
+ cell: ({ row }: { row: Row<T> }) => (
336
+ <OSTypeBadge osType={row.original.osType} iconSize="w-4 h-4 content-md:w-6 content-md:h-6" />
337
+ ),
338
+ meta: {
339
+ width: 'w-[200px] content-md:w-1/6',
340
+ hideAt: 'md',
341
+ filter: { options: osFilterOptions, pending: filtersPending },
342
+ },
343
+ },
344
+ {
345
+ accessorKey: 'organization',
346
+ id: 'organization',
347
+ header: 'CUSTOMER',
348
+ cell: ({ row }: { row: Row<T> }) => <OrganizationCell device={row.original} />,
349
+ meta: {
350
+ width: 'w-1/6',
351
+ hideAt: 'lg',
352
+ filter: { options: orgFilterOptions, placement: 'bottom-end', pending: filtersPending },
353
+ },
354
+ },
355
+ ];
356
+ }
@@ -0,0 +1,38 @@
1
+ 'use client';
2
+
3
+ import { createContext, type ReactNode, useContext } from 'react';
4
+ import type { DeviceRow } from './types';
5
+
6
+ /**
7
+ * What the device views cannot know by themselves, because it belongs to the
8
+ * host: where a device's page lives, where images are served from, and whether
9
+ * the page runs inside the mobile shell. The product provides it once, above
10
+ * every page; without a provider the views render as a picture (no links,
11
+ * image URLs used as given).
12
+ */
13
+ export interface DevicesViewConfig {
14
+ /** The device's page. Absent: rows and cards are not links. */
15
+ getDeviceHref?: (device: DeviceRow) => string | undefined;
16
+ /** A customer image's full URL from its stored path and content hash. */
17
+ resolveImageUrl?: (imageUrl: string | null | undefined, hash?: string | null) => string | undefined;
18
+ /** The page runs inside the mobile shell: options nobody can pick there are dropped. */
19
+ isMobileShell?: boolean;
20
+ }
21
+
22
+ const EMPTY_CONFIG: DevicesViewConfig = {};
23
+
24
+ const DevicesViewConfigContext = createContext<DevicesViewConfig>(EMPTY_CONFIG);
25
+
26
+ export function DevicesViewConfigProvider({ value, children }: { value: DevicesViewConfig; children: ReactNode }) {
27
+ return <DevicesViewConfigContext.Provider value={value}>{children}</DevicesViewConfigContext.Provider>;
28
+ }
29
+
30
+ export function useDevicesViewConfig(): DevicesViewConfig {
31
+ return useContext(DevicesViewConfigContext);
32
+ }
33
+
34
+ /** A customer image's URL as the host resolves it; the stored value when no host says otherwise. */
35
+ export function useDeviceImageUrl(imageUrl: string | null | undefined, hash?: string | null): string | undefined {
36
+ const { resolveImageUrl } = useDevicesViewConfig();
37
+ return resolveImageUrl ? resolveImageUrl(imageUrl, hash) : (imageUrl ?? undefined);
38
+ }