@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,1612 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
DRAG_AND_DROP_MEDIA_QUERY,
|
|
4
|
+
useHorizontalScrollbar,
|
|
5
|
+
useLocalStorage
|
|
6
|
+
} from "./chunk-3K5ZLZE7.js";
|
|
7
|
+
import {
|
|
8
|
+
ApprovalBatchMessage,
|
|
9
|
+
TicketStatusTag,
|
|
10
|
+
formatTicketFullTimestamp,
|
|
11
|
+
formatTicketRelativeTime,
|
|
12
|
+
getReadableTextColor,
|
|
13
|
+
resolveTicketStatus,
|
|
14
|
+
useCollapsible
|
|
15
|
+
} from "./chunk-2NASBO7O.js";
|
|
16
|
+
import {
|
|
17
|
+
Tooltip,
|
|
18
|
+
TooltipContent,
|
|
19
|
+
TooltipProvider,
|
|
20
|
+
TooltipTrigger
|
|
21
|
+
} from "./chunk-P3JMAMHP.js";
|
|
22
|
+
import {
|
|
23
|
+
AgentMark
|
|
24
|
+
} from "./chunk-H3PKYE4N.js";
|
|
25
|
+
import {
|
|
26
|
+
SquareAvatar,
|
|
27
|
+
Tag
|
|
28
|
+
} from "./chunk-IYVFSLWJ.js";
|
|
29
|
+
import {
|
|
30
|
+
useIsomorphicLayoutEffect,
|
|
31
|
+
useMediaQuery
|
|
32
|
+
} from "./chunk-ADBE7QF3.js";
|
|
33
|
+
import {
|
|
34
|
+
Arrow02LeftIcon,
|
|
35
|
+
Arrow02RightIcon,
|
|
36
|
+
BoxArchiveIcon,
|
|
37
|
+
Chevron02DownIcon,
|
|
38
|
+
Chevron02UpIcon,
|
|
39
|
+
ClockIcon,
|
|
40
|
+
DotsLoaderIcon,
|
|
41
|
+
Flag02Icon,
|
|
42
|
+
InfoCircleIcon,
|
|
43
|
+
MessagesIcon,
|
|
44
|
+
PlusIcon,
|
|
45
|
+
ShieldCheckIcon,
|
|
46
|
+
TagIcon,
|
|
47
|
+
UserCheckIcon,
|
|
48
|
+
UserXmarkIcon
|
|
49
|
+
} from "./chunk-NCPTID44.js";
|
|
50
|
+
import {
|
|
51
|
+
LaptopIcon
|
|
52
|
+
} from "./chunk-OSIKGEBU.js";
|
|
53
|
+
import {
|
|
54
|
+
Button
|
|
55
|
+
} from "./chunk-YDPKUAP4.js";
|
|
56
|
+
import {
|
|
57
|
+
next_link_default
|
|
58
|
+
} from "./chunk-DAAVMYUT.js";
|
|
59
|
+
import {
|
|
60
|
+
Skeleton
|
|
61
|
+
} from "./chunk-FYEJTF5Y.js";
|
|
62
|
+
import {
|
|
63
|
+
cn
|
|
64
|
+
} from "./chunk-7RXWKTAP.js";
|
|
65
|
+
|
|
66
|
+
// src/components/ui/deleted-user-avatar.tsx
|
|
67
|
+
import { jsx } from "react/jsx-runtime";
|
|
68
|
+
var SIZE_CLASSES = {
|
|
69
|
+
sm: "h-8 w-8",
|
|
70
|
+
md: "h-10 w-10",
|
|
71
|
+
lg: "h-12 w-12"
|
|
72
|
+
};
|
|
73
|
+
var ICON_CLASSES = {
|
|
74
|
+
sm: "w-4 h-4",
|
|
75
|
+
md: "w-5 h-5",
|
|
76
|
+
lg: "w-6 h-6"
|
|
77
|
+
};
|
|
78
|
+
function DeletedUserAvatar({ size = "md", className, accessibleLabel }) {
|
|
79
|
+
return /* @__PURE__ */ jsx(
|
|
80
|
+
"span",
|
|
81
|
+
{
|
|
82
|
+
role: "img",
|
|
83
|
+
"aria-label": accessibleLabel || "Deleted user",
|
|
84
|
+
className: cn(
|
|
85
|
+
"flex shrink-0 items-center justify-center rounded-full bg-ods-error/20",
|
|
86
|
+
SIZE_CLASSES[size],
|
|
87
|
+
className
|
|
88
|
+
),
|
|
89
|
+
children: /* @__PURE__ */ jsx(UserXmarkIcon, { className: cn("text-ods-error", ICON_CLASSES[size]) })
|
|
90
|
+
}
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// src/components/ui/touch-friendly-tooltip.tsx
|
|
95
|
+
import { useCallback, useRef, useState } from "react";
|
|
96
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
97
|
+
var dismissOpenTooltip = null;
|
|
98
|
+
function TouchFriendlyTooltip({ content, side = "left", children }) {
|
|
99
|
+
const [open, setOpen] = useState(false);
|
|
100
|
+
const isTouchRef = useRef(false);
|
|
101
|
+
const close = useCallback(() => setOpen(false), []);
|
|
102
|
+
if (!content) return children;
|
|
103
|
+
const toggleFromTouch = () => {
|
|
104
|
+
setOpen((prev) => {
|
|
105
|
+
const next = !prev;
|
|
106
|
+
if (next) {
|
|
107
|
+
if (dismissOpenTooltip && dismissOpenTooltip !== close) dismissOpenTooltip();
|
|
108
|
+
dismissOpenTooltip = close;
|
|
109
|
+
} else if (dismissOpenTooltip === close) {
|
|
110
|
+
dismissOpenTooltip = null;
|
|
111
|
+
}
|
|
112
|
+
return next;
|
|
113
|
+
});
|
|
114
|
+
};
|
|
115
|
+
return /* @__PURE__ */ jsx2(TooltipProvider, { delayDuration: 150, children: /* @__PURE__ */ jsxs(Tooltip, { open, onOpenChange: setOpen, children: [
|
|
116
|
+
/* @__PURE__ */ jsx2(
|
|
117
|
+
TooltipTrigger,
|
|
118
|
+
{
|
|
119
|
+
asChild: true,
|
|
120
|
+
onPointerDown: (e) => {
|
|
121
|
+
isTouchRef.current = e.pointerType === "touch";
|
|
122
|
+
if (!isTouchRef.current) return;
|
|
123
|
+
e.preventDefault();
|
|
124
|
+
toggleFromTouch();
|
|
125
|
+
},
|
|
126
|
+
onFocus: (e) => {
|
|
127
|
+
if (isTouchRef.current) e.preventDefault();
|
|
128
|
+
},
|
|
129
|
+
onClick: (e) => {
|
|
130
|
+
if (isTouchRef.current) e.preventDefault();
|
|
131
|
+
},
|
|
132
|
+
children
|
|
133
|
+
}
|
|
134
|
+
),
|
|
135
|
+
/* @__PURE__ */ jsx2(TooltipContent, { side, className: "max-w-xs", children: content })
|
|
136
|
+
] }) });
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// src/components/features/board/board-column-header.tsx
|
|
140
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
141
|
+
function BoardColumnHeader({
|
|
142
|
+
column,
|
|
143
|
+
collapsed = false,
|
|
144
|
+
onToggleCollapse,
|
|
145
|
+
onAddTicket,
|
|
146
|
+
onArchive
|
|
147
|
+
}) {
|
|
148
|
+
const count = column.total ?? column.tickets.length;
|
|
149
|
+
const tagStatus = column.statusKey ?? column.id;
|
|
150
|
+
const useStatusVariant = resolveTicketStatus(tagStatus) !== null;
|
|
151
|
+
const actionClass = "h-8 w-8 p-0 content-md:h-8 content-md:w-8";
|
|
152
|
+
if (collapsed) {
|
|
153
|
+
return /* @__PURE__ */ jsxs2("div", { className: "flex h-full flex-col items-center gap-[var(--spacing-system-xsf)]", children: [
|
|
154
|
+
onToggleCollapse && /* @__PURE__ */ jsx3(
|
|
155
|
+
Button,
|
|
156
|
+
{
|
|
157
|
+
variant: "transparent",
|
|
158
|
+
size: "icon",
|
|
159
|
+
className: actionClass,
|
|
160
|
+
onClick: onToggleCollapse,
|
|
161
|
+
"aria-label": "Expand column",
|
|
162
|
+
children: /* @__PURE__ */ jsx3(Arrow02RightIcon, { className: "h-6 w-6 text-ods-text-secondary" })
|
|
163
|
+
}
|
|
164
|
+
),
|
|
165
|
+
/* @__PURE__ */ jsx3(
|
|
166
|
+
TicketStatusTag,
|
|
167
|
+
{
|
|
168
|
+
status: tagStatus,
|
|
169
|
+
label: column.label,
|
|
170
|
+
color: useStatusVariant ? void 0 : column.color,
|
|
171
|
+
className: "h-auto [writing-mode:vertical-rl]"
|
|
172
|
+
}
|
|
173
|
+
),
|
|
174
|
+
/* @__PURE__ */ jsx3("span", { className: "text-h5", style: { color: column.color }, children: count })
|
|
175
|
+
] });
|
|
176
|
+
}
|
|
177
|
+
return /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-[var(--spacing-system-xsf)]", children: [
|
|
178
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex min-w-0 flex-1 items-center gap-[var(--spacing-system-xsf)]", children: [
|
|
179
|
+
/* @__PURE__ */ jsx3(TicketStatusTag, { status: tagStatus, label: column.label, color: useStatusVariant ? void 0 : column.color }),
|
|
180
|
+
/* @__PURE__ */ jsx3("span", { className: "text-h5", style: useStatusVariant ? void 0 : { color: column.color }, children: count })
|
|
181
|
+
] }),
|
|
182
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex shrink-0 items-center gap-[var(--spacing-system-xxs)]", children: [
|
|
183
|
+
column.tooltip && /* @__PURE__ */ jsx3(TouchFriendlyTooltip, { content: column.tooltip, side: "bottom", children: /* @__PURE__ */ jsx3(Button, { variant: "transparent", size: "icon", className: actionClass, "aria-label": column.tooltip, children: /* @__PURE__ */ jsx3(InfoCircleIcon, { className: "h-6 w-6 text-ods-text-secondary" }) }) }),
|
|
184
|
+
onToggleCollapse && /* @__PURE__ */ jsx3(
|
|
185
|
+
Button,
|
|
186
|
+
{
|
|
187
|
+
variant: "transparent",
|
|
188
|
+
size: "icon",
|
|
189
|
+
className: actionClass,
|
|
190
|
+
onClick: onToggleCollapse,
|
|
191
|
+
"aria-label": "Collapse column",
|
|
192
|
+
children: /* @__PURE__ */ jsx3(Arrow02LeftIcon, { className: "h-6 w-6 text-ods-text-secondary" })
|
|
193
|
+
}
|
|
194
|
+
),
|
|
195
|
+
onArchive && /* @__PURE__ */ jsx3(
|
|
196
|
+
Button,
|
|
197
|
+
{
|
|
198
|
+
variant: "transparent",
|
|
199
|
+
size: "icon",
|
|
200
|
+
className: actionClass,
|
|
201
|
+
onClick: onArchive,
|
|
202
|
+
"aria-label": "Archive resolved tickets",
|
|
203
|
+
children: /* @__PURE__ */ jsx3(BoxArchiveIcon, { className: "h-6 w-6 text-ods-text-secondary" })
|
|
204
|
+
}
|
|
205
|
+
),
|
|
206
|
+
onAddTicket && /* @__PURE__ */ jsx3(
|
|
207
|
+
Button,
|
|
208
|
+
{
|
|
209
|
+
variant: "transparent",
|
|
210
|
+
size: "icon",
|
|
211
|
+
className: actionClass,
|
|
212
|
+
onClick: onAddTicket,
|
|
213
|
+
"aria-label": "Add ticket",
|
|
214
|
+
children: /* @__PURE__ */ jsx3(PlusIcon, { className: "h-6 w-6 text-ods-text-secondary" })
|
|
215
|
+
}
|
|
216
|
+
)
|
|
217
|
+
] })
|
|
218
|
+
] });
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// src/components/features/board/color-utils.ts
|
|
222
|
+
function tintOnDark(hex) {
|
|
223
|
+
const n = parseInt(hex.replace("#", ""), 16);
|
|
224
|
+
const r = n >> 16 & 255;
|
|
225
|
+
const g = n >> 8 & 255;
|
|
226
|
+
const b = n & 255;
|
|
227
|
+
const mix = (c) => Math.round(0.1 * c + 0.9 * 22);
|
|
228
|
+
const toHex = (v) => v.toString(16).padStart(2, "0");
|
|
229
|
+
return `#${toHex(mix(r))}${toHex(mix(g))}${toHex(mix(b))}`;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// src/components/features/board/board-ticket-approval.tsx
|
|
233
|
+
import { useState as useState2 } from "react";
|
|
234
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
235
|
+
function BoardTicketApproval({ pendingApproval, onApprove, onReject }) {
|
|
236
|
+
const [expanded, setExpanded] = useState2(false);
|
|
237
|
+
const { innerRef, containerStyle } = useCollapsible({ expanded });
|
|
238
|
+
const isAdmin = pendingApproval.approvalType === "ADMIN";
|
|
239
|
+
return /* @__PURE__ */ jsxs3("div", { className: "pointer-events-auto flex flex-col", children: [
|
|
240
|
+
/* @__PURE__ */ jsxs3(
|
|
241
|
+
"button",
|
|
242
|
+
{
|
|
243
|
+
type: "button",
|
|
244
|
+
onClick: () => setExpanded((v) => !v),
|
|
245
|
+
"aria-expanded": expanded,
|
|
246
|
+
className: "flex w-full cursor-pointer items-center gap-[var(--spacing-system-xxs)] text-h6",
|
|
247
|
+
children: [
|
|
248
|
+
/* @__PURE__ */ jsxs3(
|
|
249
|
+
"span",
|
|
250
|
+
{
|
|
251
|
+
className: cn(
|
|
252
|
+
"flex min-w-0 flex-1 items-center gap-[var(--spacing-system-xxs)]",
|
|
253
|
+
isAdmin ? "text-ods-open-yellow" : "text-ods-text-secondary"
|
|
254
|
+
),
|
|
255
|
+
children: [
|
|
256
|
+
isAdmin ? /* @__PURE__ */ jsx4(ShieldCheckIcon, { className: "size-4 shrink-0" }) : /* @__PURE__ */ jsx4(DotsLoaderIcon, { size: 16, className: "shrink-0" }),
|
|
257
|
+
/* @__PURE__ */ jsx4("span", { className: "flex-1 truncate text-left", children: isAdmin ? "Technician approval required" : "Pending client approval" })
|
|
258
|
+
]
|
|
259
|
+
}
|
|
260
|
+
),
|
|
261
|
+
expanded ? /* @__PURE__ */ jsx4(Chevron02UpIcon, { className: "size-4 shrink-0 text-ods-text-secondary" }) : /* @__PURE__ */ jsx4(Chevron02DownIcon, { className: "size-4 shrink-0 text-ods-text-secondary" })
|
|
262
|
+
]
|
|
263
|
+
}
|
|
264
|
+
),
|
|
265
|
+
/* @__PURE__ */ jsx4("div", { style: containerStyle, children: /* @__PURE__ */ jsx4("div", { ref: innerRef, className: "pt-[var(--spacing-system-xs)]", children: /* @__PURE__ */ jsx4(
|
|
266
|
+
ApprovalBatchMessage,
|
|
267
|
+
{
|
|
268
|
+
className: "mb-0",
|
|
269
|
+
data: {
|
|
270
|
+
approvalRequestId: pendingApproval.id,
|
|
271
|
+
approvalType: pendingApproval.approvalType ?? "CLIENT",
|
|
272
|
+
toolCalls: pendingApproval.toolCalls ?? []
|
|
273
|
+
},
|
|
274
|
+
status: "pending",
|
|
275
|
+
showExecutionStatus: false,
|
|
276
|
+
onApprove,
|
|
277
|
+
onReject
|
|
278
|
+
}
|
|
279
|
+
) }) })
|
|
280
|
+
] });
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// src/components/features/board/ticket-card.tsx
|
|
284
|
+
import { attachClosestEdge } from "@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge";
|
|
285
|
+
import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine";
|
|
286
|
+
import { draggable, dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
|
|
287
|
+
import { preserveOffsetOnSource } from "@atlaskit/pragmatic-drag-and-drop/element/preserve-offset-on-source";
|
|
288
|
+
import { setCustomNativeDragPreview } from "@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview";
|
|
289
|
+
import {
|
|
290
|
+
memo,
|
|
291
|
+
useCallback as useCallback2,
|
|
292
|
+
useEffect,
|
|
293
|
+
useMemo,
|
|
294
|
+
useRef as useRef3,
|
|
295
|
+
useState as useState3
|
|
296
|
+
} from "react";
|
|
297
|
+
|
|
298
|
+
// src/utils/drag-effect.ts
|
|
299
|
+
function holdMoveDragEffect(element) {
|
|
300
|
+
const onDragStart = (event) => {
|
|
301
|
+
const transfer = event.dataTransfer;
|
|
302
|
+
if (transfer) transfer.effectAllowed = "move";
|
|
303
|
+
};
|
|
304
|
+
element.addEventListener("dragstart", onDragStart);
|
|
305
|
+
return () => element.removeEventListener("dragstart", onDragStart);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// src/components/features/board/drop-aim.ts
|
|
309
|
+
import { createContext, useContext } from "react";
|
|
310
|
+
var DropAimContext = createContext(null);
|
|
311
|
+
var BoardLiftContext = createContext(null);
|
|
312
|
+
function useBoardLift() {
|
|
313
|
+
return useContext(BoardLiftContext);
|
|
314
|
+
}
|
|
315
|
+
function useDropAim() {
|
|
316
|
+
return useContext(DropAimContext);
|
|
317
|
+
}
|
|
318
|
+
function isSameAim(a, b) {
|
|
319
|
+
if (a === b) return true;
|
|
320
|
+
if (!a || !b) return false;
|
|
321
|
+
return a.columnId === b.columnId && a.ticketId === b.ticketId && a.edge === b.edge;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// src/components/features/board/use-lane-scroll-anchor.ts
|
|
325
|
+
import { useRef as useRef2 } from "react";
|
|
326
|
+
var TICKET_ID_ATTRIBUTE = "data-ticket-id";
|
|
327
|
+
function cardPositions(root) {
|
|
328
|
+
return Array.from(root.querySelectorAll(`[${TICKET_ID_ATTRIBUTE}]`)).map((element) => ({
|
|
329
|
+
id: element.getAttribute(TICKET_ID_ATTRIBUTE) ?? "",
|
|
330
|
+
offsetTop: element.offsetTop
|
|
331
|
+
}));
|
|
332
|
+
}
|
|
333
|
+
function useLaneScrollAnchor(scrollRef, tickets) {
|
|
334
|
+
const positionsRef = useRef2([]);
|
|
335
|
+
useIsomorphicLayoutEffect(() => {
|
|
336
|
+
const root = scrollRef.current;
|
|
337
|
+
if (!root) return;
|
|
338
|
+
const previous = positionsRef.current;
|
|
339
|
+
const scrollTop = root.scrollTop;
|
|
340
|
+
const current = cardPositions(root);
|
|
341
|
+
if (previous.length > 0 && scrollTop > 0) {
|
|
342
|
+
const anchor = previous.find((card) => card.offsetTop >= scrollTop) ?? previous[previous.length - 1];
|
|
343
|
+
const moved = current.find((card) => card.id === anchor.id);
|
|
344
|
+
if (moved) {
|
|
345
|
+
const drift = moved.offsetTop - anchor.offsetTop;
|
|
346
|
+
if (Math.abs(drift) >= 1) root.scrollTop = scrollTop + drift;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
positionsRef.current = current;
|
|
350
|
+
}, [tickets]);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// src/components/features/board/lane-geometry.ts
|
|
354
|
+
var DROP_LINE_ATTRIBUTE = "data-board-drop-line";
|
|
355
|
+
function nearestCardIn(lane, pointerY, draggedTicketId) {
|
|
356
|
+
let best = null;
|
|
357
|
+
let bestDistance = Number.POSITIVE_INFINITY;
|
|
358
|
+
for (const card of lane.querySelectorAll(`[${TICKET_ID_ATTRIBUTE}]`)) {
|
|
359
|
+
if (card.dataset.ticketId === draggedTicketId) continue;
|
|
360
|
+
const rect = card.getBoundingClientRect();
|
|
361
|
+
if (rect.height === 0) continue;
|
|
362
|
+
const distance = Math.abs(pointerY - (rect.top + rect.height / 2));
|
|
363
|
+
if (distance < bestDistance) {
|
|
364
|
+
bestDistance = distance;
|
|
365
|
+
best = card;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
return best;
|
|
369
|
+
}
|
|
370
|
+
function cardById(root, ticketId) {
|
|
371
|
+
for (const card of root.querySelectorAll(`[${TICKET_ID_ATTRIBUTE}]`)) {
|
|
372
|
+
if (card.dataset.ticketId === ticketId) return card;
|
|
373
|
+
}
|
|
374
|
+
return null;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// src/components/features/board/pending-move.ts
|
|
378
|
+
import { createContext as createContext2, useContext as useContext2 } from "react";
|
|
379
|
+
function applyPendingMove(columns, move) {
|
|
380
|
+
const ticket = columns.flatMap((column) => column.tickets).find((t) => t.id === move.ticketId);
|
|
381
|
+
if (!ticket || !columns.some((column) => column.id === move.toColumnId)) return columns;
|
|
382
|
+
return columns.map((column) => {
|
|
383
|
+
const without = column.tickets.filter((t) => t.id !== move.ticketId);
|
|
384
|
+
if (column.id !== move.toColumnId) {
|
|
385
|
+
return without.length === column.tickets.length ? column : { ...column, tickets: without };
|
|
386
|
+
}
|
|
387
|
+
return { ...column, tickets: insertAfter(without, ticket, move.afterTicketId) };
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
function insertAfter(tickets, ticket, afterId) {
|
|
391
|
+
if (afterId === null) return [ticket, ...tickets];
|
|
392
|
+
const after = tickets.findIndex((t) => t.id === afterId);
|
|
393
|
+
const at = after < 0 ? tickets.length : after + 1;
|
|
394
|
+
return [...tickets.slice(0, at), ticket, ...tickets.slice(at)];
|
|
395
|
+
}
|
|
396
|
+
var LandingCardContext = createContext2(null);
|
|
397
|
+
function useIsLanding(ticketId) {
|
|
398
|
+
return useContext2(LandingCardContext) === ticketId;
|
|
399
|
+
}
|
|
400
|
+
function hasMoveSettled(columns, move) {
|
|
401
|
+
const tickets = columns.find((c) => c.id === move.toColumnId)?.tickets;
|
|
402
|
+
if (!tickets) return false;
|
|
403
|
+
const index = tickets.findIndex((t) => t.id === move.ticketId);
|
|
404
|
+
if (index < 0) return false;
|
|
405
|
+
if (move.fromColumnId === move.toColumnId) {
|
|
406
|
+
return (tickets[index - 1]?.id ?? null) === move.afterTicketId;
|
|
407
|
+
}
|
|
408
|
+
return !columns.find((c) => c.id === move.fromColumnId)?.tickets.some((t) => t.id === move.ticketId);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// src/components/features/board/ticket-card.tsx
|
|
412
|
+
import { Fragment, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
413
|
+
var PRIORITY_COLOR_CLASS = {
|
|
414
|
+
low: "text-ods-text-secondary",
|
|
415
|
+
medium: "text-ods-info",
|
|
416
|
+
high: "text-ods-warning",
|
|
417
|
+
urgent: "text-ods-error"
|
|
418
|
+
};
|
|
419
|
+
var DRAGGED_CARD_OPACITY = 0.4;
|
|
420
|
+
var DRAG_PREVIEW_OPACITY = 0.9;
|
|
421
|
+
var MAX_VISIBLE_TAGS = 2;
|
|
422
|
+
var MAX_VISIBLE_ASSIGNEES = 3;
|
|
423
|
+
var ACTIVITY_DEFAULT_LABEL = {
|
|
424
|
+
"ai-working": "AI assistant is working",
|
|
425
|
+
"user-typing": "User typing",
|
|
426
|
+
"waiting-external": "Waiting for client response",
|
|
427
|
+
stale: "No activity"
|
|
428
|
+
};
|
|
429
|
+
var TICKET_CARD_SHELL = "relative flex flex-col gap-[var(--spacing-system-sf)] rounded-md border border-ods-border bg-ods-bg p-[var(--spacing-system-sf)] select-none text-left";
|
|
430
|
+
function TicketCardBody({
|
|
431
|
+
ticket,
|
|
432
|
+
columnColor,
|
|
433
|
+
renderAssignSlot,
|
|
434
|
+
onApprove,
|
|
435
|
+
onReject,
|
|
436
|
+
href,
|
|
437
|
+
onLinkClick
|
|
438
|
+
}) {
|
|
439
|
+
const showNewMessage = !!ticket.hasNewMessage && !!columnColor;
|
|
440
|
+
const newMessageTextColor = columnColor ? getReadableTextColor(columnColor) : void 0;
|
|
441
|
+
const showDeviceRow = !!(ticket.deviceHostnames?.length || ticket.organizationName);
|
|
442
|
+
const deviceText = [ticket.deviceHostnames?.join(", "), ticket.organizationName].filter(Boolean).join(", ");
|
|
443
|
+
const hasRightSection = !!(ticket.priority || ticket.agent || ticket.assignees?.length || renderAssignSlot);
|
|
444
|
+
const rightSection = hasRightSection ? /* @__PURE__ */ jsxs4("div", { className: "pointer-events-auto flex shrink-0 items-center gap-[var(--spacing-system-xsf)]", children: [
|
|
445
|
+
ticket.priority && /* @__PURE__ */ jsx5(
|
|
446
|
+
Flag02Icon,
|
|
447
|
+
{
|
|
448
|
+
className: cn("size-4", PRIORITY_COLOR_CLASS[ticket.priority]),
|
|
449
|
+
"aria-label": `Priority: ${ticket.priority}`
|
|
450
|
+
}
|
|
451
|
+
),
|
|
452
|
+
ticket.agent && /* @__PURE__ */ jsx5(
|
|
453
|
+
"span",
|
|
454
|
+
{
|
|
455
|
+
role: "img",
|
|
456
|
+
"aria-label": `Owned by ${ticket.agent === "fae" ? "Fae" : "Mingo"}`,
|
|
457
|
+
className: "flex size-8 shrink-0 items-center justify-center overflow-hidden rounded-full border border-ods-border bg-ods-bg",
|
|
458
|
+
children: /* @__PURE__ */ jsx5(AgentMark, { agent: ticket.agent, className: ticket.agent === "fae" ? "size-full" : "size-5" })
|
|
459
|
+
}
|
|
460
|
+
),
|
|
461
|
+
renderAssignSlot ? renderAssignSlot(ticket) : ticket.assignees?.length ? /* @__PURE__ */ jsxs4("div", { className: "flex -space-x-2", children: [
|
|
462
|
+
ticket.assignees.slice(0, MAX_VISIBLE_ASSIGNEES).map(
|
|
463
|
+
(a) => a.deleted ? /* @__PURE__ */ jsx5(
|
|
464
|
+
DeletedUserAvatar,
|
|
465
|
+
{
|
|
466
|
+
size: "sm",
|
|
467
|
+
accessibleLabel: `Deleted user: ${a.name ?? a.initials ?? a.id}`
|
|
468
|
+
},
|
|
469
|
+
a.id
|
|
470
|
+
) : /* @__PURE__ */ jsx5(
|
|
471
|
+
SquareAvatar,
|
|
472
|
+
{
|
|
473
|
+
src: a.avatarUrl,
|
|
474
|
+
alt: a.name ?? a.initials ?? a.id,
|
|
475
|
+
fallback: a.name ?? a.initials,
|
|
476
|
+
size: "sm",
|
|
477
|
+
variant: "round"
|
|
478
|
+
},
|
|
479
|
+
a.id
|
|
480
|
+
)
|
|
481
|
+
),
|
|
482
|
+
ticket.assignees.length > MAX_VISIBLE_ASSIGNEES && /* @__PURE__ */ jsxs4("div", { className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full border border-ods-border bg-ods-bg text-ods-text-secondary text-h6", children: [
|
|
483
|
+
"+",
|
|
484
|
+
ticket.assignees.length - MAX_VISIBLE_ASSIGNEES
|
|
485
|
+
] })
|
|
486
|
+
] }) : null
|
|
487
|
+
] }) : null;
|
|
488
|
+
const timestampLabel = ticket.createdAt ? formatTicketRelativeTime(ticket.createdAt) : null;
|
|
489
|
+
const tooltipLabel = ticket.createdAt ? formatTicketFullTimestamp(ticket.createdAt) : null;
|
|
490
|
+
const metaLabel = [ticket.ticketNumber || null, timestampLabel].filter(Boolean).join(" \u2022 ");
|
|
491
|
+
const metaClass = "truncate text-ods-text-secondary text-h6";
|
|
492
|
+
const meta = href ? /* @__PURE__ */ jsx5(
|
|
493
|
+
next_link_default,
|
|
494
|
+
{
|
|
495
|
+
href,
|
|
496
|
+
draggable: false,
|
|
497
|
+
prefetch: false,
|
|
498
|
+
tabIndex: -1,
|
|
499
|
+
onClick: onLinkClick,
|
|
500
|
+
className: cn("pointer-events-auto block", metaClass),
|
|
501
|
+
children: metaLabel
|
|
502
|
+
}
|
|
503
|
+
) : /* @__PURE__ */ jsx5("p", { className: cn(tooltipLabel && "pointer-events-auto", metaClass), children: metaLabel });
|
|
504
|
+
return /* @__PURE__ */ jsxs4(Fragment, { children: [
|
|
505
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex items-start gap-[var(--spacing-system-sf)]", children: [
|
|
506
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex min-w-0 flex-1 flex-col gap-[var(--spacing-system-zero)]", title: ticket.title, children: [
|
|
507
|
+
/* @__PURE__ */ jsx5("p", { className: "truncate text-ods-text-primary text-h3", children: ticket.title }),
|
|
508
|
+
showDeviceRow && /* @__PURE__ */ jsxs4("div", { className: "flex min-w-0 items-center gap-[var(--spacing-system-xxs)] text-ods-text-secondary text-h6", children: [
|
|
509
|
+
/* @__PURE__ */ jsx5(LaptopIcon, { className: "size-4 shrink-0" }),
|
|
510
|
+
/* @__PURE__ */ jsx5("span", { className: "truncate", title: deviceText, children: deviceText })
|
|
511
|
+
] })
|
|
512
|
+
] }),
|
|
513
|
+
rightSection
|
|
514
|
+
] }),
|
|
515
|
+
ticket.tags?.length ? /* @__PURE__ */ jsx5(TicketTagRow, { tags: ticket.tags }) : null,
|
|
516
|
+
metaLabel && (tooltipLabel ? /* @__PURE__ */ jsx5(TooltipProvider, { children: /* @__PURE__ */ jsxs4(Tooltip, { children: [
|
|
517
|
+
/* @__PURE__ */ jsx5(TooltipTrigger, { asChild: true, children: meta }),
|
|
518
|
+
/* @__PURE__ */ jsx5(TooltipContent, { children: tooltipLabel })
|
|
519
|
+
] }) }) : meta),
|
|
520
|
+
ticket.escalatedByUser && /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-[var(--spacing-system-xxs)] text-ods-open-yellow text-h6", children: [
|
|
521
|
+
/* @__PURE__ */ jsx5(UserCheckIcon, { className: "size-4 shrink-0" }),
|
|
522
|
+
/* @__PURE__ */ jsx5("span", { className: "truncate", children: "Escalated by User" })
|
|
523
|
+
] }),
|
|
524
|
+
ticket.activity && /* @__PURE__ */ jsxs4(
|
|
525
|
+
"div",
|
|
526
|
+
{
|
|
527
|
+
className: cn(
|
|
528
|
+
"flex items-center gap-[var(--spacing-system-xxs)] text-h6",
|
|
529
|
+
ticket.activity.kind === "stale" ? "text-ods-open-yellow" : "text-ods-text-secondary"
|
|
530
|
+
),
|
|
531
|
+
children: [
|
|
532
|
+
ticket.activity.kind === "stale" ? /* @__PURE__ */ jsx5(ClockIcon, { className: "size-4 shrink-0" }) : /* @__PURE__ */ jsx5(DotsLoaderIcon, { className: "size-4 shrink-0" }),
|
|
533
|
+
/* @__PURE__ */ jsx5("span", { className: "truncate", children: ticket.activity.label ?? ACTIVITY_DEFAULT_LABEL[ticket.activity.kind] })
|
|
534
|
+
]
|
|
535
|
+
}
|
|
536
|
+
),
|
|
537
|
+
showNewMessage && /* @__PURE__ */ jsx5(
|
|
538
|
+
Tag,
|
|
539
|
+
{
|
|
540
|
+
label: "New Message",
|
|
541
|
+
icon: /* @__PURE__ */ jsx5(MessagesIcon, { size: 16, color: newMessageTextColor }),
|
|
542
|
+
className: "w-fit shrink-0",
|
|
543
|
+
style: { backgroundColor: columnColor, color: newMessageTextColor }
|
|
544
|
+
}
|
|
545
|
+
),
|
|
546
|
+
ticket.pendingApproval && /* @__PURE__ */ jsx5(BoardTicketApproval, { pendingApproval: ticket.pendingApproval, onApprove, onReject })
|
|
547
|
+
] });
|
|
548
|
+
}
|
|
549
|
+
function TicketCardView({ className, style, ...bodyProps }) {
|
|
550
|
+
const { ticket, columnColor } = bodyProps;
|
|
551
|
+
const showNewMessage = !!ticket.hasNewMessage && !!columnColor;
|
|
552
|
+
return /* @__PURE__ */ jsx5(
|
|
553
|
+
"div",
|
|
554
|
+
{
|
|
555
|
+
className: cn(TICKET_CARD_SHELL, className),
|
|
556
|
+
style: showNewMessage ? { borderColor: columnColor, ...style } : style,
|
|
557
|
+
children: /* @__PURE__ */ jsx5("div", { className: "relative z-10 flex flex-col gap-[var(--spacing-system-sf)]", children: /* @__PURE__ */ jsx5(TicketCardBody, { ...bodyProps }) })
|
|
558
|
+
}
|
|
559
|
+
);
|
|
560
|
+
}
|
|
561
|
+
var TicketCard = memo(function TicketCardImpl({
|
|
562
|
+
ticket,
|
|
563
|
+
columnId,
|
|
564
|
+
columnColor,
|
|
565
|
+
href,
|
|
566
|
+
dragDisabled,
|
|
567
|
+
dropDisabled,
|
|
568
|
+
allowedFromColumns,
|
|
569
|
+
renderAssignSlot,
|
|
570
|
+
onApprove,
|
|
571
|
+
onReject
|
|
572
|
+
}) {
|
|
573
|
+
const ref = useRef3(null);
|
|
574
|
+
const ticketRef = useRef3(ticket);
|
|
575
|
+
useEffect(() => {
|
|
576
|
+
ticketRef.current = ticket;
|
|
577
|
+
});
|
|
578
|
+
const [isDragging, setIsDragging] = useState3(false);
|
|
579
|
+
const isLanding = useIsLanding(ticket.id);
|
|
580
|
+
const aim = useDropAim();
|
|
581
|
+
const closestEdge = aim && aim.columnId === columnId && aim.ticketId === ticket.id ? aim.edge : null;
|
|
582
|
+
const isSource = isDragging || aim?.ticket.id === ticket.id;
|
|
583
|
+
const lift = useBoardLift();
|
|
584
|
+
const handleKeyDown = (e) => {
|
|
585
|
+
if (e.key !== " " || dragDisabled || !lift) return;
|
|
586
|
+
e.preventDefault();
|
|
587
|
+
lift(ticket.id);
|
|
588
|
+
};
|
|
589
|
+
const keyShortcuts = dragDisabled || !lift ? void 0 : "Space";
|
|
590
|
+
useEffect(() => {
|
|
591
|
+
const element = ref.current;
|
|
592
|
+
if (!element || dragDisabled) return void 0;
|
|
593
|
+
const identity = { type: "ticket", ticketId: ticket.id, columnId };
|
|
594
|
+
return combine(
|
|
595
|
+
// Before anything else: the drag has to start as a "move", or its first
|
|
596
|
+
// frame is drawn with the copy cursor — see `drag-effect.ts`.
|
|
597
|
+
holdMoveDragEffect(element),
|
|
598
|
+
draggable({
|
|
599
|
+
element,
|
|
600
|
+
// Read at drag start rather than captured, so a card renamed or re-tagged
|
|
601
|
+
// since it mounted travels as it is now. No height: it was here for a
|
|
602
|
+
// lane that opened room for the card, and nothing opens room any more —
|
|
603
|
+
// it was costing a forced layout read at the start of every drag to
|
|
604
|
+
// produce a field no one read.
|
|
605
|
+
getInitialData: () => ({ ...identity, ticket: ticketRef.current }),
|
|
606
|
+
/**
|
|
607
|
+
* The card under the pointer is the browser's own drag image, styled by
|
|
608
|
+
* us. Drawing it ourselves as a positioned element was tried and has one
|
|
609
|
+
* unfixable flaw: an element in the page cannot leave the page. Carry a
|
|
610
|
+
* card up towards the address bar and the pointer crosses into the
|
|
611
|
+
* browser's own chrome, where no `dragover` reaches the document — so
|
|
612
|
+
* the card freezes at the top edge and only catches up when the drag
|
|
613
|
+
* ends. A native drag image is moved by the browser itself and floats
|
|
614
|
+
* over everything, which is why Jira's card does not stick there.
|
|
615
|
+
*
|
|
616
|
+
* A clone rather than a second React tree: this is a photograph, taken
|
|
617
|
+
* once, and a copy of the card's own DOM is a photograph of exactly what
|
|
618
|
+
* is on screen — assignee slot and all — with no providers to re-supply
|
|
619
|
+
* and no chance of it rendering a loading state into the picture.
|
|
620
|
+
*/
|
|
621
|
+
onGenerateDragPreview: ({ nativeSetDragImage, location, source }) => {
|
|
622
|
+
const { width } = source.element.getBoundingClientRect();
|
|
623
|
+
setCustomNativeDragPreview({
|
|
624
|
+
nativeSetDragImage,
|
|
625
|
+
// Holds the card under the same part of itself it was grabbed by.
|
|
626
|
+
getOffset: preserveOffsetOnSource({ element: source.element, input: location.current.input }),
|
|
627
|
+
render: ({ container }) => {
|
|
628
|
+
const clone = source.element.cloneNode(true);
|
|
629
|
+
clone.style.width = `${width}px`;
|
|
630
|
+
clone.style.opacity = String(DRAG_PREVIEW_OPACITY);
|
|
631
|
+
clone.classList.add("shadow-card-hover");
|
|
632
|
+
container.appendChild(clone);
|
|
633
|
+
}
|
|
634
|
+
});
|
|
635
|
+
},
|
|
636
|
+
onDragStart: () => setIsDragging(true),
|
|
637
|
+
onDrop: () => setIsDragging(false)
|
|
638
|
+
}),
|
|
639
|
+
dropTargetForElements({
|
|
640
|
+
element,
|
|
641
|
+
canDrop: ({ source }) => {
|
|
642
|
+
if (source.data.type !== "ticket" || source.data.ticketId === ticket.id) return false;
|
|
643
|
+
const from = String(source.data.columnId);
|
|
644
|
+
if (from === columnId) return true;
|
|
645
|
+
if (dropDisabled) return false;
|
|
646
|
+
return !allowedFromColumns || allowedFromColumns.includes(from);
|
|
647
|
+
},
|
|
648
|
+
// The edge rides along in the drop target's own data, so the board reads
|
|
649
|
+
// "above or below this card" straight off the drop it receives.
|
|
650
|
+
getData: ({ input, element: self }) => attachClosestEdge({ ...identity }, { input, element: self, allowedEdges: ["top", "bottom"] }),
|
|
651
|
+
// Sticky, so crossing the gap between two cards — which is lane padding
|
|
652
|
+
// and belongs to no card's box — keeps answering with the card just
|
|
653
|
+
// left, rather than handing the question to the lane for those few
|
|
654
|
+
// pixels and back again. Both answer with the same slot (the lane
|
|
655
|
+
// resolves the nearest card and its edge), so this is about not
|
|
656
|
+
// re-deriving it from a different target every few pixels, NOT about
|
|
657
|
+
// reaching room a card has opened: nothing moves during a drag here.
|
|
658
|
+
getIsSticky: () => true
|
|
659
|
+
})
|
|
660
|
+
);
|
|
661
|
+
}, [ticket.id, columnId, dragDisabled, dropDisabled, allowedFromColumns]);
|
|
662
|
+
const showNewMessage = !!ticket.hasNewMessage && !!columnColor;
|
|
663
|
+
const style = {};
|
|
664
|
+
if (showNewMessage) style.borderColor = columnColor;
|
|
665
|
+
const handleClick = useCallback2(
|
|
666
|
+
(e) => {
|
|
667
|
+
if (isDragging) e.preventDefault();
|
|
668
|
+
},
|
|
669
|
+
[isDragging]
|
|
670
|
+
);
|
|
671
|
+
const body = useMemo(
|
|
672
|
+
() => /* @__PURE__ */ jsx5(
|
|
673
|
+
TicketCardBody,
|
|
674
|
+
{
|
|
675
|
+
ticket,
|
|
676
|
+
columnColor,
|
|
677
|
+
renderAssignSlot,
|
|
678
|
+
onApprove: onApprove ? (requestId) => onApprove(ticket.id, requestId) : void 0,
|
|
679
|
+
onReject: onReject ? (requestId) => onReject(ticket.id, requestId) : void 0,
|
|
680
|
+
href,
|
|
681
|
+
onLinkClick: handleClick
|
|
682
|
+
}
|
|
683
|
+
),
|
|
684
|
+
[ticket, columnColor, renderAssignSlot, onApprove, onReject, href, handleClick]
|
|
685
|
+
);
|
|
686
|
+
const cardClasses = cn(TICKET_CARD_SHELL, !dragDisabled && "cursor-pointer");
|
|
687
|
+
const outerProps = {
|
|
688
|
+
ref,
|
|
689
|
+
style,
|
|
690
|
+
className: cardClasses,
|
|
691
|
+
// Read by the lane's scroll anchor to keep the list still when tickets are
|
|
692
|
+
// inserted above the viewport — see `use-lane-scroll-anchor.ts`.
|
|
693
|
+
[TICKET_ID_ATTRIBUTE]: ticket.id
|
|
694
|
+
};
|
|
695
|
+
const innerWrapperClass = "relative z-10 flex flex-col gap-[var(--spacing-system-sf)]";
|
|
696
|
+
if (isSource) {
|
|
697
|
+
style.opacity = DRAGGED_CARD_OPACITY;
|
|
698
|
+
} else if (isLanding) {
|
|
699
|
+
style.visibility = "hidden";
|
|
700
|
+
}
|
|
701
|
+
const insertionLine = closestEdge ? /* @__PURE__ */ jsx5(
|
|
702
|
+
"span",
|
|
703
|
+
{
|
|
704
|
+
"aria-hidden": true,
|
|
705
|
+
...{ [DROP_LINE_ATTRIBUTE]: "" },
|
|
706
|
+
className: cn(
|
|
707
|
+
// Nothing sticks out sideways or beyond the line's own 2px: the lane
|
|
708
|
+
// scrolls, and a scroll container clips whatever leaves its padding box
|
|
709
|
+
// — an end cap or a knob on this would be cut off against the first and
|
|
710
|
+
// last card in every lane.
|
|
711
|
+
"pointer-events-none absolute inset-x-0 z-10 h-0.5 rounded-full bg-ods-accent",
|
|
712
|
+
// Centred in the lane's own gap, so it reads as sitting between two
|
|
713
|
+
// cards rather than as belonging to one of them. The lane reserves the
|
|
714
|
+
// matching sliver at its ends (see `board-column.tsx`).
|
|
715
|
+
closestEdge === "top" ? "-top-[5px]" : "-bottom-[5px]"
|
|
716
|
+
)
|
|
717
|
+
}
|
|
718
|
+
) : null;
|
|
719
|
+
if (href) {
|
|
720
|
+
return /* @__PURE__ */ jsxs4("div", { ...outerProps, children: [
|
|
721
|
+
insertionLine,
|
|
722
|
+
/* @__PURE__ */ jsx5(
|
|
723
|
+
next_link_default,
|
|
724
|
+
{
|
|
725
|
+
href,
|
|
726
|
+
draggable: false,
|
|
727
|
+
prefetch: false,
|
|
728
|
+
onClick: handleClick,
|
|
729
|
+
onKeyDown: handleKeyDown,
|
|
730
|
+
"aria-label": ticket.title,
|
|
731
|
+
"aria-keyshortcuts": keyShortcuts,
|
|
732
|
+
className: "absolute inset-0 z-0 rounded-md focus-visible:outline-none"
|
|
733
|
+
}
|
|
734
|
+
),
|
|
735
|
+
/* @__PURE__ */ jsx5("div", { className: cn("pointer-events-none", innerWrapperClass), children: body })
|
|
736
|
+
] });
|
|
737
|
+
}
|
|
738
|
+
return /* @__PURE__ */ jsxs4("div", { ...outerProps, children: [
|
|
739
|
+
insertionLine,
|
|
740
|
+
/* @__PURE__ */ jsx5(
|
|
741
|
+
"button",
|
|
742
|
+
{
|
|
743
|
+
type: "button",
|
|
744
|
+
onClick: handleClick,
|
|
745
|
+
onKeyDown: handleKeyDown,
|
|
746
|
+
"aria-label": ticket.title,
|
|
747
|
+
"aria-keyshortcuts": keyShortcuts,
|
|
748
|
+
className: "absolute inset-0 z-0 cursor-pointer rounded-md focus-visible:outline-none"
|
|
749
|
+
}
|
|
750
|
+
),
|
|
751
|
+
/* @__PURE__ */ jsx5("div", { className: cn("pointer-events-none", innerWrapperClass), children: body })
|
|
752
|
+
] });
|
|
753
|
+
});
|
|
754
|
+
function TicketTagRow({ tags }) {
|
|
755
|
+
const visible = tags.slice(0, MAX_VISIBLE_TAGS);
|
|
756
|
+
const hidden = tags.length - visible.length;
|
|
757
|
+
return /* @__PURE__ */ jsxs4("div", { className: "flex h-8 flex-wrap items-start gap-[var(--spacing-system-xxs)] overflow-clip", children: [
|
|
758
|
+
visible.map((tag) => /* @__PURE__ */ jsx5(Tag, { variant: "outline", label: tag }, tag)),
|
|
759
|
+
hidden > 0 && /* @__PURE__ */ jsx5(Tag, { variant: "outline", label: `+${hidden}` })
|
|
760
|
+
] });
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
// src/components/features/board/ticket-card-skeleton.tsx
|
|
764
|
+
import { forwardRef } from "react";
|
|
765
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
766
|
+
var TicketCardSkeleton = forwardRef(
|
|
767
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsxs5(
|
|
768
|
+
"div",
|
|
769
|
+
{
|
|
770
|
+
ref,
|
|
771
|
+
className: cn(
|
|
772
|
+
"flex flex-col gap-[var(--spacing-system-sf)] rounded-md border border-ods-border bg-ods-bg p-[var(--spacing-system-sf)]",
|
|
773
|
+
className
|
|
774
|
+
),
|
|
775
|
+
...props,
|
|
776
|
+
children: [
|
|
777
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex items-start gap-[var(--spacing-system-sf)]", children: [
|
|
778
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex min-w-0 flex-1 flex-col gap-[var(--spacing-system-xxs)]", children: [
|
|
779
|
+
/* @__PURE__ */ jsx6("div", { className: "flex items-center text-h3", children: /* @__PURE__ */ jsx6(Skeleton, { className: "h-4 w-3/4" }) }),
|
|
780
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-[var(--spacing-system-xxs)] text-h6", children: [
|
|
781
|
+
/* @__PURE__ */ jsx6(Skeleton, { className: "size-4 shrink-0 rounded-sm" }),
|
|
782
|
+
/* @__PURE__ */ jsx6(Skeleton, { className: "h-3 w-1/2" })
|
|
783
|
+
] })
|
|
784
|
+
] }),
|
|
785
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex shrink-0 items-center gap-[var(--spacing-system-xsf)]", children: [
|
|
786
|
+
/* @__PURE__ */ jsx6(Skeleton, { className: "size-4 rounded-sm" }),
|
|
787
|
+
/* @__PURE__ */ jsx6(Skeleton, { className: "size-8 rounded-full" })
|
|
788
|
+
] })
|
|
789
|
+
] }),
|
|
790
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex h-8 items-center gap-[var(--spacing-system-xxs)]", children: [
|
|
791
|
+
/* @__PURE__ */ jsx6(Skeleton, { className: "h-8 w-16 rounded-md" }),
|
|
792
|
+
/* @__PURE__ */ jsx6(Skeleton, { className: "h-8 w-12 rounded-md" })
|
|
793
|
+
] })
|
|
794
|
+
]
|
|
795
|
+
}
|
|
796
|
+
)
|
|
797
|
+
);
|
|
798
|
+
TicketCardSkeleton.displayName = "TicketCardSkeleton";
|
|
799
|
+
|
|
800
|
+
// src/components/features/board/board-column.tsx
|
|
801
|
+
import { attachClosestEdge as attachClosestEdge2 } from "@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge";
|
|
802
|
+
import { dropTargetForElements as dropTargetForElements2 } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
|
|
803
|
+
import { memo as memo2, useCallback as useCallback3, useEffect as useEffect2, useRef as useRef4, useState as useState4 } from "react";
|
|
804
|
+
|
|
805
|
+
// src/utils/auto-scroll-ancestors.ts
|
|
806
|
+
import {
|
|
807
|
+
autoScrollForElements,
|
|
808
|
+
autoScrollWindowForElements
|
|
809
|
+
} from "@atlaskit/pragmatic-drag-and-drop-auto-scroll/element";
|
|
810
|
+
import { unsafeOverflowAutoScrollForElements } from "@atlaskit/pragmatic-drag-and-drop-auto-scroll/unsafe-overflow/element";
|
|
811
|
+
import { combine as combine2 } from "@atlaskit/pragmatic-drag-and-drop/combine";
|
|
812
|
+
|
|
813
|
+
// src/utils/scroll-parent.ts
|
|
814
|
+
var SCROLLABLE = /(auto|scroll|overlay)/;
|
|
815
|
+
function scrollableAncestorsOf(element) {
|
|
816
|
+
const found = [];
|
|
817
|
+
for (let node = element.parentElement; node && node !== document.body; node = node.parentElement) {
|
|
818
|
+
const style = getComputedStyle(node);
|
|
819
|
+
if (SCROLLABLE.test(style.overflowY) || SCROLLABLE.test(style.overflowX)) found.push(node);
|
|
820
|
+
}
|
|
821
|
+
return found;
|
|
822
|
+
}
|
|
823
|
+
function nearestScrollableAncestor(element) {
|
|
824
|
+
return scrollableAncestorsOf(element)[0] ?? null;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
// src/utils/auto-scroll-ancestors.ts
|
|
828
|
+
var OVERFLOW_REACH = 5e3;
|
|
829
|
+
var overflow = () => ({
|
|
830
|
+
forTopEdge: { top: OVERFLOW_REACH, left: OVERFLOW_REACH, right: OVERFLOW_REACH },
|
|
831
|
+
forBottomEdge: { bottom: OVERFLOW_REACH, left: OVERFLOW_REACH, right: OVERFLOW_REACH },
|
|
832
|
+
forLeftEdge: { left: OVERFLOW_REACH, top: OVERFLOW_REACH, bottom: OVERFLOW_REACH },
|
|
833
|
+
forRightEdge: { right: OVERFLOW_REACH, top: OVERFLOW_REACH, bottom: OVERFLOW_REACH }
|
|
834
|
+
});
|
|
835
|
+
var verticalOverflow = () => ({
|
|
836
|
+
forTopEdge: { top: OVERFLOW_REACH },
|
|
837
|
+
forBottomEdge: { bottom: OVERFLOW_REACH }
|
|
838
|
+
});
|
|
839
|
+
function autoScrollBothWays(element) {
|
|
840
|
+
return combine2(
|
|
841
|
+
autoScrollForElements({ element }),
|
|
842
|
+
unsafeOverflowAutoScrollForElements({ element, getOverflow: overflow })
|
|
843
|
+
);
|
|
844
|
+
}
|
|
845
|
+
function autoScrollColumn(element) {
|
|
846
|
+
return combine2(
|
|
847
|
+
autoScrollForElements({ element }),
|
|
848
|
+
unsafeOverflowAutoScrollForElements({ element, getOverflow: verticalOverflow })
|
|
849
|
+
);
|
|
850
|
+
}
|
|
851
|
+
function autoScrollAncestors(element) {
|
|
852
|
+
const cleanups = scrollableAncestorsOf(element).map(autoScrollBothWays);
|
|
853
|
+
cleanups.push(autoScrollWindowForElements());
|
|
854
|
+
return combine2(...cleanups);
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
// src/components/features/board/board-column.tsx
|
|
858
|
+
import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
859
|
+
var BoardColumn = memo2(function BoardColumnImpl({
|
|
860
|
+
column,
|
|
861
|
+
collapsed = false,
|
|
862
|
+
onToggleCollapse,
|
|
863
|
+
onAddTicket,
|
|
864
|
+
onArchive,
|
|
865
|
+
getTicketHref,
|
|
866
|
+
renderAssignSlot,
|
|
867
|
+
onApprove,
|
|
868
|
+
onReject,
|
|
869
|
+
onLoadMore,
|
|
870
|
+
loadMoreRootMargin = "200px 0px",
|
|
871
|
+
joinLeft = false,
|
|
872
|
+
joinRight = false,
|
|
873
|
+
touchMode = false,
|
|
874
|
+
className
|
|
875
|
+
}) {
|
|
876
|
+
const laneRef = useRef4(null);
|
|
877
|
+
const [isOver, setIsOver] = useState4(false);
|
|
878
|
+
useEffect2(() => {
|
|
879
|
+
const element = laneRef.current;
|
|
880
|
+
if (!element || collapsed || touchMode || column.dropDisabled) return void 0;
|
|
881
|
+
return dropTargetForElements2({
|
|
882
|
+
element,
|
|
883
|
+
canDrop: ({ source }) => {
|
|
884
|
+
if (source.data.type !== "ticket") return false;
|
|
885
|
+
const from = source.data.columnId;
|
|
886
|
+
if (from === column.id) return true;
|
|
887
|
+
return !column.allowedFromColumns || column.allowedFromColumns.includes(String(from));
|
|
888
|
+
},
|
|
889
|
+
// A drop that lands between cards — most of the lane, once a hovered card
|
|
890
|
+
// has opened the room the preview is drawn in — answers with the nearest
|
|
891
|
+
// card and the edge of it the pointer is on, exactly as that card would
|
|
892
|
+
// have. Reporting a bare lane instead sent the ticket to the BOTTOM of the
|
|
893
|
+
// column, which is what made small moves look like they had not worked and
|
|
894
|
+
// large ones like the only thing that did.
|
|
895
|
+
getData: ({ input, element: lane, source }) => {
|
|
896
|
+
const nearest = nearestCardIn(lane, input.clientY, String(source.data.ticketId));
|
|
897
|
+
const ticketId = nearest?.dataset.ticketId;
|
|
898
|
+
if (!nearest || !ticketId) return { type: "column", columnId: column.id };
|
|
899
|
+
return attachClosestEdge2(
|
|
900
|
+
{ type: "ticket", ticketId, columnId: column.id },
|
|
901
|
+
{ input, element: nearest, allowedEdges: ["top", "bottom"] }
|
|
902
|
+
);
|
|
903
|
+
},
|
|
904
|
+
onDragEnter: () => setIsOver(true),
|
|
905
|
+
onDragLeave: () => setIsOver(false),
|
|
906
|
+
onDrop: () => setIsOver(false)
|
|
907
|
+
});
|
|
908
|
+
}, [column.id, column.dropDisabled, column.allowedFromColumns, collapsed, touchMode]);
|
|
909
|
+
const handleToggleCollapse = useCallback3(() => onToggleCollapse?.(column.id), [onToggleCollapse, column.id]);
|
|
910
|
+
return /* @__PURE__ */ jsxs6(
|
|
911
|
+
"div",
|
|
912
|
+
{
|
|
913
|
+
ref: laneRef,
|
|
914
|
+
className: cn(
|
|
915
|
+
"flex h-full shrink-0 flex-col gap-[var(--spacing-system-sf)] overflow-hidden rounded-md border border-ods-border p-[var(--spacing-system-sf)]",
|
|
916
|
+
"transition-[width] duration-300 ease-out",
|
|
917
|
+
collapsed ? "w-14" : "w-[400px]",
|
|
918
|
+
column.system && "bg-ods-card",
|
|
919
|
+
joinLeft && "rounded-l-none border-l-0",
|
|
920
|
+
joinRight && "rounded-r-none",
|
|
921
|
+
isOver && "outline outline-2 -outline-offset-2 outline-ods-focus",
|
|
922
|
+
className
|
|
923
|
+
),
|
|
924
|
+
style: column.system ? void 0 : { backgroundColor: tintOnDark(column.color) },
|
|
925
|
+
children: [
|
|
926
|
+
/* @__PURE__ */ jsx7(
|
|
927
|
+
BoardColumnHeader,
|
|
928
|
+
{
|
|
929
|
+
column,
|
|
930
|
+
collapsed,
|
|
931
|
+
onToggleCollapse: onToggleCollapse ? handleToggleCollapse : void 0,
|
|
932
|
+
onAddTicket: !collapsed && onAddTicket ? () => onAddTicket(column.id) : void 0,
|
|
933
|
+
onArchive: !collapsed && column.archivable && onArchive ? () => onArchive(column.id) : void 0
|
|
934
|
+
}
|
|
935
|
+
),
|
|
936
|
+
!collapsed && /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
937
|
+
/* @__PURE__ */ jsx7("div", { "aria-hidden": true, className: "-mx-[var(--spacing-system-sf)] h-px shrink-0 bg-ods-border" }),
|
|
938
|
+
/* @__PURE__ */ jsx7(
|
|
939
|
+
ColumnBody,
|
|
940
|
+
{
|
|
941
|
+
column,
|
|
942
|
+
getTicketHref,
|
|
943
|
+
renderAssignSlot,
|
|
944
|
+
onApprove,
|
|
945
|
+
onReject,
|
|
946
|
+
onLoadMore,
|
|
947
|
+
loadMoreRootMargin,
|
|
948
|
+
touchMode
|
|
949
|
+
}
|
|
950
|
+
)
|
|
951
|
+
] })
|
|
952
|
+
]
|
|
953
|
+
}
|
|
954
|
+
);
|
|
955
|
+
});
|
|
956
|
+
function ColumnBody({
|
|
957
|
+
column,
|
|
958
|
+
getTicketHref,
|
|
959
|
+
renderAssignSlot,
|
|
960
|
+
onApprove,
|
|
961
|
+
onReject,
|
|
962
|
+
onLoadMore,
|
|
963
|
+
loadMoreRootMargin,
|
|
964
|
+
touchMode
|
|
965
|
+
}) {
|
|
966
|
+
const scrollRef = useRef4(null);
|
|
967
|
+
const sentinelRef = useRef4(null);
|
|
968
|
+
useLaneScrollAnchor(scrollRef, column.tickets);
|
|
969
|
+
useEffect2(() => {
|
|
970
|
+
const element = scrollRef.current;
|
|
971
|
+
if (!element || touchMode) return void 0;
|
|
972
|
+
return autoScrollColumn(element);
|
|
973
|
+
}, [touchMode]);
|
|
974
|
+
const loadMoreRef = useRef4(onLoadMore);
|
|
975
|
+
const columnIdRef = useRef4(column.id);
|
|
976
|
+
useEffect2(() => {
|
|
977
|
+
loadMoreRef.current = onLoadMore;
|
|
978
|
+
columnIdRef.current = column.id;
|
|
979
|
+
});
|
|
980
|
+
useEffect2(() => {
|
|
981
|
+
if (!column.hasMore || column.isLoadingMore) return void 0;
|
|
982
|
+
const sentinel = sentinelRef.current;
|
|
983
|
+
const root = scrollRef.current;
|
|
984
|
+
if (!sentinel || !root || !loadMoreRef.current) return void 0;
|
|
985
|
+
const observer = new IntersectionObserver(
|
|
986
|
+
(entries) => {
|
|
987
|
+
if (entries.some((e) => e.isIntersecting)) {
|
|
988
|
+
loadMoreRef.current?.(columnIdRef.current);
|
|
989
|
+
}
|
|
990
|
+
},
|
|
991
|
+
{ root, rootMargin: loadMoreRootMargin }
|
|
992
|
+
);
|
|
993
|
+
observer.observe(sentinel);
|
|
994
|
+
return () => observer.disconnect();
|
|
995
|
+
}, [column.hasMore, column.isLoadingMore, loadMoreRootMargin]);
|
|
996
|
+
return (
|
|
997
|
+
// `overflow-anchor:none` hands scroll anchoring to `useLaneScrollAnchor`
|
|
998
|
+
// wholesale. The browser's own anchoring is unusable here — it silently
|
|
999
|
+
// skips transformed elements, so it works between drags and does nothing
|
|
1000
|
+
// during one — and leaving both on double-corrects every insertion.
|
|
1001
|
+
/* @__PURE__ */ jsxs6(
|
|
1002
|
+
"div",
|
|
1003
|
+
{
|
|
1004
|
+
ref: scrollRef,
|
|
1005
|
+
className: "flex min-h-0 flex-1 flex-col gap-[var(--spacing-system-xs)] overflow-y-auto py-[5px] [overflow-anchor:none]",
|
|
1006
|
+
children: [
|
|
1007
|
+
column.isLoading ? /* @__PURE__ */ jsx7(SkeletonStack, {}) : column.tickets.length === 0 ? /* @__PURE__ */ jsx7(EmptyState, { columnId: column.id, touchMode }) : column.tickets.map((t) => /* @__PURE__ */ jsx7(
|
|
1008
|
+
TicketCard,
|
|
1009
|
+
{
|
|
1010
|
+
ticket: t,
|
|
1011
|
+
columnId: column.id,
|
|
1012
|
+
columnColor: column.color,
|
|
1013
|
+
href: getTicketHref?.(t.id),
|
|
1014
|
+
renderAssignSlot,
|
|
1015
|
+
onApprove,
|
|
1016
|
+
onReject,
|
|
1017
|
+
dragDisabled: touchMode || column.dragDisabled,
|
|
1018
|
+
dropDisabled: touchMode || column.dropDisabled,
|
|
1019
|
+
allowedFromColumns: column.allowedFromColumns
|
|
1020
|
+
},
|
|
1021
|
+
t.id
|
|
1022
|
+
)),
|
|
1023
|
+
column.isLoadingMore && !column.isLoading && /* @__PURE__ */ jsx7(TicketCardSkeleton, {}),
|
|
1024
|
+
column.hasMore && /* @__PURE__ */ jsx7("div", { ref: sentinelRef, "aria-hidden": true, className: "h-1 shrink-0" })
|
|
1025
|
+
]
|
|
1026
|
+
}
|
|
1027
|
+
)
|
|
1028
|
+
);
|
|
1029
|
+
}
|
|
1030
|
+
function SkeletonStack({ count = 4 }) {
|
|
1031
|
+
return /* @__PURE__ */ jsx7(Fragment2, { children: Array.from({ length: count }, (_, i) => /* @__PURE__ */ jsx7(TicketCardSkeleton, {}, `skeleton-${i}`)) });
|
|
1032
|
+
}
|
|
1033
|
+
function EmptyState({ columnId, touchMode }) {
|
|
1034
|
+
const aim = useDropAim();
|
|
1035
|
+
if (aim && aim.columnId === columnId) {
|
|
1036
|
+
return /* @__PURE__ */ jsx7("div", { "aria-hidden": true, ...{ [DROP_LINE_ATTRIBUTE]: "" }, className: "h-0.5 shrink-0 rounded-full bg-ods-accent" });
|
|
1037
|
+
}
|
|
1038
|
+
return /* @__PURE__ */ jsxs6("div", { className: "flex flex-1 flex-col items-center justify-center gap-[var(--spacing-system-lf)] p-[var(--spacing-system-lf)] text-center text-ods-text-secondary", children: [
|
|
1039
|
+
/* @__PURE__ */ jsx7(TagIcon, { className: "h-6 w-6 shrink-0" }),
|
|
1040
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex w-full flex-col", children: [
|
|
1041
|
+
/* @__PURE__ */ jsx7("p", { className: "text-h4", children: "No tickets here" }),
|
|
1042
|
+
/* @__PURE__ */ jsx7("p", { className: "text-h6", children: touchMode ? "Change a ticket's status to move it to this column" : "Drag a ticket here or change its status to move it to this column" })
|
|
1043
|
+
] })
|
|
1044
|
+
] });
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
// src/components/features/board/use-board-collapse.ts
|
|
1048
|
+
import { useCallback as useCallback4, useEffect as useEffect3, useRef as useRef5, useState as useState5 } from "react";
|
|
1049
|
+
function useBoardCollapse(storageKey, initial) {
|
|
1050
|
+
const [persisted, setPersisted] = useLocalStorage(storageKey ?? "__board_collapse_unused__", {});
|
|
1051
|
+
const [memory, setMemory] = useState5(initial ?? {});
|
|
1052
|
+
const collapsed = storageKey ? persisted : memory;
|
|
1053
|
+
const setMap = storageKey ? setPersisted : setMemory;
|
|
1054
|
+
const setMapRef = useRef5(setMap);
|
|
1055
|
+
useEffect3(() => {
|
|
1056
|
+
setMapRef.current = setMap;
|
|
1057
|
+
});
|
|
1058
|
+
const toggle = useCallback4((columnId) => {
|
|
1059
|
+
setMapRef.current((prev) => ({ ...prev, [columnId]: !prev[columnId] }));
|
|
1060
|
+
}, []);
|
|
1061
|
+
const setCollapsed = useCallback4((columnId, value) => {
|
|
1062
|
+
setMapRef.current((prev) => ({ ...prev, [columnId]: value }));
|
|
1063
|
+
}, []);
|
|
1064
|
+
return { collapsed, toggle, setCollapsed };
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
// src/components/features/board/board.tsx
|
|
1068
|
+
import { combine as combine3 } from "@atlaskit/pragmatic-drag-and-drop/combine";
|
|
1069
|
+
import { monitorForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
|
|
1070
|
+
import { preventUnhandled } from "@atlaskit/pragmatic-drag-and-drop/utils/prevent-unhandled";
|
|
1071
|
+
import { Fragment as Fragment3, useCallback as useCallback5, useEffect as useEffect4, useMemo as useMemo2, useRef as useRef6, useState as useState6 } from "react";
|
|
1072
|
+
import { createPortal } from "react-dom";
|
|
1073
|
+
|
|
1074
|
+
// src/components/features/board/aim.ts
|
|
1075
|
+
import { extractClosestEdge } from "@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge";
|
|
1076
|
+
var othersIn = (columns, columnId, ticketId) => (columns.find((c) => c.id === columnId)?.tickets ?? []).filter((t) => t.id !== ticketId);
|
|
1077
|
+
function laneOf(columns, ticketId) {
|
|
1078
|
+
return columns.find((c) => c.tickets.some((t) => t.id === ticketId)) ?? null;
|
|
1079
|
+
}
|
|
1080
|
+
function initialAim(columns, ticketId) {
|
|
1081
|
+
const lane = laneOf(columns, ticketId);
|
|
1082
|
+
if (!lane) return null;
|
|
1083
|
+
return { columnId: lane.id, index: lane.tickets.findIndex((t) => t.id === ticketId) };
|
|
1084
|
+
}
|
|
1085
|
+
function aimFromTarget(columns, ticketId, target) {
|
|
1086
|
+
const columnId = String(target.columnId);
|
|
1087
|
+
if (!columns.some((c) => c.id === columnId)) return null;
|
|
1088
|
+
const others = othersIn(columns, columnId, ticketId);
|
|
1089
|
+
if (target.type !== "ticket") return { columnId, index: others.length };
|
|
1090
|
+
const over = others.findIndex((t) => t.id === String(target.ticketId));
|
|
1091
|
+
if (over < 0) return { columnId, index: others.length };
|
|
1092
|
+
return { columnId, index: over + (extractClosestEdge(target) === "bottom" ? 1 : 0) };
|
|
1093
|
+
}
|
|
1094
|
+
function moveAim(columns, ticketId, aim, key, accepts) {
|
|
1095
|
+
if (key === "ArrowUp" || key === "ArrowDown") {
|
|
1096
|
+
const limit = othersIn(columns, aim.columnId, ticketId).length;
|
|
1097
|
+
const index = Math.min(Math.max(aim.index + (key === "ArrowUp" ? -1 : 1), 0), limit);
|
|
1098
|
+
return index === aim.index ? aim : { ...aim, index };
|
|
1099
|
+
}
|
|
1100
|
+
const step = key === "ArrowLeft" ? -1 : 1;
|
|
1101
|
+
const from = columns.findIndex((c) => c.id === aim.columnId);
|
|
1102
|
+
for (let i = from + step; i >= 0 && i < columns.length; i += step) {
|
|
1103
|
+
const column = columns[i];
|
|
1104
|
+
if (!accepts(column)) continue;
|
|
1105
|
+
const limit = othersIn(columns, column.id, ticketId).length;
|
|
1106
|
+
return { columnId: column.id, index: Math.min(aim.index, limit) };
|
|
1107
|
+
}
|
|
1108
|
+
return aim;
|
|
1109
|
+
}
|
|
1110
|
+
function aimAnchor(columns, ticketId, aim) {
|
|
1111
|
+
const others = othersIn(columns, aim.columnId, ticketId);
|
|
1112
|
+
if (others.length === 0) return { ticketId: null, edge: null };
|
|
1113
|
+
if (aim.index < others.length) return { ticketId: others[aim.index].id, edge: "top" };
|
|
1114
|
+
return { ticketId: others[others.length - 1].id, edge: "bottom" };
|
|
1115
|
+
}
|
|
1116
|
+
function aimToChange(columns, ticketId, aim) {
|
|
1117
|
+
const lane = laneOf(columns, ticketId);
|
|
1118
|
+
if (!lane) return null;
|
|
1119
|
+
const others = othersIn(columns, aim.columnId, ticketId);
|
|
1120
|
+
const afterTicketId = others[aim.index - 1]?.id ?? null;
|
|
1121
|
+
const beforeTicketId = others[aim.index]?.id ?? null;
|
|
1122
|
+
if (lane.id === aim.columnId) {
|
|
1123
|
+
const currentIndex = lane.tickets.findIndex((t) => t.id === ticketId);
|
|
1124
|
+
if ((lane.tickets[currentIndex - 1]?.id ?? null) === afterTicketId) return null;
|
|
1125
|
+
}
|
|
1126
|
+
return { ticketId, fromColumnId: lane.id, toColumnId: aim.columnId, afterTicketId, beforeTicketId };
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
// src/components/features/board/resolve-drop.ts
|
|
1130
|
+
function resolveBoardDrop(columns, { source, target }) {
|
|
1131
|
+
if (!target) return null;
|
|
1132
|
+
const ticketId = String(source.ticketId);
|
|
1133
|
+
const aim = aimFromTarget(columns, ticketId, target);
|
|
1134
|
+
return aim && aimToChange(columns, ticketId, aim);
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
// src/components/features/board/touch-board.tsx
|
|
1138
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
1139
|
+
function TouchBoard({
|
|
1140
|
+
columns,
|
|
1141
|
+
onLoadMore,
|
|
1142
|
+
onAddTicket,
|
|
1143
|
+
onArchiveColumn,
|
|
1144
|
+
getTicketHref,
|
|
1145
|
+
renderAssignSlot,
|
|
1146
|
+
onApprove,
|
|
1147
|
+
onReject,
|
|
1148
|
+
collapseStorageKey,
|
|
1149
|
+
initialCollapsed,
|
|
1150
|
+
loadMoreRootMargin,
|
|
1151
|
+
className
|
|
1152
|
+
}) {
|
|
1153
|
+
const { collapsed, toggle } = useBoardCollapse(collapseStorageKey, initialCollapsed);
|
|
1154
|
+
return /* @__PURE__ */ jsx8("div", { className: cn("flex h-full min-h-0 flex-col", className), children: /* @__PURE__ */ jsx8(
|
|
1155
|
+
"div",
|
|
1156
|
+
{
|
|
1157
|
+
className: "flex min-h-0 flex-1 snap-x snap-mandatory gap-[var(--spacing-system-mf)] overflow-x-auto overscroll-x-contain [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
|
|
1158
|
+
children: columns.map((column) => /* @__PURE__ */ jsx8(
|
|
1159
|
+
BoardColumn,
|
|
1160
|
+
{
|
|
1161
|
+
column,
|
|
1162
|
+
touchMode: true,
|
|
1163
|
+
collapsed: !!collapsed[column.id],
|
|
1164
|
+
onToggleCollapse: toggle,
|
|
1165
|
+
className: cn(
|
|
1166
|
+
"snap-start",
|
|
1167
|
+
!collapsed[column.id] && "w-[min(400px,calc(100%_-_2*var(--spacing-system-mf)))]"
|
|
1168
|
+
),
|
|
1169
|
+
onAddTicket,
|
|
1170
|
+
onArchive: onArchiveColumn,
|
|
1171
|
+
getTicketHref,
|
|
1172
|
+
renderAssignSlot,
|
|
1173
|
+
onApprove,
|
|
1174
|
+
onReject,
|
|
1175
|
+
onLoadMore,
|
|
1176
|
+
loadMoreRootMargin
|
|
1177
|
+
},
|
|
1178
|
+
column.id
|
|
1179
|
+
))
|
|
1180
|
+
}
|
|
1181
|
+
) });
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
// src/components/features/board/board.tsx
|
|
1185
|
+
import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1186
|
+
var PENDING_MOVE_TIMEOUT_MS = 2e3;
|
|
1187
|
+
var DROP_MS = 160;
|
|
1188
|
+
var DROP_EASING = "cubic-bezier(0.2, 0, 0, 1)";
|
|
1189
|
+
var DRAG_PREVIEW_Z = 1200;
|
|
1190
|
+
var ARROW_KEYS = ["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"];
|
|
1191
|
+
function Board(props) {
|
|
1192
|
+
const dragAndDropEnabled = useMediaQuery(DRAG_AND_DROP_MEDIA_QUERY);
|
|
1193
|
+
if (dragAndDropEnabled === void 0) {
|
|
1194
|
+
return /* @__PURE__ */ jsx9("div", { "aria-hidden": true, className: cn("flex h-full min-h-0 flex-col", props.className) });
|
|
1195
|
+
}
|
|
1196
|
+
return dragAndDropEnabled ? /* @__PURE__ */ jsx9(DragBoard, { ...props }) : /* @__PURE__ */ jsx9(TouchBoard, { ...props });
|
|
1197
|
+
}
|
|
1198
|
+
function DragBoard({
|
|
1199
|
+
columns,
|
|
1200
|
+
onChange,
|
|
1201
|
+
onLoadMore,
|
|
1202
|
+
onAddTicket,
|
|
1203
|
+
onArchiveColumn,
|
|
1204
|
+
getTicketHref,
|
|
1205
|
+
renderAssignSlot,
|
|
1206
|
+
onApprove,
|
|
1207
|
+
onReject,
|
|
1208
|
+
collapseStorageKey,
|
|
1209
|
+
initialCollapsed,
|
|
1210
|
+
loadMoreRootMargin,
|
|
1211
|
+
className
|
|
1212
|
+
}) {
|
|
1213
|
+
const { collapsed, toggle } = useBoardCollapse(collapseStorageKey, initialCollapsed);
|
|
1214
|
+
const {
|
|
1215
|
+
scrollRef,
|
|
1216
|
+
trackRef,
|
|
1217
|
+
thumbRef,
|
|
1218
|
+
thumbRatio,
|
|
1219
|
+
onScroll,
|
|
1220
|
+
onTrackClick,
|
|
1221
|
+
onTrackWheel,
|
|
1222
|
+
onThumbPointerDown,
|
|
1223
|
+
onThumbPointerMove,
|
|
1224
|
+
onThumbPointerUp,
|
|
1225
|
+
onThumbPointerCancel
|
|
1226
|
+
} = useHorizontalScrollbar();
|
|
1227
|
+
const columnsRef = useRef6(columns);
|
|
1228
|
+
const onChangeRef = useRef6(onChange);
|
|
1229
|
+
const boardRef = useRef6(null);
|
|
1230
|
+
const scrollerRef = useRef6(null);
|
|
1231
|
+
const setScroller = useCallback5(
|
|
1232
|
+
(node) => {
|
|
1233
|
+
scrollerRef.current = node;
|
|
1234
|
+
scrollRef(node);
|
|
1235
|
+
},
|
|
1236
|
+
[scrollRef]
|
|
1237
|
+
);
|
|
1238
|
+
const [aim, setAim] = useState6(null);
|
|
1239
|
+
const [lifted, setLifted] = useState6(null);
|
|
1240
|
+
const [announcement, setAnnouncement] = useState6("");
|
|
1241
|
+
const dragGeometry = useRef6(null);
|
|
1242
|
+
const [landingPreview, setLandingPreview] = useState6(null);
|
|
1243
|
+
const previewRef = useRef6(null);
|
|
1244
|
+
const [reportedMove, setPendingMove] = useState6(null);
|
|
1245
|
+
const pendingMove = reportedMove && !hasMoveSettled(columns, reportedMove) ? reportedMove : null;
|
|
1246
|
+
const view = useMemo2(() => pendingMove ? applyPendingMove(columns, pendingMove) : columns, [columns, pendingMove]);
|
|
1247
|
+
useEffect4(() => {
|
|
1248
|
+
columnsRef.current = view;
|
|
1249
|
+
onChangeRef.current = onChange;
|
|
1250
|
+
});
|
|
1251
|
+
const [landing, setLanding] = useState6(null);
|
|
1252
|
+
const landingTimer = useRef6(null);
|
|
1253
|
+
const pointRef = useRef6({ x: 0, y: 0 });
|
|
1254
|
+
const laneLabel = useCallback5((columnId) => view.find((c) => c.id === columnId)?.label ?? columnId, [view]);
|
|
1255
|
+
const acceptsLifted = useCallback5(
|
|
1256
|
+
(fromColumnId) => (column) => {
|
|
1257
|
+
if (column.dropDisabled || collapsed[column.id]) return false;
|
|
1258
|
+
if (column.id === fromColumnId) return true;
|
|
1259
|
+
return !column.allowedFromColumns || column.allowedFromColumns.includes(fromColumnId);
|
|
1260
|
+
},
|
|
1261
|
+
[collapsed]
|
|
1262
|
+
);
|
|
1263
|
+
const lift = useCallback5(
|
|
1264
|
+
(ticketId) => {
|
|
1265
|
+
const start = initialAim(view, ticketId);
|
|
1266
|
+
if (!start) return;
|
|
1267
|
+
setLifted({ ticketId, aim: start });
|
|
1268
|
+
const title = laneOf(view, ticketId)?.tickets.find((t) => t.id === ticketId)?.title ?? "Ticket";
|
|
1269
|
+
setAnnouncement(`${title} lifted. Use the arrow keys to move it, space to drop it, escape to put it back.`);
|
|
1270
|
+
},
|
|
1271
|
+
[view]
|
|
1272
|
+
);
|
|
1273
|
+
const drop = useCallback5(() => {
|
|
1274
|
+
if (!lifted) return;
|
|
1275
|
+
const change = aimToChange(view, lifted.ticketId, lifted.aim);
|
|
1276
|
+
setLifted(null);
|
|
1277
|
+
if (!change) {
|
|
1278
|
+
setAnnouncement("Put back where it was.");
|
|
1279
|
+
return;
|
|
1280
|
+
}
|
|
1281
|
+
setAnnouncement(`Dropped into ${laneLabel(change.toColumnId)}.`);
|
|
1282
|
+
setPendingMove({
|
|
1283
|
+
ticketId: change.ticketId,
|
|
1284
|
+
fromColumnId: change.fromColumnId,
|
|
1285
|
+
toColumnId: change.toColumnId,
|
|
1286
|
+
afterTicketId: change.afterTicketId
|
|
1287
|
+
});
|
|
1288
|
+
onChange(change);
|
|
1289
|
+
}, [lifted, view, laneLabel, onChange]);
|
|
1290
|
+
const walk = useCallback5(
|
|
1291
|
+
(key) => {
|
|
1292
|
+
if (!lifted) return;
|
|
1293
|
+
const from = laneOf(view, lifted.ticketId)?.id ?? lifted.aim.columnId;
|
|
1294
|
+
const next = moveAim(view, lifted.ticketId, lifted.aim, key, acceptsLifted(from));
|
|
1295
|
+
if (next === lifted.aim) return;
|
|
1296
|
+
setLifted({ ...lifted, aim: next });
|
|
1297
|
+
const total = (view.find((c) => c.id === next.columnId)?.tickets ?? []).filter(
|
|
1298
|
+
(t) => t.id !== lifted.ticketId
|
|
1299
|
+
).length;
|
|
1300
|
+
setAnnouncement(`${laneLabel(next.columnId)}, position ${next.index + 1} of ${total + 1}.`);
|
|
1301
|
+
},
|
|
1302
|
+
[lifted, view, acceptsLifted, laneLabel]
|
|
1303
|
+
);
|
|
1304
|
+
useEffect4(() => {
|
|
1305
|
+
if (!lifted) return void 0;
|
|
1306
|
+
const onKeyDown = (event) => {
|
|
1307
|
+
if (event.key === "Escape") {
|
|
1308
|
+
setLifted(null);
|
|
1309
|
+
setAnnouncement("Move cancelled.");
|
|
1310
|
+
} else if (event.key === " " || event.key === "Enter") {
|
|
1311
|
+
drop();
|
|
1312
|
+
} else if (ARROW_KEYS.includes(event.key)) {
|
|
1313
|
+
walk(event.key);
|
|
1314
|
+
} else {
|
|
1315
|
+
return;
|
|
1316
|
+
}
|
|
1317
|
+
event.preventDefault();
|
|
1318
|
+
};
|
|
1319
|
+
window.addEventListener("keydown", onKeyDown);
|
|
1320
|
+
return () => window.removeEventListener("keydown", onKeyDown);
|
|
1321
|
+
}, [lifted, drop, walk]);
|
|
1322
|
+
useEffect4(() => {
|
|
1323
|
+
if (!lifted) return;
|
|
1324
|
+
boardRef.current?.querySelector(`[${DROP_LINE_ATTRIBUTE}]`)?.scrollIntoView({ block: "nearest", inline: "nearest" });
|
|
1325
|
+
}, [lifted]);
|
|
1326
|
+
const keyboardAim = useMemo2(() => {
|
|
1327
|
+
if (!lifted) return null;
|
|
1328
|
+
const ticket = laneOf(view, lifted.ticketId)?.tickets.find((t) => t.id === lifted.ticketId);
|
|
1329
|
+
if (!ticket) return null;
|
|
1330
|
+
const anchor = aimToChange(view, lifted.ticketId, lifted.aim) ? aimAnchor(view, lifted.ticketId, lifted.aim) : { ticketId: null, edge: null };
|
|
1331
|
+
return { columnId: lifted.aim.columnId, ...anchor, ticket };
|
|
1332
|
+
}, [lifted, view]);
|
|
1333
|
+
useEffect4(() => {
|
|
1334
|
+
if (!pendingMove) return void 0;
|
|
1335
|
+
const timer = setTimeout(() => setPendingMove(null), PENDING_MOVE_TIMEOUT_MS);
|
|
1336
|
+
return () => clearTimeout(timer);
|
|
1337
|
+
}, [pendingMove]);
|
|
1338
|
+
useEffect4(() => {
|
|
1339
|
+
const scroller = scrollerRef.current;
|
|
1340
|
+
const readAim = (source, target) => {
|
|
1341
|
+
const ticket = source.data.ticket;
|
|
1342
|
+
if (!target || !ticket) return null;
|
|
1343
|
+
const ticketId = String(source.data.ticketId);
|
|
1344
|
+
const slot = aimFromTarget(columnsRef.current, ticketId, target);
|
|
1345
|
+
if (!slot) return null;
|
|
1346
|
+
const anchor = aimToChange(columnsRef.current, ticketId, slot) ? aimAnchor(columnsRef.current, ticketId, slot) : { ticketId: null, edge: null };
|
|
1347
|
+
return { columnId: slot.columnId, ...anchor, ticket };
|
|
1348
|
+
};
|
|
1349
|
+
const aimAt = (source, targets) => {
|
|
1350
|
+
const next = readAim(source, targets[0]?.data);
|
|
1351
|
+
setAim((prev) => isSameAim(prev, next) ? prev : next);
|
|
1352
|
+
};
|
|
1353
|
+
return combine3(
|
|
1354
|
+
// Dragging towards the edge of the board scrolls the lanes sideways —
|
|
1355
|
+
// and keeps scrolling once the pointer is past that edge.
|
|
1356
|
+
scroller ? autoScrollBothWays(scroller) : () => {
|
|
1357
|
+
},
|
|
1358
|
+
// ...and towards the edge of the SCREEN scrolls whatever the page is
|
|
1359
|
+
// actually scrolled by, which is the layout's `<main>`, not the document.
|
|
1360
|
+
// Auto-scroll is registered on those; a DROP is not. Nothing outside the
|
|
1361
|
+
// lanes is a drop target: a card carried over the filters, the header or
|
|
1362
|
+
// the sidebar is aimed at nothing, draws nothing, and cancels when
|
|
1363
|
+
// released. Resolving a lane from a pointer that has left the board — by
|
|
1364
|
+
// matching it horizontally to the column above or below it — was tried and
|
|
1365
|
+
// is not what a board does; the answer has to be somewhere the user is
|
|
1366
|
+
// actually pointing.
|
|
1367
|
+
monitorForElements({
|
|
1368
|
+
canMonitor: ({ source }) => source.data.type === "ticket",
|
|
1369
|
+
onDragStart: ({ source, location }) => {
|
|
1370
|
+
const ticket = source.data.ticket;
|
|
1371
|
+
if (!ticket) return;
|
|
1372
|
+
const rect = source.element.getBoundingClientRect();
|
|
1373
|
+
const { clientX, clientY } = location.current.input;
|
|
1374
|
+
pointRef.current = { x: clientX, y: clientY };
|
|
1375
|
+
preventUnhandled.start();
|
|
1376
|
+
setLanding(null);
|
|
1377
|
+
dragGeometry.current = {
|
|
1378
|
+
ticket,
|
|
1379
|
+
columnColor: columnsRef.current.find((c) => c.id === source.data.columnId)?.color,
|
|
1380
|
+
width: rect.width,
|
|
1381
|
+
grabX: clientX - rect.left,
|
|
1382
|
+
grabY: clientY - rect.top
|
|
1383
|
+
};
|
|
1384
|
+
},
|
|
1385
|
+
onDropTargetChange: ({ source, location }) => aimAt(source, location.current.dropTargets),
|
|
1386
|
+
onDrag: ({ source, location }) => {
|
|
1387
|
+
aimAt(source, location.current.dropTargets);
|
|
1388
|
+
const { clientX, clientY } = location.current.input;
|
|
1389
|
+
pointRef.current = { x: clientX, y: clientY };
|
|
1390
|
+
},
|
|
1391
|
+
onDrop: ({ source, location }) => {
|
|
1392
|
+
preventUnhandled.stop();
|
|
1393
|
+
setAim(null);
|
|
1394
|
+
const change = resolveBoardDrop(columnsRef.current, {
|
|
1395
|
+
source: source.data,
|
|
1396
|
+
target: location.current.dropTargets[0]?.data
|
|
1397
|
+
});
|
|
1398
|
+
if (!change) return;
|
|
1399
|
+
setPendingMove({
|
|
1400
|
+
ticketId: change.ticketId,
|
|
1401
|
+
fromColumnId: change.fromColumnId,
|
|
1402
|
+
toColumnId: change.toColumnId,
|
|
1403
|
+
afterTicketId: change.afterTicketId
|
|
1404
|
+
});
|
|
1405
|
+
const geometry = dragGeometry.current;
|
|
1406
|
+
if (geometry) {
|
|
1407
|
+
setLandingPreview({ ...geometry, startX: pointRef.current.x, startY: pointRef.current.y });
|
|
1408
|
+
setLanding(change.ticketId);
|
|
1409
|
+
}
|
|
1410
|
+
onChangeRef.current(change);
|
|
1411
|
+
}
|
|
1412
|
+
})
|
|
1413
|
+
);
|
|
1414
|
+
}, []);
|
|
1415
|
+
useIsomorphicLayoutEffect(() => {
|
|
1416
|
+
if (!landing) return void 0;
|
|
1417
|
+
const finish = () => {
|
|
1418
|
+
landingTimer.current = null;
|
|
1419
|
+
setLanding(null);
|
|
1420
|
+
setLandingPreview(null);
|
|
1421
|
+
};
|
|
1422
|
+
const preview2 = previewRef.current;
|
|
1423
|
+
const card = boardRef.current && cardById(boardRef.current, landing);
|
|
1424
|
+
if (!preview2 || !landingPreview || !card) {
|
|
1425
|
+
finish();
|
|
1426
|
+
return void 0;
|
|
1427
|
+
}
|
|
1428
|
+
const to = card.getBoundingClientRect();
|
|
1429
|
+
const lane = nearestScrollableAncestor(card)?.getBoundingClientRect();
|
|
1430
|
+
if (lane && (to.top < lane.top || to.bottom > lane.bottom)) {
|
|
1431
|
+
finish();
|
|
1432
|
+
return void 0;
|
|
1433
|
+
}
|
|
1434
|
+
const { startX, startY } = landingPreview;
|
|
1435
|
+
preview2.style.transition = "none";
|
|
1436
|
+
preview2.style.opacity = String(DRAG_PREVIEW_OPACITY);
|
|
1437
|
+
preview2.style.transform = `translate(${startX}px, ${startY}px)`;
|
|
1438
|
+
const from = preview2.getBoundingClientRect();
|
|
1439
|
+
void preview2.offsetHeight;
|
|
1440
|
+
preview2.style.transition = `transform ${DROP_MS}ms ${DROP_EASING}, opacity ${DROP_MS}ms ${DROP_EASING}`;
|
|
1441
|
+
preview2.style.opacity = "1";
|
|
1442
|
+
preview2.style.transform = `translate(${startX + to.left - from.left}px, ${startY + to.top - from.top}px)`;
|
|
1443
|
+
landingTimer.current = setTimeout(finish, DROP_MS);
|
|
1444
|
+
return () => {
|
|
1445
|
+
if (landingTimer.current) clearTimeout(landingTimer.current);
|
|
1446
|
+
landingTimer.current = null;
|
|
1447
|
+
};
|
|
1448
|
+
}, [landing, landingPreview]);
|
|
1449
|
+
const preview = landingPreview && createPortal(
|
|
1450
|
+
/* @__PURE__ */ jsx9(
|
|
1451
|
+
"div",
|
|
1452
|
+
{
|
|
1453
|
+
ref: previewRef,
|
|
1454
|
+
"aria-hidden": true,
|
|
1455
|
+
className: "pointer-events-none fixed left-0 top-0 [&_*]:!pointer-events-none",
|
|
1456
|
+
style: {
|
|
1457
|
+
zIndex: DRAG_PREVIEW_Z,
|
|
1458
|
+
width: landingPreview.width,
|
|
1459
|
+
// The grip offset lives here, so the animated property is a plain
|
|
1460
|
+
// translate in pointer coordinates and nothing else.
|
|
1461
|
+
margin: `${-landingPreview.grabY}px 0 0 ${-landingPreview.grabX}px`
|
|
1462
|
+
},
|
|
1463
|
+
children: /* @__PURE__ */ jsx9(
|
|
1464
|
+
TicketCardView,
|
|
1465
|
+
{
|
|
1466
|
+
ticket: landingPreview.ticket,
|
|
1467
|
+
columnColor: landingPreview.columnColor,
|
|
1468
|
+
renderAssignSlot,
|
|
1469
|
+
className: "shadow-card-hover"
|
|
1470
|
+
}
|
|
1471
|
+
)
|
|
1472
|
+
}
|
|
1473
|
+
),
|
|
1474
|
+
document.body
|
|
1475
|
+
);
|
|
1476
|
+
return /* @__PURE__ */ jsx9(LandingCardContext.Provider, { value: landing, children: /* @__PURE__ */ jsx9(DropAimContext.Provider, { value: aim ?? keyboardAim, children: /* @__PURE__ */ jsxs7(BoardLiftContext.Provider, { value: lift, children: [
|
|
1477
|
+
preview,
|
|
1478
|
+
/* @__PURE__ */ jsxs7("div", { ref: boardRef, className: cn("flex h-full flex-col", className), children: [
|
|
1479
|
+
/* @__PURE__ */ jsx9(
|
|
1480
|
+
"div",
|
|
1481
|
+
{
|
|
1482
|
+
ref: setScroller,
|
|
1483
|
+
onScroll,
|
|
1484
|
+
className: "flex min-h-0 flex-1 overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
|
|
1485
|
+
children: view.map((column, i) => {
|
|
1486
|
+
const prev = view[i - 1];
|
|
1487
|
+
const next = view[i + 1];
|
|
1488
|
+
const joinLeft = !!(column.system && prev?.system);
|
|
1489
|
+
const joinRight = !!(column.system && next?.system);
|
|
1490
|
+
const showGap = i > 0 && !joinLeft;
|
|
1491
|
+
return /* @__PURE__ */ jsxs7(Fragment3, { children: [
|
|
1492
|
+
showGap && /* @__PURE__ */ jsx9("div", { "aria-hidden": true, className: "w-[var(--spacing-system-mf)] shrink-0" }),
|
|
1493
|
+
/* @__PURE__ */ jsx9(
|
|
1494
|
+
BoardColumn,
|
|
1495
|
+
{
|
|
1496
|
+
column,
|
|
1497
|
+
collapsed: !!collapsed[column.id],
|
|
1498
|
+
onToggleCollapse: toggle,
|
|
1499
|
+
onAddTicket,
|
|
1500
|
+
onArchive: onArchiveColumn,
|
|
1501
|
+
getTicketHref,
|
|
1502
|
+
renderAssignSlot,
|
|
1503
|
+
onApprove,
|
|
1504
|
+
onReject,
|
|
1505
|
+
onLoadMore,
|
|
1506
|
+
loadMoreRootMargin,
|
|
1507
|
+
joinLeft,
|
|
1508
|
+
joinRight
|
|
1509
|
+
}
|
|
1510
|
+
)
|
|
1511
|
+
] }, column.id);
|
|
1512
|
+
})
|
|
1513
|
+
}
|
|
1514
|
+
),
|
|
1515
|
+
/* @__PURE__ */ jsx9("p", { "aria-live": "polite", className: "sr-only", children: announcement }),
|
|
1516
|
+
thumbRatio > 0 && /* @__PURE__ */ jsx9(
|
|
1517
|
+
"div",
|
|
1518
|
+
{
|
|
1519
|
+
ref: trackRef,
|
|
1520
|
+
onClick: onTrackClick,
|
|
1521
|
+
onWheel: onTrackWheel,
|
|
1522
|
+
className: "relative mt-[var(--spacing-system-mf)] h-2 shrink-0 cursor-pointer rounded-full bg-ods-border",
|
|
1523
|
+
children: /* @__PURE__ */ jsx9(
|
|
1524
|
+
"div",
|
|
1525
|
+
{
|
|
1526
|
+
ref: thumbRef,
|
|
1527
|
+
"data-scrollbar-thumb": true,
|
|
1528
|
+
className: "absolute top-0 h-full touch-none rounded-full bg-ods-text-secondary transition-colors",
|
|
1529
|
+
style: { width: `${thumbRatio * 100}%`, cursor: "grab" },
|
|
1530
|
+
onPointerDown: onThumbPointerDown,
|
|
1531
|
+
onPointerMove: onThumbPointerMove,
|
|
1532
|
+
onPointerUp: onThumbPointerUp,
|
|
1533
|
+
onPointerCancel: onThumbPointerCancel
|
|
1534
|
+
}
|
|
1535
|
+
)
|
|
1536
|
+
}
|
|
1537
|
+
)
|
|
1538
|
+
] })
|
|
1539
|
+
] }) }) });
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
// src/components/features/board/types.ts
|
|
1543
|
+
var STATUS_DEFAULTS = {
|
|
1544
|
+
ACTIVE: { label: "Active", color: "#5ea62e" },
|
|
1545
|
+
AI_ASSISTANCE: { label: "AI Handling", color: "#888888" },
|
|
1546
|
+
TECH_REQUIRED: { label: "Tech Required", color: "#e1b32f" },
|
|
1547
|
+
ON_HOLD: { label: "On Hold", color: "#f36666" },
|
|
1548
|
+
RESOLVED: { label: "Resolved", color: "#888888" },
|
|
1549
|
+
ARCHIVED: { label: "Archived", color: "#3a3a3a" }
|
|
1550
|
+
};
|
|
1551
|
+
function columnFromTicketStatus(status, tickets, overrides = {}) {
|
|
1552
|
+
const defaults = STATUS_DEFAULTS[status];
|
|
1553
|
+
return {
|
|
1554
|
+
id: status,
|
|
1555
|
+
label: overrides.label ?? defaults.label,
|
|
1556
|
+
color: overrides.color ?? defaults.color,
|
|
1557
|
+
tooltip: overrides.tooltip,
|
|
1558
|
+
tickets,
|
|
1559
|
+
total: overrides.total,
|
|
1560
|
+
hasMore: overrides.hasMore,
|
|
1561
|
+
isLoading: overrides.isLoading,
|
|
1562
|
+
isLoadingMore: overrides.isLoadingMore,
|
|
1563
|
+
system: overrides.system,
|
|
1564
|
+
dropDisabled: overrides.dropDisabled,
|
|
1565
|
+
dragDisabled: overrides.dragDisabled,
|
|
1566
|
+
allowedFromColumns: overrides.allowedFromColumns,
|
|
1567
|
+
archivable: overrides.archivable
|
|
1568
|
+
};
|
|
1569
|
+
}
|
|
1570
|
+
function groupTicketsByStatus(tickets, statuses) {
|
|
1571
|
+
const buckets = {
|
|
1572
|
+
ACTIVE: [],
|
|
1573
|
+
AI_ASSISTANCE: [],
|
|
1574
|
+
TECH_REQUIRED: [],
|
|
1575
|
+
ON_HOLD: [],
|
|
1576
|
+
RESOLVED: [],
|
|
1577
|
+
ARCHIVED: []
|
|
1578
|
+
};
|
|
1579
|
+
for (const t of tickets) {
|
|
1580
|
+
const canonical = canonicalize(t.status);
|
|
1581
|
+
if (canonical) buckets[canonical].push(t);
|
|
1582
|
+
}
|
|
1583
|
+
return statuses.map((s) => columnFromTicketStatus(s, buckets[s]));
|
|
1584
|
+
}
|
|
1585
|
+
function canonicalize(status) {
|
|
1586
|
+
const upper = status.toUpperCase().replace(/\s+/g, "_");
|
|
1587
|
+
if (upper === "ACTION_REQUIRED") return "TECH_REQUIRED";
|
|
1588
|
+
if (upper === "ACTIVE" || upper === "AI_ASSISTANCE" || upper === "TECH_REQUIRED" || upper === "ON_HOLD" || upper === "RESOLVED" || upper === "ARCHIVED") {
|
|
1589
|
+
return upper;
|
|
1590
|
+
}
|
|
1591
|
+
return null;
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1594
|
+
export {
|
|
1595
|
+
DeletedUserAvatar,
|
|
1596
|
+
TouchFriendlyTooltip,
|
|
1597
|
+
autoScrollBothWays,
|
|
1598
|
+
autoScrollAncestors,
|
|
1599
|
+
BoardColumnHeader,
|
|
1600
|
+
tintOnDark,
|
|
1601
|
+
holdMoveDragEffect,
|
|
1602
|
+
BoardTicketApproval,
|
|
1603
|
+
TicketCardBody,
|
|
1604
|
+
TicketCardView,
|
|
1605
|
+
TicketCard,
|
|
1606
|
+
TicketCardSkeleton,
|
|
1607
|
+
BoardColumn,
|
|
1608
|
+
useBoardCollapse,
|
|
1609
|
+
Board,
|
|
1610
|
+
columnFromTicketStatus,
|
|
1611
|
+
groupTicketsByStatus
|
|
1612
|
+
};
|