@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,412 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { type KeyboardEvent, type ReactNode, useRef } from 'react';
|
|
4
|
+
import { useContentLgUp } from '../../hooks/ui/use-content-breakpoint';
|
|
5
|
+
import { cn } from '../../utils/cn';
|
|
6
|
+
import { EntityIcon } from '../icon-display';
|
|
7
|
+
import { Chevron02RightIcon } from '../icons-v2-generated/arrows/chevron-02-right-icon';
|
|
8
|
+
import { CheckIcon } from '../icons-v2-generated/signs-and-symbols/check-icon';
|
|
9
|
+
import { Skeleton } from '../ui/skeleton';
|
|
10
|
+
import { SnapCarousel, SnapCarouselControlsSkeleton } from '../ui/snap-carousel';
|
|
11
|
+
import { TruncateText } from '../ui/truncate-text';
|
|
12
|
+
|
|
13
|
+
/** One job the product does, as the explorer shows it. Every field is the host's data. */
|
|
14
|
+
export interface CapabilityExplorerItem {
|
|
15
|
+
/**
|
|
16
|
+
* The job's key: what `activeId` names. The host owns the element a link to
|
|
17
|
+
* `#id` lands on (an anchor at the section's heading), so no element here
|
|
18
|
+
* carries it: a tab is `capabilityTabId(id)`.
|
|
19
|
+
*/
|
|
20
|
+
id: string;
|
|
21
|
+
title: string;
|
|
22
|
+
/** An icons-v2 name. */
|
|
23
|
+
iconName?: string;
|
|
24
|
+
intro: string;
|
|
25
|
+
/** Short bullets under the intro; the first three are shown. */
|
|
26
|
+
highlights?: readonly string[];
|
|
27
|
+
/** One line under the title in the list ("Built on ..."). */
|
|
28
|
+
caption?: string;
|
|
29
|
+
/** A mark beside the title in the list (a generation badge). */
|
|
30
|
+
badge?: ReactNode;
|
|
31
|
+
/**
|
|
32
|
+
* A request in plain words and what happened. `requester` and `responder`
|
|
33
|
+
* are who the two turns belong to in THIS example (a name, a note beside it,
|
|
34
|
+
* the host's own avatar); what is left out falls back to the explorer's
|
|
35
|
+
* labels and marks.
|
|
36
|
+
*/
|
|
37
|
+
example?: {
|
|
38
|
+
request: string;
|
|
39
|
+
outcome: string;
|
|
40
|
+
requester?: CapabilityExampleParty;
|
|
41
|
+
responder?: CapabilityExampleParty;
|
|
42
|
+
} | null;
|
|
43
|
+
/** The line pinned under the screen (what it is built on, what it replaces). */
|
|
44
|
+
footer?: ReactNode;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** One side of an example: who it is, as the host draws its people and agents everywhere else. */
|
|
48
|
+
export interface CapabilityExampleParty {
|
|
49
|
+
name?: string;
|
|
50
|
+
note?: string;
|
|
51
|
+
/** The host's avatar component for this person or agent, sized for the turn (24px). */
|
|
52
|
+
mark?: ReactNode;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface CapabilityExplorerLabels {
|
|
56
|
+
/** Names the list of jobs for assistive tech. */
|
|
57
|
+
list: string;
|
|
58
|
+
/** Who asks in the example ("You"). */
|
|
59
|
+
requester: string;
|
|
60
|
+
/** Who answers in the example (the assistant's configured name). */
|
|
61
|
+
responder: string;
|
|
62
|
+
/** A note beside the requester ("to Mingo"). */
|
|
63
|
+
requesterNote?: string;
|
|
64
|
+
/** A note beside the responder ("a few seconds later"). */
|
|
65
|
+
responderNote?: string;
|
|
66
|
+
/** Carousel controls. */
|
|
67
|
+
previous?: string;
|
|
68
|
+
next?: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface CapabilityExplorerProps {
|
|
72
|
+
items: readonly CapabilityExplorerItem[];
|
|
73
|
+
labels: CapabilityExplorerLabels;
|
|
74
|
+
activeId: string;
|
|
75
|
+
onActiveChange: (id: string) => void;
|
|
76
|
+
/** The job's product screen; `compact` is the card rendering. Null: the job has none. */
|
|
77
|
+
renderScreen: (item: CapabilityExplorerItem, options: { compact: boolean }) => ReactNode;
|
|
78
|
+
/** The marks beside the two turns of an example that names nobody of its own. */
|
|
79
|
+
requesterMark?: ReactNode;
|
|
80
|
+
responderMark?: ReactNode;
|
|
81
|
+
className?: string;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Heights are constants so the panel never moves between jobs and the
|
|
86
|
+
* skeleton is the loaded box: every text is clamped to fit them.
|
|
87
|
+
*/
|
|
88
|
+
const PANEL_HEIGHT_CLASS = 'h-[824px]';
|
|
89
|
+
/** The panel's rows: the copy beside the example, the screen, the footer line. */
|
|
90
|
+
const PANEL_TOP_HEIGHT_CLASS = 'h-[256px]';
|
|
91
|
+
const PANEL_SCREEN_HEIGHT_CLASS = 'h-[420px]';
|
|
92
|
+
const PANEL_FOOTER_HEIGHT_CLASS = 'h-[52px]';
|
|
93
|
+
const CARD_HEIGHT_CLASS = 'h-[700px]';
|
|
94
|
+
/** Both, for the box shown before the layout is known (literal, so the class is generated). */
|
|
95
|
+
const SKELETON_HEIGHT_CLASS = 'h-[700px] content-lg:h-[824px]';
|
|
96
|
+
|
|
97
|
+
/** The element id of a job's tab (never the job's own id: that is the host's anchor). */
|
|
98
|
+
export const capabilityTabId = (id: string): string => `${id}-tab`;
|
|
99
|
+
|
|
100
|
+
function Highlights({ items, className }: { items: readonly string[]; className?: string }) {
|
|
101
|
+
if (items.length === 0) return null;
|
|
102
|
+
return (
|
|
103
|
+
<ul className={cn('grid grid-cols-1 gap-2', className)}>
|
|
104
|
+
{items.slice(0, 3).map(text => (
|
|
105
|
+
<li key={text} className="flex min-w-0 items-center gap-2.5">
|
|
106
|
+
<CheckIcon size={16} className="shrink-0 text-ods-flamingo-cyan" />
|
|
107
|
+
<TruncateText variant="h6" triggerClassName="flex-1">
|
|
108
|
+
{text}
|
|
109
|
+
</TruncateText>
|
|
110
|
+
</li>
|
|
111
|
+
))}
|
|
112
|
+
</ul>
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function Example({
|
|
117
|
+
example,
|
|
118
|
+
labels,
|
|
119
|
+
requesterMark,
|
|
120
|
+
responderMark,
|
|
121
|
+
className,
|
|
122
|
+
}: {
|
|
123
|
+
example: NonNullable<CapabilityExplorerItem['example']>;
|
|
124
|
+
labels: CapabilityExplorerLabels;
|
|
125
|
+
requesterMark?: ReactNode;
|
|
126
|
+
responderMark?: ReactNode;
|
|
127
|
+
className?: string;
|
|
128
|
+
}) {
|
|
129
|
+
const who = (name: string, note?: string) => (
|
|
130
|
+
<p className="flex min-w-0 items-baseline gap-2 text-ods-text-primary text-h6">
|
|
131
|
+
<span className="shrink-0">{name}</span>
|
|
132
|
+
{note && <span className="truncate text-ods-text-secondary">{note}</span>}
|
|
133
|
+
</p>
|
|
134
|
+
);
|
|
135
|
+
// The mark is the host's own avatar: its shape says who it is (a person who uses a computer, one who runs it, an agent), so it is never clipped here.
|
|
136
|
+
const mark = (node: ReactNode) =>
|
|
137
|
+
node ? <span className="flex size-6 shrink-0 items-center justify-center">{node}</span> : null;
|
|
138
|
+
const requester = example.requester;
|
|
139
|
+
const responder = example.responder;
|
|
140
|
+
return (
|
|
141
|
+
<div
|
|
142
|
+
className={cn(
|
|
143
|
+
'flex min-w-0 flex-col justify-center gap-3 overflow-hidden rounded-xl border border-ods-border bg-ods-bg px-[var(--spacing-system-mf)] py-[var(--spacing-system-sf)]',
|
|
144
|
+
className,
|
|
145
|
+
)}
|
|
146
|
+
>
|
|
147
|
+
<div className="flex min-w-0 gap-2.5">
|
|
148
|
+
{mark(requester?.mark ?? requesterMark)}
|
|
149
|
+
<div className="flex min-w-0 flex-1 flex-col gap-1">
|
|
150
|
+
{who(requester?.name ?? labels.requester, requester?.note ?? labels.requesterNote)}
|
|
151
|
+
<TruncateText lines={2} variant="h4" className="min-h-[2lh]">
|
|
152
|
+
{`\u201c${example.request}\u201d`}
|
|
153
|
+
</TruncateText>
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
<div className="flex min-w-0 gap-2.5 border-t border-ods-border pt-3">
|
|
157
|
+
{mark(responder?.mark ?? responderMark)}
|
|
158
|
+
<div className="flex min-w-0 flex-1 flex-col gap-1">
|
|
159
|
+
{who(responder?.name ?? labels.responder, responder?.note ?? labels.responderNote)}
|
|
160
|
+
<div className="flex min-w-0 items-start gap-2">
|
|
161
|
+
<CheckIcon size={16} className="mt-0.5 shrink-0 text-ods-flamingo-cyan" />
|
|
162
|
+
<TruncateText lines={2} variant="h6" tone="secondary" className="min-h-[2lh]" triggerClassName="flex-1">
|
|
163
|
+
{example.outcome}
|
|
164
|
+
</TruncateText>
|
|
165
|
+
</div>
|
|
166
|
+
</div>
|
|
167
|
+
</div>
|
|
168
|
+
</div>
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/** The box the explorer occupies while its data loads, at both layouts: the panel, or the carousel's card over its controls. */
|
|
173
|
+
export function CapabilityExplorerSkeleton({ className }: { className?: string }) {
|
|
174
|
+
return (
|
|
175
|
+
<div className={className}>
|
|
176
|
+
<Skeleton className={cn(SKELETON_HEIGHT_CLASS, 'w-full')} />
|
|
177
|
+
<SnapCarouselControlsSkeleton className="content-lg:hidden" />
|
|
178
|
+
</div>
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* The jobs a product does, one at a time with its real screen.
|
|
184
|
+
*
|
|
185
|
+
* From the content `lg` step: a vertical tablist (roving focus, arrow keys,
|
|
186
|
+
* Home and End) beside one panel of fixed height: the job's copy and example
|
|
187
|
+
* on top, its screen full width below, the footer pinned. Below it: a swipe
|
|
188
|
+
* carousel of equal-height cards, each with the compact screen, that moves to
|
|
189
|
+
* the next job by itself under the carousel's own rule (`useAutoplay`: on
|
|
190
|
+
* screen, tab visible, not paused, motion allowed), like every carousel.
|
|
191
|
+
*
|
|
192
|
+
* The host owns which job is shown (it reads the URL hash) through `activeId`
|
|
193
|
+
* and `onActiveChange`, and the element a link to a job lands on: nothing here
|
|
194
|
+
* carries a job's id, so an anchor scroll never aims inside the list. In the
|
|
195
|
+
* carousel `activeId` brings that job's card into view (the track moves, the
|
|
196
|
+
* page does not).
|
|
197
|
+
*/
|
|
198
|
+
export function CapabilityExplorer({
|
|
199
|
+
items,
|
|
200
|
+
labels,
|
|
201
|
+
activeId,
|
|
202
|
+
onActiveChange,
|
|
203
|
+
renderScreen,
|
|
204
|
+
requesterMark,
|
|
205
|
+
responderMark,
|
|
206
|
+
className,
|
|
207
|
+
}: CapabilityExplorerProps) {
|
|
208
|
+
const wide = useContentLgUp();
|
|
209
|
+
const listRef = useRef<HTMLDivElement>(null);
|
|
210
|
+
|
|
211
|
+
if (items.length === 0) return null;
|
|
212
|
+
// Unknown until measured: one box, so neither layout's ids are in the page twice.
|
|
213
|
+
if (wide === undefined) return <CapabilityExplorerSkeleton className={className} />;
|
|
214
|
+
|
|
215
|
+
if (!wide) {
|
|
216
|
+
return (
|
|
217
|
+
<SnapCarousel
|
|
218
|
+
className={className}
|
|
219
|
+
items={items}
|
|
220
|
+
label={labels.list}
|
|
221
|
+
prevLabel={labels.previous}
|
|
222
|
+
nextLabel={labels.next}
|
|
223
|
+
getKey={item => item.id}
|
|
224
|
+
focusIndex={items.findIndex(item => item.id === activeId)}
|
|
225
|
+
slideClassName="min-w-0 basis-[86%]"
|
|
226
|
+
renderItem={item => (
|
|
227
|
+
<article
|
|
228
|
+
className={cn(
|
|
229
|
+
'flex w-full min-w-0 flex-col gap-[var(--spacing-system-sf)] overflow-hidden rounded-xl border border-ods-border bg-ods-card p-[var(--spacing-system-mf)]',
|
|
230
|
+
CARD_HEIGHT_CLASS,
|
|
231
|
+
)}
|
|
232
|
+
>
|
|
233
|
+
<div className="flex min-w-0 items-center gap-3">
|
|
234
|
+
{item.iconName && (
|
|
235
|
+
<span className="flex size-9 shrink-0 items-center justify-center rounded-lg border border-ods-border bg-ods-bg text-ods-flamingo-cyan">
|
|
236
|
+
<EntityIcon icon={{ name: item.iconName }} size={18} />
|
|
237
|
+
</span>
|
|
238
|
+
)}
|
|
239
|
+
<div className="min-w-0 flex-1">
|
|
240
|
+
<h3 className="flex min-w-0 items-center gap-2 text-ods-text-primary text-h4">
|
|
241
|
+
<TruncateText as="span" variant="h4" triggerClassName="flex-1">
|
|
242
|
+
{item.title}
|
|
243
|
+
</TruncateText>
|
|
244
|
+
{item.badge}
|
|
245
|
+
</h3>
|
|
246
|
+
{item.caption && (
|
|
247
|
+
<TruncateText variant="h6" tone="secondary">
|
|
248
|
+
{item.caption}
|
|
249
|
+
</TruncateText>
|
|
250
|
+
)}
|
|
251
|
+
</div>
|
|
252
|
+
</div>
|
|
253
|
+
<TruncateText lines={3} variant="h6" tone="secondary" className="min-h-[3lh]">
|
|
254
|
+
{item.intro}
|
|
255
|
+
</TruncateText>
|
|
256
|
+
<div className="shrink-0 overflow-hidden rounded-lg border border-ods-border">
|
|
257
|
+
{renderScreen(item, { compact: true })}
|
|
258
|
+
</div>
|
|
259
|
+
{item.example && (
|
|
260
|
+
<Example
|
|
261
|
+
example={item.example}
|
|
262
|
+
labels={labels}
|
|
263
|
+
requesterMark={requesterMark}
|
|
264
|
+
responderMark={responderMark}
|
|
265
|
+
className="shrink-0"
|
|
266
|
+
/>
|
|
267
|
+
)}
|
|
268
|
+
{item.footer && <div className="mt-auto min-w-0 shrink-0 overflow-hidden">{item.footer}</div>}
|
|
269
|
+
</article>
|
|
270
|
+
)}
|
|
271
|
+
/>
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const activeIndex = Math.max(
|
|
276
|
+
0,
|
|
277
|
+
items.findIndex(item => item.id === activeId),
|
|
278
|
+
);
|
|
279
|
+
const active = items[activeIndex];
|
|
280
|
+
const panelId = 'capability-explorer-panel';
|
|
281
|
+
|
|
282
|
+
const onKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {
|
|
283
|
+
const last = items.length - 1;
|
|
284
|
+
const next =
|
|
285
|
+
event.key === 'ArrowDown'
|
|
286
|
+
? (activeIndex + 1) % items.length
|
|
287
|
+
: event.key === 'ArrowUp'
|
|
288
|
+
? (activeIndex + last) % items.length
|
|
289
|
+
: event.key === 'Home'
|
|
290
|
+
? 0
|
|
291
|
+
: event.key === 'End'
|
|
292
|
+
? last
|
|
293
|
+
: null;
|
|
294
|
+
if (next === null) return;
|
|
295
|
+
event.preventDefault();
|
|
296
|
+
onActiveChange(items[next].id);
|
|
297
|
+
listRef.current?.querySelectorAll<HTMLButtonElement>('[role="tab"]')[next]?.focus();
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
return (
|
|
301
|
+
<div
|
|
302
|
+
className={cn(
|
|
303
|
+
'grid grid-cols-[minmax(0,360px)_minmax(0,1fr)] gap-[var(--spacing-system-lf)]',
|
|
304
|
+
PANEL_HEIGHT_CLASS,
|
|
305
|
+
className,
|
|
306
|
+
)}
|
|
307
|
+
>
|
|
308
|
+
<div
|
|
309
|
+
ref={listRef}
|
|
310
|
+
role="tablist"
|
|
311
|
+
aria-orientation="vertical"
|
|
312
|
+
aria-label={labels.list}
|
|
313
|
+
onKeyDown={onKeyDown}
|
|
314
|
+
className="flex min-h-0 flex-col gap-1 overflow-y-auto"
|
|
315
|
+
>
|
|
316
|
+
{items.map((item, index) => {
|
|
317
|
+
const selected = index === activeIndex;
|
|
318
|
+
return (
|
|
319
|
+
<button
|
|
320
|
+
key={item.id}
|
|
321
|
+
id={capabilityTabId(item.id)}
|
|
322
|
+
type="button"
|
|
323
|
+
role="tab"
|
|
324
|
+
aria-selected={selected}
|
|
325
|
+
aria-controls={panelId}
|
|
326
|
+
tabIndex={selected ? 0 : -1}
|
|
327
|
+
onClick={() => onActiveChange(item.id)}
|
|
328
|
+
className={cn(
|
|
329
|
+
'flex min-w-0 shrink-0 items-center gap-3.5 rounded-lg border px-3.5 py-3 text-left transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ods-accent',
|
|
330
|
+
selected ? 'border-ods-border bg-ods-card' : 'border-transparent hover:bg-ods-bg-hover',
|
|
331
|
+
)}
|
|
332
|
+
>
|
|
333
|
+
{item.iconName && (
|
|
334
|
+
<span
|
|
335
|
+
className={cn(
|
|
336
|
+
'flex size-9 shrink-0 items-center justify-center rounded-lg border border-ods-border bg-ods-bg',
|
|
337
|
+
selected ? 'text-ods-flamingo-cyan' : 'text-ods-text-secondary',
|
|
338
|
+
)}
|
|
339
|
+
>
|
|
340
|
+
<EntityIcon icon={{ name: item.iconName }} size={18} />
|
|
341
|
+
</span>
|
|
342
|
+
)}
|
|
343
|
+
<span className="min-w-0 flex-1">
|
|
344
|
+
<span
|
|
345
|
+
className={cn(
|
|
346
|
+
'flex min-w-0 items-center gap-2 text-h4',
|
|
347
|
+
selected ? 'text-ods-text-primary' : 'text-ods-text-secondary',
|
|
348
|
+
)}
|
|
349
|
+
>
|
|
350
|
+
<span className="truncate">{item.title}</span>
|
|
351
|
+
{item.badge}
|
|
352
|
+
</span>
|
|
353
|
+
{item.caption && (
|
|
354
|
+
<span className="mt-0.5 block truncate text-ods-text-secondary text-h6" title={item.caption}>
|
|
355
|
+
{item.caption}
|
|
356
|
+
</span>
|
|
357
|
+
)}
|
|
358
|
+
</span>
|
|
359
|
+
<Chevron02RightIcon
|
|
360
|
+
size={16}
|
|
361
|
+
className={cn('shrink-0', selected ? 'text-ods-flamingo-cyan' : 'invisible')}
|
|
362
|
+
aria-hidden
|
|
363
|
+
/>
|
|
364
|
+
</button>
|
|
365
|
+
);
|
|
366
|
+
})}
|
|
367
|
+
</div>
|
|
368
|
+
|
|
369
|
+
<div
|
|
370
|
+
id={panelId}
|
|
371
|
+
role="tabpanel"
|
|
372
|
+
aria-labelledby={capabilityTabId(active.id)}
|
|
373
|
+
className="flex min-h-0 min-w-0 flex-col gap-5 overflow-hidden rounded-xl border border-ods-border bg-ods-card px-8 py-7"
|
|
374
|
+
>
|
|
375
|
+
<div
|
|
376
|
+
className={cn(
|
|
377
|
+
'grid shrink-0 gap-8',
|
|
378
|
+
// A job with no example gives its copy the whole row.
|
|
379
|
+
active.example ? 'grid-cols-[minmax(0,1fr)_minmax(0,380px)]' : 'grid-cols-1',
|
|
380
|
+
PANEL_TOP_HEIGHT_CLASS,
|
|
381
|
+
)}
|
|
382
|
+
>
|
|
383
|
+
<div className="flex min-w-0 flex-col overflow-hidden">
|
|
384
|
+
<TruncateText lines={2} variant="h2" className="mb-2">
|
|
385
|
+
{active.title}
|
|
386
|
+
</TruncateText>
|
|
387
|
+
<TruncateText lines={3} variant="h4" tone="secondary" className="min-h-[3lh]">
|
|
388
|
+
{active.intro}
|
|
389
|
+
</TruncateText>
|
|
390
|
+
<Highlights items={active.highlights ?? []} className="mt-auto" />
|
|
391
|
+
</div>
|
|
392
|
+
{active.example && (
|
|
393
|
+
<Example
|
|
394
|
+
example={active.example}
|
|
395
|
+
labels={labels}
|
|
396
|
+
requesterMark={requesterMark}
|
|
397
|
+
responderMark={responderMark}
|
|
398
|
+
/>
|
|
399
|
+
)}
|
|
400
|
+
</div>
|
|
401
|
+
<div className={cn('shrink-0 overflow-hidden rounded-xl border border-ods-border', PANEL_SCREEN_HEIGHT_CLASS)}>
|
|
402
|
+
{renderScreen(active, { compact: false })}
|
|
403
|
+
</div>
|
|
404
|
+
{active.footer && (
|
|
405
|
+
<div className={cn('flex min-w-0 shrink-0 items-center overflow-hidden', PANEL_FOOTER_HEIGHT_CLASS)}>
|
|
406
|
+
{active.footer}
|
|
407
|
+
</div>
|
|
408
|
+
)}
|
|
409
|
+
</div>
|
|
410
|
+
</div>
|
|
411
|
+
);
|
|
412
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
export { TenantsTableView } from './tenants-table-view';
|
|
4
|
+
export type { TenantsTableViewProps } from './tenants-table-view';
|
|
5
|
+
export { TenantCell } from './tenant-cell';
|
|
6
|
+
export type { TenantCellProps } from './tenant-cell';
|
|
7
|
+
export { TenantCustomerCell } from './tenant-customer-cell';
|
|
8
|
+
export type { TenantCustomerCellProps } from './tenant-customer-cell';
|
|
9
|
+
export { TenantAccessCell } from './tenant-access-cell';
|
|
10
|
+
export type { TenantAccessCellProps } from './tenant-access-cell';
|
|
11
|
+
export { TENANT_COLUMNS, TENANTS_TABLE_COLUMNS } from './tenants-table-columns';
|
|
12
|
+
export type { TenantsTableColumn } from './tenants-table-columns';
|
|
13
|
+
export type { TenantRow } from './tenant-row';
|
|
14
|
+
export {
|
|
15
|
+
accessStateTag,
|
|
16
|
+
formatLastRead,
|
|
17
|
+
lastReadAt,
|
|
18
|
+
providerMark,
|
|
19
|
+
TENANT_EMPTY_VALUE,
|
|
20
|
+
usersCountLabel,
|
|
21
|
+
} from './tenant-presentation';
|
|
22
|
+
export type {
|
|
23
|
+
ProviderLogo,
|
|
24
|
+
ProviderMark,
|
|
25
|
+
TenantStatusTag,
|
|
26
|
+
TenantAccessState,
|
|
27
|
+
TenantProvider,
|
|
28
|
+
} from './tenant-presentation';
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Tag } from '../../ui/tag';
|
|
4
|
+
import { TruncateText } from '../../ui/truncate-text';
|
|
5
|
+
import { accessStateTag, formatLastRead } from './tenant-presentation';
|
|
6
|
+
|
|
7
|
+
export interface TenantAccessCellProps {
|
|
8
|
+
accessState: string;
|
|
9
|
+
lastReadAt?: string | null;
|
|
10
|
+
/** The clock "Last read" is relative to. Default: the moment of the render. */
|
|
11
|
+
now?: Date;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** ACCESS column: the access tag over "Last read: ...". */
|
|
15
|
+
export function TenantAccessCell({ accessState, lastReadAt, now }: TenantAccessCellProps) {
|
|
16
|
+
return (
|
|
17
|
+
<div className="flex min-w-0 flex-col justify-center gap-[var(--spacing-system-xxs)]">
|
|
18
|
+
<Tag {...accessStateTag(accessState)} className="self-start" />
|
|
19
|
+
<TruncateText variant="h6" tone="secondary">
|
|
20
|
+
{`Last read: ${formatLastRead(lastReadAt, now)}`}
|
|
21
|
+
</TruncateText>
|
|
22
|
+
</div>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { TruncateText } from '../../ui/truncate-text';
|
|
4
|
+
import { providerMark, TENANT_EMPTY_VALUE } from './tenant-presentation';
|
|
5
|
+
|
|
6
|
+
export interface TenantCellProps {
|
|
7
|
+
provider: string;
|
|
8
|
+
name: string;
|
|
9
|
+
domain?: string | null;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** TENANT column: provider mark + name over the domain. */
|
|
13
|
+
export function TenantCell({ provider, name, domain }: TenantCellProps) {
|
|
14
|
+
const { Logo, label } = providerMark(provider);
|
|
15
|
+
return (
|
|
16
|
+
<div className="flex min-w-0 flex-col justify-center">
|
|
17
|
+
<div className="flex min-w-0 items-center gap-[var(--spacing-system-xxs)]">
|
|
18
|
+
<Logo size={24} role="img" aria-label={label} className="shrink-0" />
|
|
19
|
+
<TruncateText>{name}</TruncateText>
|
|
20
|
+
</div>
|
|
21
|
+
<TruncateText variant="h6" tone="secondary">
|
|
22
|
+
{domain ?? TENANT_EMPTY_VALUE}
|
|
23
|
+
</TruncateText>
|
|
24
|
+
</div>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { SquareAvatar } from '../../ui/square-avatar';
|
|
4
|
+
import { TruncateText } from '../../ui/truncate-text';
|
|
5
|
+
import { usersCountLabel } from './tenant-presentation';
|
|
6
|
+
|
|
7
|
+
export interface TenantCustomerCellProps {
|
|
8
|
+
name: string;
|
|
9
|
+
/** A URL the browser can load as is. */
|
|
10
|
+
imageUrl?: string | null;
|
|
11
|
+
userCount?: number | null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** CUSTOMERS column: customer logo + name over the synced user count. */
|
|
15
|
+
export function TenantCustomerCell({ name, imageUrl, userCount }: TenantCustomerCellProps) {
|
|
16
|
+
return (
|
|
17
|
+
<div className="flex min-w-0 flex-col justify-center">
|
|
18
|
+
<div className="flex min-w-0 items-center gap-[var(--spacing-system-xxs)]">
|
|
19
|
+
<SquareAvatar src={imageUrl ?? undefined} alt={name} fallback={name} size="xs" variant="square" />
|
|
20
|
+
<TruncateText>{name}</TruncateText>
|
|
21
|
+
</div>
|
|
22
|
+
<TruncateText variant="h6" tone="secondary">
|
|
23
|
+
{usersCountLabel(userCount)}
|
|
24
|
+
</TruncateText>
|
|
25
|
+
</div>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
// Presentation tables of the cloud tenants list.
|
|
2
|
+
//
|
|
3
|
+
// Every value → label/variant decision of the list lives here, declared with
|
|
4
|
+
// `satisfies Record<Union, …>`. The unions restate the directory enums of the
|
|
5
|
+
// product's GraphQL schema (the library holds no generated types); the product
|
|
6
|
+
// app asserts that its generated enums are covered, so a widened enum stops
|
|
7
|
+
// type-checking there until the new value is given an answer here. Values reach
|
|
8
|
+
// the UI as plain strings and a backend ahead of the schema is a runtime
|
|
9
|
+
// possibility, so every reader takes a `string` and degrades to a neutral answer.
|
|
10
|
+
|
|
11
|
+
import type { ComponentType, SVGProps } from 'react';
|
|
12
|
+
import { formatRelativeTimeFrom } from '../../../utils/date-utils';
|
|
13
|
+
import { formatDate } from '../../../utils/format-date';
|
|
14
|
+
import { GoogleLogoIcon } from '../../icons-v2-generated/brand-logos/google-logo-icon';
|
|
15
|
+
import { Office365LogoIcon } from '../../icons-v2-generated/brand-logos/office-365-logo-icon';
|
|
16
|
+
import { CodingForkIcon } from '../../icons-v2-generated/coding/coding-fork-icon';
|
|
17
|
+
import type { TagProps } from '../../ui/tag';
|
|
18
|
+
|
|
19
|
+
/** What a cell shows when it has no value. */
|
|
20
|
+
export const TENANT_EMPTY_VALUE = '—';
|
|
21
|
+
|
|
22
|
+
type TagVariant = NonNullable<TagProps['variant']>;
|
|
23
|
+
|
|
24
|
+
export interface TenantStatusTag {
|
|
25
|
+
label: string;
|
|
26
|
+
variant: TagVariant;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** What the last probe of a directory connection found. */
|
|
30
|
+
export type TenantAccessState =
|
|
31
|
+
'DISCONNECTED' | 'NOT_AUTHORISED' | 'CONSENT_REVOKED' | 'READ_ONLY' | 'WRITE_AVAILABLE' | 'WRITE_ENABLED';
|
|
32
|
+
|
|
33
|
+
/** The directory providers a tenant connects to. */
|
|
34
|
+
export type TenantProvider = 'MICROSOFT_365' | 'GOOGLE_WORKSPACE';
|
|
35
|
+
|
|
36
|
+
function presentationFor<K extends string, V>(map: Record<K, V>, key: string | null | undefined): V | undefined {
|
|
37
|
+
return key != null && key in map ? map[key as K] : undefined;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Colours read off the Figma list (node 1699-8249): red for the two states that
|
|
41
|
+
// need the customer's admin, grey for read-only, outline for write-available,
|
|
42
|
+
// green for write-enabled. NOT_AUTHORISED has no frame of its own
|
|
43
|
+
// and follows CONSENT_REVOKED: it is the other "the directory refused us" state.
|
|
44
|
+
const ACCESS_STATE_PRESENTATION = {
|
|
45
|
+
DISCONNECTED: { label: 'Disconnected', variant: 'error' },
|
|
46
|
+
NOT_AUTHORISED: { label: 'Not authorised', variant: 'error' },
|
|
47
|
+
CONSENT_REVOKED: { label: 'Consent revoked', variant: 'error' },
|
|
48
|
+
READ_ONLY: { label: 'Read only', variant: 'grey' },
|
|
49
|
+
WRITE_AVAILABLE: { label: 'Write available', variant: 'outline' },
|
|
50
|
+
WRITE_ENABLED: { label: 'Write enabled', variant: 'success' },
|
|
51
|
+
} satisfies Record<TenantAccessState, TenantStatusTag>;
|
|
52
|
+
|
|
53
|
+
/** Tag props for an access state; an unknown value renders as itself in grey. */
|
|
54
|
+
export function accessStateTag(state: string | null | undefined): TenantStatusTag {
|
|
55
|
+
return presentationFor(ACCESS_STATE_PRESENTATION, state) ?? { label: state || TENANT_EMPTY_VALUE, variant: 'grey' };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** An icons-v2 brand mark: sized by `size`, labelled for assistive tech where it stands alone. */
|
|
59
|
+
export type ProviderLogo = ComponentType<
|
|
60
|
+
{ className?: string; size?: number } & Pick<SVGProps<SVGSVGElement>, 'role' | 'aria-label'>
|
|
61
|
+
>;
|
|
62
|
+
|
|
63
|
+
export interface ProviderMark {
|
|
64
|
+
label: string;
|
|
65
|
+
Logo: ProviderLogo;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const PROVIDER_MARK = {
|
|
69
|
+
MICROSOFT_365: { label: 'Microsoft 365', Logo: Office365LogoIcon },
|
|
70
|
+
GOOGLE_WORKSPACE: { label: 'Google Workspace', Logo: GoogleLogoIcon },
|
|
71
|
+
} satisfies Record<TenantProvider, ProviderMark>;
|
|
72
|
+
|
|
73
|
+
/** Name and brand mark of a provider; an unknown value keeps its raw name and a neutral mark. */
|
|
74
|
+
export function providerMark(provider: string | null | undefined): ProviderMark {
|
|
75
|
+
return presentationFor(PROVIDER_MARK, provider) ?? { label: provider || 'Unknown provider', Logo: CodingForkIcon };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* The instant "Last read" reports: the directory sync, not the access probe. A probe proves the
|
|
80
|
+
* link, a sync is when the data was read. The instant arrives untyped, so anything but text is absent.
|
|
81
|
+
*/
|
|
82
|
+
export function lastReadAt(connection: { readonly lastSyncAt?: unknown }): string | null {
|
|
83
|
+
return typeof connection.lastSyncAt === 'string' && connection.lastSyncAt !== '' ? connection.lastSyncAt : null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
87
|
+
|
|
88
|
+
// `Date` reads three fraction digits; Safari rejects a longer fraction outright, and V8 truncates it.
|
|
89
|
+
const FRACTION_PAST_MILLIS = /(\.\d{3})\d+(?=Z$)/;
|
|
90
|
+
|
|
91
|
+
function toValidInstant(iso: string | null | undefined): Date | null {
|
|
92
|
+
if (iso == null || iso === '') return null;
|
|
93
|
+
const date = new Date(iso.replace(FRACTION_PAST_MILLIS, '$1'));
|
|
94
|
+
return Number.isNaN(date.getTime()) ? null : date;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* "41m ago" while fresh, the calendar date once a day old (the design shows
|
|
99
|
+
* "Last read: 10/10/2016" on a stale row), the empty mark when there was never a read.
|
|
100
|
+
*/
|
|
101
|
+
export function formatLastRead(iso: string | null | undefined, now: Date = new Date()): string {
|
|
102
|
+
const date = toValidInstant(iso);
|
|
103
|
+
if (!date) return TENANT_EMPTY_VALUE;
|
|
104
|
+
return now.getTime() - date.getTime() < DAY_MS ? formatRelativeTimeFrom(date, now) : formatDate(date);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** "227 Users" under the customer, the empty mark before the first read. */
|
|
108
|
+
export function usersCountLabel(count: number | null | undefined): string {
|
|
109
|
+
if (count == null) return TENANT_EMPTY_VALUE;
|
|
110
|
+
return `${count} ${count === 1 ? 'User' : 'Users'}`;
|
|
111
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** One connected directory tenant, as the tenants list shows it. */
|
|
2
|
+
export interface TenantRow {
|
|
3
|
+
id: string;
|
|
4
|
+
/** The tenant's own name in its directory. */
|
|
5
|
+
name: string;
|
|
6
|
+
/** The directory provider (`MICROSOFT_365`, `GOOGLE_WORKSPACE`); an unknown value keeps its raw name. */
|
|
7
|
+
provider: string;
|
|
8
|
+
domain?: string | null;
|
|
9
|
+
/** The customer the tenant belongs to. */
|
|
10
|
+
customer: {
|
|
11
|
+
name: string;
|
|
12
|
+
/** A URL the browser can load as is. */
|
|
13
|
+
imageUrl?: string | null;
|
|
14
|
+
};
|
|
15
|
+
/** Users read from the directory; absent before the first read. */
|
|
16
|
+
userCount?: number | null;
|
|
17
|
+
/** What the last access probe found (`WRITE_ENABLED`, `DISCONNECTED`, ...). */
|
|
18
|
+
accessState: string;
|
|
19
|
+
/** When the directory was last read; absent when it never was. */
|
|
20
|
+
lastReadAt?: string | null;
|
|
21
|
+
}
|