@jmruthers/pace-core 0.6.10 → 0.6.11
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/CHANGELOG.md +21 -0
- package/audit-tool/00-dependencies.cjs +46 -13
- package/audit-tool/audits/01-pace-core-compliance.cjs +96 -21
- package/audit-tool/audits/02-project-structure.cjs +13 -3
- package/audit-tool/audits/03-architecture.cjs +78 -4
- package/audit-tool/audits/04-code-quality.cjs +9 -2
- package/audit-tool/audits/05-styling.cjs +19 -7
- package/audit-tool/audits/06-security-rbac.cjs +105 -14
- package/audit-tool/audits/07-api-tech-stack.cjs +31 -15
- package/audit-tool/audits/08-testing-documentation.cjs +11 -3
- package/audit-tool/audits/09-operations.cjs +19 -7
- package/audit-tool/index.cjs +22 -11
- package/audit-tool/utils/report-utils.cjs +4 -0
- package/cursor-rules/01-pace-core-compliance.mdc +1 -0
- package/cursor-rules/02-project-structure.mdc +1 -0
- package/cursor-rules/03-architecture.mdc +3 -1
- package/cursor-rules/04-code-quality.mdc +1 -0
- package/cursor-rules/05-styling.mdc +41 -7
- package/cursor-rules/06-security-rbac.mdc +2 -1
- package/cursor-rules/07-api-tech-stack.mdc +1 -0
- package/cursor-rules/08-testing-documentation.mdc +1 -0
- package/cursor-rules/09-operations.mdc +1 -0
- package/dist/{DataTable-SAXFG4XI.js → DataTable-EFYP2QLE.js} +10 -7
- package/dist/{InactivityServiceProvider-DHryoh6K.d.ts → InactivityServiceProvider-BbxwwDz1.d.ts} +10 -1
- package/dist/{UnifiedAuthProvider-CiBAl9-s.d.ts → UnifiedAuthProvider-Bkt_tzdS.d.ts} +56 -24
- package/dist/{api-F47QJ7FX.js → api-BZR2CYXL.js} +3 -2
- package/dist/api-result-USV1Czr-.d.ts +51 -0
- package/dist/{audit-Z6ZZBWLU.js → audit-HI2DHUVU.js} +2 -1
- package/dist/{auth-BZOJqrdd.d.ts → auth-JvdRVaud.d.ts} +1 -1
- package/dist/{chunk-KSNLMI7N.js → chunk-2DL2WSOE.js} +1 -155
- package/dist/{chunk-MPY44PWB.js → chunk-2OEVOGGR.js} +4648 -3560
- package/dist/chunk-44CNXN4P.js +15 -0
- package/dist/{chunk-Y4PF6HIM.js → chunk-4R3T5ENU.js} +867 -786
- package/dist/{chunk-LNHFAF4X.js → chunk-7A6IMHH2.js} +289 -247
- package/dist/chunk-CU2BU2MQ.js +2 -0
- package/dist/{chunk-JJEYZ3DX.js → chunk-D6BMFMQZ.js} +37 -2
- package/dist/{chunk-BCTXBU6U.js → chunk-ENLXB7GP.js} +88 -71
- package/dist/{chunk-FBZ7U3ID.js → chunk-J2KQK6DG.js} +937 -987
- package/dist/{chunk-TFIPNIPE.js → chunk-KJXRL3XE.js} +3300 -2245
- package/dist/{chunk-3GWSPISD.js → chunk-L5LFKKLJ.js} +1 -1
- package/dist/{chunk-X5EAU5G7.js → chunk-PCSHBLPB.js} +132 -114
- package/dist/{chunk-NIU6DPQV.js → chunk-QRYSEPHB.js} +2 -0
- package/dist/{chunk-KYURMOQM.js → chunk-V7FTM2LU.js} +423 -320
- package/dist/chunk-WY6Y7KC3.js +264 -0
- package/dist/{chunk-FN52B75D.js → chunk-XOJME5T7.js} +176 -15
- package/dist/{chunk-7YDC7LMU.js → chunk-XPFVT3GN.js} +71 -66
- package/dist/{chunk-66R6RLUZ.js → chunk-YFTFFJIV.js} +3 -3
- package/dist/{chunk-W46INAVW.js → chunk-YYTWKVHO.js} +688 -570
- package/dist/components.d.ts +8 -7
- package/dist/components.js +17 -15
- package/dist/{database.generated-DT8JTZiP.d.ts → database.generated-qkdoiVrJ.d.ts} +45 -10
- package/dist/eslint-rules/index.cjs +3 -0
- package/dist/eslint-rules/rules/03-architecture.cjs +74 -0
- package/dist/eslint-rules/rules/06-security-rbac.cjs +74 -0
- package/dist/{event-WTAQuGcq.d.ts → event-BfCox3N2.d.ts} +36 -10
- package/dist/{file-reference-BavO2eQj.d.ts → file-reference-DU1hcawx.d.ts} +29 -13
- package/dist/hooks.d.ts +22 -9
- package/dist/hooks.js +34 -25
- package/dist/icons/index.d.ts +1 -0
- package/dist/icons/index.js +1 -0
- package/dist/index.d.ts +66 -177
- package/dist/index.js +316 -340
- package/dist/pagination-BW1mqywp.d.ts +201 -0
- package/dist/providers.d.ts +6 -5
- package/dist/providers.js +5 -3
- package/dist/rbac/index.d.ts +123 -138
- package/dist/rbac/index.js +10 -8
- package/dist/theming/runtime.d.ts +19 -2
- package/dist/theming/runtime.js +1 -1
- package/dist/{timezone-K-ptz3HO.d.ts → timezone-BTWWXKVY.d.ts} +1 -1
- package/dist/types.d.ts +17 -10
- package/dist/types.js +1 -0
- package/dist/{usePublicPageContext-vxBlEHO9.d.ts → usePublicPageContext-B91dGYW1.d.ts} +433 -356
- package/dist/{usePublicRouteParams-G3Ks53mk.d.ts → usePublicRouteParams-BgV6VhMi.d.ts} +73 -4
- package/dist/utils.d.ts +163 -145
- package/dist/utils.js +42 -25
- package/docs/api/modules.md +782 -643
- package/docs/api-reference/rpc-functions.md +12 -3
- package/docs/core-concepts/rbac-system.md +8 -0
- package/docs/getting-started/cursor-rules.md +17 -20
- package/docs/getting-started/dependencies.md +1 -1
- package/docs/getting-started/setup.md +235 -0
- package/docs/implementation-guides/authentication.md +27 -0
- package/docs/implementation-guides/data-tables.md +176 -3
- package/docs/migration/ApiResult-migration.md +25 -0
- package/docs/rbac/api-reference.md +33 -31
- package/docs/standards/0-standards-overview.md +50 -15
- package/docs/standards/1-pace-core-compliance-standards.md +62 -57
- package/docs/standards/2-project-structure-standards.md +33 -16
- package/docs/standards/3-architecture-standards.md +41 -1
- package/docs/standards/4-code-quality-standards.md +26 -6
- package/docs/standards/5-styling-standards.md +35 -1
- package/docs/standards/6-security-rbac-standards.md +66 -0
- package/docs/standards/7-api-tech-stack-standards.md +25 -14
- package/docs/standards/8-testing-documentation-standards.md +31 -0
- package/docs/standards/9-operations-standards.md +19 -0
- package/docs/standards/README.md +20 -201
- package/docs/testing/test-setup-for-consumers.md +2 -0
- package/docs/troubleshooting/common-issues.md +17 -1
- package/docs/troubleshooting/organisation-context-setup.md +8 -0
- package/docs/troubleshooting/print-event-name-css-variable-analysis.md +217 -0
- package/eslint-config-pace-core.cjs +20 -0
- package/package.json +14 -20
- package/scripts/{build-docs-incremental.js → build-docs.js} +3 -2
- package/scripts/setup.cjs +536 -0
- package/scripts/validate.cjs +480 -0
- package/src/__tests__/helpers/{__tests__/component-test-utils.test.tsx → component-test-utils.test.tsx} +3 -3
- package/src/__tests__/helpers/{__tests__/optimized-test-setup.test.ts → optimized-test-setup.test.ts} +2 -2
- package/src/__tests__/helpers/{__tests__/supabaseMock.test.ts → supabaseMock.test.ts} +2 -2
- package/src/__tests__/helpers/{__tests__/test-providers.test.tsx → test-providers.test.tsx} +1 -1
- package/src/__tests__/helpers/test-providers.tsx +37 -39
- package/src/__tests__/helpers/{__tests__/test-utils.test.tsx → test-utils.test.tsx} +4 -3
- package/src/__tests__/helpers/{__tests__/timer-utils.test.ts → timer-utils.test.ts} +2 -2
- package/src/assets/app-icons/index.test.ts +304 -0
- package/src/components/AddressField/AddressField.test.tsx +1 -1
- package/src/components/AddressField/AddressField.tsx +238 -212
- package/src/components/Button/Button.tsx +1 -1
- package/src/components/Card/Card.test.tsx +172 -17
- package/src/components/Card/Card.tsx +19 -10
- package/src/components/ContextSelector/ContextSelector.internals.tsx +204 -0
- package/src/components/ContextSelector/{__tests__/ContextSelector.test.tsx → ContextSelector.test.tsx} +6 -6
- package/src/components/ContextSelector/ContextSelector.tsx +66 -280
- package/src/components/ContextSelector/ContextSelector.types.ts +35 -0
- package/src/components/ContextSelector/useContextSelectorState.tsx +195 -0
- package/src/components/DataTable/AUDIT_REPORT.md +59 -44
- package/src/components/DataTable/{__tests__/DataTable.comprehensive.test.tsx → DataTable.comprehensive.test.tsx} +6 -6
- package/src/components/DataTable/{__tests__/DataTable.default-state.test.tsx → DataTable.default-state.test.tsx} +5 -5
- package/src/components/DataTable/{__tests__/DataTable.export.test.tsx → DataTable.export.test.tsx} +10 -10
- package/src/components/DataTable/{__tests__/DataTable.grouping-aggregation.test.tsx → DataTable.grouping-aggregation.test.tsx} +6 -6
- package/src/components/DataTable/{__tests__/DataTable.hooks.test.tsx → DataTable.hooks.test.tsx} +6 -6
- package/src/components/DataTable/{__tests__/DataTable.select-label-display.test.tsx → DataTable.select-label-display.test.tsx} +6 -6
- package/src/components/DataTable/DataTable.test.tsx +787 -416
- package/src/components/DataTable/DataTable.tsx +12 -12
- package/src/components/DataTable/DataTableCore.integration.test.tsx +458 -0
- package/src/components/DataTable/{__tests__/DataTableCore.test-setup.ts → DataTableCore.test-setup.ts} +10 -9
- package/src/components/DataTable/{__tests__/DataTableCore.test.tsx → DataTableCore.test.tsx} +8 -8
- package/src/components/DataTable/{__tests__/README.md → README.md} +17 -7
- package/src/components/DataTable/TESTING.md +101 -0
- package/src/components/DataTable/{__tests__/a11y.basic.test.tsx → a11y.basic.test.tsx} +34 -34
- package/src/components/DataTable/components/DataTableCore.tsx +104 -864
- package/src/components/DataTable/components/{__tests__/GroupingDropdown.test.tsx → GroupingDropdown.test.tsx} +17 -8
- package/src/components/DataTable/components/GroupingDropdown.tsx +2 -2
- package/src/components/DataTable/components/ImportModal.tsx +61 -559
- package/src/components/DataTable/components/ImportModalFileSection.tsx +148 -0
- package/src/components/DataTable/context/{__tests__/DataTableContext.test.tsx → DataTableContext.test.tsx} +2 -2
- package/src/components/DataTable/context/DataTableContext.tsx +7 -6
- package/src/components/DataTable/core/{__tests__/ColumnFactory.test.ts → ColumnFactory.test.ts} +2 -2
- package/src/components/DataTable/hooks/{__tests__/useColumnOrderPersistence.test.ts → useColumnOrderPersistence.test.ts} +2 -2
- package/src/components/DataTable/hooks/{__tests__/useColumnVisibilityPersistence.test.ts → useColumnVisibilityPersistence.test.ts} +2 -2
- package/src/components/DataTable/hooks/{__tests__/useDataTableConfiguration.test.ts → useDataTableConfiguration.test.ts} +3 -3
- package/src/components/DataTable/hooks/useDataTableConfiguration.ts +14 -2
- package/src/components/DataTable/hooks/{__tests__/useDataTableDataPipeline.test.ts → useDataTableDataPipeline.test.ts} +6 -6
- package/src/components/DataTable/hooks/useDataTableDeletionBatching.test.ts +127 -0
- package/src/components/DataTable/hooks/useDataTableDeletionBatching.ts +106 -0
- package/src/components/DataTable/hooks/useDataTableEffectiveActions.test.ts +461 -0
- package/src/components/DataTable/hooks/useDataTableEffectiveActions.ts +238 -0
- package/src/components/DataTable/hooks/useDataTableLayoutHandlers.test.ts +296 -0
- package/src/components/DataTable/hooks/useDataTableLayoutHandlers.ts +175 -0
- package/src/components/DataTable/hooks/useDataTablePaginationSync.test.ts +203 -0
- package/src/components/DataTable/hooks/useDataTablePaginationSync.ts +109 -0
- package/src/components/DataTable/hooks/{__tests__/useDataTablePermissions.test.ts → useDataTablePermissions.test.ts} +11 -11
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +79 -247
- package/src/components/DataTable/hooks/useDataTablePipeline.test.tsx +219 -0
- package/src/components/DataTable/hooks/useDataTablePipeline.tsx +239 -0
- package/src/components/DataTable/hooks/useDataTableRenderGuard.test.tsx +316 -0
- package/src/components/DataTable/hooks/useDataTableRenderGuard.tsx +195 -0
- package/src/components/DataTable/hooks/useDataTableScope.test.ts +110 -0
- package/src/components/DataTable/hooks/useDataTableScope.ts +123 -0
- package/src/components/DataTable/hooks/{__tests__/useDataTableState.test.ts → useDataTableState.test.ts} +47 -5
- package/src/components/DataTable/hooks/useDataTableState.ts +145 -94
- package/src/components/DataTable/hooks/useDataTableStateAndPersistence.test.ts +277 -0
- package/src/components/DataTable/hooks/useDataTableStateAndPersistence.ts +222 -0
- package/src/components/DataTable/hooks/useDataTableSuperAdmin.test.ts +93 -0
- package/src/components/DataTable/hooks/useDataTableSuperAdmin.ts +86 -0
- package/src/components/DataTable/hooks/useDataTableTableInstance.test.ts +185 -0
- package/src/components/DataTable/hooks/useDataTableTableInstance.ts +178 -0
- package/src/components/DataTable/hooks/{__tests__/useEffectiveColumnOrder.test.ts → useEffectiveColumnOrder.test.ts} +2 -2
- package/src/components/DataTable/hooks/{__tests__/useHierarchicalState.test.ts → useHierarchicalState.test.ts} +2 -2
- package/src/components/DataTable/{components/hooks → hooks}/useImportModalFocus.test.ts +3 -3
- package/src/components/DataTable/{components/hooks → hooks}/useImportModalFocus.ts +2 -2
- package/src/components/DataTable/hooks/useImportModalState.test.ts +390 -0
- package/src/components/DataTable/hooks/useImportModalState.ts +345 -0
- package/src/components/DataTable/hooks/{__tests__/useKeyboardNavigation.test.ts → useKeyboardNavigation.test.ts} +3 -3
- package/src/components/DataTable/hooks/useKeyboardNavigation.ts +309 -269
- package/src/components/DataTable/{components/hooks → hooks}/usePermissionTracking.test.ts +3 -3
- package/src/components/DataTable/{components/hooks → hooks}/usePermissionTracking.ts +3 -3
- package/src/components/DataTable/hooks/{__tests__/useServerSideDataEffect.test.ts → useServerSideDataEffect.test.ts} +2 -2
- package/src/components/DataTable/hooks/useServerSideDataEffect.ts +14 -3
- package/src/components/DataTable/hooks/{__tests__/useTableColumns.test.ts → useTableColumns.test.ts} +2 -2
- package/src/components/DataTable/hooks/{__tests__/useTableHandlers.test.ts → useTableHandlers.test.ts} +25 -4
- package/src/components/DataTable/hooks/useTableHandlers.ts +5 -2
- package/src/components/DataTable/index.ts +18 -17
- package/src/components/DataTable/{__tests__/keyboard.test.tsx → keyboard.test.tsx} +41 -63
- package/src/components/DataTable/{__tests__/mocks → mocks}/MockRBACProvider.tsx +1 -1
- package/src/components/DataTable/{__tests__/pagination.modes.test.tsx → pagination.modes.test.tsx} +6 -6
- package/src/components/DataTable/{__tests__/ssr.strict-mode.test.tsx → ssr.strict-mode.test.tsx} +2 -2
- package/src/components/DataTable/{__tests__/styles.test.ts → styles.test.ts} +1 -4
- package/src/components/DataTable/styles.ts +0 -1
- package/src/components/DataTable/test-utils/MockDataTableComponents.tsx +55 -0
- package/src/components/DataTable/{__tests__/test-utils → test-utils}/dataFactories.ts +2 -2
- package/src/components/DataTable/test-utils/featureConfig.ts +10 -0
- package/src/components/DataTable/{__tests__/test-utils/sharedTestUtils.tsx → test-utils/sharedTestUtils.ts} +97 -66
- package/src/components/DataTable/{__tests__/test-utils.ts → test-utils.ts} +1 -1
- package/src/components/DataTable/types/actions.ts +71 -0
- package/src/components/DataTable/types/base.ts +39 -0
- package/src/components/DataTable/types/columns.ts +125 -0
- package/src/components/DataTable/types/export.ts +32 -0
- package/src/components/DataTable/types/features.ts +81 -0
- package/src/components/DataTable/types/hierarchical.ts +44 -0
- package/src/components/DataTable/types/index.ts +43 -0
- package/src/components/DataTable/types/pagination.ts +85 -0
- package/src/components/DataTable/types/performance.ts +47 -0
- package/src/components/DataTable/types/props.ts +62 -0
- package/src/components/DataTable/types/rbac.ts +45 -0
- package/src/components/DataTable/{components/__tests__ → ui/layout}/DataTableCore.test.tsx +430 -28
- package/src/components/DataTable/ui/layout/DataTableCore.tsx +345 -0
- package/src/components/DataTable/{components/__tests__ → ui/layout}/DataTableErrorBoundary.test.tsx +4 -4
- package/src/components/DataTable/{components → ui/layout}/DataTableErrorBoundary.tsx +7 -7
- package/src/components/DataTable/ui/layout/DataTableLayout.test.tsx +1352 -0
- package/src/components/DataTable/ui/layout/DataTableLayout.tsx +661 -0
- package/src/components/DataTable/ui/modals/BulkDeleteConfirmDialog.test.tsx +91 -0
- package/src/components/DataTable/ui/modals/BulkDeleteConfirmDialog.tsx +43 -0
- package/src/components/DataTable/ui/modals/DataTableModals.test.tsx +749 -0
- package/src/components/DataTable/{components → ui/modals}/DataTableModals.tsx +36 -28
- package/src/components/DataTable/ui/modals/ImportModal.test.tsx +1834 -0
- package/src/components/DataTable/ui/modals/ImportModal.tsx +197 -0
- package/src/components/DataTable/ui/modals/ImportModalFailedRowsSection.tsx +60 -0
- package/src/components/DataTable/ui/modals/ImportModalFileSection.tsx +148 -0
- package/src/components/DataTable/ui/modals/ImportModalPreviewSection.tsx +60 -0
- package/src/components/DataTable/ui/modals/ImportModalSummarySection.tsx +59 -0
- package/src/components/DataTable/ui/modals/importModalPersistence.ts +73 -0
- package/src/components/DataTable/{components/__tests__ → ui/shared}/AccessDeniedPage.test.tsx +2 -2
- package/src/components/DataTable/{components → ui/shared}/AccessDeniedPage.tsx +2 -2
- package/src/components/DataTable/{components/__tests__ → ui/shared}/ActionButtons.test.tsx +6 -4
- package/src/components/DataTable/{components → ui/shared}/ActionButtons.tsx +4 -4
- package/src/components/DataTable/{components/__tests__ → ui/shared}/ColumnFilter.test.tsx +29 -16
- package/src/components/DataTable/{components → ui/shared}/ColumnFilter.tsx +4 -4
- package/src/components/DataTable/{components/__tests__ → ui/shared}/PaginationControls.test.tsx +38 -16
- package/src/components/DataTable/{components → ui/shared}/PaginationControls.tsx +21 -15
- package/src/components/DataTable/{components/__tests__ → ui/shared}/SortIndicator.test.tsx +2 -2
- package/src/components/DataTable/{components → ui/shared}/SortIndicator.tsx +1 -1
- package/src/components/DataTable/{components/__tests__ → ui/table}/EditFields.test.tsx +3 -3
- package/src/components/DataTable/{components → ui/table}/EditFields.tsx +138 -69
- package/src/components/DataTable/{components/__tests__ → ui/table}/EditableRow.test.tsx +36 -27
- package/src/components/DataTable/{components → ui/table}/EditableRow.tsx +86 -104
- package/src/components/DataTable/{components/__tests__ → ui/table}/EmptyState.test.tsx +2 -62
- package/src/components/DataTable/{components → ui/table}/EmptyState.tsx +7 -15
- package/src/components/DataTable/{components/__tests__ → ui/table}/FilterRow.test.tsx +5 -4
- package/src/components/DataTable/{components → ui/table}/FilterRow.tsx +3 -3
- package/src/components/DataTable/{components/__tests__ → ui/table}/LoadingState.test.tsx +6 -10
- package/src/components/DataTable/{components → ui/table}/LoadingState.tsx +4 -4
- package/src/components/DataTable/{components/__tests__ → ui/table}/RowComponent.test.tsx +412 -17
- package/src/components/DataTable/{components → ui/table}/RowComponent.tsx +183 -177
- package/src/components/DataTable/{components/__tests__ → ui/table}/UnifiedTableBody.test.tsx +425 -16
- package/src/components/DataTable/ui/table/UnifiedTableBody.tsx +440 -0
- package/src/components/DataTable/{components/__tests__ → ui/table}/cellValueUtils.test.ts +2 -2
- package/src/components/DataTable/{components → ui/table}/cellValueUtils.ts +1 -1
- package/src/components/DataTable/{components/__tests__ → ui/toolbar}/BulkOperationsDropdown.test.tsx +12 -5
- package/src/components/DataTable/{components → ui/toolbar}/BulkOperationsDropdown.tsx +3 -3
- package/src/components/DataTable/{components/__tests__ → ui/toolbar}/ColumnVisibilityDropdown.test.tsx +7 -4
- package/src/components/DataTable/{components → ui/toolbar}/ColumnVisibilityDropdown.tsx +7 -7
- package/src/components/DataTable/{components/__tests__ → ui/toolbar}/DataTableToolbar.test.tsx +4 -4
- package/src/components/DataTable/{components → ui/toolbar}/DataTableToolbar.tsx +4 -4
- package/src/components/DataTable/ui/toolbar/GroupingDropdown.test.tsx +621 -0
- package/src/components/DataTable/ui/toolbar/GroupingDropdown.tsx +107 -0
- package/src/components/DataTable/utils/{__tests__/a11yUtils.test.ts → a11yUtils.test.ts} +2 -2
- package/src/components/DataTable/utils/{__tests__/aggregationUtils.test.ts → aggregationUtils.test.ts} +3 -3
- package/src/components/DataTable/utils/{__tests__/columnUtils.test.ts → columnUtils.test.ts} +2 -2
- package/src/components/DataTable/utils/csvParse.test.ts +74 -0
- package/src/components/DataTable/utils/csvParse.ts +65 -0
- package/src/components/DataTable/utils/{__tests__/errorHandling.test.ts → errorHandling.test.ts} +2 -2
- package/src/components/DataTable/utils/{__tests__/exportUtils.test.ts → exportUtils.test.ts} +3 -3
- package/src/components/DataTable/utils/{__tests__/flexibleImport.test.ts → flexibleImport.test.ts} +2 -2
- package/src/components/DataTable/utils/flexibleImport.ts +3 -186
- package/src/components/DataTable/utils/{__tests__/hierarchicalSorting.test.ts → hierarchicalSorting.test.ts} +3 -3
- package/src/components/DataTable/utils/{__tests__/hierarchicalUtils.test.ts → hierarchicalUtils.test.ts} +3 -3
- package/src/components/DataTable/utils/importDateParser.test.ts +162 -0
- package/src/components/DataTable/utils/importDateParser.ts +114 -0
- package/src/components/DataTable/utils/importValueParser.test.ts +138 -0
- package/src/components/DataTable/utils/importValueParser.ts +91 -0
- package/src/components/DataTable/utils/{__tests__/paginationUtils.test.ts → paginationUtils.test.ts} +2 -2
- package/src/components/DataTable/utils/paginationUtils.ts +6 -3
- package/src/components/DataTable/utils/{__tests__/performanceUtils.test.ts → performanceUtils.test.ts} +3 -3
- package/src/components/DataTable/utils/{__tests__/rowUtils.test.ts → rowUtils.test.ts} +3 -3
- package/src/components/DataTable/utils/{__tests__/selectFieldUtils.test.ts → selectFieldUtils.test.ts} +66 -3
- package/src/components/DataTable/utils/selectFieldUtils.ts +97 -60
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +1 -1
- package/src/components/DateTimeField/DateTimeField.test.tsx +1 -1
- package/src/components/Dialog/Dialog.test-utils.ts +49 -0
- package/src/components/Dialog/Dialog.test.tsx +896 -89
- package/src/components/Dialog/Dialog.tsx +174 -882
- package/src/components/Dialog/dialogLock.test.ts +238 -0
- package/src/components/Dialog/dialogLock.ts +98 -0
- package/src/components/Dialog/index.ts +2 -0
- package/src/components/Dialog/useDialogDimensions.test.ts +163 -0
- package/src/components/Dialog/useDialogDimensions.ts +140 -0
- package/src/components/Dialog/useDialogLifecycle.test.ts +358 -0
- package/src/components/Dialog/useDialogLifecycle.ts +135 -0
- package/src/components/Dialog/useDialogPersistence.test.ts +381 -0
- package/src/components/Dialog/useDialogPersistence.ts +357 -0
- package/src/components/FileDisplay/FileDisplay.test.tsx +40 -40
- package/src/components/FileDisplay/FileDisplay.tsx +24 -656
- package/src/components/FileDisplay/FileDisplayContent.test.tsx +395 -0
- package/src/components/FileDisplay/FileDisplayContent.tsx +242 -0
- package/src/components/FileDisplay/FileDisplayDeleteConfirmDialog.test.tsx +74 -0
- package/src/components/FileDisplay/FileDisplayDeleteConfirmDialog.tsx +38 -0
- package/src/components/FileDisplay/FileDisplayEmptyView.test.tsx +33 -0
- package/src/components/FileDisplay/FileDisplayEmptyView.tsx +33 -0
- package/src/components/FileDisplay/FileDisplayErrorView.test.tsx +71 -0
- package/src/components/FileDisplay/FileDisplayErrorView.tsx +50 -0
- package/src/components/FileDisplay/FileDisplayLoadingFallbackView.test.tsx +22 -0
- package/src/components/FileDisplay/FileDisplayLoadingFallbackView.tsx +22 -0
- package/src/components/FileDisplay/FileDisplayLoadingView.test.tsx +21 -0
- package/src/components/FileDisplay/FileDisplayLoadingView.tsx +23 -0
- package/src/components/FileDisplay/FileDisplayMultipleFilesView.test.tsx +101 -0
- package/src/components/FileDisplay/FileDisplayMultipleFilesView.tsx +109 -0
- package/src/components/FileDisplay/FileDisplaySingleDocumentLinkView.test.tsx +58 -0
- package/src/components/FileDisplay/FileDisplaySingleDocumentLinkView.tsx +48 -0
- package/src/components/FileDisplay/FileDisplaySingleFileWithActionsView.test.tsx +111 -0
- package/src/components/FileDisplay/FileDisplaySingleFileWithActionsView.tsx +270 -0
- package/src/components/FileDisplay/FileDisplaySingleImageView.test.tsx +78 -0
- package/src/components/FileDisplay/FileDisplaySingleImageView.tsx +67 -0
- package/src/components/FileDisplay/fallbackUtils.test.ts +50 -0
- package/src/components/FileDisplay/fallbackUtils.ts +44 -0
- package/src/components/FileDisplay/fetchFileDisplayData.ts +24 -0
- package/src/components/FileDisplay/fetchFileDisplayData.unit.test.ts +183 -0
- package/src/components/FileDisplay/fileDisplayUtils.test.ts +58 -0
- package/src/components/FileDisplay/fileDisplayUtils.ts +24 -0
- package/src/{hooks/__tests__ → components/FileDisplay}/useFileDisplay.test.ts +40 -42
- package/src/components/FileDisplay/useFileDisplay.ts +515 -0
- package/src/{hooks/__tests__ → components/FileDisplay}/useFileDisplay.unit.test.ts +406 -77
- package/src/components/FileDisplay/useFileDisplayData.ts +126 -0
- package/src/{hooks/public → components/FileDisplay}/usePublicFileDisplay.test.ts +94 -88
- package/src/components/FileDisplay/usePublicFileDisplay.ts +579 -0
- package/src/components/FileUpload/FileUpload.test.tsx +16 -10
- package/src/components/FileUpload/FileUpload.tsx +107 -525
- package/src/components/FileUpload/FileUploadDropZone.tsx +112 -0
- package/src/components/FileUpload/FileUploadProgressItem.tsx +86 -0
- package/src/components/FileUpload/FileUploadProgressList.tsx +40 -0
- package/src/components/FileUpload/useFileUploadManager.test.ts +308 -0
- package/src/components/FileUpload/useFileUploadManager.ts +454 -0
- package/src/components/FileUpload/useResolvedAppId.test.ts +102 -0
- package/src/components/FileUpload/useResolvedAppId.ts +77 -0
- package/src/components/Footer/Footer.test.tsx +6 -292
- package/src/components/Footer/Footer.tsx +8 -125
- package/src/components/Form/Form.test.tsx +44 -27
- package/src/components/Form/Form.tsx +64 -287
- package/src/components/Form/useFormPersistence.ts +257 -0
- package/src/components/Header/Header.test.tsx +17 -18
- package/src/components/Header/Header.tsx +10 -1
- package/src/components/Input/Input.tsx +1 -1
- package/src/components/Label/Label.test.tsx +1 -1
- package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +1 -1
- package/src/components/NavigationMenu/HierarchicalNavItem.tsx +104 -0
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +1029 -26
- package/src/components/NavigationMenu/NavigationMenu.tsx +61 -361
- package/src/components/NavigationMenu/index.ts +6 -1
- package/src/components/NavigationMenu/navigationPermissionHelper.ts +188 -0
- package/src/components/NavigationMenu/{__tests__/useNavigationFiltering.test.ts → useNavigationFiltering.test.ts} +68 -53
- package/src/components/NavigationMenu/useNavigationFiltering.ts +197 -296
- package/src/components/NavigationMenu/useNavigationScope.ts +125 -0
- package/src/components/PaceAppLayout/PaceAppLayout.edge-cases.test.tsx +77 -62
- package/src/components/PaceAppLayout/PaceAppLayout.integration.test.tsx +3 -3
- package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +16 -19
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +529 -5
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +280 -756
- package/src/components/PaceAppLayout/useFilteredNavItems.ts +304 -0
- package/src/components/PaceAppLayout/usePaceAppLayoutConfig.ts +142 -0
- package/src/components/PaceAppLayout/usePaceAppLayoutGate.tsx +150 -0
- package/src/components/PaceAppLayout/usePaceAppLayoutPermissions.ts +162 -0
- package/src/components/PaceAppLayout/usePaceAppLayoutScope.ts +79 -0
- package/src/components/PaceAppLayout/useRoleBasedRouteAccess.ts +157 -0
- package/src/components/PaceAppLayout/useSuperAdminFallback.ts +58 -0
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +31 -25
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +31 -122
- package/src/components/PaceLoginPage/useLoginAppAccess.ts +153 -0
- package/src/components/Progress/Progress.tsx +1 -2
- package/src/components/ProtectedRoute/ProtectedRoute.tsx +29 -235
- package/src/components/ProtectedRoute/useProtectedRouteState.ts +128 -0
- package/src/components/ProtectedRoute/useVisibilityRedirectGrace.ts +89 -0
- package/src/components/PublicLayout/PublicLayout.test.tsx +217 -36
- package/src/components/PublicLayout/PublicPageLayout.tsx +132 -73
- package/src/components/PublicLayout/PublicPageProvider.tsx +5 -1
- package/src/components/Select/Select.test.tsx +1 -1
- package/src/components/Select/Select.tsx +28 -18
- package/src/components/Select/{__tests__/context.test.tsx → context.test.tsx} +3 -3
- package/src/components/Select/{utils/__tests__/text.test.tsx → text.test.tsx} +2 -2
- package/src/components/Select/{utils/text.ts → text.ts} +1 -1
- package/src/components/Select/{hooks/__tests__/useSelectEvents.test.ts → useSelectEvents.test.ts} +5 -5
- package/src/components/Select/{hooks/useSelectEvents.ts → useSelectEvents.ts} +2 -2
- package/src/components/Select/{hooks/__tests__/useSelectSearch.test.tsx → useSelectSearch.test.tsx} +7 -7
- package/src/components/Select/{hooks/useSelectSearch.ts → useSelectSearch.ts} +2 -2
- package/src/components/Select/{hooks/__tests__/useSelectState.test.ts → useSelectState.test.ts} +16 -2
- package/src/components/Select/{hooks/useSelectState.ts → useSelectState.ts} +3 -3
- package/src/components/Table/Table.test.tsx +348 -0
- package/src/components/Tabs/Tabs.test.tsx +270 -0
- package/src/components/Tabs/Tabs.tsx +1 -1
- package/src/components/Toast/Toast.test.tsx +420 -0
- package/src/components/{__tests__/index.test.ts → index.test.ts} +2 -2
- package/src/constants/{__tests__/performance.test.ts → performance.test.ts} +2 -2
- package/src/hooks/{__tests__/ServiceHooks.test.tsx → ServiceHooks.test.tsx} +8 -8
- package/src/hooks/{__tests__/hooks.integration.test.tsx → hooks.integration.test.tsx} +11 -11
- package/src/hooks/index.ts +7 -4
- package/src/hooks/{__tests__/index.unit.test.ts → index.unit.test.ts} +2 -2
- package/src/hooks/public/usePublicEvent.test.ts +1 -1
- package/src/hooks/public/usePublicEventLogo.test.ts +1 -1
- package/src/hooks/public/usePublicRouteParams.test.ts +1 -1
- package/src/hooks/services/useAuth.ts +9 -7
- package/src/hooks/useAddressAutocomplete.test.ts +22 -22
- package/src/hooks/useAddressAutocomplete.ts +90 -75
- package/src/hooks/{__tests__/useAppConfig.unit.test.ts → useAppConfig.unit.test.ts} +328 -22
- package/src/hooks/{__tests__/useComponentPerformance.unit.test.tsx → useComponentPerformance.unit.test.tsx} +27 -41
- package/src/hooks/useDataTablePerformance.ts +100 -120
- package/src/hooks/{__tests__/useDataTablePerformance.unit.test.ts → useDataTablePerformance.unit.test.ts} +5 -5
- package/src/hooks/{__tests__/useDataTableState.test.ts → useDataTableState.test.ts} +2 -2
- package/src/hooks/{__tests__/useDebounce.unit.test.ts → useDebounce.unit.test.ts} +2 -2
- package/src/hooks/useEventTheme.test.ts +4 -1
- package/src/hooks/useEventTheme.ts +49 -21
- package/src/hooks/useEvents.ts +41 -1
- package/src/hooks/{__tests__/useEvents.unit.test.ts → useEvents.unit.test.ts} +5 -5
- package/src/hooks/useFileReference.test.ts +44 -41
- package/src/hooks/useFileReference.ts +182 -173
- package/src/hooks/useFileUrl.ts +1 -1
- package/src/hooks/{__tests__/useFileUrl.unit.test.ts → useFileUrl.unit.test.ts} +26 -36
- package/src/hooks/{__tests__/useFileUrlCache.test.ts → useFileUrlCache.test.ts} +8 -8
- package/src/hooks/useFileUrlCache.ts +1 -1
- package/src/hooks/{__tests__/useFocusManagement.unit.test.ts → useFocusManagement.unit.test.ts} +2 -2
- package/src/hooks/{__tests__/useFocusTrap.unit.test.tsx → useFocusTrap.unit.test.tsx} +2 -2
- package/src/hooks/{__tests__/useFormDialog.test.ts → useFormDialog.test.ts} +2 -2
- package/src/hooks/useInactivityTracker.ts +138 -131
- package/src/hooks/{__tests__/useInactivityTracker.unit.test.ts → useInactivityTracker.unit.test.ts} +3 -3
- package/src/hooks/{__tests__/useIsMobile.unit.test.ts → useIsMobile.unit.test.ts} +2 -2
- package/src/hooks/useIsPrint.ts +62 -0
- package/src/hooks/useIsPrint.unit.test.ts +545 -0
- package/src/hooks/{__tests__/useKeyboardShortcuts.unit.test.ts → useKeyboardShortcuts.unit.test.ts} +2 -2
- package/src/hooks/{__tests__/useOrganisationPermissions.unit.test.tsx → useOrganisationPermissions.unit.test.tsx} +4 -4
- package/src/hooks/useOrganisationSecurity.test.ts +3 -3
- package/src/hooks/useOrganisationSecurity.ts +190 -201
- package/src/hooks/{__tests__/useOrganisationSecurity.unit.test.tsx → useOrganisationSecurity.unit.test.tsx} +61 -63
- package/src/hooks/{__tests__/useOrganisations.unit.test.ts → useOrganisations.unit.test.ts} +5 -5
- package/src/hooks/{__tests__/usePerformanceMonitor.unit.test.ts → usePerformanceMonitor.unit.test.ts} +13 -14
- package/src/hooks/{__tests__/usePermissionCache.test.ts → usePermissionCache.test.ts} +26 -27
- package/src/hooks/usePermissionCache.ts +276 -271
- package/src/hooks/{__tests__/usePreventTabReload.test.ts → usePreventTabReload.test.ts} +2 -2
- package/src/hooks/{__tests__/usePublicEvent.simple.test.ts → usePublicEvent.simple.test.ts} +4 -4
- package/src/hooks/{__tests__/usePublicEvent.test.ts → usePublicEvent.test.ts} +4 -4
- package/src/hooks/{__tests__/usePublicEvent.unit.test.ts → usePublicEvent.unit.test.ts} +4 -4
- package/src/hooks/{__tests__/usePublicFileDisplay.test.ts → usePublicFileDisplay.test.ts} +12 -12
- package/src/hooks/{__tests__/usePublicRouteParams.unit.test.ts → usePublicRouteParams.unit.test.ts} +3 -3
- package/src/hooks/{__tests__/useQueryCache.test.ts → useQueryCache.test.ts} +2 -2
- package/src/hooks/useQueryCache.ts +0 -2
- package/src/hooks/{__tests__/useRBAC.unit.test.ts → useRBAC.unit.test.ts} +55 -38
- package/src/hooks/{__tests__/useSessionDraft.test.ts → useSessionDraft.test.ts} +2 -2
- package/src/hooks/{__tests__/useSessionRestoration.unit.test.tsx → useSessionRestoration.unit.test.tsx} +10 -19
- package/src/hooks/useStorage.ts +21 -16
- package/src/hooks/{__tests__/useStorage.unit.test.ts → useStorage.unit.test.ts} +38 -75
- package/src/hooks/{__tests__/useToast.test.ts → useToast.test.ts} +2 -2
- package/src/hooks/{__tests__/useToast.unit.test.tsx → useToast.unit.test.tsx} +2 -2
- package/src/hooks/{__tests__/useZodForm.unit.test.tsx → useZodForm.unit.test.tsx} +2 -2
- package/src/icons/{__tests__/index.test.ts → index.test.ts} +2 -2
- package/src/icons/index.ts +2 -0
- package/src/{__tests__/index.test.ts → index.test.ts} +3 -7
- package/src/index.ts +15 -7
- package/src/providers/{__tests__/AuthProvider.test.tsx → AuthProvider.test.tsx} +3 -3
- package/src/providers/{__tests__/EventProvider.test.tsx → EventProvider.test.tsx} +3 -3
- package/src/providers/InactivityProvider.test-helper.tsx +40 -0
- package/src/providers/{__tests__/InactivityProvider.test.tsx → InactivityProvider.test.tsx} +14 -21
- package/src/providers/{__tests__/ProviderLifecycle.test.tsx → ProviderLifecycle.test.tsx} +4 -4
- package/src/providers/{__tests__/UnifiedAuthProvider.test.tsx → UnifiedAuthProvider.test.tsx} +1 -1
- package/src/providers/{__tests__/index.test.ts → index.test.ts} +2 -2
- package/src/providers/services/{__tests__/AuthServiceProvider.integration.test.tsx → AuthServiceProvider.integration.test.tsx} +4 -4
- package/src/providers/services/{__tests__/AuthServiceProvider.test.tsx → AuthServiceProvider.test.tsx} +7 -7
- package/src/providers/services/{__tests__/EventServiceProvider.test.tsx → EventServiceProvider.test.tsx} +7 -7
- package/src/providers/services/{__tests__/InactivityServiceProvider.test.tsx → InactivityServiceProvider.test.tsx} +5 -5
- package/src/providers/services/{__tests__/OrganisationServiceProvider.test.tsx → OrganisationServiceProvider.test.tsx} +6 -6
- package/src/providers/services/UnifiedAuthContext.ts +30 -27
- package/src/providers/services/{__tests__/UnifiedAuthProvider.advanced.test.tsx → UnifiedAuthProvider.advanced.test.tsx} +8 -9
- package/src/providers/services/{__tests__/UnifiedAuthProvider.appId.test.tsx → UnifiedAuthProvider.appId.test.tsx} +25 -25
- package/src/providers/services/{__tests__/UnifiedAuthProvider.integration.test.tsx → UnifiedAuthProvider.integration.test.tsx} +14 -11
- package/src/providers/services/UnifiedAuthProvider.tsx +115 -360
- package/src/providers/services/{__tests__/contexts.test.tsx → contexts.test.tsx} +6 -6
- package/src/providers/services/{__tests__/useUnifiedAuth.test.tsx → useUnifiedAuth.test.tsx} +6 -6
- package/src/providers/services/useUnifiedAuthContextValue.ts +279 -0
- package/src/providers/useInactivity.test-helper.ts +27 -0
- package/src/rbac/{__tests__/adapters.comprehensive.test.tsx → adapters.comprehensive.test.tsx} +24 -24
- package/src/rbac/adapters.test.tsx +22 -22
- package/src/rbac/adapters.tsx +29 -29
- package/src/rbac/api.test.ts +973 -42
- package/src/rbac/api.ts +228 -253
- package/src/rbac/{__tests__/audit-batched.test.ts → audit-batched.test.ts} +6 -6
- package/src/rbac/audit.ts +4 -1
- package/src/rbac/{__tests__/auth-rbac-security.integration.test.tsx → auth-rbac-security.integration.test.tsx} +1 -1
- package/src/rbac/{__tests__/auth-rbac.e2e.test.tsx → auth-rbac.e2e.test.tsx} +27 -34
- package/src/rbac/cache-invalidation.test.ts +715 -0
- package/src/rbac/components/{__tests__/AccessDenied.test.tsx → AccessDenied.test.tsx} +3 -3
- package/src/rbac/components/{__tests__/NavigationGuard.test.tsx → NavigationGuard.test.tsx} +13 -11
- package/src/{__tests__/rbac/PagePermissionGuard.test.tsx → rbac/components/PagePermissionGuard.guard.test.tsx} +33 -19
- package/src/rbac/components/{__tests__/PagePermissionGuard.performance.test.tsx → PagePermissionGuard.performance.test.tsx} +30 -9
- package/src/rbac/components/{__tests__/PagePermissionGuard.race-condition.test.tsx → PagePermissionGuard.race-condition.test.tsx} +7 -7
- package/src/rbac/components/{__tests__/PagePermissionGuard.test.tsx → PagePermissionGuard.test.tsx} +10 -10
- package/src/rbac/components/PagePermissionGuard.tsx +177 -372
- package/src/rbac/components/{__tests__/PagePermissionGuard.verification.test.tsx → PagePermissionGuard.verification.test.tsx} +7 -7
- package/src/rbac/config.ts +58 -18
- package/src/rbac/{__tests__/engine.comprehensive.test.ts → engine.comprehensive.test.ts} +3 -3
- package/src/rbac/engine.test.ts +494 -0
- package/src/rbac/errors.ts +89 -55
- package/src/rbac/hooks/permissions/runPermissionCheck.ts +77 -0
- package/src/rbac/hooks/permissions/{__tests__/useAccessLevel.test.ts → useAccessLevel.test.ts} +40 -40
- package/src/rbac/hooks/permissions/useAccessLevel.ts +16 -6
- package/src/rbac/hooks/permissions/{__tests__/useCan.test.ts → useCan.test.ts} +41 -41
- package/src/rbac/hooks/permissions/useCan.ts +170 -252
- package/src/rbac/hooks/permissions/{__tests__/useMultiplePermissions.test.ts → useMultiplePermissions.test.ts} +49 -49
- package/src/rbac/hooks/permissions/useMultiplePermissions.ts +6 -2
- package/src/rbac/hooks/permissions/{__tests__/usePermissions.test.ts → usePermissions.test.ts} +10 -12
- package/src/rbac/hooks/permissions/usePermissions.ts +36 -65
- package/src/rbac/hooks/useCan.test.ts +42 -42
- package/src/rbac/hooks/usePageAccessLogging.ts +160 -0
- package/src/rbac/hooks/usePageGuardScope.ts +117 -0
- package/src/rbac/hooks/usePagePermissionCheck.ts +67 -0
- package/src/rbac/hooks/{__tests__/usePermissions.integration.test.ts → usePermissions.integration.test.ts} +9 -9
- package/src/{__tests__/hooks/usePermissions.test.ts → rbac/hooks/usePermissions.stability.test.ts} +18 -18
- package/src/rbac/hooks/usePermissions.test.ts +54 -54
- package/src/rbac/hooks/useRBAC.test.ts +313 -217
- package/src/rbac/hooks/useRBAC.ts +145 -81
- package/src/rbac/hooks/useResourcePermissions.test.ts +25 -25
- package/src/rbac/hooks/useResourcePermissions.ts +68 -134
- package/src/rbac/hooks/useResourcePermissionsSuperAdmin.ts +67 -0
- package/src/rbac/hooks/useRoleManagement.test.ts +27 -112
- package/src/rbac/hooks/useRoleManagement.ts +153 -585
- package/src/rbac/hooks/{__tests__/useSecureSupabase.test.ts → useSecureSupabase.test.ts} +17 -17
- package/src/rbac/hooks/useSecureSupabase.ts +10 -2
- package/src/rbac/hooks/useSuperAdminCheck.ts +80 -0
- package/src/rbac/{__tests__/performance.test.ts → performance.test.ts} +1 -1
- package/src/rbac/{__tests__/rbac-core.test.tsx → rbac-core.test.tsx} +3 -3
- package/src/rbac/{__tests__/rbac-engine-core-logic.test.ts → rbac-engine-core-logic.test.ts} +2 -2
- package/src/rbac/{__tests__/rbac-engine-simplified.test.ts → rbac-engine-simplified.test.ts} +3 -3
- package/src/rbac/{__tests__/rbac-functions.test.ts → rbac-functions.test.ts} +57 -0
- package/src/rbac/{__tests__/rbac-role-isolation.test.ts → rbac-role-isolation.test.ts} +2 -2
- package/src/rbac/request-deduplication.test.ts +14 -9
- package/src/rbac/request-deduplication.ts +5 -4
- package/src/rbac/{__tests__/scenarios.user-role.test.tsx → scenarios.user-role.test.tsx} +23 -23
- package/src/rbac/secureClient.test.ts +514 -83
- package/src/rbac/secureClient.ts +8 -2
- package/src/rbac/security.test.ts +323 -0
- package/src/rbac/types/roleManagement.ts +66 -0
- package/src/rbac/utils/{__tests__/clientSecurity.test.ts → clientSecurity.test.ts} +4 -4
- package/src/rbac/utils/{__tests__/contextValidator.test.ts → contextValidator.test.ts} +4 -4
- package/src/rbac/utils/contextValidator.ts +5 -1
- package/src/rbac/utils/{__tests__/deep-equal.test.ts → deep-equal.test.ts} +1 -1
- package/src/rbac/utils/{__tests__/eventContext.test.ts → eventContext.test.ts} +36 -21
- package/src/rbac/utils/eventContext.ts +37 -33
- package/src/rbac/utils/fetchPermissionMap.ts +13 -0
- package/src/rbac/utils/permissionMapHelpers.ts +34 -0
- package/src/rbac/utils/roleManagementRpc.ts +303 -0
- package/src/services/{__tests__/AuthService.edge-cases.test.ts → AuthService.edge-cases.test.ts} +19 -19
- package/src/services/{__tests__/AuthService.restoreSession.test.ts → AuthService.restoreSession.test.ts} +2 -2
- package/src/services/{__tests__/AuthService.test.ts → AuthService.test.ts} +89 -55
- package/src/services/AuthService.ts +184 -205
- package/src/services/{__tests__/BaseService.edge-cases.test.ts → BaseService.edge-cases.test.ts} +3 -3
- package/src/services/{__tests__/BaseService.test.ts → BaseService.test.ts} +2 -2
- package/src/services/{__tests__/EventService.edge-cases.test.ts → EventService.edge-cases.test.ts} +27 -24
- package/src/services/{__tests__/EventService.eventColours.test.ts → EventService.eventColours.test.ts} +1 -1
- package/src/services/{__tests__/EventService.test.ts → EventService.test.ts} +256 -24
- package/src/services/EventService.ts +242 -312
- package/src/services/{__tests__/InactivityService.edge-cases.test.ts → InactivityService.edge-cases.test.ts} +3 -3
- package/src/services/{__tests__/InactivityService.lifecycle.test.ts → InactivityService.lifecycle.test.ts} +2 -2
- package/src/services/{__tests__/InactivityService.test.ts → InactivityService.test.ts} +179 -4
- package/src/services/InactivityService.ts +172 -213
- package/src/services/{__tests__/OrganisationService.edge-cases.test.ts → OrganisationService.edge-cases.test.ts} +5 -5
- package/src/services/{__tests__/OrganisationService.pagination.test.ts → OrganisationService.pagination.test.ts} +4 -4
- package/src/services/{__tests__/OrganisationService.test.ts → OrganisationService.test.ts} +410 -7
- package/src/services/OrganisationService.ts +184 -238
- package/src/services/base/BaseService.test.ts +1 -1
- package/src/services/interfaces/{__tests__/IAuthService.test.ts → IAuthService.test.ts} +21 -27
- package/src/services/interfaces/IAuthService.ts +10 -9
- package/src/services/interfaces/{__tests__/IEventService.test.ts → IEventService.test.ts} +4 -4
- package/src/services/interfaces/{__tests__/IInactivityService.test.ts → IInactivityService.test.ts} +3 -3
- package/src/services/interfaces/{__tests__/IOrganisationService.test.ts → IOrganisationService.test.ts} +3 -3
- package/src/styles/core.css +243 -12
- package/src/theming/{__tests__/parseEventColours.test.ts → parseEventColours.test.ts} +1 -1
- package/src/theming/{__tests__/runtime.test.ts → runtime.test.ts} +8 -17
- package/src/theming/runtime.ts +71 -2
- package/src/types/api-result.ts +53 -0
- package/src/types/{__tests__/core.test.ts → core.test.ts} +2 -2
- package/src/types/{__tests__/database-generated.test.ts → database-generated.test.ts} +3 -3
- package/src/types/database.generated.ts +45 -10
- package/src/types/event.ts +38 -18
- package/src/types/{__tests__/file-reference.test.ts → file-reference.test.ts} +13 -13
- package/src/types/file-reference.ts +37 -12
- package/src/types/{__tests__/guards.test.ts → guards.test.ts} +2 -2
- package/src/types/{__tests__/index.test.ts → index.test.ts} +2 -2
- package/src/types/index.ts +3 -0
- package/src/types/{__tests__/organisation.roles.test.ts → organisation.roles.test.ts} +1 -1
- package/src/types/{__tests__/organisation.test.ts → organisation.test.ts} +3 -31
- package/src/types/organisation.ts +15 -15
- package/src/types/supabase.ts +13 -4
- package/src/types/{__tests__/theme.test.ts → theme.test.ts} +1 -1
- package/src/types/{__tests__/type-validation.test.ts → type-validation.test.ts} +1 -1
- package/src/types/{__tests__/validation.test.ts → validation.test.ts} +2 -2
- package/src/utils/app/appIdResolver.test.ts +98 -71
- package/src/utils/app/appIdResolver.ts +31 -20
- package/src/utils/{__tests__/appConfig.unit.test.ts → appConfig.unit.test.ts} +1 -1
- package/src/utils/{__tests__/audit.unit.test.ts → audit.unit.test.ts} +1 -1
- package/src/utils/{__tests__/auth-utils.unit.test.ts → auth-utils.unit.test.ts} +16 -17
- package/src/utils/{__tests__/bundleAnalysis.unit.test.ts → bundleAnalysis.unit.test.ts} +35 -35
- package/src/utils/{__tests__/cn.unit.test.ts → cn.unit.test.ts} +1 -1
- package/src/utils/context/organisationContext.test.ts +105 -91
- package/src/utils/context/organisationContext.ts +29 -40
- package/src/utils/core/{__tests__/cn.test.ts → cn.test.ts} +3 -3
- package/src/utils/core/{__tests__/debugLogger.test.ts → debugLogger.test.ts} +2 -2
- package/src/utils/core/{__tests__/logger.test.ts → logger.test.ts} +2 -2
- package/src/utils/core/mergeRefs.ts +24 -0
- package/src/utils/{__tests__/debugLogger.test.ts → debugLogger.test.ts} +1 -1
- package/src/utils/{__tests__/deviceFingerprint.unit.test.ts → deviceFingerprint.unit.test.ts} +1 -1
- package/src/utils/dynamic/createLazyComponent.tsx +9 -1
- package/src/utils/dynamic/{__tests__/dynamicUtils.test.ts → dynamicUtils.test.ts} +2 -2
- package/src/utils/dynamic/{__tests__/lazyLoad.test.tsx → lazyLoad.test.tsx} +2 -2
- package/src/utils/{__tests__/dynamicUtils.unit.test.ts → dynamicUtils.unit.test.ts} +1 -1
- package/src/utils/file-reference/{__tests__/file-reference.test.ts → file-reference.test.ts} +214 -289
- package/src/utils/file-reference/index.ts +330 -347
- package/src/utils/{__tests__/formatDate.unit.test.ts → formatDate.unit.test.ts} +2 -2
- package/src/utils/formatting/formatDateTimeTimezone.test.ts +1 -1
- package/src/utils/formatting/formatNumber.test.ts +1 -1
- package/src/utils/{__tests__/formatting.unit.test.ts → formatting.unit.test.ts} +1 -1
- package/src/utils/google-places/googlePlacesUtils.test.ts +70 -48
- package/src/utils/google-places/googlePlacesUtils.ts +67 -99
- package/src/utils/google-places/loadGoogleMapsScript.test.ts +25 -22
- package/src/utils/google-places/loadGoogleMapsScript.ts +138 -117
- package/src/utils/{__tests__/index.unit.test.ts → index.unit.test.ts} +1 -1
- package/src/utils/{__tests__/lazyLoad.unit.test.tsx → lazyLoad.unit.test.tsx} +13 -14
- package/src/utils/location/location.test.ts +1 -1
- package/src/utils/{__tests__/logger.unit.test.ts → logger.unit.test.ts} +1 -1
- package/src/utils/{__tests__/organisationContext.unit.test.ts → organisationContext.unit.test.ts} +37 -48
- package/src/utils/performance/{__tests__/bundleAnalysis.test.ts → bundleAnalysis.test.ts} +2 -2
- package/src/utils/performance/{__tests__/performanceBenchmark.test.ts → performanceBenchmark.test.ts} +2 -2
- package/src/utils/performance/{__tests__/performanceBudgets.test.ts → performanceBudgets.test.ts} +2 -2
- package/src/utils/{__tests__/performanceBenchmark.test.ts → performanceBenchmark.test.ts} +2 -2
- package/src/utils/{__tests__/performanceBudgets.unit.test.ts → performanceBudgets.unit.test.ts} +2 -2
- package/src/utils/{__tests__/permissionTypes.unit.test.ts → permissionTypes.unit.test.ts} +1 -1
- package/src/utils/{__tests__/permissionUtils.unit.test.ts → permissionUtils.unit.test.ts} +1 -1
- package/src/utils/permissions/{__tests__/permissionTypes.test.ts → permissionTypes.test.ts} +2 -2
- package/src/utils/persistence/{__tests__/keyDerivation.test.ts → keyDerivation.test.ts} +2 -2
- package/src/utils/persistence/{__tests__/sensitiveFieldDetection.test.ts → sensitiveFieldDetection.test.ts} +2 -2
- package/src/utils/{__tests__/request-deduplication.test.ts → request-deduplication.test.ts} +2 -2
- package/src/utils/{__tests__/sanitization.unit.test.ts → sanitization.unit.test.ts} +1 -1
- package/src/utils/{__tests__/schemaUtils.unit.test.ts → schemaUtils.unit.test.ts} +1 -1
- package/src/utils/{__tests__/secureDataAccess.unit.test.ts → secureDataAccess.unit.test.ts} +2 -2
- package/src/utils/{__tests__/secureErrors.unit.test.ts → secureErrors.unit.test.ts} +4 -4
- package/src/utils/{__tests__/secureStorage.unit.test.ts → secureStorage.unit.test.ts} +1 -1
- package/src/utils/security/auth-utils.ts +34 -23
- package/src/utils/security/secureDataAccess.ts +241 -281
- package/src/utils/security/secureErrors.test.ts +1 -1
- package/src/utils/security/secureStorage.test.ts +1 -1
- package/src/utils/security/security.test.ts +25 -17
- package/src/utils/security/security.ts +15 -18
- package/src/utils/security/securityMonitor.test.ts +1 -1
- package/src/utils/{__tests__/security.unit.test.ts → security.unit.test.ts} +21 -15
- package/src/utils/{__tests__/securityMonitor.unit.test.ts → securityMonitor.unit.test.ts} +1 -1
- package/src/utils/{__tests__/sessionTracking.unit.test.ts → sessionTracking.unit.test.ts} +12 -12
- package/src/utils/storage/{__tests__/config.unit.test.ts → config.unit.test.ts} +2 -2
- package/src/utils/storage/helpers.test.ts +88 -102
- package/src/utils/storage/helpers.ts +173 -251
- package/src/utils/storage/{__tests__/index.unit.test.ts → index.unit.test.ts} +3 -3
- package/src/utils/storage/types.ts +7 -0
- package/src/utils/supabase/createBaseClient.test.ts +1 -1
- package/src/utils/timezone/timezone.test.ts +1 -1
- package/src/utils/{__tests__/timezone.test.ts → timezone.test.ts} +2 -2
- package/src/utils/validation/{__tests__/common.test.ts → common.test.ts} +2 -2
- package/src/utils/validation/{__tests__/csrf.test.ts → csrf.test.ts} +56 -28
- package/src/utils/validation/csrf.ts +42 -41
- package/src/utils/validation/{__tests__/htmlSanitization.unit.test.ts → htmlSanitization.unit.test.ts} +2 -2
- package/src/utils/validation/{__tests__/passwordSchema.test.ts → passwordSchema.test.ts} +2 -2
- package/src/utils/validation/{__tests__/schema.test.ts → schema.test.ts} +2 -2
- package/src/utils/validation/{__tests__/sqlInjectionProtection.test.ts → sqlInjectionProtection.test.ts} +2 -2
- package/src/utils/validation/{__tests__/user.test.ts → user.test.ts} +2 -2
- package/src/utils/validation/{__tests__/validation.test.ts → validation.test.ts} +2 -2
- package/src/utils/validation/{__tests__/validationUtils.test.ts → validationUtils.test.ts} +2 -2
- package/src/utils/{__tests__/validation.unit.test.ts → validation.unit.test.ts} +1 -1
- package/src/utils/{__tests__/validationUtils.unit.test.ts → validationUtils.unit.test.ts} +5 -2
- package/dist/UnifiedAuthProvider-BBD2PS3Q.js +0 -7
- package/dist/chunk-KPYQWGFQ.js +0 -183
- package/dist/types-D05dCGma.d.ts +0 -521
- package/scripts/eslint-audit.cjs +0 -222
- package/scripts/generate-docs.js +0 -157
- package/scripts/install-cursor-rules.cjs +0 -255
- package/scripts/install-eslint-config.cjs +0 -349
- package/scripts/setup-build-cache.js +0 -73
- package/scripts/validate-pre-publish.js +0 -145
- package/src/__tests__/integration/UserProfile.test.tsx +0 -124
- package/src/__tests__/public-recipe-view.test.ts +0 -228
- package/src/__tests__/rls-policies.test.ts +0 -472
- package/src/components/DataTable/__tests__/DataTable.test.tsx +0 -876
- package/src/components/DataTable/components/DataTableLayout.tsx +0 -584
- package/src/components/DataTable/components/UnifiedTableBody.tsx +0 -395
- package/src/components/DataTable/components/__tests__/DataTableLayout.test.tsx +0 -467
- package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +0 -358
- package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +0 -957
- package/src/components/DataTable/core/ActionManager.ts +0 -235
- package/src/components/DataTable/core/ColumnManager.ts +0 -204
- package/src/components/DataTable/core/DataManager.ts +0 -190
- package/src/components/DataTable/core/LocalDataAdapter.ts +0 -274
- package/src/components/DataTable/core/PluginRegistry.ts +0 -229
- package/src/components/DataTable/core/StateManager.ts +0 -312
- package/src/components/DataTable/core/__tests__/ActionManager.test.ts +0 -235
- package/src/components/DataTable/core/__tests__/ColumnManager.test.ts +0 -141
- package/src/components/DataTable/core/__tests__/DataManager.test.ts +0 -178
- package/src/components/DataTable/core/__tests__/LocalDataAdapter.test.ts +0 -133
- package/src/components/DataTable/core/__tests__/PluginRegistry.test.ts +0 -142
- package/src/components/DataTable/core/__tests__/StateManager.test.ts +0 -158
- package/src/components/DataTable/core/interfaces.ts +0 -338
- package/src/components/DataTable/types.ts +0 -764
- package/src/hooks/public/usePublicFileDisplay.ts +0 -534
- package/src/hooks/useFileDisplay.ts +0 -748
- package/src/providers/OrganisationProvider.test.tsx +0 -40
- package/src/providers/OrganisationProvider.tsx +0 -92
- package/src/providers/__tests__/InactivityProvider.test-helper.tsx +0 -65
- package/src/providers/__tests__/OrganisationProvider.test.tsx +0 -616
- package/src/providers/__tests__/OrganisationProvider.wrapper.test.tsx +0 -591
- package/src/rbac/__tests__/cache-invalidation.test.ts +0 -393
- /package/src/components/DataTable/{components/__tests__ → ui}/COVERAGE_NOTE.md +0 -0
- /package/src/components/DataTable/utils/{__tests__/COVERAGE_NOTE.md → COVERAGE_NOTE.md} +0 -0
- /package/src/hooks/{__tests__/useApiFetch.unit.test.ts → useApiFetch.unit.test.ts} +0 -0
- /package/src/providers/{__tests__/README.md → README.md} +0 -0
- /package/src/rbac/{__tests__/index.test.ts → index.test.ts} +0 -0
- /package/src/rbac/{__tests__/rbac-integration.test.ts → rbac-integration.test.ts} +0 -0
- /package/src/types/{__tests__/README.md → README.md} +0 -0
|
@@ -8,37 +8,23 @@
|
|
|
8
8
|
* This is the main component that consumers will use.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import React, { useMemo, useCallback
|
|
12
|
-
import {
|
|
11
|
+
import React, { useMemo, useCallback } from 'react';
|
|
12
|
+
import type { SortingState } from '@tanstack/react-table';
|
|
13
13
|
import { useLocation } from 'react-router-dom';
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import { useServerSideDataEffect } from '../hooks/useServerSideDataEffect';
|
|
24
|
-
import { useEffectiveColumnOrder } from '../hooks/useEffectiveColumnOrder';
|
|
25
|
-
import { useTableHandlers, type TableStateSnapshot } from '../hooks/useTableHandlers';
|
|
26
|
-
import { useDataTableConfiguration } from '../hooks/useDataTableConfiguration';
|
|
27
|
-
import { AccessDeniedPage } from './AccessDeniedPage';
|
|
28
|
-
// NOTE: All toast() calls in this component use the default timeout (5 seconds).
|
|
29
|
-
// Do NOT set duration or timeout properties - let the toast system use its default.
|
|
30
|
-
import { toast } from '../../../hooks/useToast';
|
|
14
|
+
import { useIsPrint } from '../../../hooks/useIsPrint';
|
|
15
|
+
import { LoadingState } from '../ui/table/LoadingState';
|
|
16
|
+
import { DataTableLayout } from '../ui/layout/DataTableLayout';
|
|
17
|
+
import { DataTableErrorBoundary } from '../ui/layout/DataTableErrorBoundary';
|
|
18
|
+
import { useDataTableDeletionBatching } from '../hooks/useDataTableDeletionBatching';
|
|
19
|
+
import { useDataTableStateAndPersistence } from '../hooks/useDataTableStateAndPersistence';
|
|
20
|
+
import { useDataTablePipeline } from '../hooks/useDataTablePipeline';
|
|
21
|
+
import { useDataTableRenderGuard } from '../hooks/useDataTableRenderGuard';
|
|
22
|
+
import { AccessDeniedPage } from '../ui/shared/AccessDeniedPage';
|
|
31
23
|
import { useUnifiedAuth } from '../../../providers/services/UnifiedAuthProvider';
|
|
32
24
|
import { useDataTablePermissions } from '../hooks/useDataTablePermissions';
|
|
33
|
-
import { useTableColumns } from '../hooks/useTableColumns';
|
|
34
|
-
import { initializeLiveRegion } from '../utils/a11yUtils';
|
|
35
|
-
import { useKeyboardNavigation } from '../hooks/useKeyboardNavigation';
|
|
36
25
|
import { getRowIdSafe } from '../utils/rowUtils';
|
|
37
26
|
import { createLogger } from '../../../utils/core/logger';
|
|
38
|
-
import { usePermissionTracking } from '
|
|
39
|
-
import { useImportModalFocus } from './hooks/useImportModalFocus';
|
|
40
|
-
import { toCellValueRecord } from './cellValueUtils';
|
|
41
|
-
|
|
27
|
+
import { usePermissionTracking } from '../hooks/usePermissionTracking';
|
|
42
28
|
import {
|
|
43
29
|
normalizeDataTableFeatures,
|
|
44
30
|
type DataRecord,
|
|
@@ -106,7 +92,7 @@ export interface DataTableCoreProps<TData extends DataRecord> {
|
|
|
106
92
|
onEditRow?: (row: TData, data: Partial<TData>) => void;
|
|
107
93
|
onDeleteRow?: (row: TData) => void;
|
|
108
94
|
onCreateRow?: (data: Partial<TData>) => void;
|
|
109
|
-
onImport?: (data: TData[]) =>
|
|
95
|
+
onImport?: (data: TData[]) => import('../ui/modals/importModalPersistence').ImportHandlerResult;
|
|
110
96
|
onExport?: (options: import('../types').ExportOptions<TData>) => void | Promise<void>;
|
|
111
97
|
onRowSelectionChange?: (selection: Record<string, boolean>) => void;
|
|
112
98
|
selection?: Record<string, boolean>;
|
|
@@ -118,6 +104,8 @@ export interface DataTableCoreProps<TData extends DataRecord> {
|
|
|
118
104
|
emptyState?: EmptyStateConfig | React.ReactElement;
|
|
119
105
|
aggregates?: AggregateConfig[];
|
|
120
106
|
importModalConfig?: ImportModalConfig;
|
|
107
|
+
/** Called when the import modal is closed (e.g. to refetch table data). */
|
|
108
|
+
onImportModalClose?: () => void;
|
|
121
109
|
actions?: DataTableAction<TData>[];
|
|
122
110
|
columnOrder?: string[];
|
|
123
111
|
|
|
@@ -170,6 +158,7 @@ function DataTableInternal<TData extends DataRecord>(props: DataTableCoreProps<T
|
|
|
170
158
|
emptyState,
|
|
171
159
|
aggregates = [],
|
|
172
160
|
importModalConfig,
|
|
161
|
+
onImportModalClose,
|
|
173
162
|
actions = [],
|
|
174
163
|
columnOrder: externalColumnOrder,
|
|
175
164
|
defaultGrouping,
|
|
@@ -180,85 +169,26 @@ function DataTableInternal<TData extends DataRecord>(props: DataTableCoreProps<T
|
|
|
180
169
|
} = props;
|
|
181
170
|
|
|
182
171
|
const logger = createLogger('DataTableCore');
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
const pendingDeletionsRef = useRef<Set<string>>(new Set());
|
|
188
|
-
const dataSnapshotRef = useRef<TData[]>(data);
|
|
189
|
-
const dataChangeCountRef = useRef(0);
|
|
190
|
-
const previousDataLengthRef = useRef(data.length);
|
|
191
|
-
|
|
192
|
-
// CRITICAL: Use useLayoutEffect to capture previous length synchronously
|
|
193
|
-
// This runs before paint, so we can detect changes before React commits
|
|
194
|
-
useLayoutEffect(() => {
|
|
195
|
-
const currentLength = data.length;
|
|
196
|
-
const previousLength = previousDataLengthRef.current;
|
|
197
|
-
|
|
198
|
-
// Check if length decreased - this is the key detection
|
|
199
|
-
const lengthDecreased = currentLength < previousLength;
|
|
200
|
-
|
|
201
|
-
if (lengthDecreased && !isDeleting) {
|
|
202
|
-
// Data length decreased - start deletion batching
|
|
203
|
-
const snapshotLength = dataSnapshotRef.current.length;
|
|
204
|
-
|
|
205
|
-
// Data decrease detected (logging removed for performance)
|
|
206
|
-
|
|
207
|
-
// If snapshot is larger, it's valid (has pre-deletion state)
|
|
208
|
-
// Otherwise, update it to preserve current state
|
|
209
|
-
if (snapshotLength <= currentLength) {
|
|
210
|
-
dataSnapshotRef.current = [...data];
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
setIsDeleting(true);
|
|
214
|
-
|
|
215
|
-
// Set timeout to reset after batching
|
|
216
|
-
if (deletionTimeoutRef.current) {
|
|
217
|
-
clearTimeout(deletionTimeoutRef.current);
|
|
218
|
-
}
|
|
219
|
-
deletionTimeoutRef.current = setTimeout(() => {
|
|
220
|
-
setIsDeleting(false);
|
|
221
|
-
dataSnapshotRef.current = data;
|
|
222
|
-
previousDataLengthRef.current = data.length;
|
|
223
|
-
// Batching complete (logging removed for performance)
|
|
224
|
-
}, 150);
|
|
225
|
-
|
|
226
|
-
// Update previous length AFTER setting up batching
|
|
227
|
-
previousDataLengthRef.current = currentLength;
|
|
228
|
-
} else if (!lengthDecreased && !isDeleting) {
|
|
229
|
-
// No deletion - update snapshot and previous length normally
|
|
230
|
-
dataSnapshotRef.current = data;
|
|
231
|
-
previousDataLengthRef.current = currentLength;
|
|
232
|
-
} else if (isDeleting) {
|
|
233
|
-
// Already deleting - just update previous length for next comparison
|
|
234
|
-
previousDataLengthRef.current = currentLength;
|
|
235
|
-
}
|
|
236
|
-
}, [data, isDeleting]);
|
|
237
|
-
|
|
238
|
-
// Keep data snapshot stable during deletions to prevent flashing
|
|
239
|
-
// Logging effect - runs after layout to show what happened
|
|
240
|
-
useEffect(() => {
|
|
241
|
-
dataChangeCountRef.current += 1;
|
|
242
|
-
|
|
243
|
-
// Data prop changed (logging removed for performance)
|
|
244
|
-
}, [data, isDeleting]);
|
|
245
|
-
|
|
246
|
-
// Use snapshot data during deletions to prevent flashing
|
|
247
|
-
// CRITICAL: If we're deleting and data length decreased, use snapshot to prevent flashing
|
|
248
|
-
const dataLengthChanged = data.length !== dataSnapshotRef.current.length;
|
|
249
|
-
const isDataDecreasing = data.length < dataSnapshotRef.current.length;
|
|
250
|
-
const effectiveData = (isDeleting && isDataDecreasing) ? dataSnapshotRef.current : data;
|
|
251
|
-
|
|
252
|
-
// Effective data tracking (logging removed for performance)
|
|
253
|
-
|
|
172
|
+
|
|
173
|
+
const { effectiveData, isDeleting, setIsDeleting, deletionRefs } =
|
|
174
|
+
useDataTableDeletionBatching<TData>(data);
|
|
175
|
+
|
|
254
176
|
// ============================================================================
|
|
255
177
|
// ALL HOOKS MUST BE CALLED IN THE SAME ORDER EVERY RENDER
|
|
178
|
+
// Responsibilities: useDataTableDeletionBatching (in-flight delete UI),
|
|
179
|
+
// useUnifiedAuth (user), useIsPrint (print), useDataTablePermissions (RBAC),
|
|
180
|
+
// usePermissionTracking (timeout/loading), useDataTableStateAndPersistence (state +
|
|
181
|
+
// column order/visibility), useDataTablePipeline (table instance + layout props),
|
|
182
|
+
// useDataTableRenderGuard (loading / access-denied gate).
|
|
256
183
|
// ============================================================================
|
|
257
|
-
|
|
184
|
+
|
|
258
185
|
// MANDATORY: Get authenticated user - ALWAYS call this hook
|
|
259
186
|
const authResult = useUnifiedAuth();
|
|
260
187
|
const user = authResult.user;
|
|
261
188
|
|
|
189
|
+
// Detect print mode to disable pagination when printing
|
|
190
|
+
const isPrint = useIsPrint();
|
|
191
|
+
|
|
262
192
|
const requestedFeatures = useMemo<NormalizedDataTableFeatureConfig>(() =>
|
|
263
193
|
normalizeDataTableFeatures(incomingFeatures),
|
|
264
194
|
[incomingFeatures]);
|
|
@@ -278,807 +208,117 @@ function DataTableInternal<TData extends DataRecord>(props: DataTableCoreProps<T
|
|
|
278
208
|
|
|
279
209
|
|
|
280
210
|
// ============================================================================
|
|
281
|
-
//
|
|
211
|
+
// STATE AND PERSISTENCE - column order/visibility, core state, sync effects
|
|
282
212
|
// ============================================================================
|
|
283
|
-
|
|
284
|
-
const
|
|
213
|
+
|
|
214
|
+
const location = useLocation();
|
|
215
|
+
|
|
216
|
+
const {
|
|
217
|
+
state,
|
|
218
|
+
stateActions,
|
|
219
|
+
rowSelection,
|
|
220
|
+
effectiveColumnOrder,
|
|
221
|
+
updateSavedColumnVisibility,
|
|
222
|
+
updateColumnOrder,
|
|
223
|
+
} = useDataTableStateAndPersistence<TData>({
|
|
285
224
|
columns,
|
|
286
225
|
externalColumnOrder,
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
// ============================================================================
|
|
291
|
-
// COLUMN VISIBILITY PERSISTENCE - ALWAYS call these hooks
|
|
292
|
-
// ============================================================================
|
|
293
|
-
|
|
294
|
-
const {
|
|
295
|
-
columnVisibility: savedColumnVisibility,
|
|
296
|
-
isLoaded: isColumnVisibilityLoaded,
|
|
297
|
-
updateColumnVisibility: updateSavedColumnVisibility,
|
|
298
|
-
} = useColumnVisibilityPersistence({
|
|
299
|
-
tableId: title ? `datatable-${title.toLowerCase().replace(/\s+/g, '-')}` : undefined,
|
|
300
|
-
defaultVisibility: initialColumnVisibilityProp || {},
|
|
301
|
-
enablePersistence: secureFeatures.columnVisibility,
|
|
226
|
+
title,
|
|
227
|
+
initialColumnVisibility: initialColumnVisibilityProp || {},
|
|
302
228
|
storageKey,
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
}
|
|
310
|
-
// Fall back to prop if no saved visibility
|
|
311
|
-
return initialColumnVisibilityProp || {};
|
|
312
|
-
}, [secureFeatures.columnVisibility, savedColumnVisibility, initialColumnVisibilityProp]);
|
|
313
|
-
|
|
314
|
-
// Get location for route-based key derivation
|
|
315
|
-
let location: { pathname: string } | null = null;
|
|
316
|
-
try {
|
|
317
|
-
// useLocation may not be available if React Router is not set up
|
|
318
|
-
const routerLocation = useLocation();
|
|
319
|
-
location = routerLocation;
|
|
320
|
-
} catch {
|
|
321
|
-
// Router not available, location will be null
|
|
322
|
-
location = null;
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
// Extract column field names for sensitive field filtering
|
|
326
|
-
const columnFieldNames = useMemo(() => {
|
|
327
|
-
return columns
|
|
328
|
-
.map((col) => col.accessorKey || col.id)
|
|
329
|
-
.filter((key): key is string => Boolean(key));
|
|
330
|
-
}, [columns]);
|
|
331
|
-
|
|
332
|
-
// Use the centralized state management hook for ALL table state
|
|
333
|
-
// Note: 'actions' prop parameter is shadowed by destructuring, so we rename to stateActions
|
|
334
|
-
const { state, actions: stateActions } = useDataTableState<TData>({
|
|
229
|
+
secureFeatures: {
|
|
230
|
+
columnVisibility: secureFeatures.columnVisibility,
|
|
231
|
+
columnReordering: secureFeatures.columnReordering,
|
|
232
|
+
selection: secureFeatures.selection,
|
|
233
|
+
},
|
|
234
|
+
rbacPageId: rbac.pageId,
|
|
335
235
|
initialPageSize,
|
|
336
|
-
|
|
337
|
-
initialRowSelection: selection || {},
|
|
236
|
+
selection,
|
|
338
237
|
onRowSelectionChange,
|
|
339
238
|
defaultSorting: defaultSorting || [],
|
|
340
239
|
defaultGrouping: defaultGrouping || [],
|
|
341
|
-
// Persistence props
|
|
342
|
-
rbacPageId: rbac.pageId,
|
|
343
|
-
title,
|
|
344
240
|
location,
|
|
345
|
-
columnFieldNames,
|
|
346
241
|
});
|
|
347
|
-
|
|
348
|
-
// Apply saved visibility to state if available
|
|
349
|
-
useEffect(() => {
|
|
350
|
-
if (secureFeatures.columnVisibility && isColumnVisibilityLoaded && Object.keys(initialColumnVisibility).length > 0) {
|
|
351
|
-
stateActions.setColumnVisibility(initialColumnVisibility);
|
|
352
|
-
}
|
|
353
|
-
}, [secureFeatures.columnVisibility, isColumnVisibilityLoaded, initialColumnVisibility, stateActions]);
|
|
354
|
-
|
|
355
|
-
// Initialize live region for accessibility announcements
|
|
356
|
-
useEffect(() => {
|
|
357
|
-
initializeLiveRegion();
|
|
358
|
-
}, []);
|
|
359
|
-
|
|
360
|
-
// Row selection: prefer controlled prop, fall back to state
|
|
361
|
-
const rowSelection = selection !== undefined ? selection : state.rowSelection;
|
|
362
242
|
|
|
363
243
|
const resolvedGetRowId = useCallback(
|
|
364
244
|
(row: TData, index: number) => getRowIdSafe(row, index, getRowId),
|
|
365
245
|
[getRowId]
|
|
366
246
|
);
|
|
367
|
-
|
|
368
|
-
// ============================================================================
|
|
369
|
-
// AUTO-EXPAND GROUPS WHEN DEFAULT GROUPING IS PROVIDED
|
|
370
|
-
// ============================================================================
|
|
371
|
-
|
|
372
|
-
// Track if we've already initialized expansion state
|
|
373
|
-
const hasInitializedExpansion = useRef(false);
|
|
374
|
-
|
|
375
|
-
// Auto-expand all groups when default grouping is provided (only once on mount)
|
|
376
|
-
useEffect(() => {
|
|
377
|
-
if (!hasInitializedExpansion.current && defaultGrouping && defaultGrouping.length > 0) {
|
|
378
|
-
stateActions.setExpanded(true); // Expand all groups
|
|
379
|
-
hasInitializedExpansion.current = true;
|
|
380
|
-
}
|
|
381
|
-
}, [defaultGrouping, stateActions]);
|
|
382
247
|
|
|
383
|
-
|
|
384
|
-
// Note: Most state values are accessed via state object directly when needed
|
|
385
|
-
|
|
386
|
-
// ============================================================================
|
|
387
|
-
// PERFORMANCE HOOK - ALWAYS call this hook
|
|
388
|
-
// ============================================================================
|
|
389
|
-
|
|
390
|
-
const performanceHook = useDataTablePerformance({
|
|
248
|
+
const pipeline = useDataTablePipeline<TData>({
|
|
391
249
|
data,
|
|
250
|
+
effectiveData,
|
|
251
|
+
columns,
|
|
252
|
+
state,
|
|
253
|
+
stateActions,
|
|
254
|
+
rowSelection,
|
|
255
|
+
effectiveColumnOrder,
|
|
256
|
+
updateSavedColumnVisibility,
|
|
257
|
+
updateColumnOrder,
|
|
258
|
+
secureFeatures,
|
|
259
|
+
permissions,
|
|
260
|
+
deletionRefs,
|
|
261
|
+
isDeleting,
|
|
262
|
+
setIsDeleting,
|
|
263
|
+
onCreateRow,
|
|
264
|
+
onEditRow,
|
|
265
|
+
onDeleteRow,
|
|
266
|
+
onImport,
|
|
267
|
+
onExport,
|
|
268
|
+
onDeleteSelected,
|
|
269
|
+
actions,
|
|
270
|
+
resolvedGetRowId,
|
|
392
271
|
performance,
|
|
393
272
|
serverSide,
|
|
394
273
|
chunking,
|
|
395
274
|
searchIndex,
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
const finalPaginationMode = paginationMode || detectedMode;
|
|
410
|
-
|
|
411
|
-
// ============================================================================
|
|
412
|
-
// KEYBOARD NAVIGATION - ALWAYS call this hook
|
|
413
|
-
// ============================================================================
|
|
414
|
-
|
|
415
|
-
const keyboardNavigation = useKeyboardNavigation(
|
|
416
|
-
data.length,
|
|
417
|
-
columns.length,
|
|
418
|
-
{
|
|
419
|
-
enabled: true,
|
|
420
|
-
announceNavigation: true,
|
|
421
|
-
supportsColumnReorder: secureFeatures.columnReordering,
|
|
422
|
-
supportsColumnResize: false, // Column resizing is not currently supported
|
|
423
|
-
}
|
|
424
|
-
);
|
|
425
|
-
|
|
426
|
-
const { lastFocusedElementRef } = useImportModalFocus(state.showImportModal, keyboardNavigation);
|
|
427
|
-
|
|
428
|
-
// ============================================================================
|
|
429
|
-
// HIERARCHICAL DATA VALIDATION AND PROCESSING - ALWAYS call these hooks
|
|
430
|
-
// ============================================================================
|
|
431
|
-
|
|
432
|
-
const {
|
|
433
|
-
finalTableData,
|
|
434
|
-
dataCount: finalDataCount,
|
|
435
|
-
hierarchicalState,
|
|
436
|
-
hierarchicalValidation,
|
|
437
|
-
} = useDataTableDataPipeline<TData>({
|
|
438
|
-
data: effectiveData,
|
|
439
|
-
features: secureFeatures,
|
|
275
|
+
paginationMode,
|
|
276
|
+
initialPageSize,
|
|
277
|
+
externalIsLoading,
|
|
278
|
+
isPrint,
|
|
279
|
+
effectivePageId,
|
|
280
|
+
logger,
|
|
281
|
+
title,
|
|
282
|
+
description,
|
|
283
|
+
variant,
|
|
284
|
+
className,
|
|
285
|
+
emptyState,
|
|
286
|
+
virtualHeight,
|
|
440
287
|
hierarchical,
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
});
|
|
445
|
-
|
|
446
|
-
useEffect(() => {
|
|
447
|
-
if (!hierarchicalValidation.isValid) {
|
|
448
|
-
logger.error('Hierarchical data validation failed:', hierarchicalValidation.errors);
|
|
449
|
-
}
|
|
450
|
-
}, [hierarchicalValidation, logger]);
|
|
451
|
-
|
|
452
|
-
// Final table data tracking (logging removed for performance)
|
|
453
|
-
|
|
454
|
-
// Cleanup deletion timeout on unmount
|
|
455
|
-
useEffect(() => {
|
|
456
|
-
const pendingDeletions = pendingDeletionsRef.current;
|
|
457
|
-
return () => {
|
|
458
|
-
if (deletionTimeoutRef.current) {
|
|
459
|
-
clearTimeout(deletionTimeoutRef.current);
|
|
460
|
-
}
|
|
461
|
-
pendingDeletions.clear();
|
|
462
|
-
};
|
|
463
|
-
}, []);
|
|
464
|
-
|
|
465
|
-
// Update data snapshot when data changes and we're not deleting
|
|
466
|
-
useEffect(() => {
|
|
467
|
-
if (!isDeleting && data !== dataSnapshotRef.current) {
|
|
468
|
-
dataSnapshotRef.current = data;
|
|
469
|
-
}
|
|
470
|
-
}, [data, isDeleting]);
|
|
471
|
-
|
|
472
|
-
// Cleanup deletion timeout on unmount
|
|
473
|
-
useEffect(() => {
|
|
474
|
-
return () => {
|
|
475
|
-
if (deletionTimeoutRef.current) {
|
|
476
|
-
clearTimeout(deletionTimeoutRef.current);
|
|
477
|
-
}
|
|
478
|
-
};
|
|
479
|
-
}, []);
|
|
480
|
-
|
|
481
|
-
const {
|
|
482
|
-
columnOrder: savedColumnOrder,
|
|
483
|
-
isLoaded: isColumnOrderLoaded,
|
|
484
|
-
updateColumnOrder,
|
|
485
|
-
} = useColumnOrderPersistence({
|
|
486
|
-
tableId: title ? `datatable-${title.toLowerCase().replace(/\s+/g, '-')}` : undefined,
|
|
487
|
-
defaultOrder: columns.map(col => col.id || col.accessorKey || ''),
|
|
488
|
-
enablePersistence: secureFeatures.columnReordering,
|
|
288
|
+
aggregates,
|
|
289
|
+
importModalConfig,
|
|
290
|
+
onImportModalClose,
|
|
489
291
|
storageKey,
|
|
490
|
-
});
|
|
491
|
-
|
|
492
|
-
useEffect(() => {
|
|
493
|
-
if (
|
|
494
|
-
secureFeatures.columnReordering &&
|
|
495
|
-
isColumnOrderLoaded &&
|
|
496
|
-
savedColumnOrder &&
|
|
497
|
-
savedColumnOrder.length > 0
|
|
498
|
-
) {
|
|
499
|
-
// Normalize: ensure 'select' is first if selection is enabled
|
|
500
|
-
const normalizedOrder = secureFeatures.selection && savedColumnOrder.includes('select')
|
|
501
|
-
? ['select', ...savedColumnOrder.filter(id => id !== 'select')]
|
|
502
|
-
: savedColumnOrder;
|
|
503
|
-
stateActions.setColumnOrder(normalizedOrder);
|
|
504
|
-
}
|
|
505
|
-
}, [secureFeatures.columnReordering, secureFeatures.selection, isColumnOrderLoaded, savedColumnOrder, stateActions]);
|
|
506
|
-
|
|
507
|
-
// CRITICAL: Always ensure state.columnOrder has 'select' first if selection is enabled
|
|
508
|
-
// This fixes any state that gets out of sync (e.g., from localStorage or user reordering)
|
|
509
|
-
useEffect(() => {
|
|
510
|
-
if (secureFeatures.selection && state.columnOrder.includes('select') && state.columnOrder[0] !== 'select') {
|
|
511
|
-
const normalizedOrder = ['select', ...state.columnOrder.filter(id => id !== 'select')];
|
|
512
|
-
stateActions.setColumnOrder(normalizedOrder);
|
|
513
|
-
// Also update persisted order if persistence is enabled
|
|
514
|
-
if (secureFeatures.columnReordering) {
|
|
515
|
-
updateColumnOrder(normalizedOrder);
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
}, [secureFeatures.selection, secureFeatures.columnReordering, state.columnOrder, stateActions, updateColumnOrder]);
|
|
519
|
-
|
|
520
|
-
// ============================================================================
|
|
521
|
-
// CONFIGURATION RESOLUTION - ALWAYS call these hooks
|
|
522
|
-
// ============================================================================
|
|
523
|
-
|
|
524
|
-
const finalPageSizeOptions = optimizedPageSizeOptions;
|
|
525
|
-
|
|
526
|
-
const validatedInitialPageSize = useMemo(() => {
|
|
527
|
-
if (!secureFeatures.pagination || !finalPageSizeOptions.length) {
|
|
528
|
-
return initialPageSize;
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
if (finalPageSizeOptions.includes(initialPageSize)) {
|
|
532
|
-
return initialPageSize;
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
const sortedOptions = [...finalPageSizeOptions].sort((a, b) => a - b);
|
|
536
|
-
const closestOption = sortedOptions.reduce((prev, curr) =>
|
|
537
|
-
Math.abs(curr - initialPageSize) < Math.abs(prev - initialPageSize) ? curr : prev
|
|
538
|
-
);
|
|
539
|
-
|
|
540
|
-
logger.warn(
|
|
541
|
-
`initialPageSize ${initialPageSize} is not available in page size options [${finalPageSizeOptions.join(', ')}]. Using closest option: ${closestOption}`
|
|
542
|
-
);
|
|
543
|
-
|
|
544
|
-
return closestOption;
|
|
545
|
-
}, [initialPageSize, finalPageSizeOptions, secureFeatures.pagination, logger]);
|
|
546
|
-
|
|
547
|
-
// Determine the effective pageSize to use (validated or current state)
|
|
548
|
-
// CRITICAL: This ensures we always pass a valid pageSize to TanStack Table configuration.
|
|
549
|
-
// An invalid pageSize can cause getPaginationRowModel() to return empty rows.
|
|
550
|
-
const effectivePageSize = useMemo(() => {
|
|
551
|
-
if (!secureFeatures.pagination || !finalPageSizeOptions.length) {
|
|
552
|
-
return state.pagination.pageSize;
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
// If current pageSize is invalid (not in options), use validated value immediately
|
|
556
|
-
// This is a safety net in case the useEffect hasn't run yet
|
|
557
|
-
if (!finalPageSizeOptions.includes(state.pagination.pageSize)) {
|
|
558
|
-
return validatedInitialPageSize;
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
return state.pagination.pageSize;
|
|
562
|
-
}, [state.pagination.pageSize, validatedInitialPageSize, secureFeatures.pagination, finalPageSizeOptions]);
|
|
563
|
-
|
|
564
|
-
// CRITICAL FIX: Ensure pagination state always uses a valid pageSize and pageIndex
|
|
565
|
-
// An invalid pageSize (not in page size options) causes getPaginationRowModel() to return empty rows,
|
|
566
|
-
// which manifests as "DataTable shows record count but no rows" bug for large datasets.
|
|
567
|
-
// An out-of-bounds pageIndex (beyond available pages) also causes empty rows.
|
|
568
|
-
// This fixes the bug where DataTable shows record count but no rows for large datasets.
|
|
569
|
-
useEffect(() => {
|
|
570
|
-
if (secureFeatures.pagination && finalPageSizeOptions.length > 0) {
|
|
571
|
-
const needsFix = !finalPageSizeOptions.includes(state.pagination.pageSize);
|
|
572
|
-
|
|
573
|
-
// Also check if pageIndex is out of bounds for the current data
|
|
574
|
-
const currentPageSize = effectivePageSize || validatedInitialPageSize;
|
|
575
|
-
const totalPages = currentPageSize > 0 ? Math.ceil(finalDataCount / currentPageSize) : 0;
|
|
576
|
-
const pageIndexOutOfBounds = totalPages > 0 && state.pagination.pageIndex >= totalPages;
|
|
577
|
-
|
|
578
|
-
if (needsFix || pageIndexOutOfBounds) {
|
|
579
|
-
// PageSize is invalid OR pageIndex is out of bounds - correct both to prevent empty rows
|
|
580
|
-
stateActions.setPagination({
|
|
581
|
-
pageSize: validatedInitialPageSize,
|
|
582
|
-
pageIndex: 0, // Reset to first page when correcting pagination issues
|
|
583
|
-
});
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
}, [
|
|
587
|
-
secureFeatures.pagination,
|
|
588
|
-
finalPageSizeOptions,
|
|
589
|
-
state.pagination.pageSize,
|
|
590
|
-
state.pagination.pageIndex,
|
|
591
|
-
validatedInitialPageSize,
|
|
592
|
-
stateActions,
|
|
593
|
-
effectivePageSize,
|
|
594
|
-
finalDataCount
|
|
595
|
-
]);
|
|
596
|
-
|
|
597
|
-
// React 19 fix: Use useMemo to ensure isLoading updates when props change
|
|
598
|
-
// This prevents the component from getting stuck in loading state when externalIsLoading
|
|
599
|
-
// changes from true to false in React 19 with automatic memoization
|
|
600
|
-
const isLoading = useMemo(
|
|
601
|
-
() => externalIsLoading || performanceLoading,
|
|
602
|
-
[externalIsLoading, performanceLoading]
|
|
603
|
-
);
|
|
604
|
-
|
|
605
|
-
// ============================================================================
|
|
606
|
-
// DATA PROCESSING - ALWAYS call these hooks
|
|
607
|
-
// ============================================================================
|
|
608
|
-
|
|
609
|
-
// ============================================================================
|
|
610
|
-
// ACTIONS PROCESSING - ALWAYS call these hooks
|
|
611
|
-
// ============================================================================
|
|
612
|
-
|
|
613
|
-
// ============================================================================
|
|
614
|
-
// COLUMN PROCESSING - ALWAYS call these hooks
|
|
615
|
-
// ============================================================================
|
|
616
|
-
|
|
617
|
-
// ============================================================================
|
|
618
|
-
// TABLE CONFIGURATION - ALWAYS call these hooks
|
|
619
|
-
// ============================================================================
|
|
620
|
-
|
|
621
|
-
// ============================================================================
|
|
622
|
-
// SEARCH HANDLERS - ALWAYS call these hooks
|
|
623
|
-
// ============================================================================
|
|
624
|
-
|
|
625
|
-
/**
|
|
626
|
-
* Handle search input changes.
|
|
627
|
-
*
|
|
628
|
-
* When a search query is entered, we reset to the first page to show results
|
|
629
|
-
* from the beginning. This provides a better user experience when searching
|
|
630
|
-
* large datasets.
|
|
631
|
-
*
|
|
632
|
-
* CRITICAL: Must sync both state.searchQuery (used by state management) and
|
|
633
|
-
* performance hook's searchQuery (used by table filtering and search index).
|
|
634
|
-
*
|
|
635
|
-
* @param value - The search query string
|
|
636
|
-
*/
|
|
637
|
-
const handleSearch = useCallback((value: string) => {
|
|
638
|
-
// Update both search query states to keep them in sync
|
|
639
|
-
stateActions.setSearchQuery(value);
|
|
640
|
-
setSearchQuery(value);
|
|
641
|
-
|
|
642
|
-
// Reset to first page when searching to show results from the beginning
|
|
643
|
-
if (secureFeatures.pagination) {
|
|
644
|
-
stateActions.setPagination({ ...state.pagination, pageIndex: 0 });
|
|
645
|
-
}
|
|
646
|
-
}, [stateActions, setSearchQuery, secureFeatures.pagination, state.pagination]);
|
|
647
|
-
|
|
648
|
-
// ============================================================================
|
|
649
|
-
// SERVER-SIDE DATA FETCHING - ALWAYS call these hooks
|
|
650
|
-
// ============================================================================
|
|
651
|
-
|
|
652
|
-
/**
|
|
653
|
-
* Handle server-side data fetching.
|
|
654
|
-
*
|
|
655
|
-
* This function is called when any state that affects server-side data changes:
|
|
656
|
-
* - pagination (page/size)
|
|
657
|
-
* - sorting (column/sort order)
|
|
658
|
-
* - filtering (column filters or global search)
|
|
659
|
-
* - grouping
|
|
660
|
-
*
|
|
661
|
-
* It collects all current table state and makes a single request to the server
|
|
662
|
-
* with those parameters, allowing for efficient server-side pagination, sorting,
|
|
663
|
-
* and filtering without loading all data client-side.
|
|
664
|
-
*
|
|
665
|
-
* Early return guards prevent unnecessary server calls when:
|
|
666
|
-
* - Component is in client-side mode (finalPaginationMode !== 'server')
|
|
667
|
-
* - No server-side config is provided (!serverSide)
|
|
668
|
-
*/
|
|
669
|
-
useServerSideDataEffect<TData>({
|
|
670
|
-
finalPaginationMode,
|
|
671
|
-
serverSide,
|
|
672
|
-
pagination: state.pagination,
|
|
673
|
-
sorting: state.sorting,
|
|
674
|
-
columnFilters: state.columnFilters,
|
|
675
|
-
grouping: state.grouping,
|
|
676
|
-
searchQuery,
|
|
677
|
-
tableDataLength: finalTableData.length,
|
|
678
|
-
fetchServerData,
|
|
679
|
-
cleanup,
|
|
680
|
-
});
|
|
681
|
-
|
|
682
|
-
// ============================================================================
|
|
683
|
-
// RBAC VALIDATION AND SECURE CONFIGURATION - ALWAYS call these hooks
|
|
684
|
-
// ============================================================================
|
|
685
|
-
|
|
686
|
-
// Wrap handlers - persistence is handled automatically via useDataTableState
|
|
687
|
-
// The state actions (clearCreationData, clearEditing) will automatically update persisted state
|
|
688
|
-
const wrappedOnCreateRow = onCreateRow;
|
|
689
|
-
const wrappedOnEditRow = onEditRow;
|
|
690
|
-
|
|
691
|
-
// MANDATORY: Handlers are automatically secured
|
|
692
|
-
const secureHandlers = useMemo(() => {
|
|
693
|
-
const handlers = {
|
|
694
|
-
onEditRow: permissions.canUpdate.can ? wrappedOnEditRow : undefined,
|
|
695
|
-
onDeleteRow: permissions.canDelete.can ? onDeleteRow : undefined,
|
|
696
|
-
onCreateRow: permissions.canCreate.can ? wrappedOnCreateRow : undefined,
|
|
697
|
-
onImport: permissions.canImport.can ? onImport : undefined,
|
|
698
|
-
onExport: permissions.canExport.can ? onExport : undefined,
|
|
699
|
-
onDeleteSelected: permissions.canDelete.can ? onDeleteSelected : undefined,
|
|
700
|
-
};
|
|
701
|
-
|
|
702
|
-
return handlers;
|
|
703
|
-
}, [permissions.canUpdate.can, permissions.canDelete.can, permissions.canCreate.can, permissions.canImport.can, permissions.canExport.can, wrappedOnEditRow, onDeleteRow, wrappedOnCreateRow, onImport, onExport, onDeleteSelected]);
|
|
704
|
-
|
|
705
|
-
// MANDATORY: Process actions with RBAC checks
|
|
706
|
-
const effectiveActions = useMemo(() => {
|
|
707
|
-
// Create a new array to avoid mutating the original
|
|
708
|
-
const result = [...actions];
|
|
709
|
-
|
|
710
|
-
// Add Edit action with RBAC check
|
|
711
|
-
if (secureFeatures.editing && secureHandlers.onEditRow && !result.some(a => a.label === 'Edit')) {
|
|
712
|
-
result.push({
|
|
713
|
-
label: 'Edit',
|
|
714
|
-
onClick: (row: TData) => {
|
|
715
|
-
if (!permissions.canUpdate.can) {
|
|
716
|
-
throw new Error('Insufficient permissions to edit this resource');
|
|
717
|
-
}
|
|
718
|
-
|
|
719
|
-
const rowIndex = data.findIndex(r => r === row);
|
|
720
|
-
const rowId = resolvedGetRowId(row, rowIndex >= 0 ? rowIndex : 0);
|
|
721
|
-
|
|
722
|
-
// Set the row into editing mode with the current row data
|
|
723
|
-
stateActions.setEditingRow(rowId, toCellValueRecord(row));
|
|
724
|
-
},
|
|
725
|
-
icon: Edit,
|
|
726
|
-
testId: 'edit',
|
|
727
|
-
hidden: !permissions.canUpdate.can,
|
|
728
|
-
});
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
// Add Delete action with RBAC check
|
|
732
|
-
if (secureFeatures.deletion && secureHandlers.onDeleteRow && !result.some(a => a.label === 'Delete')) {
|
|
733
|
-
result.push({
|
|
734
|
-
label: 'Delete',
|
|
735
|
-
onClick: async (row: TData) => {
|
|
736
|
-
if (!permissions.canDelete.can) {
|
|
737
|
-
// NOTE: Toast notifications use default timeout (5 seconds) - do not set duration property
|
|
738
|
-
toast({
|
|
739
|
-
title: "Delete Failed",
|
|
740
|
-
description: "Insufficient permissions to delete this resource",
|
|
741
|
-
variant: "destructive"
|
|
742
|
-
});
|
|
743
|
-
return;
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
// Get row ID for tracking - use current data, not effectiveData
|
|
747
|
-
const rowIndex = data.findIndex(r => r === row);
|
|
748
|
-
const rowId = resolvedGetRowId(row, rowIndex >= 0 ? rowIndex : 0);
|
|
749
|
-
|
|
750
|
-
// Mark deletion as in progress and track this deletion
|
|
751
|
-
// CRITICAL: Set isDeleting and snapshot BEFORE calling the handler
|
|
752
|
-
// This prevents the parent's data update from causing a flash
|
|
753
|
-
if (!isDeleting) {
|
|
754
|
-
// Snapshot current data BEFORE deletion
|
|
755
|
-
dataSnapshotRef.current = [...data]; // Create a copy to prevent reference issues
|
|
756
|
-
setIsDeleting(true);
|
|
757
|
-
}
|
|
758
|
-
pendingDeletionsRef.current.add(rowId);
|
|
759
|
-
|
|
760
|
-
// Clear any existing timeout
|
|
761
|
-
if (deletionTimeoutRef.current) {
|
|
762
|
-
clearTimeout(deletionTimeoutRef.current);
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
try {
|
|
766
|
-
// Call the delete handler - this may update the parent's data prop
|
|
767
|
-
const result = secureHandlers.onDeleteRow!(row);
|
|
768
|
-
// Handle async operations (even though typed as void, handlers might return Promise)
|
|
769
|
-
if (result !== undefined && result !== null && typeof result === 'object' && 'then' in result && typeof (result as { then: unknown }).then === 'function') {
|
|
770
|
-
await (result as Promise<unknown>);
|
|
771
|
-
}
|
|
772
|
-
// Remove from pending deletions
|
|
773
|
-
pendingDeletionsRef.current.delete(rowId);
|
|
774
|
-
|
|
775
|
-
// Reset deletion state after a delay to allow batching
|
|
776
|
-
// This prevents the table from refreshing after each individual deletion
|
|
777
|
-
deletionTimeoutRef.current = setTimeout(() => {
|
|
778
|
-
// Only reset if all deletions are complete
|
|
779
|
-
if (pendingDeletionsRef.current.size === 0) {
|
|
780
|
-
setIsDeleting(false);
|
|
781
|
-
// Update snapshot to latest data
|
|
782
|
-
dataSnapshotRef.current = data;
|
|
783
|
-
toast({
|
|
784
|
-
title: "Delete Successful",
|
|
785
|
-
description: "Row deleted successfully",
|
|
786
|
-
variant: "default"
|
|
787
|
-
});
|
|
788
|
-
}
|
|
789
|
-
}, 150); // Delay to batch rapid deletions
|
|
790
|
-
|
|
791
|
-
} catch (error) {
|
|
792
|
-
logger.error('Delete error:', error);
|
|
793
|
-
pendingDeletionsRef.current.delete(rowId);
|
|
794
|
-
if (pendingDeletionsRef.current.size === 0) {
|
|
795
|
-
setIsDeleting(false);
|
|
796
|
-
dataSnapshotRef.current = data;
|
|
797
|
-
}
|
|
798
|
-
toast({
|
|
799
|
-
title: "Delete Failed",
|
|
800
|
-
description: error instanceof Error ? error.message : 'Failed to delete row',
|
|
801
|
-
variant: "destructive"
|
|
802
|
-
});
|
|
803
|
-
}
|
|
804
|
-
},
|
|
805
|
-
icon: Trash2,
|
|
806
|
-
testId: 'delete',
|
|
807
|
-
variant: 'destructive' as const,
|
|
808
|
-
hidden: !permissions.canDelete.can,
|
|
809
|
-
});
|
|
810
|
-
}
|
|
811
|
-
|
|
812
|
-
return result;
|
|
813
|
-
}, [actions, secureFeatures, permissions, secureHandlers, resolvedGetRowId, stateActions, data, isDeleting, logger]);
|
|
814
|
-
|
|
815
|
-
// Normalize columnOrder for useTableColumns: ensure 'select' is always first
|
|
816
|
-
const normalizedColumnOrderForColumns = useMemo(() => {
|
|
817
|
-
if (secureFeatures.selection && state.columnOrder.includes('select')) {
|
|
818
|
-
return ['select', ...state.columnOrder.filter(id => id !== 'select')];
|
|
819
|
-
}
|
|
820
|
-
return state.columnOrder;
|
|
821
|
-
}, [state.columnOrder, secureFeatures.selection]);
|
|
822
|
-
|
|
823
|
-
// MANDATORY: Process columns with actions
|
|
824
|
-
const { enhancedColumns } = useTableColumns({
|
|
825
|
-
columns,
|
|
826
|
-
features: secureFeatures,
|
|
827
|
-
effectiveActions,
|
|
828
|
-
columnOrder: normalizedColumnOrderForColumns
|
|
829
|
-
});
|
|
830
|
-
|
|
831
|
-
// Use effective pageSize in pagination state snapshot to ensure table receives valid pageSize
|
|
832
|
-
const paginationStateWithValidatedSize = useMemo(() => ({
|
|
833
|
-
...state.pagination,
|
|
834
|
-
pageSize: effectivePageSize,
|
|
835
|
-
}), [state.pagination, effectivePageSize]);
|
|
836
|
-
|
|
837
|
-
const tableStateSnapshot = useMemo<TableStateSnapshot>(() => {
|
|
838
|
-
// Normalize columnOrder in snapshot: ensure 'select' is always first if selection is enabled
|
|
839
|
-
const normalizedColumnOrder = secureFeatures.selection && state.columnOrder.includes('select')
|
|
840
|
-
? ['select', ...state.columnOrder.filter(id => id !== 'select')]
|
|
841
|
-
: state.columnOrder;
|
|
842
|
-
|
|
843
|
-
return {
|
|
844
|
-
sorting: state.sorting,
|
|
845
|
-
columnFilters: state.columnFilters,
|
|
846
|
-
columnVisibility: state.columnVisibility,
|
|
847
|
-
rowSelection,
|
|
848
|
-
grouping: state.grouping,
|
|
849
|
-
expanded: state.expanded,
|
|
850
|
-
pagination: paginationStateWithValidatedSize,
|
|
851
|
-
globalFilter: searchQuery,
|
|
852
|
-
columnOrder: normalizedColumnOrder,
|
|
853
|
-
};
|
|
854
|
-
}, [
|
|
855
|
-
state.sorting,
|
|
856
|
-
state.columnFilters,
|
|
857
|
-
state.columnVisibility,
|
|
858
|
-
rowSelection,
|
|
859
|
-
state.grouping,
|
|
860
|
-
state.expanded,
|
|
861
|
-
paginationStateWithValidatedSize,
|
|
862
|
-
searchQuery,
|
|
863
|
-
state.columnOrder,
|
|
864
|
-
secureFeatures.selection,
|
|
865
|
-
]);
|
|
866
|
-
|
|
867
|
-
const tableHandlers = useTableHandlers({
|
|
868
|
-
state,
|
|
869
|
-
stateSnapshot: tableStateSnapshot,
|
|
870
|
-
actions: stateActions,
|
|
871
292
|
selection,
|
|
872
293
|
onRowSelectionChange,
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
updateSavedColumnVisibility,
|
|
877
|
-
updateColumnOrder,
|
|
294
|
+
shouldAllowRenderAfterTimeout,
|
|
295
|
+
rbac,
|
|
296
|
+
enhancedPagination,
|
|
878
297
|
onLayoutChange,
|
|
879
298
|
});
|
|
880
299
|
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
return [] as TData[];
|
|
892
|
-
}
|
|
893
|
-
// Permissions confirmed - return actual data
|
|
894
|
-
return finalTableData as TData[];
|
|
895
|
-
}, [finalTableData, permissions.canRead.isLoading, permissions.canRead.can, shouldAllowRenderAfterTimeout]);
|
|
896
|
-
|
|
897
|
-
const tableConfig = useDataTableConfiguration({
|
|
898
|
-
data: safeTableData,
|
|
899
|
-
columns: enhancedColumns,
|
|
900
|
-
stateSnapshot: tableStateSnapshot,
|
|
901
|
-
handlers: tableHandlers,
|
|
902
|
-
features: secureFeatures,
|
|
903
|
-
getRowId: resolvedGetRowId,
|
|
904
|
-
finalPaginationMode,
|
|
905
|
-
finalDataCount: safeTableData.length > 0 ? finalDataCount : 0,
|
|
906
|
-
pageSize: effectivePageSize,
|
|
907
|
-
hasServerSideConfig: !!serverSide,
|
|
300
|
+
const renderGuard = useDataTableRenderGuard<TData>({
|
|
301
|
+
...pipeline.guardInputs,
|
|
302
|
+
user,
|
|
303
|
+
permissions,
|
|
304
|
+
isPermissionLoading,
|
|
305
|
+
permissionElapsed,
|
|
306
|
+
shouldAllowRenderAfterTimeout,
|
|
307
|
+
logger,
|
|
308
|
+
LoadingComponent,
|
|
309
|
+
AccessDeniedPage,
|
|
908
310
|
});
|
|
909
|
-
|
|
910
311
|
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
// ============================================================================
|
|
914
|
-
// RBAC VALIDATION AND EARLY RETURNS - AFTER ALL HOOKS
|
|
915
|
-
// ============================================================================
|
|
916
|
-
|
|
917
|
-
// DIAGNOSTIC: Log render state for debugging
|
|
918
|
-
const renderDiagnostics = {
|
|
919
|
-
hasUser: !!user,
|
|
920
|
-
userId: user?.id,
|
|
921
|
-
permissionLoading: permissions.canRead.isLoading,
|
|
922
|
-
permissionCan: permissions.canRead.can,
|
|
923
|
-
permissionError: permissions.canRead.error,
|
|
924
|
-
effectivePageId,
|
|
925
|
-
externalIsLoading,
|
|
926
|
-
performanceLoading,
|
|
927
|
-
computedIsLoading: isLoading,
|
|
928
|
-
dataLength: data.length,
|
|
929
|
-
finalTableDataLength: finalTableData.length,
|
|
930
|
-
columnsLength: columns.length,
|
|
931
|
-
tableRowsCount: table?.getRowModel().rows.length || 0,
|
|
932
|
-
};
|
|
933
|
-
|
|
934
|
-
// Log diagnostics in development mode
|
|
935
|
-
if (process.env.NODE_ENV === 'development') {
|
|
936
|
-
logger.debug('DataTable render diagnostics:', renderDiagnostics);
|
|
937
|
-
}
|
|
938
|
-
|
|
939
|
-
// MANDATORY: Every DataTable must have a user
|
|
940
|
-
if (!user) {
|
|
941
|
-
logger.error('DataTable render blocked: No user', renderDiagnostics);
|
|
312
|
+
if (renderGuard.gate === 'throw') {
|
|
942
313
|
throw new Error('DataTable requires authenticated user for RBAC');
|
|
943
314
|
}
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
// After 3 seconds, allow table to render but keep data hidden until permissions confirm
|
|
947
|
-
// This provides better UX while maintaining security (data remains protected)
|
|
948
|
-
// Note: permissionElapsed and shouldAllowRenderAfterTimeout are calculated above for useMemo
|
|
949
|
-
// Wait for permission check to complete before making access decisions
|
|
950
|
-
// BUT: After 3s timeout, allow table structure to render (data will remain hidden)
|
|
951
|
-
if (isPermissionLoading) {
|
|
952
|
-
// Enhanced diagnostics for hanging permission checks
|
|
953
|
-
if (permissionElapsed > 10000) {
|
|
954
|
-
logger.error('DataTableCore', 'DataTable: Permission check hanging (>10s)', {
|
|
955
|
-
...renderDiagnostics,
|
|
956
|
-
permissionState: {
|
|
957
|
-
can: permissions.canRead.can,
|
|
958
|
-
isLoading: permissions.canRead.isLoading,
|
|
959
|
-
error: permissions.canRead.error?.message,
|
|
960
|
-
},
|
|
961
|
-
elapsedMs: permissionElapsed,
|
|
962
|
-
diagnostic: 'Permission check has been loading for over 10 seconds. This likely indicates a hanging database query or network issue. Check browser network tab for pending requests to Supabase.',
|
|
963
|
-
recommendation: 'Check: 1) Browser network tab for pending requests, 2) Supabase connection, 3) Database query performance, 4) Super admin check completion',
|
|
964
|
-
});
|
|
965
|
-
}
|
|
966
|
-
|
|
967
|
-
if (process.env.NODE_ENV === 'development') {
|
|
968
|
-
logger.debug('DataTable render blocked: Permissions loading', {
|
|
969
|
-
...renderDiagnostics,
|
|
970
|
-
permissionState: permissions.canRead,
|
|
971
|
-
elapsedMs: permissionElapsed,
|
|
972
|
-
});
|
|
973
|
-
}
|
|
974
|
-
return <LoadingComponent />;
|
|
975
|
-
}
|
|
976
|
-
|
|
977
|
-
// If timeout reached but permissions still loading, log warning and proceed with caution
|
|
978
|
-
if (permissions.canRead.isLoading && shouldAllowRenderAfterTimeout) {
|
|
979
|
-
logger.warn('DataTable: Rendering after timeout - permissions still loading. Data will remain hidden until confirmed.', {
|
|
980
|
-
pageId: effectivePageId,
|
|
981
|
-
elapsedMs: permissionElapsed,
|
|
982
|
-
permissionState: permissions.canRead,
|
|
983
|
-
});
|
|
984
|
-
// Continue to render check below - we'll show empty state until permissions confirm
|
|
985
|
-
}
|
|
986
|
-
|
|
987
|
-
// MANDATORY: No data access without read permission
|
|
988
|
-
// SECURITY: If permissions are still loading after timeout, allow table structure but hide data
|
|
989
|
-
// If permissions are confirmed as denied, show access denied page
|
|
990
|
-
if (!permissions.canRead.isLoading && !permissions.canRead.can) {
|
|
991
|
-
logger.warn('Access denied - no read permission:', {
|
|
992
|
-
canRead: permissions.canRead,
|
|
993
|
-
pageId: effectivePageId,
|
|
994
|
-
isLoading: permissions.canRead.isLoading,
|
|
995
|
-
diagnostics: renderDiagnostics,
|
|
996
|
-
});
|
|
997
|
-
return <AccessDeniedPage resource={effectivePageId || 'unknown-page'} operation="read" />;
|
|
998
|
-
}
|
|
999
|
-
|
|
1000
|
-
// If permissions still loading after timeout, proceed to render but data will be empty/hidden
|
|
1001
|
-
// The table structure will render, but rows will be empty until permissions confirm
|
|
1002
|
-
if (permissions.canRead.isLoading && shouldAllowRenderAfterTimeout) {
|
|
1003
|
-
// Log that we're proceeding with timeout
|
|
1004
|
-
logger.debug('DataTable: Proceeding to render after timeout - permissions still loading', {
|
|
1005
|
-
pageId: effectivePageId,
|
|
1006
|
-
elapsedMs: permissionElapsed,
|
|
1007
|
-
});
|
|
1008
|
-
// Continue to render - data will be empty until permissions confirm
|
|
1009
|
-
}
|
|
1010
|
-
|
|
1011
|
-
// ============================================================================
|
|
1012
|
-
// RENDER
|
|
1013
|
-
// ============================================================================
|
|
1014
|
-
|
|
1015
|
-
if (isLoading) {
|
|
1016
|
-
if (process.env.NODE_ENV === 'development') {
|
|
1017
|
-
logger.debug('DataTable render blocked: External isLoading', {
|
|
1018
|
-
...renderDiagnostics,
|
|
1019
|
-
isLoadingSource: {
|
|
1020
|
-
externalIsLoading,
|
|
1021
|
-
performanceLoading,
|
|
1022
|
-
computed: isLoading,
|
|
1023
|
-
},
|
|
1024
|
-
});
|
|
1025
|
-
}
|
|
1026
|
-
return <LoadingComponent />;
|
|
1027
|
-
}
|
|
1028
|
-
|
|
1029
|
-
// DIAGNOSTIC: Log successful render path
|
|
1030
|
-
if (process.env.NODE_ENV === 'development') {
|
|
1031
|
-
logger.debug('DataTable proceeding to render:', {
|
|
1032
|
-
...renderDiagnostics,
|
|
1033
|
-
willRender: true,
|
|
1034
|
-
tableState: {
|
|
1035
|
-
rowCount: table?.getRowModel().rows.length || 0,
|
|
1036
|
-
columnCount: table?.getVisibleFlatColumns().length || 0,
|
|
1037
|
-
paginationMode: finalPaginationMode,
|
|
1038
|
-
},
|
|
1039
|
-
});
|
|
315
|
+
if (renderGuard.component) {
|
|
316
|
+
return renderGuard.component;
|
|
1040
317
|
}
|
|
1041
318
|
|
|
1042
319
|
return (
|
|
1043
320
|
<DataTableLayout
|
|
1044
|
-
|
|
1045
|
-
title={title}
|
|
1046
|
-
description={description}
|
|
1047
|
-
variant={variant}
|
|
1048
|
-
className={className}
|
|
1049
|
-
columns={columns}
|
|
1050
|
-
secureFeatures={secureFeatures}
|
|
1051
|
-
enhancedPagination={enhancedPagination}
|
|
1052
|
-
searchQuery={searchQuery}
|
|
1053
|
-
onSearch={handleSearch}
|
|
1054
|
-
state={state}
|
|
1055
|
-
stateActions={stateActions}
|
|
1056
|
-
rowSelection={rowSelection}
|
|
1057
|
-
onCreateRow={secureHandlers.onCreateRow}
|
|
1058
|
-
onEditRow={secureHandlers.onEditRow}
|
|
1059
|
-
onImport={secureHandlers.onImport}
|
|
1060
|
-
onExport={secureHandlers.onExport}
|
|
1061
|
-
onDeleteSelected={secureHandlers.onDeleteSelected}
|
|
1062
|
-
rbac={rbac}
|
|
1063
|
-
permissions={permissions}
|
|
1064
|
-
effectiveActions={effectiveActions}
|
|
1065
|
-
finalPageSizeOptions={finalPageSizeOptions}
|
|
1066
|
-
finalPaginationMode={finalPaginationMode}
|
|
1067
|
-
finalDataCount={finalDataCount}
|
|
1068
|
-
isLoading={isLoading}
|
|
1069
|
-
finalTableData={finalTableData}
|
|
1070
|
-
aggregates={aggregates}
|
|
1071
|
-
resolvedGetRowId={resolvedGetRowId}
|
|
1072
|
-
data={data}
|
|
1073
|
-
emptyState={emptyState}
|
|
1074
|
-
virtualHeight={virtualHeight}
|
|
1075
|
-
hierarchical={hierarchical}
|
|
1076
|
-
hierarchicalState={hierarchicalState}
|
|
1077
|
-
logger={logger}
|
|
1078
|
-
secureHandlers={secureHandlers}
|
|
1079
|
-
importModalConfig={importModalConfig}
|
|
1080
|
-
keyboardNavigation={keyboardNavigation}
|
|
1081
|
-
lastFocusedElementRef={lastFocusedElementRef}
|
|
321
|
+
{...(pipeline.layoutProps as unknown as React.ComponentProps<typeof DataTableLayout>)}
|
|
1082
322
|
/>
|
|
1083
323
|
);
|
|
1084
324
|
}
|