@flamingo-stack/openframe-frontend-core 0.0.710 → 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.
- package/dist/chunk-2NASBO7O.js +1137 -0
- package/dist/{chunk-RQRX4YC3.cjs → chunk-2RKFMUNW.cjs} +46 -46
- package/dist/chunk-2Y7QZAB2.cjs +158 -0
- package/dist/chunk-34I6XI3N.js +136 -0
- package/dist/chunk-3K5ZLZE7.js +292 -0
- package/dist/chunk-3LU4UFPS.cjs +14 -0
- package/dist/{chunk-YBUT4AMG.cjs → chunk-3RKBJT6K.cjs} +8 -6
- package/dist/{chunk-LNW45N2C.js → chunk-3SEEGNRE.js} +35 -27
- package/dist/{chunk-L6Y6OOKG.cjs → chunk-3UAJLO5U.cjs} +41 -39
- package/dist/chunk-4HJRHEXD.cjs +1612 -0
- package/dist/{chunk-JPG7OHEG.js → chunk-4QFWGLZO.js} +1 -1
- package/dist/chunk-4R2L3DSA.js +14 -0
- package/dist/{chunk-36BCTE7D.js → chunk-4UYKNOZG.js} +12 -10
- package/dist/{chunk-DA5UDTLG.js → chunk-5SDELRH3.js} +5 -5
- package/dist/{chunk-CZSZSDD4.js → chunk-5Y72YQEK.js} +22 -113
- package/dist/{chunk-KUC673HM.js → chunk-6T3BTD6Q.js} +204 -982
- package/dist/{chunk-F57ECE2I.js → chunk-6YPTUHM7.js} +4 -4
- package/dist/{chunk-TDYIREDJ.js → chunk-7HNYYNKE.js} +28 -22
- package/dist/{chunk-2G7UYK35.cjs → chunk-7NSU5EQD.cjs} +57 -148
- package/dist/chunk-AAYNCJMW.cjs +48 -0
- package/dist/{chunk-FXJ3WWUB.js → chunk-ADBE7QF3.js} +5 -252
- package/dist/chunk-AECTRMGQ.cjs +334 -0
- package/dist/chunk-AGVXKD4K.js +334 -0
- package/dist/chunk-AL2GUHAJ.cjs +18 -0
- package/dist/{chunk-WMX26HB5.js → chunk-APJZBDQN.js} +12 -12
- package/dist/chunk-AUMKE74M.cjs +16 -0
- package/dist/chunk-B4NCVYEQ.cjs +292 -0
- package/dist/{chunk-2RNB5DTN.cjs → chunk-BXSRTBLU.cjs} +82 -54
- package/dist/chunk-CMGFZHCN.js +233 -0
- package/dist/chunk-CMZ3QTFQ.js +1207 -0
- package/dist/chunk-CPA2CKRZ.cjs +125 -0
- package/dist/{chunk-B73373AG.cjs → chunk-CSCJU6YC.cjs} +35 -33
- package/dist/chunk-CYUUHFXL.js +41 -0
- package/dist/chunk-DC4RTYWK.cjs +1122 -0
- package/dist/{chunk-6YKAT7NV.js → chunk-DDWFCWOE.js} +5 -7
- package/dist/{chunk-F5FF4DME.js → chunk-EFNKS5W4.js} +322 -428
- package/dist/{chunk-2KXTOP6G.cjs → chunk-EOKSKJSS.cjs} +25 -83
- package/dist/{chunk-6NTPY5QA.cjs → chunk-ETYLOZOB.cjs} +978 -2413
- package/dist/chunk-F5BPGWGT.cjs +931 -0
- package/dist/{chunk-4L6XCMOU.js → chunk-FCAVAEHF.js} +8277 -9990
- package/dist/chunk-FFT56TYB.cjs +401 -0
- package/dist/chunk-FYEJTF5Y.js +125 -0
- package/dist/chunk-G3GRYDMS.js +16 -0
- package/dist/{chunk-MR3A4MZV.js → chunk-G3OMVCID.js} +13 -7
- package/dist/chunk-G6OHIX5C.cjs +100 -0
- package/dist/{chunk-UDFRUKLC.cjs → chunk-GEDY7HQI.cjs} +2 -2
- package/dist/chunk-GQ7JJUIT.cjs +1207 -0
- package/dist/chunk-H3PKYE4N.js +18 -0
- package/dist/{chunk-CNWOMQQJ.js → chunk-H5R7U2D2.js} +206 -5
- package/dist/{chunk-SEXWHIMS.cjs → chunk-HETQETPV.cjs} +9648 -9680
- package/dist/{chunk-Y2GSOUCS.cjs → chunk-HWVUR735.cjs} +2 -2
- package/dist/chunk-II4QMH26.cjs +35 -0
- package/dist/chunk-ILNN6QRW.js +1612 -0
- package/dist/chunk-IYVFSLWJ.js +931 -0
- package/dist/{chunk-3AHTOSXJ.cjs → chunk-JGCFRTND.cjs} +23 -17
- package/dist/chunk-JHQ334WS.js +655 -0
- package/dist/{chunk-WCVZCGK5.cjs → chunk-JO5TLJPM.cjs} +129 -907
- package/dist/{chunk-JRU2CXLB.cjs → chunk-JVCAK4W3.cjs} +210 -9
- package/dist/chunk-KBJJQFYU.js +1122 -0
- package/dist/chunk-KEKCQENI.js +48 -0
- package/dist/chunk-KHXZFLIN.cjs +41 -0
- package/dist/chunk-KT3U3ZRP.cjs +1137 -0
- package/dist/chunk-L2VUINHN.js +35 -0
- package/dist/{chunk-P42V6N34.cjs → chunk-L6ZQGWCX.cjs} +4521 -6234
- package/dist/{chunk-PLYEKV3N.cjs → chunk-MA4Q5RBP.cjs} +6 -6
- package/dist/{chunk-SS5MBHDP.js → chunk-N67XG5GY.js} +10 -8
- package/dist/chunk-NPAQSMRY.js +2087 -0
- package/dist/{chunk-I3ST4PLM.js → chunk-NQWJAOHO.js} +6 -4
- package/dist/{chunk-QAOFMK2A.cjs → chunk-OBZJICEA.cjs} +8 -8
- package/dist/{chunk-6IW7TWPV.js → chunk-OPYODNV2.js} +3 -3
- package/dist/chunk-P3JMAMHP.js +401 -0
- package/dist/chunk-PPXR22YC.cjs +2087 -0
- package/dist/chunk-PSVSEN4J.cjs +655 -0
- package/dist/{chunk-4UM2ETLM.js → chunk-RBYVFPER.js} +74 -46
- package/dist/{chunk-PO33GZVY.js → chunk-ROBQ5TR7.js} +10549 -10581
- package/dist/{chunk-ZCLBYT2V.cjs → chunk-T3CLXR43.cjs} +114 -220
- package/dist/{chunk-FI6GMDO7.js → chunk-TTVOLEUS.js} +3605 -5040
- package/dist/{chunk-LM7TXMLU.cjs → chunk-ULWVKHSI.cjs} +8 -255
- package/dist/{chunk-6I4ZAFO2.cjs → chunk-UT3ODMBU.cjs} +15 -15
- package/dist/chunk-WANCBTUE.js +71 -0
- package/dist/{chunk-BIZNSF3U.cjs → chunk-WBNAEYTQ.cjs} +2 -51
- package/dist/chunk-WFPCCBOM.cjs +71 -0
- package/dist/chunk-WI6FHKD7.js +158 -0
- package/dist/chunk-WMNCVLES.js +100 -0
- package/dist/{chunk-UT4YHQZW.js → chunk-WSDT7LYL.js} +0 -49
- package/dist/chunk-WVOTC7HW.cjs +136 -0
- package/dist/{chunk-AOWDNSTM.cjs → chunk-WWJG4GVG.cjs} +93 -87
- package/dist/chunk-XXBLN4BP.cjs +233 -0
- package/dist/{chunk-4IBPRIQH.js → chunk-YBQQNDC7.js} +1 -1
- package/dist/{chunk-LFFB6EMB.js → chunk-YBS5QGON.js} +70 -128
- package/dist/{chunk-NSGXARGJ.cjs → chunk-Z5SWJW5Q.cjs} +125 -117
- package/dist/{chunk-OJLR5MEO.cjs → chunk-ZX7SCPLO.cjs} +6 -8
- package/dist/cloud-tenants-KZUZGD4A.cjs +117 -0
- package/dist/cloud-tenants-OGLVVQ7X.js +117 -0
- package/dist/components/case-studies/index.cjs +45 -29
- package/dist/components/case-studies/index.js +32 -16
- package/dist/components/chat/ask-prompts.d.ts +64 -0
- package/dist/components/chat/ask-prompts.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/case-study-card.d.ts +6 -3
- package/dist/components/chat/entity-cards/case-study-card.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-chat-dialog-manager.d.ts +4 -1
- package/dist/components/chat/hooks/use-chat-dialog-manager.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-unified-chat.d.ts.map +1 -1
- package/dist/components/chat/index.cjs +27 -8
- package/dist/components/chat/index.d.ts +1 -0
- package/dist/components/chat/index.d.ts.map +1 -1
- package/dist/components/chat/index.js +57 -38
- package/dist/components/chat/quick-action-chip.d.ts +7 -3
- package/dist/components/chat/quick-action-chip.d.ts.map +1 -1
- package/dist/components/chat/types/component.types.d.ts +4 -0
- package/dist/components/chat/types/component.types.d.ts.map +1 -1
- package/dist/components/chat/types/unified-chat-state.types.d.ts +12 -0
- package/dist/components/chat/types/unified-chat-state.types.d.ts.map +1 -1
- package/dist/components/contact/index.cjs +29 -13
- package/dist/components/contact/index.js +28 -12
- package/dist/components/docs/index.cjs +33 -16
- package/dist/components/docs/index.js +33 -16
- package/dist/components/docs/use-scroll-spy.d.ts +23 -1
- package/dist/components/docs/use-scroll-spy.d.ts.map +1 -1
- package/dist/components/embeds/index.cjs +29 -13
- package/dist/components/embeds/index.js +28 -12
- package/dist/components/faq/faq-section.d.ts +8 -1
- package/dist/components/faq/faq-section.d.ts.map +1 -1
- package/dist/components/faq/index.cjs +30 -14
- package/dist/components/faq/index.js +29 -13
- package/dist/components/features/array-entry-manager.d.ts +5 -1
- package/dist/components/features/array-entry-manager.d.ts.map +1 -1
- package/dist/components/features/board/board.d.ts +2 -0
- package/dist/components/features/board/board.d.ts.map +1 -1
- package/dist/components/features/board/ticket-card.d.ts.map +1 -1
- package/dist/components/features/board/touch-board.d.ts +1 -1
- package/dist/components/features/board/touch-board.d.ts.map +1 -1
- package/dist/components/features/board/types.d.ts +3 -0
- package/dist/components/features/board/types.d.ts.map +1 -1
- package/dist/components/features/board/use-board-collapse.d.ts +6 -1
- package/dist/components/features/board/use-board-collapse.d.ts.map +1 -1
- package/dist/components/features/capability-explorer.d.ts +94 -0
- package/dist/components/features/capability-explorer.d.ts.map +1 -0
- package/dist/components/features/cloud-tenants/index.d.ts +14 -0
- package/dist/components/features/cloud-tenants/index.d.ts.map +1 -0
- package/dist/components/features/cloud-tenants/tenant-access-cell.d.ts +9 -0
- package/dist/components/features/cloud-tenants/tenant-access-cell.d.ts.map +1 -0
- package/dist/components/features/cloud-tenants/tenant-cell.d.ts +8 -0
- package/dist/components/features/cloud-tenants/tenant-cell.d.ts.map +1 -0
- package/dist/components/features/cloud-tenants/tenant-customer-cell.d.ts +9 -0
- package/dist/components/features/cloud-tenants/tenant-customer-cell.d.ts.map +1 -0
- package/dist/components/features/cloud-tenants/tenant-presentation.d.ts +42 -0
- package/dist/components/features/cloud-tenants/tenant-presentation.d.ts.map +1 -0
- package/dist/components/features/cloud-tenants/tenant-row.d.ts +22 -0
- package/dist/components/features/cloud-tenants/tenant-row.d.ts.map +1 -0
- package/dist/components/features/cloud-tenants/tenants-table-columns.d.ts +42 -0
- package/dist/components/features/cloud-tenants/tenants-table-columns.d.ts.map +1 -0
- package/dist/components/features/cloud-tenants/tenants-table-view.d.ts +26 -0
- package/dist/components/features/cloud-tenants/tenants-table-view.d.ts.map +1 -0
- package/dist/components/features/devices/device-last-online.d.ts +3 -0
- package/dist/components/features/devices/device-last-online.d.ts.map +1 -0
- package/dist/components/features/devices/device-name.d.ts +42 -0
- package/dist/components/features/devices/device-name.d.ts.map +1 -0
- package/dist/components/features/devices/device-selector/device-selection-mode-radio.d.ts +26 -0
- package/dist/components/features/devices/device-selector/device-selection-mode-radio.d.ts.map +1 -0
- package/dist/components/features/devices/device-selector/device-selector-skeleton.d.ts +25 -0
- package/dist/components/features/devices/device-selector/device-selector-skeleton.d.ts.map +1 -0
- package/dist/components/features/devices/device-selector/device-selector.d.ts +38 -0
- package/dist/components/features/devices/device-selector/device-selector.d.ts.map +1 -0
- package/dist/components/features/devices/device-selector/device-selector.types.d.ts +133 -0
- package/dist/components/features/devices/device-selector/device-selector.types.d.ts.map +1 -0
- package/dist/components/features/devices/device-selector/narrowing.d.ts +13 -0
- package/dist/components/features/devices/device-selector/narrowing.d.ts.map +1 -0
- package/dist/components/features/devices/device-selector/use-device-selector.d.ts +17 -0
- package/dist/components/features/devices/device-selector/use-device-selector.d.ts.map +1 -0
- package/dist/components/features/devices/device-status.d.ts +23 -0
- package/dist/components/features/devices/device-status.d.ts.map +1 -0
- package/dist/components/features/devices/device-statuses.d.ts +40 -0
- package/dist/components/features/devices/device-statuses.d.ts.map +1 -0
- package/dist/components/features/devices/device-tags-filter-button.d.ts +22 -0
- package/dist/components/features/devices/device-tags-filter-button.d.ts.map +1 -0
- package/dist/components/features/devices/device-type-icon.d.ts +11 -0
- package/dist/components/features/devices/device-type-icon.d.ts.map +1 -0
- package/dist/components/features/devices/device-type-tile.d.ts +9 -0
- package/dist/components/features/devices/device-type-tile.d.ts.map +1 -0
- package/dist/components/features/devices/devices-filter-toolbar.d.ts +46 -0
- package/dist/components/features/devices/devices-filter-toolbar.d.ts.map +1 -0
- package/dist/components/features/devices/devices-grid-filters.d.ts +25 -0
- package/dist/components/features/devices/devices-grid-filters.d.ts.map +1 -0
- package/dist/components/features/devices/devices-grid.d.ts +12 -0
- package/dist/components/features/devices/devices-grid.d.ts.map +1 -0
- package/dist/components/features/devices/devices-list.d.ts +131 -0
- package/dist/components/features/devices/devices-list.d.ts.map +1 -0
- package/dist/components/features/devices/devices-panel-header.d.ts +46 -0
- package/dist/components/features/devices/devices-panel-header.d.ts.map +1 -0
- package/dist/components/features/devices/devices-panel-view.d.ts +79 -0
- package/dist/components/features/devices/devices-panel-view.d.ts.map +1 -0
- package/dist/components/features/devices/devices-table-columns.d.ts +76 -0
- package/dist/components/features/devices/devices-table-columns.d.ts.map +1 -0
- package/dist/components/features/devices/devices-view-config.d.ts +25 -0
- package/dist/components/features/devices/devices-view-config.d.ts.map +1 -0
- package/dist/components/features/devices/index.d.ts +24 -0
- package/dist/components/features/devices/index.d.ts.map +1 -0
- package/dist/components/features/devices/types.d.ts +68 -0
- package/dist/components/features/devices/types.d.ts.map +1 -0
- package/dist/components/features/devices/use-tag-filter-modal.d.ts +50 -0
- package/dist/components/features/devices/use-tag-filter-modal.d.ts.map +1 -0
- package/dist/components/features/index.cjs +227 -12
- package/dist/components/features/index.d.ts +7 -0
- package/dist/components/features/index.d.ts.map +1 -1
- package/dist/components/features/index.js +266 -51
- package/dist/components/features/knowledge-base/index.d.ts +7 -0
- package/dist/components/features/knowledge-base/index.d.ts.map +1 -0
- package/dist/components/features/knowledge-base/knowledge-base-article-view.d.ts +44 -0
- package/dist/components/features/knowledge-base/knowledge-base-article-view.d.ts.map +1 -0
- package/dist/components/features/knowledge-base/knowledge-base-item-icon.d.ts +13 -0
- package/dist/components/features/knowledge-base/knowledge-base-item-icon.d.ts.map +1 -0
- package/dist/components/features/knowledge-base/knowledge-base-status.d.ts +8 -0
- package/dist/components/features/knowledge-base/knowledge-base-status.d.ts.map +1 -0
- package/dist/components/features/knowledge-base/knowledge-base-table.d.ts +52 -0
- package/dist/components/features/knowledge-base/knowledge-base-table.d.ts.map +1 -0
- package/dist/components/features/logs/index.d.ts +12 -0
- package/dist/components/features/logs/index.d.ts.map +1 -0
- package/dist/components/features/logs/log-drawer.d.ts +29 -0
- package/dist/components/features/logs/log-drawer.d.ts.map +1 -0
- package/dist/components/features/logs/log-source-labels.d.ts +11 -0
- package/dist/components/features/logs/log-source-labels.d.ts.map +1 -0
- package/dist/components/features/logs/logs-page-view.d.ts +32 -0
- package/dist/components/features/logs/logs-page-view.d.ts.map +1 -0
- package/dist/components/features/logs/logs-table-columns.d.ts +15 -0
- package/dist/components/features/logs/logs-table-columns.d.ts.map +1 -0
- package/dist/components/features/logs/logs-table-view.d.ts +64 -0
- package/dist/components/features/logs/logs-table-view.d.ts.map +1 -0
- package/dist/components/features/logs/types.d.ts +52 -0
- package/dist/components/features/logs/types.d.ts.map +1 -0
- package/dist/components/features/policies/compute-policy-summary.d.ts +37 -0
- package/dist/components/features/policies/compute-policy-summary.d.ts.map +1 -0
- package/dist/components/features/policies/index.d.ts +8 -0
- package/dist/components/features/policies/index.d.ts.map +1 -0
- package/dist/components/features/policies/policies-table.d.ts +34 -0
- package/dist/components/features/policies/policies-table.d.ts.map +1 -0
- package/dist/components/features/policies/policy-summary-cards.d.ts +17 -0
- package/dist/components/features/policies/policy-summary-cards.d.ts.map +1 -0
- package/dist/components/features/policies/policy-table-row.d.ts +37 -0
- package/dist/components/features/policies/policy-table-row.d.ts.map +1 -0
- package/dist/components/features/remote-session/index.d.ts +8 -0
- package/dist/components/features/remote-session/index.d.ts.map +1 -1
- package/dist/components/features/remote-session/remote-desktop-chat-message-row.d.ts +21 -0
- package/dist/components/features/remote-session/remote-desktop-chat-message-row.d.ts.map +1 -0
- package/dist/components/features/remote-session/remote-desktop-chat-panel.d.ts +31 -0
- package/dist/components/features/remote-session/remote-desktop-chat-panel.d.ts.map +1 -0
- package/dist/components/features/remote-session/remote-desktop-fullscreen-toolbar.d.ts +21 -0
- package/dist/components/features/remote-session/remote-desktop-fullscreen-toolbar.d.ts.map +1 -0
- package/dist/components/features/remote-session/remote-desktop-view.d.ts +50 -0
- package/dist/components/features/remote-session/remote-desktop-view.d.ts.map +1 -0
- package/dist/components/features/software/index.d.ts +8 -0
- package/dist/components/features/software/index.d.ts.map +1 -0
- package/dist/components/features/software/package-managers.d.ts +30 -0
- package/dist/components/features/software/package-managers.d.ts.map +1 -0
- package/dist/components/features/software/package-search-field-placeholder.d.ts +7 -0
- package/dist/components/features/software/package-search-field-placeholder.d.ts.map +1 -0
- package/dist/components/features/software/schedule-fields.d.ts +34 -0
- package/dist/components/features/software/schedule-fields.d.ts.map +1 -0
- package/dist/components/features/software/software-action-copy.d.ts +25 -0
- package/dist/components/features/software/software-action-copy.d.ts.map +1 -0
- package/dist/components/features/software/software-action-form.d.ts +71 -0
- package/dist/components/features/software/software-action-form.d.ts.map +1 -0
- package/dist/components/features/software/software-row-fields.d.ts +23 -0
- package/dist/components/features/software/software-row-fields.d.ts.map +1 -0
- package/dist/components/features/software/software-row.d.ts +18 -0
- package/dist/components/features/software/software-row.d.ts.map +1 -0
- package/dist/components/features/sortable-list/index.d.ts +1 -0
- package/dist/components/features/sortable-list/index.d.ts.map +1 -1
- package/dist/components/features/sortable-list/sortable-drag-handle.d.ts +21 -0
- package/dist/components/features/sortable-list/sortable-drag-handle.d.ts.map +1 -0
- package/dist/components/help-center-pages/index.cjs +133 -114
- package/dist/components/help-center-pages/index.js +58 -39
- package/dist/components/index.cjs +320 -82
- package/dist/components/index.js +451 -213
- package/dist/components/layout/page-heading.d.ts +12 -3
- package/dist/components/layout/page-heading.d.ts.map +1 -1
- package/dist/components/meeting-scheduler/index.cjs +120 -98
- package/dist/components/meeting-scheduler/index.js +50 -28
- package/dist/components/navigation/index.cjs +36 -17
- package/dist/components/navigation/index.d.ts +3 -0
- package/dist/components/navigation/index.d.ts.map +1 -1
- package/dist/components/navigation/index.js +36 -17
- package/dist/components/navigation/mingo-ai-button.d.ts +23 -10
- package/dist/components/navigation/mingo-ai-button.d.ts.map +1 -1
- package/dist/components/navigation/sticky-section-nav.d.ts +14 -1
- package/dist/components/navigation/sticky-section-nav.d.ts.map +1 -1
- package/dist/components/onboarding-guides/index.cjs +32 -16
- package/dist/components/onboarding-guides/index.js +31 -15
- package/dist/components/product-demo/cast.d.ts +58 -0
- package/dist/components/product-demo/cast.d.ts.map +1 -0
- package/dist/components/product-demo/fixtures/cloud-tenants.d.ts +10 -0
- package/dist/components/product-demo/fixtures/cloud-tenants.d.ts.map +1 -0
- package/dist/components/product-demo/fixtures/devices.d.ts +14 -0
- package/dist/components/product-demo/fixtures/devices.d.ts.map +1 -0
- package/dist/components/product-demo/fixtures/knowledge.d.ts +14 -0
- package/dist/components/product-demo/fixtures/knowledge.d.ts.map +1 -0
- package/dist/components/product-demo/fixtures/logs.d.ts +15 -0
- package/dist/components/product-demo/fixtures/logs.d.ts.map +1 -0
- package/dist/components/product-demo/fixtures/policies.d.ts +13 -0
- package/dist/components/product-demo/fixtures/policies.d.ts.map +1 -0
- package/dist/components/product-demo/fixtures/remote-session.d.ts +20 -0
- package/dist/components/product-demo/fixtures/remote-session.d.ts.map +1 -0
- package/dist/components/product-demo/fixtures/shared.d.ts +156 -0
- package/dist/components/product-demo/fixtures/shared.d.ts.map +1 -0
- package/dist/components/product-demo/fixtures/software-update.d.ts +19 -0
- package/dist/components/product-demo/fixtures/software-update.d.ts.map +1 -0
- package/dist/components/product-demo/fixtures/tickets-board.d.ts +8 -0
- package/dist/components/product-demo/fixtures/tickets-board.d.ts.map +1 -0
- package/dist/components/product-demo/index.cjs +112 -0
- package/dist/components/product-demo/index.d.ts +6 -0
- package/dist/components/product-demo/index.d.ts.map +1 -0
- package/dist/components/product-demo/index.js +112 -0
- package/dist/components/product-demo/product-screen.d.ts +22 -0
- package/dist/components/product-demo/product-screen.d.ts.map +1 -0
- package/dist/components/product-demo/registry.d.ts +13 -0
- package/dist/components/product-demo/registry.d.ts.map +1 -0
- package/dist/components/product-demo/screen-keys.cjs +25 -0
- package/dist/components/product-demo/screen-keys.d.ts +27 -0
- package/dist/components/product-demo/screen-keys.d.ts.map +1 -0
- package/dist/components/product-demo/screen-keys.js +20 -0
- package/dist/components/product-demo/screens/cloud-tenants.d.ts +8 -0
- package/dist/components/product-demo/screens/cloud-tenants.d.ts.map +1 -0
- package/dist/components/product-demo/screens/devices.d.ts +10 -0
- package/dist/components/product-demo/screens/devices.d.ts.map +1 -0
- package/dist/components/product-demo/screens/knowledge.d.ts +9 -0
- package/dist/components/product-demo/screens/knowledge.d.ts.map +1 -0
- package/dist/components/product-demo/screens/logs.d.ts +4 -0
- package/dist/components/product-demo/screens/logs.d.ts.map +1 -0
- package/dist/components/product-demo/screens/policies.d.ts +8 -0
- package/dist/components/product-demo/screens/policies.d.ts.map +1 -0
- package/dist/components/product-demo/screens/remote-desktop-picture.d.ts +11 -0
- package/dist/components/product-demo/screens/remote-desktop-picture.d.ts.map +1 -0
- package/dist/components/product-demo/screens/remote-session.d.ts +8 -0
- package/dist/components/product-demo/screens/remote-session.d.ts.map +1 -0
- package/dist/components/product-demo/screens/software-update.d.ts +12 -0
- package/dist/components/product-demo/screens/software-update.d.ts.map +1 -0
- package/dist/components/product-demo/screens/tickets-board.d.ts +4 -0
- package/dist/components/product-demo/screens/tickets-board.d.ts.map +1 -0
- package/dist/components/product-demo/types.d.ts +9 -0
- package/dist/components/product-demo/types.d.ts.map +1 -0
- package/dist/components/related-content/index.cjs +14 -8
- package/dist/components/related-content/index.js +13 -7
- package/dist/components/tickets/index.cjs +36 -20
- package/dist/components/tickets/index.js +35 -19
- package/dist/components/ui/file-manager/index.cjs +38 -34
- package/dist/components/ui/file-manager/index.js +8 -4
- package/dist/components/ui/index.cjs +57 -17
- package/dist/components/ui/index.d.ts +1 -0
- package/dist/components/ui/index.d.ts.map +1 -1
- package/dist/components/ui/index.js +141 -101
- package/dist/components/ui/product-screen-frame.d.ts +45 -0
- package/dist/components/ui/product-screen-frame.d.ts.map +1 -0
- package/dist/components/ui/radio-group.d.ts +5 -0
- package/dist/components/ui/radio-group.d.ts.map +1 -1
- package/dist/components/ui/snap-carousel.d.ts +11 -1
- package/dist/components/ui/snap-carousel.d.ts.map +1 -1
- package/dist/components/ui/tag.d.ts +1 -1
- package/dist/components/ui/tag.d.ts.map +1 -1
- package/dist/devices-LBMG42K6.js +81 -0
- package/dist/devices-YGYJIXQY.cjs +81 -0
- package/dist/hooks/index.cjs +17 -8
- package/dist/hooks/index.js +32 -23
- package/dist/hooks/ui/index.d.ts +1 -0
- package/dist/hooks/ui/index.d.ts.map +1 -1
- package/dist/hooks/ui/use-header-height.d.ts +12 -0
- package/dist/hooks/ui/use-header-height.d.ts.map +1 -1
- package/dist/hooks/ui/use-sticky-toolbar.d.ts +29 -0
- package/dist/hooks/ui/use-sticky-toolbar.d.ts.map +1 -0
- package/dist/hooks/use-location-hash.d.ts +2 -2
- package/dist/hooks/use-location-hash.d.ts.map +1 -1
- package/dist/hooks/use-scroll-to-hash.d.ts +7 -0
- package/dist/hooks/use-scroll-to-hash.d.ts.map +1 -1
- package/dist/index.cjs +276 -25
- package/dist/index.js +729 -478
- package/dist/knowledge-H5BIWJVI.js +108 -0
- package/dist/knowledge-KTCVJIWN.cjs +108 -0
- package/dist/logs-DB5Z7M5Q.js +216 -0
- package/dist/logs-RVCC2UQW.cjs +216 -0
- package/dist/policies-EWUULFBR.js +121 -0
- package/dist/policies-HV4IQCBV.cjs +121 -0
- package/dist/remote-session-GSGZOFDX.js +196 -0
- package/dist/remote-session-R6VAFESR.cjs +196 -0
- package/dist/software-update-6PXKRKBT.js +179 -0
- package/dist/software-update-D4OVSWSG.cjs +179 -0
- package/dist/tickets-board-BHLPAVNJ.cjs +137 -0
- package/dist/tickets-board-PYDNELSK.js +137 -0
- package/dist/types/case-study.d.ts +15 -1
- package/dist/types/case-study.d.ts.map +1 -1
- package/dist/utils/date-utils.d.ts +5 -0
- package/dist/utils/date-utils.d.ts.map +1 -1
- package/dist/utils/index.cjs +45 -2
- package/dist/utils/index.d.ts +2 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +41 -3
- package/dist/utils/open-in-new-tab.d.ts +7 -0
- package/dist/utils/open-in-new-tab.d.ts.map +1 -0
- package/dist/utils/same-page-hash-nav.d.ts +31 -0
- package/dist/utils/same-page-hash-nav.d.ts.map +1 -1
- package/dist/utils/scroll-into-view.d.ts +14 -1
- package/dist/utils/scroll-into-view.d.ts.map +1 -1
- package/package.json +13 -1
- package/src/components/chat/ask-prompts.tsx +226 -0
- package/src/components/chat/embeddable-chat.tsx +38 -2
- package/src/components/chat/entity-cards/case-study-card.tsx +122 -46
- package/src/components/chat/hooks/use-chat-dialog-manager.ts +22 -4
- package/src/components/chat/hooks/use-unified-chat.ts +1 -0
- package/src/components/chat/index.ts +1 -0
- package/src/components/chat/quick-action-chip.tsx +33 -9
- package/src/components/chat/types/component.types.ts +4 -0
- package/src/components/chat/types/unified-chat-state.types.ts +13 -0
- package/src/components/docs/use-scroll-spy.ts +93 -18
- package/src/components/faq/faq-section.tsx +82 -43
- package/src/components/features/array-entry-manager.tsx +10 -1
- package/src/components/features/board/board.tsx +4 -1
- package/src/components/features/board/ticket-card.tsx +11 -1
- package/src/components/features/board/touch-board.tsx +2 -1
- package/src/components/features/board/types.ts +3 -0
- package/src/components/features/board/use-board-collapse.ts +7 -2
- package/src/components/features/capability-explorer.tsx +412 -0
- package/src/components/features/cloud-tenants/index.ts +28 -0
- package/src/components/features/cloud-tenants/tenant-access-cell.tsx +24 -0
- package/src/components/features/cloud-tenants/tenant-cell.tsx +26 -0
- package/src/components/features/cloud-tenants/tenant-customer-cell.tsx +27 -0
- package/src/components/features/cloud-tenants/tenant-presentation.ts +111 -0
- package/src/components/features/cloud-tenants/tenant-row.ts +21 -0
- package/src/components/features/cloud-tenants/tenants-table-columns.ts +30 -0
- package/src/components/features/cloud-tenants/tenants-table-view.tsx +142 -0
- package/src/components/features/devices/device-last-online.ts +6 -0
- package/src/components/features/devices/device-name.ts +51 -0
- package/src/components/features/devices/device-selector/device-selection-mode-radio.tsx +107 -0
- package/src/components/features/devices/device-selector/device-selector-skeleton.tsx +32 -0
- package/src/components/features/devices/device-selector/device-selector.tsx +799 -0
- package/src/components/features/devices/device-selector/device-selector.types.ts +138 -0
- package/src/components/features/devices/device-selector/narrowing.ts +33 -0
- package/src/components/features/devices/device-selector/use-device-selector.ts +51 -0
- package/src/components/features/devices/device-status.ts +102 -0
- package/src/components/features/devices/device-statuses.ts +88 -0
- package/src/components/features/devices/device-tags-filter-button.tsx +49 -0
- package/src/components/features/devices/device-type-icon.tsx +29 -0
- package/src/components/features/devices/device-type-tile.tsx +17 -0
- package/src/components/features/devices/devices-filter-toolbar.tsx +114 -0
- package/src/components/features/devices/devices-grid-filters.tsx +99 -0
- package/src/components/features/devices/devices-grid.tsx +86 -0
- package/src/components/features/devices/devices-list.tsx +357 -0
- package/src/components/features/devices/devices-panel-header.tsx +97 -0
- package/src/components/features/devices/devices-panel-view.tsx +261 -0
- package/src/components/features/devices/devices-table-columns.tsx +356 -0
- package/src/components/features/devices/devices-view-config.tsx +38 -0
- package/src/components/features/devices/index.ts +89 -0
- package/src/components/features/devices/types.ts +74 -0
- package/src/components/features/devices/use-tag-filter-modal.ts +109 -0
- package/src/components/features/index.ts +9 -0
- package/src/components/features/knowledge-base/index.ts +19 -0
- package/src/components/features/knowledge-base/knowledge-base-article-view.tsx +134 -0
- package/src/components/features/knowledge-base/knowledge-base-item-icon.ts +14 -0
- package/src/components/features/knowledge-base/knowledge-base-status.ts +12 -0
- package/src/components/features/knowledge-base/knowledge-base-table.tsx +180 -0
- package/src/components/features/logs/index.ts +20 -0
- package/src/components/features/logs/log-drawer.tsx +138 -0
- package/src/components/features/logs/log-source-labels.ts +25 -0
- package/src/components/features/logs/logs-page-view.tsx +100 -0
- package/src/components/features/logs/logs-table-columns.ts +16 -0
- package/src/components/features/logs/logs-table-view.tsx +509 -0
- package/src/components/features/logs/types.ts +71 -0
- package/src/components/features/policies/compute-policy-summary.ts +115 -0
- package/src/components/features/policies/index.ts +14 -0
- package/src/components/features/policies/policies-table.tsx +235 -0
- package/src/components/features/policies/policy-summary-cards.tsx +69 -0
- package/src/components/features/policies/policy-table-row.ts +37 -0
- package/src/components/features/remote-session/index.ts +8 -0
- package/src/components/features/remote-session/remote-desktop-chat-message-row.tsx +56 -0
- package/src/components/features/remote-session/remote-desktop-chat-panel.tsx +102 -0
- package/src/components/features/remote-session/remote-desktop-fullscreen-toolbar.tsx +119 -0
- package/src/components/features/remote-session/remote-desktop-view.tsx +209 -0
- package/src/components/features/software/index.ts +39 -0
- package/src/components/features/software/package-managers.ts +54 -0
- package/src/components/features/software/package-search-field-placeholder.tsx +23 -0
- package/src/components/features/software/schedule-fields.tsx +105 -0
- package/src/components/features/software/software-action-copy.ts +70 -0
- package/src/components/features/software/software-action-form.tsx +199 -0
- package/src/components/features/software/software-row-fields.tsx +105 -0
- package/src/components/features/software/software-row.ts +22 -0
- package/src/components/features/sortable-list/index.ts +1 -0
- package/src/components/features/sortable-list/sortable-drag-handle.tsx +41 -0
- package/src/components/layout/page-heading.tsx +23 -6
- package/src/components/navigation/index.ts +5 -0
- package/src/components/navigation/mingo-ai-button.tsx +37 -13
- package/src/components/navigation/sticky-section-nav.tsx +99 -1
- package/src/components/product-demo/cast.tsx +78 -0
- package/src/components/product-demo/fixtures/cloud-tenants.ts +63 -0
- package/src/components/product-demo/fixtures/devices.ts +87 -0
- package/src/components/product-demo/fixtures/knowledge.ts +48 -0
- package/src/components/product-demo/fixtures/logs.ts +103 -0
- package/src/components/product-demo/fixtures/policies.ts +77 -0
- package/src/components/product-demo/fixtures/remote-session.ts +65 -0
- package/src/components/product-demo/fixtures/shared.ts +53 -0
- package/src/components/product-demo/fixtures/software-update.ts +63 -0
- package/src/components/product-demo/fixtures/tickets-board.ts +100 -0
- package/src/components/product-demo/index.ts +7 -0
- package/src/components/product-demo/product-screen.tsx +94 -0
- package/src/components/product-demo/registry.ts +20 -0
- package/src/components/product-demo/screen-keys.ts +31 -0
- package/src/components/product-demo/screens/cloud-tenants.tsx +23 -0
- package/src/components/product-demo/screens/devices.tsx +41 -0
- package/src/components/product-demo/screens/knowledge.tsx +27 -0
- package/src/components/product-demo/screens/logs.tsx +113 -0
- package/src/components/product-demo/screens/policies.tsx +29 -0
- package/src/components/product-demo/screens/remote-desktop-picture.tsx +118 -0
- package/src/components/product-demo/screens/remote-session.tsx +46 -0
- package/src/components/product-demo/screens/software-update.tsx +97 -0
- package/src/components/product-demo/screens/tickets-board.tsx +28 -0
- package/src/components/product-demo/types.ts +10 -0
- package/src/components/ui/index.ts +1 -0
- package/src/components/ui/product-screen-frame.tsx +136 -0
- package/src/components/ui/radio-group.tsx +16 -4
- package/src/components/ui/snap-carousel.tsx +26 -1
- package/src/components/ui/tag.tsx +5 -0
- package/src/hooks/ui/index.ts +1 -0
- package/src/hooks/ui/use-header-height.ts +51 -2
- package/src/hooks/ui/use-sticky-toolbar.ts +60 -0
- package/src/hooks/use-location-hash.ts +9 -5
- package/src/hooks/use-scroll-to-hash.ts +9 -1
- package/src/types/case-study.ts +21 -1
- package/src/utils/date-utils.ts +8 -1
- package/src/utils/index.ts +5 -0
- package/src/utils/open-in-new-tab.ts +12 -0
- package/src/utils/same-page-hash-nav.ts +57 -0
- package/src/utils/scroll-into-view.ts +21 -5
- package/dist/chunk-BM5MVGH3.cjs +0 -499
- package/dist/chunk-CUME3VTQ.js +0 -144
- package/dist/chunk-CZ7Y7UG4.js +0 -732
- package/dist/chunk-FLKJYMVB.js +0 -499
- package/dist/chunk-OF6GEI5A.cjs +0 -144
- 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
|
+
}
|