@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,509 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { type ReactNode, useCallback, useEffect, useMemo } from 'react';
|
|
4
|
+
import { openInNewTab } from '../../../utils/open-in-new-tab';
|
|
5
|
+
import { normalizeToolTypeWithFallback, toToolLabel } from '../../../utils/tool-utils';
|
|
6
|
+
import {
|
|
7
|
+
ArrowRightUpIcon,
|
|
8
|
+
ClipboardListIcon,
|
|
9
|
+
EyeAltIcon,
|
|
10
|
+
EyeIcon,
|
|
11
|
+
Filter01ListIcon,
|
|
12
|
+
SearchIcon,
|
|
13
|
+
} from '../../icons-v2-generated';
|
|
14
|
+
import { ToolBadge } from '../../platform/ToolBadge';
|
|
15
|
+
import { Button } from '../../ui/button';
|
|
16
|
+
import { type ColumnDef, DataTable, multiSelectFilterFn, type Row, useDataTable } from '../../ui/data-table';
|
|
17
|
+
import { FilterModal } from '../../ui/filter-modal';
|
|
18
|
+
import { NoData, type NoDataProps } from '../../ui/no-data';
|
|
19
|
+
import { Tag } from '../../ui/tag';
|
|
20
|
+
import { TruncateText } from '../../ui/truncate-text';
|
|
21
|
+
import { logSourceLabels } from './log-source-labels';
|
|
22
|
+
import { LOG_COLUMN_WIDTHS } from './logs-table-columns';
|
|
23
|
+
import type { LogsTableColumnId, LogsTableDateFilter, LogsTableFacets, UiLogEntry } from './types';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* TanStack's column-filter state as `useDataTable` hands it back.
|
|
27
|
+
*/
|
|
28
|
+
type ColumnFilterState = { id: string; value: unknown }[];
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* The lib's multi-select `filterFn` for a typed `ColumnDef<T>[]`: it is typed
|
|
32
|
+
* for `unknown` rows and only ever reads the cell value, so the row type is free.
|
|
33
|
+
*/
|
|
34
|
+
function multiSelectFor<T>(): ColumnDef<T>['filterFn'] {
|
|
35
|
+
return multiSelectFilterFn as unknown as ColumnDef<T>['filterFn'];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** The footer button of the onboarding empty state (a guide link, when the host has one). */
|
|
39
|
+
export type LogsTableGuideButton = Pick<NoDataProps, 'buttonLabel' | 'buttonIcon' | 'buttonProps' | 'onButtonClick'>;
|
|
40
|
+
|
|
41
|
+
const EMPTY_TITLE = 'No logs yet';
|
|
42
|
+
const EMPTY_DESCRIPTION =
|
|
43
|
+
'A timeline of every action taken across the platform (scripts run, policies applied, devices connected, tickets updated) will be displayed here.';
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Click handler that opens `href` in a new tab. The row is a link, and a link
|
|
47
|
+
* cannot hold another link, so the button opens the tab itself.
|
|
48
|
+
*/
|
|
49
|
+
export interface LogsTableViewProps<T extends UiLogEntry = UiLogEntry> {
|
|
50
|
+
/** The rows loaded so far. Keep the array stable between renders. */
|
|
51
|
+
logs: T[];
|
|
52
|
+
/** A new first page is in flight: the body shows skeleton rows. */
|
|
53
|
+
loading?: boolean;
|
|
54
|
+
/** What the columns can be filtered by; null while unknown. */
|
|
55
|
+
facets?: LogsTableFacets | null;
|
|
56
|
+
/** Applied filters by column id: `status`, `tool`, `source`. */
|
|
57
|
+
filters: Record<string, string[]>;
|
|
58
|
+
onFilterChange: (filters: Record<string, string[]>) => void;
|
|
59
|
+
/** The applied search text, which counts as a query for the empty states. */
|
|
60
|
+
search?: string;
|
|
61
|
+
/** The applied date filter: its range counts as a query, and the mobile filter modal edits it. */
|
|
62
|
+
dateFilter?: LogsTableDateFilter;
|
|
63
|
+
/** Header of the Log ID column (the host's date sort and range control). Default: the label. */
|
|
64
|
+
logIdHeader?: ReactNode;
|
|
65
|
+
/** The table shows one device's logs (a device tab). */
|
|
66
|
+
deviceScoped?: boolean;
|
|
67
|
+
/** The table is locked to one organization: the Source column has no filter. */
|
|
68
|
+
organizationLocked?: boolean;
|
|
69
|
+
/** Where a row leads; also what the "Open in new tab" button opens. */
|
|
70
|
+
getLogHref?: (log: T) => string;
|
|
71
|
+
/** The row's copy action (the host fetches the full log). */
|
|
72
|
+
renderCopyAction?: (log: T) => ReactNode;
|
|
73
|
+
/** The eye button of a row. */
|
|
74
|
+
onQuickView?: (log: T) => void;
|
|
75
|
+
hasNextPage?: boolean;
|
|
76
|
+
isFetchingNextPage?: boolean;
|
|
77
|
+
onLoadMore?: () => void;
|
|
78
|
+
/** The mobile filter modal; its trigger lives in the search toolbar. */
|
|
79
|
+
mobileFilterOpen?: boolean;
|
|
80
|
+
onMobileFilterClose?: () => void;
|
|
81
|
+
/** Told when the search toolbar should hide: there is nothing to search yet. */
|
|
82
|
+
onHideSearchChange?: (hide: boolean) => void;
|
|
83
|
+
/** How the onboarding empty state is drawn. Default: the plain `NoData` panel. */
|
|
84
|
+
renderEmptyState?: (props: NoDataProps) => ReactNode;
|
|
85
|
+
guideButton?: LogsTableGuideButton;
|
|
86
|
+
/** Columns left out (a narrow rendering). */
|
|
87
|
+
hiddenColumns?: readonly LogsTableColumnId[];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const noop = () => {};
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* The logs table: its columns, rows, filters, empty and loading states. The host
|
|
94
|
+
* loads the rows and owns the filter, search and date state.
|
|
95
|
+
*/
|
|
96
|
+
export function LogsTableView<T extends UiLogEntry = UiLogEntry>({
|
|
97
|
+
logs,
|
|
98
|
+
loading = false,
|
|
99
|
+
facets,
|
|
100
|
+
filters,
|
|
101
|
+
onFilterChange,
|
|
102
|
+
search,
|
|
103
|
+
dateFilter,
|
|
104
|
+
logIdHeader,
|
|
105
|
+
deviceScoped = false,
|
|
106
|
+
organizationLocked = false,
|
|
107
|
+
getLogHref,
|
|
108
|
+
renderCopyAction,
|
|
109
|
+
onQuickView,
|
|
110
|
+
hasNextPage = false,
|
|
111
|
+
isFetchingNextPage = false,
|
|
112
|
+
onLoadMore = noop,
|
|
113
|
+
mobileFilterOpen = false,
|
|
114
|
+
onMobileFilterClose = noop,
|
|
115
|
+
onHideSearchChange,
|
|
116
|
+
renderEmptyState,
|
|
117
|
+
guideButton,
|
|
118
|
+
hiddenColumns,
|
|
119
|
+
}: LogsTableViewProps<T>) {
|
|
120
|
+
const columns = useMemo<ColumnDef<T>[]>(() => {
|
|
121
|
+
const multiSelect = multiSelectFor<T>();
|
|
122
|
+
const all: ColumnDef<T>[] = [
|
|
123
|
+
{
|
|
124
|
+
accessorKey: 'logId',
|
|
125
|
+
header: logIdHeader ? () => logIdHeader : 'Log ID',
|
|
126
|
+
cell: ({ row }: { row: Row<T> }) => (
|
|
127
|
+
<div className="flex shrink-0 flex-col justify-center">
|
|
128
|
+
<TruncateText>{row.original.timestamp}</TruncateText>
|
|
129
|
+
<TruncateText variant="h6" tone="secondary">
|
|
130
|
+
{row.original.logId}
|
|
131
|
+
</TruncateText>
|
|
132
|
+
</div>
|
|
133
|
+
),
|
|
134
|
+
enableSorting: false,
|
|
135
|
+
meta: { width: LOG_COLUMN_WIDTHS.logId, alwaysShowHeader: true },
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
accessorKey: 'status',
|
|
139
|
+
header: 'Status',
|
|
140
|
+
cell: ({ row }: { row: Row<T> }) => (
|
|
141
|
+
<div className="shrink-0">
|
|
142
|
+
<Tag label={row.original.status.label} variant={row.original.status.variant} />
|
|
143
|
+
</div>
|
|
144
|
+
),
|
|
145
|
+
enableSorting: false,
|
|
146
|
+
filterFn: multiSelect,
|
|
147
|
+
meta: {
|
|
148
|
+
width: LOG_COLUMN_WIDTHS.status,
|
|
149
|
+
filter: {
|
|
150
|
+
options:
|
|
151
|
+
facets?.severities.map(severity => ({
|
|
152
|
+
id: severity,
|
|
153
|
+
label: severity.charAt(0).toUpperCase() + severity.slice(1).toLowerCase(),
|
|
154
|
+
value: severity,
|
|
155
|
+
})) ?? [],
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
accessorKey: 'tool',
|
|
161
|
+
header: 'Tool',
|
|
162
|
+
cell: ({ row }: { row: Row<T> }) => (
|
|
163
|
+
<ToolBadge
|
|
164
|
+
toolType={normalizeToolTypeWithFallback(row.original.source.toolType)}
|
|
165
|
+
iconClassName="h-4 w-4 content-md:h-6 content-md:w-6"
|
|
166
|
+
/>
|
|
167
|
+
),
|
|
168
|
+
enableSorting: false,
|
|
169
|
+
filterFn: multiSelect,
|
|
170
|
+
meta: {
|
|
171
|
+
width: LOG_COLUMN_WIDTHS.tool,
|
|
172
|
+
hideAt: 'md',
|
|
173
|
+
filter: {
|
|
174
|
+
options:
|
|
175
|
+
facets?.toolTypes.map(toolType => ({
|
|
176
|
+
id: toolType,
|
|
177
|
+
label: toToolLabel(toolType),
|
|
178
|
+
value: toolType,
|
|
179
|
+
})) ?? [],
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
accessorKey: 'source',
|
|
185
|
+
header: 'SOURCE',
|
|
186
|
+
cell: ({ row }: { row: Row<T> }) => {
|
|
187
|
+
const { deviceName, organization } = logSourceLabels(row.original.device);
|
|
188
|
+
return (
|
|
189
|
+
<div className="flex min-h-[60px] flex-col justify-center gap-1 py-2">
|
|
190
|
+
{deviceName && <TruncateText>{deviceName}</TruncateText>}
|
|
191
|
+
{organization && (
|
|
192
|
+
<TruncateText variant="h6" tone="secondary">
|
|
193
|
+
{organization}
|
|
194
|
+
</TruncateText>
|
|
195
|
+
)}
|
|
196
|
+
</div>
|
|
197
|
+
);
|
|
198
|
+
},
|
|
199
|
+
enableSorting: false,
|
|
200
|
+
filterFn: multiSelect,
|
|
201
|
+
meta: {
|
|
202
|
+
width: LOG_COLUMN_WIDTHS.source,
|
|
203
|
+
hideAt: 'md',
|
|
204
|
+
filter: organizationLocked ? undefined : { options: [...(facets?.organizations ?? [])] },
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
accessorKey: 'description',
|
|
209
|
+
header: 'Log Details',
|
|
210
|
+
cell: ({ row }: { row: Row<T> }) => (
|
|
211
|
+
<TruncateText lines={3} className="text-ods-text-secondary text-h6">
|
|
212
|
+
{row.original.description.title}
|
|
213
|
+
</TruncateText>
|
|
214
|
+
),
|
|
215
|
+
enableSorting: false,
|
|
216
|
+
meta: { width: LOG_COLUMN_WIDTHS.description, hideAt: 'lg' },
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
id: 'copy',
|
|
220
|
+
cell: ({ row }: { row: Row<T> }) => (
|
|
221
|
+
<div data-no-row-click className="pointer-events-auto flex items-center justify-end">
|
|
222
|
+
{renderCopyAction?.(row.original)}
|
|
223
|
+
</div>
|
|
224
|
+
),
|
|
225
|
+
enableSorting: false,
|
|
226
|
+
meta: { width: `${LOG_COLUMN_WIDTHS.action} ml-auto`, align: 'right' },
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
id: 'quickView',
|
|
230
|
+
cell: ({ row }: { row: Row<T> }) => (
|
|
231
|
+
<div data-no-row-click className="pointer-events-auto flex items-center justify-end">
|
|
232
|
+
<Button
|
|
233
|
+
onClick={() => onQuickView?.(row.original)}
|
|
234
|
+
variant="outline"
|
|
235
|
+
size="icon"
|
|
236
|
+
leftIcon={<EyeIcon className="h-5 w-5" />}
|
|
237
|
+
aria-label="Quick view"
|
|
238
|
+
className="bg-ods-card"
|
|
239
|
+
/>
|
|
240
|
+
</div>
|
|
241
|
+
),
|
|
242
|
+
enableSorting: false,
|
|
243
|
+
meta: { width: LOG_COLUMN_WIDTHS.action, align: 'right' },
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
id: 'open',
|
|
247
|
+
cell: ({ row }: { row: Row<T> }) => (
|
|
248
|
+
<div data-no-row-click className="pointer-events-auto flex items-center justify-end">
|
|
249
|
+
<Button
|
|
250
|
+
onClick={getLogHref ? openInNewTab(getLogHref(row.original)) : undefined}
|
|
251
|
+
variant="outline"
|
|
252
|
+
size="icon"
|
|
253
|
+
leftIcon={<ArrowRightUpIcon className="h-5 w-5" />}
|
|
254
|
+
aria-label="Open in new tab"
|
|
255
|
+
className="bg-ods-card"
|
|
256
|
+
/>
|
|
257
|
+
</div>
|
|
258
|
+
),
|
|
259
|
+
enableSorting: false,
|
|
260
|
+
meta: { width: LOG_COLUMN_WIDTHS.action, hideAt: 'md', align: 'right' },
|
|
261
|
+
},
|
|
262
|
+
];
|
|
263
|
+
if (!hiddenColumns?.length) return all;
|
|
264
|
+
return all.filter(column => !hiddenColumns.includes(columnId(column) as LogsTableColumnId));
|
|
265
|
+
}, [facets, getLogHref, organizationLocked, logIdHeader, renderCopyAction, onQuickView, hiddenColumns]);
|
|
266
|
+
|
|
267
|
+
// Mobile filter groups reuse the column filter options the desktop headers
|
|
268
|
+
// show, so the modal is never empty.
|
|
269
|
+
const filterGroups = useMemo(
|
|
270
|
+
() =>
|
|
271
|
+
columns
|
|
272
|
+
.filter(column => column.meta?.filter?.options)
|
|
273
|
+
.map(column => ({
|
|
274
|
+
id: columnId(column),
|
|
275
|
+
title: typeof column.header === 'string' ? column.header : '',
|
|
276
|
+
options: column.meta?.filter?.options || [],
|
|
277
|
+
})),
|
|
278
|
+
[columns],
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
const columnFilters = useMemo(
|
|
282
|
+
() =>
|
|
283
|
+
Object.entries(filters)
|
|
284
|
+
.filter(([, value]) => value && value.length > 0)
|
|
285
|
+
.map(([id, value]) => ({ id, value })),
|
|
286
|
+
[filters],
|
|
287
|
+
);
|
|
288
|
+
|
|
289
|
+
const handleColumnFiltersChange = useCallback(
|
|
290
|
+
// TanStack's updater signature: either the next state or a reducer over it.
|
|
291
|
+
(updater: ColumnFilterState | ((prev: ColumnFilterState) => ColumnFilterState)) => {
|
|
292
|
+
const next = typeof updater === 'function' ? updater(columnFilters) : updater;
|
|
293
|
+
const nextFilters: Record<string, string[]> = {};
|
|
294
|
+
for (const f of next) {
|
|
295
|
+
nextFilters[f.id] = Array.isArray(f.value) ? (f.value as string[]) : [String(f.value)];
|
|
296
|
+
}
|
|
297
|
+
onFilterChange(nextFilters);
|
|
298
|
+
},
|
|
299
|
+
[columnFilters, onFilterChange],
|
|
300
|
+
);
|
|
301
|
+
|
|
302
|
+
const table = useDataTable<T>({
|
|
303
|
+
data: logs,
|
|
304
|
+
columns,
|
|
305
|
+
getRowId: (row: T) => row.id,
|
|
306
|
+
enableSorting: false,
|
|
307
|
+
state: { columnFilters },
|
|
308
|
+
onColumnFiltersChange: handleColumnFiltersChange,
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
const hasActiveFilters = Object.values(filters).some(values => values.length > 0);
|
|
312
|
+
// The applied date range counts as a query too: an empty result must keep
|
|
313
|
+
// the table header so the date filter stays reachable to pick another period.
|
|
314
|
+
const hasQuery = Boolean(search) || hasActiveFilters || Boolean(dateFilter?.range);
|
|
315
|
+
const noRows = !loading && logs.length === 0;
|
|
316
|
+
|
|
317
|
+
// The standalone page and a device tab share the onboarding empty state when
|
|
318
|
+
// there is no data at all (no query). An empty result under an active query
|
|
319
|
+
// keeps the table chrome below.
|
|
320
|
+
const showEmptyState = !organizationLocked && !hasQuery && noRows;
|
|
321
|
+
|
|
322
|
+
// Scoped (device or organization) tabs: when the table is empty, hide the
|
|
323
|
+
// column header and render the unified `DataTable.Body` empty state.
|
|
324
|
+
const scoped = deviceScoped || organizationLocked;
|
|
325
|
+
const scopedEmpty = scoped && noRows;
|
|
326
|
+
|
|
327
|
+
// The search field lives outside this view. It hides for the onboarding empty
|
|
328
|
+
// state and for an empty scoped tab, and stays while a query is active so the
|
|
329
|
+
// query can be cleared.
|
|
330
|
+
const hideSearch = showEmptyState || (scopedEmpty && !hasQuery);
|
|
331
|
+
useEffect(() => {
|
|
332
|
+
onHideSearchChange?.(hideSearch);
|
|
333
|
+
}, [hideSearch, onHideSearchChange]);
|
|
334
|
+
|
|
335
|
+
if (showEmptyState) {
|
|
336
|
+
// A device tab shows the message only: the onboarding rows and the guide
|
|
337
|
+
// button belong to the standalone page.
|
|
338
|
+
const emptyProps: NoDataProps = deviceScoped
|
|
339
|
+
? { icon: <ClipboardListIcon />, title: EMPTY_TITLE, description: EMPTY_DESCRIPTION }
|
|
340
|
+
: {
|
|
341
|
+
icon: <ClipboardListIcon />,
|
|
342
|
+
title: EMPTY_TITLE,
|
|
343
|
+
description: EMPTY_DESCRIPTION,
|
|
344
|
+
actions: [
|
|
345
|
+
{ icon: <EyeAltIcon />, label: 'Track who did what, when, and on which device' },
|
|
346
|
+
{ icon: <Filter01ListIcon />, label: 'Filter by user, action type, Customer, or date range' },
|
|
347
|
+
{ icon: <SearchIcon />, label: 'Investigate incidents and audit security events' },
|
|
348
|
+
],
|
|
349
|
+
...guideButton,
|
|
350
|
+
};
|
|
351
|
+
return <>{renderEmptyState ? renderEmptyState(emptyProps) : <NoData {...emptyProps} />}</>;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
return (
|
|
355
|
+
<>
|
|
356
|
+
<DataTable table={table}>
|
|
357
|
+
{/* Keep the header while a query (search, filters, date range) is active,
|
|
358
|
+
even with zero rows: its controls are the only way to change it. */}
|
|
359
|
+
{!(scopedEmpty && !hasQuery) && (
|
|
360
|
+
<DataTable.Header stickyHeader stickyHeaderOffset="top-[96px]" rightSlot={<DataTable.RowCount />} />
|
|
361
|
+
)}
|
|
362
|
+
<DataTable.Body
|
|
363
|
+
loading={loading}
|
|
364
|
+
skeletonRows={10}
|
|
365
|
+
// Scoped tabs get the unified empty state (as every other device and
|
|
366
|
+
// customer tab); the standalone page keeps its inline message.
|
|
367
|
+
{...(scoped
|
|
368
|
+
? {
|
|
369
|
+
emptyState: {
|
|
370
|
+
icon: <ClipboardListIcon />,
|
|
371
|
+
title: 'No logs found',
|
|
372
|
+
description: hasQuery
|
|
373
|
+
? 'No results. Try adjusting your search or filters.'
|
|
374
|
+
: deviceScoped
|
|
375
|
+
? 'Logs for this device will appear here.'
|
|
376
|
+
: 'Logs for this customer will appear here.',
|
|
377
|
+
},
|
|
378
|
+
}
|
|
379
|
+
: { emptyMessage: 'No logs found. Try adjusting your search or filters.' })}
|
|
380
|
+
rowHref={getLogHref}
|
|
381
|
+
rowClassName="mb-1"
|
|
382
|
+
/>
|
|
383
|
+
<DataTable.InfiniteFooter
|
|
384
|
+
hasNextPage={hasNextPage}
|
|
385
|
+
isFetchingNextPage={isFetchingNextPage}
|
|
386
|
+
onLoadMore={onLoadMore}
|
|
387
|
+
skeletonRows={2}
|
|
388
|
+
/>
|
|
389
|
+
</DataTable>
|
|
390
|
+
|
|
391
|
+
<FilterModal
|
|
392
|
+
isOpen={mobileFilterOpen}
|
|
393
|
+
onClose={onMobileFilterClose}
|
|
394
|
+
filterGroups={filterGroups}
|
|
395
|
+
onFilterChange={onFilterChange}
|
|
396
|
+
currentFilters={filters}
|
|
397
|
+
// Date sort and range: the last section, committed together with the
|
|
398
|
+
// group filters.
|
|
399
|
+
dateFilter={
|
|
400
|
+
dateFilter
|
|
401
|
+
? {
|
|
402
|
+
title: 'Date',
|
|
403
|
+
sort: dateFilter.sortDirection,
|
|
404
|
+
range: dateFilter.range,
|
|
405
|
+
onChange: dateFilter.onApply,
|
|
406
|
+
}
|
|
407
|
+
: undefined
|
|
408
|
+
}
|
|
409
|
+
/>
|
|
410
|
+
</>
|
|
411
|
+
);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
function columnId<T>(column: ColumnDef<T>): string {
|
|
415
|
+
return String(column.id ?? (column as { accessorKey?: string }).accessorKey ?? '');
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// ----------------------------------------------------------------
|
|
419
|
+
// Loading skeleton
|
|
420
|
+
// ----------------------------------------------------------------
|
|
421
|
+
|
|
422
|
+
const EMPTY_LOG_ROWS: unknown[] = [];
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* A filterable column while the facets are still in flight: no options, plus the
|
|
426
|
+
* flag saying they are coming. The flag keeps the funnel drawn (inert); an empty
|
|
427
|
+
* filter without it means "there is nothing to filter by", and the table hides
|
|
428
|
+
* the funnel for that column.
|
|
429
|
+
*/
|
|
430
|
+
const PENDING_FILTER = { options: [] as never[], pending: true };
|
|
431
|
+
|
|
432
|
+
export interface LogsTableSkeletonProps {
|
|
433
|
+
/** The Log ID header in its inert form, so the icon does not arrive with the data. */
|
|
434
|
+
logIdHeader?: ReactNode;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* Loading fallback of the logs table: an empty `DataTable` with the table's own
|
|
439
|
+
* columns, so the header row and the column widths match the loaded table.
|
|
440
|
+
*/
|
|
441
|
+
export function LogsTableSkeleton({ logIdHeader }: LogsTableSkeletonProps) {
|
|
442
|
+
const columns = useMemo<ColumnDef<unknown>[]>(() => {
|
|
443
|
+
const multiSelect = multiSelectFor<unknown>();
|
|
444
|
+
return [
|
|
445
|
+
{
|
|
446
|
+
id: 'logId',
|
|
447
|
+
header: logIdHeader ? () => logIdHeader : 'Log ID',
|
|
448
|
+
enableSorting: false,
|
|
449
|
+
meta: { width: LOG_COLUMN_WIDTHS.logId, alwaysShowHeader: true },
|
|
450
|
+
},
|
|
451
|
+
{
|
|
452
|
+
id: 'status',
|
|
453
|
+
header: 'Status',
|
|
454
|
+
enableSorting: false,
|
|
455
|
+
filterFn: multiSelect,
|
|
456
|
+
meta: { width: LOG_COLUMN_WIDTHS.status, filter: PENDING_FILTER },
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
id: 'tool',
|
|
460
|
+
header: 'Tool',
|
|
461
|
+
enableSorting: false,
|
|
462
|
+
filterFn: multiSelect,
|
|
463
|
+
meta: { width: LOG_COLUMN_WIDTHS.tool, hideAt: 'md', filter: PENDING_FILTER },
|
|
464
|
+
},
|
|
465
|
+
{
|
|
466
|
+
id: 'source',
|
|
467
|
+
header: 'SOURCE',
|
|
468
|
+
enableSorting: false,
|
|
469
|
+
filterFn: multiSelect,
|
|
470
|
+
meta: { width: LOG_COLUMN_WIDTHS.source, hideAt: 'md', filter: PENDING_FILTER },
|
|
471
|
+
},
|
|
472
|
+
{
|
|
473
|
+
id: 'description',
|
|
474
|
+
header: 'Log Details',
|
|
475
|
+
enableSorting: false,
|
|
476
|
+
meta: { width: LOG_COLUMN_WIDTHS.description, hideAt: 'lg' },
|
|
477
|
+
},
|
|
478
|
+
{
|
|
479
|
+
id: 'copy',
|
|
480
|
+
enableSorting: false,
|
|
481
|
+
meta: { width: `${LOG_COLUMN_WIDTHS.action} ml-auto`, align: 'right' },
|
|
482
|
+
},
|
|
483
|
+
{
|
|
484
|
+
id: 'quickView',
|
|
485
|
+
enableSorting: false,
|
|
486
|
+
meta: { width: LOG_COLUMN_WIDTHS.action, align: 'right' },
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
id: 'open',
|
|
490
|
+
enableSorting: false,
|
|
491
|
+
meta: { width: LOG_COLUMN_WIDTHS.action, hideAt: 'md', align: 'right' },
|
|
492
|
+
},
|
|
493
|
+
];
|
|
494
|
+
}, [logIdHeader]);
|
|
495
|
+
|
|
496
|
+
const table = useDataTable<unknown>({
|
|
497
|
+
data: EMPTY_LOG_ROWS,
|
|
498
|
+
columns,
|
|
499
|
+
getRowId: () => '',
|
|
500
|
+
enableSorting: false,
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
return (
|
|
504
|
+
<DataTable table={table}>
|
|
505
|
+
<DataTable.Header stickyHeader stickyHeaderOffset="top-[96px]" />
|
|
506
|
+
<DataTable.Body loading={true} skeletonRows={10} emptyMessage="" rowClassName="mb-1" />
|
|
507
|
+
</DataTable>
|
|
508
|
+
);
|
|
509
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { DateFilterResult } from '../../ui/date-picker';
|
|
3
|
+
|
|
4
|
+
/** The tag colour a log severity is drawn in. */
|
|
5
|
+
export type LogStatusVariant = 'success' | 'warning' | 'error' | 'grey' | 'critical';
|
|
6
|
+
|
|
7
|
+
/** One row of the logs table, as plain display data. */
|
|
8
|
+
export interface UiLogEntry {
|
|
9
|
+
id: string;
|
|
10
|
+
logId: string;
|
|
11
|
+
/** Already formatted for display. */
|
|
12
|
+
timestamp: string;
|
|
13
|
+
status: {
|
|
14
|
+
label: string;
|
|
15
|
+
variant?: LogStatusVariant;
|
|
16
|
+
};
|
|
17
|
+
source: {
|
|
18
|
+
name: string;
|
|
19
|
+
toolType: string;
|
|
20
|
+
icon?: ReactNode;
|
|
21
|
+
};
|
|
22
|
+
device: {
|
|
23
|
+
name: string;
|
|
24
|
+
organization?: string;
|
|
25
|
+
};
|
|
26
|
+
description: {
|
|
27
|
+
title: string;
|
|
28
|
+
details?: string;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** A filter choice of a column header and of the mobile filter modal. */
|
|
33
|
+
export interface LogsTableFilterOption {
|
|
34
|
+
id: string;
|
|
35
|
+
label: string;
|
|
36
|
+
value: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** What the table can be filtered by, as the API reports it. */
|
|
40
|
+
export interface LogsTableFacets {
|
|
41
|
+
severities: readonly string[];
|
|
42
|
+
toolTypes: readonly string[];
|
|
43
|
+
/** Ready-made options: the caller owns how an organization is labelled. */
|
|
44
|
+
organizations: readonly LogsTableFilterOption[];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** The applied date sort and range, and how a new one is committed. */
|
|
48
|
+
export interface LogsTableDateFilter {
|
|
49
|
+
sortDirection: 'asc' | 'desc';
|
|
50
|
+
range: DateFilterResult['range'];
|
|
51
|
+
onApply: (result: DateFilterResult) => void;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** The columns of the logs table, by id. */
|
|
55
|
+
export type LogsTableColumnId = 'logId' | 'status' | 'tool' | 'source' | 'description' | 'copy' | 'quickView' | 'open';
|
|
56
|
+
|
|
57
|
+
/** The tag colour for a severity as the API spells it. */
|
|
58
|
+
export function logSeverityVariant(severity: string): LogStatusVariant {
|
|
59
|
+
switch (severity) {
|
|
60
|
+
case 'ERROR':
|
|
61
|
+
return 'error';
|
|
62
|
+
case 'WARNING':
|
|
63
|
+
return 'warning';
|
|
64
|
+
case 'INFO':
|
|
65
|
+
return 'grey';
|
|
66
|
+
case 'CRITICAL':
|
|
67
|
+
return 'critical';
|
|
68
|
+
default:
|
|
69
|
+
return 'success';
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import type { PolicyTableStatus } from './policy-table-row';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The host counts of a fleet-wide policy, as Fleet reports them. The product's
|
|
5
|
+
* own `Policy` model satisfies this structurally.
|
|
6
|
+
*/
|
|
7
|
+
export interface PolicyHostCounts {
|
|
8
|
+
passing_host_count: number;
|
|
9
|
+
failing_host_count: number;
|
|
10
|
+
host_count_updated_at?: string;
|
|
11
|
+
hosts_include_any?: readonly unknown[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface PolicySummaryStats {
|
|
15
|
+
totalPolicies: number;
|
|
16
|
+
failingPolicies: number;
|
|
17
|
+
failingPoliciesPercentage: number;
|
|
18
|
+
compliantPolicies: number;
|
|
19
|
+
compliantPoliciesPercentage: number;
|
|
20
|
+
lastUpdatedAt: string | null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type PolicyStatus = 'compliant' | 'failing' | 'pending' | 'partial';
|
|
24
|
+
|
|
25
|
+
export const POLICY_STATUS_CONFIG: Record<PolicyStatus, { label: string; variant: 'success' | 'error' | 'warning' }> = {
|
|
26
|
+
compliant: { label: 'Compliant', variant: 'success' },
|
|
27
|
+
failing: { label: 'Failing', variant: 'error' },
|
|
28
|
+
pending: { label: 'Pending', variant: 'warning' },
|
|
29
|
+
partial: { label: 'Partial', variant: 'warning' },
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/** Targeted hosts that have not answered the policy yet. */
|
|
33
|
+
function missingHostCount(policy: PolicyHostCounts): number {
|
|
34
|
+
const responded = policy.passing_host_count + policy.failing_host_count;
|
|
35
|
+
return (policy.hosts_include_any?.length ?? 0) - responded;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function getPolicyStatus(policy: PolicyHostCounts): PolicyStatus {
|
|
39
|
+
const failing = policy.failing_host_count;
|
|
40
|
+
const responded = policy.passing_host_count + failing;
|
|
41
|
+
const missing = missingHostCount(policy);
|
|
42
|
+
|
|
43
|
+
if (missing > 0 && responded === 0) return 'pending';
|
|
44
|
+
if (missing > 0) return 'partial';
|
|
45
|
+
if (failing > 0) return 'failing';
|
|
46
|
+
return 'compliant';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* The STATUS cell of a fleet-wide policy: its status tag, plus how many devices
|
|
51
|
+
* fail it or have not answered yet.
|
|
52
|
+
*/
|
|
53
|
+
export function getPolicyTableStatus(policy: PolicyHostCounts): PolicyTableStatus {
|
|
54
|
+
const status = getPolicyStatus(policy);
|
|
55
|
+
const config = POLICY_STATUS_CONFIG[status];
|
|
56
|
+
const failing = policy.failing_host_count;
|
|
57
|
+
const missing = missingHostCount(policy);
|
|
58
|
+
|
|
59
|
+
let note: PolicyTableStatus['note'];
|
|
60
|
+
if (status === 'partial' && missing > 0) {
|
|
61
|
+
note = { text: `${missing} ${missing === 1 ? 'device' : 'devices'} left`, tone: 'warning' };
|
|
62
|
+
} else if (status === 'failing') {
|
|
63
|
+
note = { text: `${failing} ${failing === 1 ? 'device' : 'devices'}`, tone: 'error' };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return { label: config.label, variant: config.variant, note };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const EMPTY_SUMMARY: PolicySummaryStats = {
|
|
70
|
+
totalPolicies: 0,
|
|
71
|
+
failingPolicies: 0,
|
|
72
|
+
failingPoliciesPercentage: 0,
|
|
73
|
+
compliantPolicies: 0,
|
|
74
|
+
compliantPoliciesPercentage: 0,
|
|
75
|
+
lastUpdatedAt: null,
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Compute policy compliance summary from a list of policies.
|
|
80
|
+
* Only policies with a definitive status (compliant or failing) are included
|
|
81
|
+
* in compliance stats. Pending and partial policies are excluded.
|
|
82
|
+
*/
|
|
83
|
+
export function computePolicySummary(policies: readonly PolicyHostCounts[]): PolicySummaryStats {
|
|
84
|
+
const totalPolicies = policies.length;
|
|
85
|
+
if (totalPolicies === 0) return EMPTY_SUMMARY;
|
|
86
|
+
|
|
87
|
+
let failingPolicies = 0;
|
|
88
|
+
let compliantPolicies = 0;
|
|
89
|
+
let latestUpdate: string | null = null;
|
|
90
|
+
|
|
91
|
+
for (const policy of policies) {
|
|
92
|
+
const status = getPolicyStatus(policy);
|
|
93
|
+
|
|
94
|
+
if (status === 'compliant') {
|
|
95
|
+
compliantPolicies++;
|
|
96
|
+
} else if (status === 'failing') {
|
|
97
|
+
failingPolicies++;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (policy.host_count_updated_at && (!latestUpdate || policy.host_count_updated_at > latestUpdate)) {
|
|
101
|
+
latestUpdate = policy.host_count_updated_at;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const resolvedPolicies = compliantPolicies + failingPolicies;
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
totalPolicies,
|
|
109
|
+
failingPolicies,
|
|
110
|
+
failingPoliciesPercentage: resolvedPolicies > 0 ? Math.round((failingPolicies / resolvedPolicies) * 100) : 0,
|
|
111
|
+
compliantPolicies,
|
|
112
|
+
compliantPoliciesPercentage: resolvedPolicies > 0 ? Math.round((compliantPolicies / resolvedPolicies) * 100) : 0,
|
|
113
|
+
lastUpdatedAt: latestUpdate,
|
|
114
|
+
};
|
|
115
|
+
}
|