@jmruthers/pace-core 0.6.5 → 0.6.7
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 +104 -0
- package/README.md +5 -403
- package/audit-tool/00-dependencies.cjs +394 -0
- package/audit-tool/audits/01-pace-core-compliance.cjs +556 -0
- package/audit-tool/audits/02-project-structure.cjs +255 -0
- package/audit-tool/audits/03-architecture.cjs +196 -0
- package/audit-tool/audits/04-code-quality.cjs +149 -0
- package/audit-tool/audits/05-styling.cjs +224 -0
- package/audit-tool/audits/06-security-rbac.cjs +544 -0
- package/audit-tool/audits/07-api-tech-stack.cjs +301 -0
- package/audit-tool/audits/08-testing-documentation.cjs +202 -0
- package/audit-tool/audits/09-operations.cjs +208 -0
- package/audit-tool/index.cjs +291 -0
- package/audit-tool/utils/code-utils.cjs +218 -0
- package/audit-tool/utils/file-utils.cjs +230 -0
- package/audit-tool/utils/report-utils.cjs +241 -0
- package/core-usage-manifest.json +93 -0
- package/cursor-rules/00-standards-overview.mdc +156 -0
- package/cursor-rules/01-pace-core-compliance.mdc +586 -0
- package/cursor-rules/02-project-structure.mdc +42 -4
- package/cursor-rules/{03-solid-principles.mdc → 03-architecture.mdc} +126 -10
- package/cursor-rules/04-code-quality.mdc +419 -0
- package/cursor-rules/{08-markup-quality.mdc → 05-styling.mdc} +104 -34
- package/cursor-rules/06-security-rbac.mdc +518 -0
- package/cursor-rules/07-api-tech-stack.mdc +377 -0
- package/cursor-rules/08-testing-documentation.mdc +324 -0
- package/cursor-rules/09-operations.mdc +365 -0
- package/dist/{AuthService-Cb34EQs3.d.ts → AuthService-DmfO5rGS.d.ts} +10 -0
- package/dist/DataTable-7PMH7XN7.js +15 -0
- package/dist/{DataTable-BMRU8a1j.d.ts → DataTable-DRUIgtUH.d.ts} +1 -1
- package/dist/{PublicPageProvider-QTFVrL-Z.d.ts → PublicPageProvider-DlsCaR5v.d.ts} +33 -72
- package/dist/UnifiedAuthProvider-ZT6TIGM7.js +7 -0
- package/dist/api-Y4MQWOFW.js +4 -0
- package/dist/audit-MYQXYZFU.js +3 -0
- package/dist/{chunk-DGUM43GV.js → chunk-3RG5ZIWI.js} +1 -4
- package/dist/{chunk-QXHPKYJV.js → chunk-4SXLQIZO.js} +1 -26
- package/dist/{chunk-UPPMRMYG.js → chunk-5X4QLXRG.js} +73 -151
- package/dist/chunk-6F3IILHI.js +62 -0
- package/dist/{chunk-E66EQZE6.js → chunk-6GLLNA6U.js} +3 -9
- package/dist/{chunk-ZSAAAMVR.js → chunk-6QYDGKQY.js} +1 -4
- package/dist/{chunk-FMUCXFII.js → chunk-7ILTDCL2.js} +9 -5
- package/dist/{chunk-M43Y4SSO.js → chunk-A3W6LW53.js} +15 -13
- package/dist/{chunk-63FOKYGO.js → chunk-AHU7G2R5.js} +2 -11
- package/dist/{chunk-HU2C6SSC.js → chunk-BM4CQ5P3.js} +606 -559
- package/dist/chunk-C7NSAPTL.js +1 -0
- package/dist/{chunk-J36DSWQK.js → chunk-FEJLJNWA.js} +7 -41
- package/dist/{chunk-IHB5DR3H.js → chunk-FTCRZOG2.js} +188 -387
- package/dist/{chunk-G37KK66H.js → chunk-FYHN4DD5.js} +60 -19
- package/dist/chunk-GHYHJTYV.js +994 -0
- package/dist/{chunk-VBXEHIUJ.js → chunk-HF6O3O37.js} +6 -88
- package/dist/{chunk-FFQEQTNW.js → chunk-IUBRCBSY.js} +134 -45
- package/dist/{chunk-6COVEUS7.js → chunk-JGWDVX64.js} +983 -1034
- package/dist/{chunk-RGAWHO7N.js → chunk-L4XMVJKY.js} +77 -222
- package/dist/chunk-MBADTM7L.js +64 -0
- package/dist/{chunk-M7MPQISP.js → chunk-OJ4SKRSV.js} +3 -16
- package/dist/{chunk-IVOFDYWT.js → chunk-Q7Q7V5NV.js} +2109 -1604
- package/dist/{chunk-JGRYX5UX.js → chunk-S7DKJPLT.js} +29 -58
- package/dist/{chunk-PWLANIRT.js → chunk-TTRFSOKR.js} +1 -7
- package/dist/{chunk-5DRSZLL2.js → chunk-UH3NTO3F.js} +1 -6
- package/dist/{chunk-NTM7ZSB6.js → chunk-VBCS3DUA.js} +261 -168
- package/dist/{chunk-EFN2EIMK.js → chunk-ZFYPMX46.js} +271 -87
- package/dist/{chunk-L4OXEN46.js → chunk-ZKAWKYT4.js} +10 -24
- package/dist/components.d.ts +7 -5
- package/dist/components.js +46 -257
- package/dist/{database.generated-CzIvgcPu.d.ts → database.generated-CcnC_DRc.d.ts} +4795 -3691
- package/dist/eslint-rules/index.cjs +35 -0
- package/{src/eslint-rules/pace-core-compliance.cjs → dist/eslint-rules/rules/01-pace-core-compliance.cjs} +234 -235
- package/dist/eslint-rules/rules/04-code-quality.cjs +290 -0
- package/dist/eslint-rules/rules/05-styling.cjs +61 -0
- package/dist/eslint-rules/rules/06-security-rbac.cjs +806 -0
- package/dist/eslint-rules/rules/07-api-tech-stack.cjs +263 -0
- package/dist/eslint-rules/rules/08-testing.cjs +94 -0
- package/dist/eslint-rules/utils/helpers.cjs +42 -0
- package/dist/eslint-rules/utils/manifest-loader.cjs +75 -0
- package/dist/hooks.d.ts +6 -6
- package/dist/hooks.js +62 -172
- package/dist/icons/index.d.ts +1 -0
- package/dist/icons/index.js +1 -0
- package/dist/index.d.ts +12 -11
- package/dist/index.js +67 -660
- package/dist/providers.d.ts +2 -2
- package/dist/providers.js +8 -35
- package/dist/rbac/eslint-rules.d.ts +46 -44
- package/dist/rbac/eslint-rules.js +7 -4
- package/dist/rbac/index.d.ts +109 -586
- package/dist/rbac/index.js +14 -207
- package/dist/styles/index.js +2 -12
- package/dist/theming/runtime.d.ts +14 -1
- package/dist/theming/runtime.js +3 -19
- package/dist/{timezone-CHhWg6b4.d.ts → timezone-BZe_eUxx.d.ts} +175 -1
- package/dist/{types-CkbwOr4Y.d.ts → types-DXstZpNI.d.ts} +4 -17
- package/dist/types-t9H8qKRw.d.ts +55 -0
- package/dist/types.d.ts +1 -1
- package/dist/types.js +7 -94
- package/dist/{usePublicRouteParams-ClnV4tnv.d.ts → usePublicRouteParams-MamNgwqe.d.ts} +20 -20
- package/dist/utils.d.ts +24 -117
- package/dist/utils.js +54 -392
- package/docs/README.md +17 -7
- package/docs/api/README.md +4 -402
- package/docs/api/modules.md +301 -871
- package/docs/api-reference/components.md +21 -21
- package/docs/api-reference/deprecated.md +31 -6
- package/docs/api-reference/hooks.md +80 -80
- package/docs/api-reference/rpc-functions.md +78 -3
- package/docs/api-reference/types.md +1 -1
- package/docs/api-reference/utilities.md +1 -1
- package/docs/architecture/README.md +1 -1
- package/docs/core-concepts/events.md +3 -3
- package/docs/core-concepts/organisations.md +6 -6
- package/docs/core-concepts/permissions.md +6 -6
- package/docs/documentation-index.md +12 -18
- package/docs/getting-started/cursor-rules.md +3 -23
- package/docs/getting-started/dependencies.md +650 -0
- package/docs/getting-started/documentation-index.md +1 -1
- package/docs/getting-started/examples/README.md +4 -4
- package/docs/getting-started/examples/full-featured-app.md +1 -1
- package/docs/getting-started/faq.md +2 -2
- package/docs/getting-started/installation-guide.md +20 -7
- package/docs/getting-started/quick-reference.md +4 -4
- package/docs/getting-started/quick-start.md +23 -12
- package/docs/implementation-guides/authentication.md +15 -15
- package/docs/implementation-guides/component-styling.md +1 -1
- package/docs/implementation-guides/data-tables.md +126 -33
- package/docs/implementation-guides/datatable-rbac-usage.md +1 -1
- package/docs/implementation-guides/dynamic-colors.md +3 -3
- package/docs/implementation-guides/file-upload-storage.md +2 -2
- package/docs/implementation-guides/hierarchical-datatable.md +40 -60
- package/docs/implementation-guides/inactivity-tracking.md +3 -3
- package/docs/implementation-guides/large-datasets.md +3 -2
- package/docs/implementation-guides/organisation-security.md +2 -2
- package/docs/implementation-guides/performance.md +2 -2
- package/docs/implementation-guides/permission-enforcement.md +5 -1
- package/docs/migration/V0.3.44_organisation-context-timing-fix.md +1 -1
- package/docs/migration/V0.4.0_rbac-migration.md +6 -6
- package/docs/rbac/MIGRATION_GUIDE.md +819 -0
- package/docs/rbac/RBAC_CONTRACT.md +724 -0
- package/docs/rbac/README.md +17 -8
- package/docs/rbac/advanced-patterns.md +6 -6
- package/docs/rbac/api-reference.md +20 -20
- package/docs/rbac/edge-functions-guide.md +376 -0
- package/docs/rbac/event-based-apps.md +3 -3
- package/docs/rbac/examples.md +41 -41
- package/docs/rbac/getting-started.md +37 -37
- package/docs/rbac/performance.md +1 -1
- package/docs/rbac/quick-start.md +52 -52
- package/docs/rbac/secure-client-protection.md +1 -35
- package/docs/rbac/troubleshooting.md +1 -1
- package/docs/security/README.md +5 -5
- package/docs/standards/0-standards-overview.md +220 -0
- package/docs/standards/1-pace-core-compliance-standards.md +986 -0
- package/docs/standards/2-project-structure-standards.md +949 -0
- package/docs/standards/3-architecture-standards.md +606 -0
- package/docs/standards/4-code-quality-standards.md +728 -0
- package/docs/standards/5-styling-standards.md +348 -0
- package/docs/standards/{07-rbac-and-rls-standard.md → 6-security-rbac-standards.md} +269 -66
- package/docs/standards/7-api-tech-stack-standards.md +662 -0
- package/docs/standards/8-testing-documentation-standards.md +401 -0
- package/docs/standards/9-operations-standards.md +1102 -0
- package/docs/standards/README.md +185 -57
- package/docs/troubleshooting/README.md +4 -4
- package/docs/troubleshooting/common-issues.md +2 -2
- package/docs/troubleshooting/debugging.md +9 -9
- package/docs/troubleshooting/migration.md +4 -4
- package/docs/troubleshooting/organisation-context-setup.md +42 -19
- package/eslint-config-pace-core.cjs +33 -6
- package/package.json +35 -23
- package/scripts/install-cursor-rules.cjs +25 -6
- package/scripts/install-eslint-config.cjs +284 -0
- package/src/__tests__/fixtures/supabase.ts +1 -1
- package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +3 -3
- package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +1 -1
- package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +1 -1
- package/src/__tests__/helpers/__tests__/test-providers.test.tsx +2 -2
- package/src/__tests__/helpers/__tests__/test-utils.test.tsx +13 -13
- package/src/__tests__/helpers/component-test-utils.tsx +1 -1
- package/src/__tests__/helpers/supabaseMock.ts +2 -2
- package/src/__tests__/integration/UserProfile.test.tsx +14 -14
- package/src/__tests__/public-recipe-view.test.ts +38 -9
- package/src/__tests__/rbac/PagePermissionGuard.test.tsx +6 -6
- package/src/__tests__/templates/accessibility.test.template.tsx +9 -9
- package/src/__tests__/templates/component.test.template.tsx +18 -15
- package/src/components/Button/Button.tsx +5 -1
- package/src/components/Calendar/Calendar.tsx +201 -47
- package/src/components/ContextSelector/ContextSelector.tsx +106 -119
- package/src/components/DataTable/AUDIT_REPORT.md +293 -0
- package/src/components/DataTable/__tests__/DataTableCore.test.tsx +10 -2
- package/src/components/DataTable/__tests__/a11y.basic.test.tsx +10 -4
- package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +9 -9
- package/src/components/DataTable/components/ColumnFilter.tsx +63 -74
- package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +43 -41
- package/src/components/DataTable/components/DataTableCore.tsx +186 -13
- package/src/components/DataTable/components/DataTableErrorBoundary.tsx +9 -11
- package/src/components/DataTable/components/DataTableLayout.tsx +35 -21
- package/src/components/DataTable/components/EditFields.tsx +23 -3
- package/src/components/DataTable/components/EditableRow.tsx +12 -9
- package/src/components/DataTable/components/EmptyState.tsx +10 -9
- package/src/components/DataTable/components/FilterRow.tsx +2 -4
- package/src/components/DataTable/components/ImportModal.tsx +124 -126
- package/src/components/DataTable/components/LoadingState.tsx +5 -6
- package/src/components/DataTable/components/RowComponent.tsx +12 -0
- package/src/components/DataTable/components/SortIndicator.tsx +50 -0
- package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +4 -4
- package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +23 -82
- package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +37 -9
- package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +7 -4
- package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +12 -4
- package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +41 -27
- package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -4
- package/src/components/DataTable/components/index.ts +2 -1
- package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +51 -47
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +24 -21
- package/src/components/DataTable/hooks/useDataTableState.ts +125 -9
- package/src/components/DataTable/hooks/useTableColumns.ts +40 -2
- package/src/components/DataTable/hooks/useTableHandlers.ts +11 -0
- package/src/components/DataTable/types.ts +5 -18
- package/src/components/DataTable/utils/a11yUtils.ts +17 -0
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +2 -1
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +11 -15
- package/src/components/DateTimeField/DateTimeField.tsx +10 -9
- package/src/components/Dialog/Dialog.test.tsx +128 -104
- package/src/components/Dialog/Dialog.tsx +742 -24
- package/src/components/ErrorBoundary/ErrorBoundary.tsx +77 -79
- package/src/components/FileDisplay/FileDisplay.test.tsx +4 -2
- package/src/components/FileDisplay/FileDisplay.tsx +23 -17
- package/src/components/FileUpload/FileUpload.test.tsx +52 -14
- package/src/components/FileUpload/FileUpload.tsx +112 -130
- package/src/components/Form/Form.test.tsx +6 -8
- package/src/components/Form/Form.tsx +365 -4
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +14 -13
- package/src/components/NavigationMenu/useNavigationFiltering.ts +11 -21
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +6 -4
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +11 -15
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +108 -61
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +27 -3
- package/src/components/Progress/Progress.tsx +2 -4
- package/src/components/ProtectedRoute/ProtectedRoute.tsx +8 -8
- package/src/components/Select/Select.tsx +109 -98
- package/src/components/Select/types.ts +4 -1
- package/src/components/UserMenu/UserMenu.tsx +9 -6
- package/src/hooks/__tests__/ServiceHooks.test.tsx +16 -16
- package/src/hooks/__tests__/hooks.integration.test.tsx +55 -57
- package/src/hooks/__tests__/useAppConfig.unit.test.ts +129 -67
- package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +97 -97
- package/src/hooks/__tests__/usePublicEvent.simple.test.ts +149 -67
- package/src/hooks/__tests__/usePublicEvent.test.ts +149 -79
- package/src/hooks/__tests__/usePublicEvent.unit.test.ts +158 -109
- package/src/hooks/__tests__/useSessionDraft.test.ts +163 -0
- package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +10 -5
- package/src/hooks/public/usePublicEvent.ts +67 -195
- package/src/hooks/public/usePublicEventLogo.test.ts +70 -17
- package/src/hooks/public/usePublicEventLogo.ts +24 -14
- package/src/hooks/public/usePublicFileDisplay.ts +2 -2
- package/src/hooks/public/usePublicRouteParams.ts +5 -5
- package/src/hooks/useAppConfig.ts +28 -26
- package/src/hooks/useEventTheme.test.ts +217 -239
- package/src/hooks/useEventTheme.ts +16 -28
- package/src/hooks/useFileDisplay.ts +2 -2
- package/src/hooks/useOrganisationPermissions.ts +5 -7
- package/src/hooks/useQueryCache.ts +0 -1
- package/src/hooks/useSessionDraft.ts +380 -0
- package/src/hooks/useSessionRestoration.ts +3 -1
- package/src/icons/index.ts +27 -0
- package/src/index.ts +5 -0
- package/src/providers/OrganisationProvider.tsx +23 -14
- package/src/providers/UnifiedAuthProvider.smoke.test.tsx +21 -21
- package/src/providers/__tests__/AuthProvider.test.tsx +21 -21
- package/src/providers/__tests__/EventProvider.test.tsx +61 -61
- package/src/providers/__tests__/InactivityProvider.test.tsx +56 -56
- package/src/providers/__tests__/OrganisationProvider.test.tsx +75 -75
- package/src/providers/__tests__/ProviderLifecycle.test.tsx +37 -37
- package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +103 -103
- package/src/providers/services/EventServiceProvider.tsx +1 -24
- package/src/providers/services/UnifiedAuthProvider.tsx +5 -48
- package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +7 -7
- package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +13 -10
- package/src/rbac/__tests__/adapters.comprehensive.test.tsx +7 -457
- package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +33 -7
- package/src/rbac/adapters.tsx +7 -295
- package/src/rbac/api.test.ts +44 -56
- package/src/rbac/api.ts +10 -17
- package/src/rbac/cache-invalidation.ts +0 -1
- package/src/rbac/compliance/index.ts +10 -0
- package/src/rbac/compliance/pattern-detector.ts +553 -0
- package/src/rbac/compliance/runtime-compliance.ts +22 -0
- package/src/rbac/components/AccessDenied.tsx +150 -0
- package/src/rbac/components/NavigationGuard.tsx +12 -20
- package/src/rbac/components/PagePermissionGuard.tsx +4 -24
- package/src/rbac/components/__tests__/NavigationGuard.test.tsx +21 -8
- package/src/rbac/components/index.ts +3 -41
- package/src/rbac/eslint-rules.js +1 -1
- package/src/rbac/hooks/index.ts +0 -3
- package/src/rbac/hooks/permissions/index.ts +0 -3
- package/src/rbac/hooks/permissions/useAccessLevel.ts +4 -8
- package/src/rbac/hooks/usePermissions.ts +0 -3
- package/src/rbac/hooks/useResolvedScope.test.ts +57 -47
- package/src/rbac/hooks/useResolvedScope.ts +58 -140
- package/src/rbac/hooks/useResourcePermissions.test.ts +124 -38
- package/src/rbac/hooks/useResourcePermissions.ts +139 -48
- package/src/rbac/hooks/useRoleManagement.test.ts +65 -22
- package/src/rbac/hooks/useRoleManagement.ts +147 -19
- package/src/rbac/hooks/useSecureSupabase.ts +4 -8
- package/src/rbac/index.ts +7 -9
- package/src/rbac/utils/contextValidator.ts +9 -7
- package/src/services/AuthService.ts +130 -18
- package/src/services/EventService.ts +4 -97
- package/src/services/InactivityService.ts +16 -0
- package/src/services/OrganisationService.ts +7 -44
- package/src/services/__tests__/OrganisationService.test.ts +26 -8
- package/src/services/base/BaseService.ts +0 -3
- package/src/styles/core.css +7 -0
- package/src/theming/__tests__/parseEventColours.test.ts +9 -3
- package/src/theming/parseEventColours.ts +22 -10
- package/src/types/database.generated.ts +4733 -3809
- package/src/utils/__tests__/lazyLoad.unit.test.tsx +42 -39
- package/src/utils/__tests__/organisationContext.unit.test.ts +9 -10
- package/src/utils/context/organisationContext.test.ts +13 -28
- package/src/utils/context/organisationContext.ts +21 -52
- package/src/utils/dynamic/dynamicUtils.ts +1 -1
- package/src/utils/file-reference/index.ts +39 -15
- package/src/utils/formatting/formatDateTime.test.ts +3 -2
- package/src/utils/google-places/loadGoogleMapsScript.ts +29 -4
- package/src/utils/index.ts +4 -1
- package/src/utils/persistence/__tests__/keyDerivation.test.ts +135 -0
- package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +123 -0
- package/src/utils/persistence/keyDerivation.ts +304 -0
- package/src/utils/persistence/sensitiveFieldDetection.ts +212 -0
- package/src/utils/security/secureStorage.ts +5 -5
- package/src/utils/storage/README.md +1 -1
- package/src/utils/storage/helpers.ts +3 -3
- package/src/utils/supabase/createBaseClient.ts +147 -0
- package/src/utils/timezone/timezone.test.ts +1 -2
- package/src/utils/timezone/timezone.ts +1 -1
- package/src/utils/validation/csrf.ts +4 -4
- package/cursor-rules/00-pace-core-compliance.mdc +0 -331
- package/cursor-rules/01-standards-compliance.mdc +0 -244
- package/cursor-rules/04-testing-standards.mdc +0 -268
- package/cursor-rules/05-bug-reports-and-features.mdc +0 -246
- package/cursor-rules/06-code-quality.mdc +0 -309
- package/cursor-rules/07-tech-stack-compliance.mdc +0 -214
- package/cursor-rules/CHANGELOG.md +0 -119
- package/cursor-rules/README.md +0 -192
- package/dist/DataTable-AOVNCPTX.js +0 -175
- package/dist/DataTable-AOVNCPTX.js.map +0 -1
- package/dist/UnifiedAuthProvider-4SBX4LU5.js +0 -18
- package/dist/UnifiedAuthProvider-4SBX4LU5.js.map +0 -1
- package/dist/api-O6HTBX5Y.js +0 -52
- package/dist/api-O6HTBX5Y.js.map +0 -1
- package/dist/audit-V53FV5AG.js +0 -17
- package/dist/audit-V53FV5AG.js.map +0 -1
- package/dist/chunk-5DRSZLL2.js.map +0 -1
- package/dist/chunk-63FOKYGO.js.map +0 -1
- package/dist/chunk-6COVEUS7.js.map +0 -1
- package/dist/chunk-AFVQODI2.js +0 -263
- package/dist/chunk-AFVQODI2.js.map +0 -1
- package/dist/chunk-DGUM43GV.js.map +0 -1
- package/dist/chunk-E66EQZE6.js.map +0 -1
- package/dist/chunk-EFN2EIMK.js.map +0 -1
- package/dist/chunk-FFQEQTNW.js.map +0 -1
- package/dist/chunk-FMUCXFII.js.map +0 -1
- package/dist/chunk-G37KK66H.js.map +0 -1
- package/dist/chunk-G7QEZTYQ.js +0 -2053
- package/dist/chunk-G7QEZTYQ.js.map +0 -1
- package/dist/chunk-HU2C6SSC.js.map +0 -1
- package/dist/chunk-IHB5DR3H.js.map +0 -1
- package/dist/chunk-IVOFDYWT.js.map +0 -1
- package/dist/chunk-J36DSWQK.js.map +0 -1
- package/dist/chunk-JGRYX5UX.js.map +0 -1
- package/dist/chunk-KQCRWDSA.js +0 -1
- package/dist/chunk-KQCRWDSA.js.map +0 -1
- package/dist/chunk-L4OXEN46.js.map +0 -1
- package/dist/chunk-LMC26NLJ.js +0 -84
- package/dist/chunk-LMC26NLJ.js.map +0 -1
- package/dist/chunk-M43Y4SSO.js.map +0 -1
- package/dist/chunk-M7MPQISP.js.map +0 -1
- package/dist/chunk-NTM7ZSB6.js.map +0 -1
- package/dist/chunk-PWLANIRT.js.map +0 -1
- package/dist/chunk-QXHPKYJV.js.map +0 -1
- package/dist/chunk-RGAWHO7N.js.map +0 -1
- package/dist/chunk-UPPMRMYG.js.map +0 -1
- package/dist/chunk-VBXEHIUJ.js.map +0 -1
- package/dist/chunk-ZSAAAMVR.js.map +0 -1
- package/dist/components.js.map +0 -1
- package/dist/contextValidator-5OGXSPKS.js +0 -9
- package/dist/contextValidator-5OGXSPKS.js.map +0 -1
- package/dist/eslint-rules/pace-core-compliance.cjs +0 -510
- package/dist/hooks.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/providers.js.map +0 -1
- package/dist/rbac/eslint-rules.js.map +0 -1
- package/dist/rbac/index.js.map +0 -1
- package/dist/styles/index.js.map +0 -1
- package/dist/theming/runtime.js.map +0 -1
- package/dist/types.js.map +0 -1
- package/dist/utils.js.map +0 -1
- package/docs/best-practices/README.md +0 -472
- package/docs/best-practices/accessibility.md +0 -601
- package/docs/best-practices/common-patterns.md +0 -516
- package/docs/best-practices/deployment.md +0 -1103
- package/docs/best-practices/performance.md +0 -1328
- package/docs/best-practices/security.md +0 -940
- package/docs/best-practices/testing.md +0 -1034
- package/docs/rbac/compliance/compliance-guide.md +0 -544
- package/docs/standards/01-architecture-standard.md +0 -44
- package/docs/standards/02-api-and-rpc-standard.md +0 -39
- package/docs/standards/03-component-standard.md +0 -32
- package/docs/standards/04-code-style-standard.md +0 -32
- package/docs/standards/05-security-standard.md +0 -44
- package/docs/standards/06-testing-and-docs-standard.md +0 -29
- package/docs/standards/pace-core-compliance.md +0 -432
- package/scripts/audit/core/checks/accessibility.cjs +0 -197
- package/scripts/audit/core/checks/api-usage.cjs +0 -191
- package/scripts/audit/core/checks/bundle.cjs +0 -142
- package/scripts/audit/core/checks/compliance.cjs +0 -2706
- package/scripts/audit/core/checks/config.cjs +0 -54
- package/scripts/audit/core/checks/coverage.cjs +0 -84
- package/scripts/audit/core/checks/dependencies.cjs +0 -994
- package/scripts/audit/core/checks/documentation.cjs +0 -268
- package/scripts/audit/core/checks/environment.cjs +0 -116
- package/scripts/audit/core/checks/error-handling.cjs +0 -340
- package/scripts/audit/core/checks/forms.cjs +0 -172
- package/scripts/audit/core/checks/heuristics.cjs +0 -68
- package/scripts/audit/core/checks/hooks.cjs +0 -334
- package/scripts/audit/core/checks/imports.cjs +0 -244
- package/scripts/audit/core/checks/performance.cjs +0 -325
- package/scripts/audit/core/checks/routes.cjs +0 -117
- package/scripts/audit/core/checks/state.cjs +0 -130
- package/scripts/audit/core/checks/structure.cjs +0 -65
- package/scripts/audit/core/checks/style.cjs +0 -584
- package/scripts/audit/core/checks/testing.cjs +0 -122
- package/scripts/audit/core/checks/typescript.cjs +0 -61
- package/scripts/audit/core/scanner.cjs +0 -199
- package/scripts/audit/core/utils.cjs +0 -137
- package/scripts/audit/index.cjs +0 -223
- package/scripts/audit/reporters/console.cjs +0 -151
- package/scripts/audit/reporters/json.cjs +0 -54
- package/scripts/audit/reporters/markdown.cjs +0 -124
- package/scripts/audit-consuming-app.cjs +0 -86
- package/src/components/DataTable/components/DataTableBody.tsx +0 -454
- package/src/components/DataTable/components/DraggableColumnHeader.tsx +0 -156
- package/src/components/DataTable/components/ExpandButton.tsx +0 -113
- package/src/components/DataTable/components/GroupHeader.tsx +0 -54
- package/src/components/DataTable/components/ViewRowModal.tsx +0 -68
- package/src/components/DataTable/components/VirtualizedDataTable.tsx +0 -525
- package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +0 -462
- package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +0 -393
- package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +0 -476
- package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +0 -128
- package/src/components/DataTable/core/DataTableContext.tsx +0 -216
- package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +0 -136
- package/src/components/DataTable/hooks/__tests__/useColumnReordering.test.ts +0 -570
- package/src/components/DataTable/hooks/useColumnReordering.ts +0 -123
- package/src/components/DataTable/utils/debugTools.ts +0 -514
- package/src/eslint-rules/pace-core-compliance.js +0 -638
- package/src/rbac/components/EnhancedNavigationMenu.test.tsx +0 -555
- package/src/rbac/components/EnhancedNavigationMenu.tsx +0 -293
- package/src/rbac/components/NavigationProvider.test.tsx +0 -481
- package/src/rbac/components/NavigationProvider.tsx +0 -345
- package/src/rbac/components/PagePermissionProvider.test.tsx +0 -476
- package/src/rbac/components/PagePermissionProvider.tsx +0 -279
- package/src/rbac/components/PermissionEnforcer.tsx +0 -312
- package/src/rbac/components/RoleBasedRouter.tsx +0 -440
- package/src/rbac/components/SecureDataProvider.test.tsx +0 -543
- package/src/rbac/components/SecureDataProvider.tsx +0 -339
- package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +0 -620
- package/src/rbac/components/__tests__/NavigationProvider.test.tsx +0 -726
- package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +0 -661
- package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +0 -881
- package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +0 -783
- package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +0 -645
- package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +0 -659
- package/src/rbac/hooks/permissions/useCachedPermissions.ts +0 -79
- package/src/rbac/hooks/permissions/useHasAllPermissions.ts +0 -90
- package/src/rbac/hooks/permissions/useHasAnyPermission.ts +0 -90
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
import React, { Component, ErrorInfo, ReactNode } from 'react';
|
|
11
11
|
import { Alert, AlertDescription, AlertTitle } from '../../Alert/Alert';
|
|
12
|
-
import { Button } from '../../Button/Button';
|
|
12
|
+
import { Button, ButtonGroup } from '../../Button/Button';
|
|
13
13
|
import { createLogger } from '../../../utils/core/logger';
|
|
14
14
|
// Icons removed to avoid test mocking issues
|
|
15
15
|
|
|
@@ -142,8 +142,7 @@ export class DataTableErrorBoundary extends Component<
|
|
|
142
142
|
|
|
143
143
|
// Default error UI
|
|
144
144
|
return (
|
|
145
|
-
|
|
146
|
-
<Alert variant="destructive" className="max-w-md">
|
|
145
|
+
<Alert variant="destructive">
|
|
147
146
|
<AlertTitle>DataTable Error</AlertTitle>
|
|
148
147
|
<AlertDescription className="mt-2">
|
|
149
148
|
<span>Something went wrong</span>
|
|
@@ -164,17 +163,16 @@ export class DataTableErrorBoundary extends Component<
|
|
|
164
163
|
</pre>
|
|
165
164
|
</details>
|
|
166
165
|
) : (
|
|
167
|
-
<
|
|
168
|
-
<
|
|
169
|
-
</
|
|
166
|
+
<Alert variant="destructive">
|
|
167
|
+
<AlertDescription>An unexpected error occurred</AlertDescription>
|
|
168
|
+
</Alert>
|
|
170
169
|
)}
|
|
171
|
-
<
|
|
170
|
+
<ButtonGroup>
|
|
172
171
|
{showRetryButton && retryCount < maxRetries && (
|
|
173
172
|
<Button
|
|
174
173
|
variant="outline"
|
|
175
174
|
size="sm"
|
|
176
|
-
onClick={this.handleRetry}
|
|
177
|
-
className="flex items-center gap-2"
|
|
175
|
+
onClick={this.handleRetry}
|
|
178
176
|
>
|
|
179
177
|
Retry ({retryCount + 1}/{maxRetries})
|
|
180
178
|
</Button>
|
|
@@ -186,9 +184,9 @@ export class DataTableErrorBoundary extends Component<
|
|
|
186
184
|
>
|
|
187
185
|
Reset
|
|
188
186
|
</Button>
|
|
189
|
-
|
|
187
|
+
</ButtonGroup>
|
|
190
188
|
</Alert>
|
|
191
|
-
|
|
189
|
+
|
|
192
190
|
);
|
|
193
191
|
}
|
|
194
192
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { Edit, Trash
|
|
2
|
+
import { Edit, Trash } from 'lucide-react';
|
|
3
|
+
import { SortIndicator } from './SortIndicator';
|
|
3
4
|
import type { Table } from '@tanstack/react-table';
|
|
4
5
|
import { cn } from '../../../utils/core/cn';
|
|
5
6
|
import { Button } from '../../Button/Button';
|
|
@@ -7,12 +8,13 @@ import { DataTableToolbar } from './DataTableToolbar';
|
|
|
7
8
|
import { UnifiedTableBody } from './UnifiedTableBody';
|
|
8
9
|
import { PaginationControls, EnhancedPaginationControls } from './PaginationControls';
|
|
9
10
|
import { DataTableModals } from './DataTableModals';
|
|
10
|
-
import { announceSortChange } from '../utils/a11yUtils';
|
|
11
|
+
import { announceSortChange, getAriaSortState } from '../utils/a11yUtils';
|
|
11
12
|
import { exportToCSVWithTableRows } from '../utils/exportUtils';
|
|
12
13
|
import { getTableClasses } from '../styles';
|
|
13
14
|
import { toast } from '../../../hooks/useToast';
|
|
14
15
|
import type {
|
|
15
16
|
AggregateConfig,
|
|
17
|
+
CellValue,
|
|
16
18
|
DataRecord,
|
|
17
19
|
DataTableAction,
|
|
18
20
|
DataTableColumn,
|
|
@@ -130,6 +132,12 @@ export function DataTableLayout<TData extends DataRecord>({
|
|
|
130
132
|
keyboardNavigation,
|
|
131
133
|
lastFocusedElementRef,
|
|
132
134
|
}: DataTableLayoutProps<TData>) {
|
|
135
|
+
// CRITICAL FIX: Use a ref to track the latest editingData to avoid stale closure issues
|
|
136
|
+
// The ref is always kept in sync with state.editingData via useEffect
|
|
137
|
+
const editingDataRef = React.useRef(state.editingData);
|
|
138
|
+
React.useEffect(() => {
|
|
139
|
+
editingDataRef.current = state.editingData;
|
|
140
|
+
}, [state.editingData]);
|
|
133
141
|
const handleExport = async () => {
|
|
134
142
|
try {
|
|
135
143
|
const tableRows = table.getFilteredRowModel().rows;
|
|
@@ -282,6 +290,8 @@ export function DataTableLayout<TData extends DataRecord>({
|
|
|
282
290
|
if (result !== undefined && result !== null && typeof result === 'object' && typeof result.then === 'function') {
|
|
283
291
|
await result;
|
|
284
292
|
}
|
|
293
|
+
// Clear selection after successful deletion
|
|
294
|
+
stateActions.clearRowSelection();
|
|
285
295
|
toast({
|
|
286
296
|
title: 'Delete Successful',
|
|
287
297
|
description: `Successfully deleted ${selectedCount} ${selectedCount === 1 ? 'row' : 'rows'}`,
|
|
@@ -325,13 +335,7 @@ export function DataTableLayout<TData extends DataRecord>({
|
|
|
325
335
|
const isFirst = index === 0;
|
|
326
336
|
const isLast = index === visibleHeaders.length - 1;
|
|
327
337
|
const isSortable = header.column.getCanSort();
|
|
328
|
-
const ariaSort =
|
|
329
|
-
? header.column.getIsSorted() === 'asc'
|
|
330
|
-
? 'ascending'
|
|
331
|
-
: header.column.getIsSorted() === 'desc'
|
|
332
|
-
? 'descending'
|
|
333
|
-
: 'none'
|
|
334
|
-
: undefined;
|
|
338
|
+
const ariaSort = getAriaSortState(header.column);
|
|
335
339
|
const isRightAligned = header.column.columnDef.meta?.align === 'right';
|
|
336
340
|
|
|
337
341
|
const handleSortClick = (event: React.MouseEvent) => {
|
|
@@ -397,13 +401,7 @@ export function DataTableLayout<TData extends DataRecord>({
|
|
|
397
401
|
{typeof header.column.columnDef.header === 'function'
|
|
398
402
|
? header.column.columnDef.header(header.getContext())
|
|
399
403
|
: header.column.columnDef.header}
|
|
400
|
-
{header.column.getIsSorted()
|
|
401
|
-
<ChevronUp className="size-4" />
|
|
402
|
-
) : header.column.getIsSorted() === 'desc' ? (
|
|
403
|
-
<ChevronDown className="size-4" />
|
|
404
|
-
) : (
|
|
405
|
-
<ChevronsUpDown className="size-4" />
|
|
406
|
-
)}
|
|
404
|
+
<SortIndicator sortState={header.column.getIsSorted() || false} />
|
|
407
405
|
</Button>
|
|
408
406
|
) : typeof header.column.columnDef.header === 'function' ? (
|
|
409
407
|
header.column.columnDef.header(header.getContext())
|
|
@@ -424,8 +422,18 @@ export function DataTableLayout<TData extends DataRecord>({
|
|
|
424
422
|
creationData={state.creationData}
|
|
425
423
|
onCreationDataChange={stateActions.setCreationData}
|
|
426
424
|
onSaveCreation={() => {
|
|
425
|
+
const creationDataToUse = state.creationData;
|
|
426
|
+
// CRITICAL FIX: Ensure status field is included with default value "active" if not already set
|
|
427
|
+
// This ensures new rows are created with the correct status
|
|
428
|
+
const finalCreationData = {
|
|
429
|
+
...creationDataToUse,
|
|
430
|
+
// Only set status to "active" if it's not already set and if status is a column in the table
|
|
431
|
+
...(creationDataToUse.status === undefined && table.getAllColumns().some(col => col.id === 'status')
|
|
432
|
+
? { status: 'active' as CellValue }
|
|
433
|
+
: {}),
|
|
434
|
+
};
|
|
427
435
|
if (onCreateRow) {
|
|
428
|
-
onCreateRow(
|
|
436
|
+
onCreateRow(finalCreationData as Partial<TData>);
|
|
429
437
|
stateActions.clearCreationData();
|
|
430
438
|
stateActions.setCreating(false);
|
|
431
439
|
}
|
|
@@ -442,17 +450,23 @@ export function DataTableLayout<TData extends DataRecord>({
|
|
|
442
450
|
}
|
|
443
451
|
}}
|
|
444
452
|
onSaveEditing={() => {
|
|
453
|
+
// CRITICAL FIX: Use ref to get the latest editingData to avoid stale closure issues
|
|
454
|
+
// The ref is always kept in sync with state.editingData, so it should always have the correct value
|
|
455
|
+
const latestEditingData = editingDataRef.current;
|
|
445
456
|
if (onEditRow && state.editingRowId) {
|
|
446
|
-
|
|
457
|
+
// CRITICAL FIX: Use findIndex to get the actual index, then use that index for getRowId
|
|
458
|
+
const originalRowIndex = data.findIndex((row, index) => {
|
|
447
459
|
try {
|
|
448
|
-
const rowId = resolvedGetRowId(row,
|
|
460
|
+
const rowId = resolvedGetRowId(row, index);
|
|
449
461
|
return rowId === state.editingRowId;
|
|
450
462
|
} catch {
|
|
451
463
|
return false;
|
|
452
464
|
}
|
|
453
465
|
});
|
|
454
|
-
|
|
455
|
-
|
|
466
|
+
|
|
467
|
+
if (originalRowIndex >= 0) {
|
|
468
|
+
const originalRow = data[originalRowIndex];
|
|
469
|
+
onEditRow(originalRow, latestEditingData as Partial<TData>);
|
|
456
470
|
}
|
|
457
471
|
}
|
|
458
472
|
stateActions.clearEditing();
|
|
@@ -33,7 +33,7 @@ export function SelectEditField<TData extends DataRecord>({
|
|
|
33
33
|
const logger = createLogger('SelectEditField');
|
|
34
34
|
const isSearchable = columnDef.selectSearchable !== false;
|
|
35
35
|
const isCreatable = columnDef.creatable === true;
|
|
36
|
-
const selectRef = React.useRef<
|
|
36
|
+
const selectRef = React.useRef<HTMLFieldSetElement>(null);
|
|
37
37
|
const [searchTerm, setSearchTerm] = React.useState('');
|
|
38
38
|
const [isOpen, setIsOpen] = React.useState(false);
|
|
39
39
|
const [showCreateOption, setShowCreateOption] = React.useState(false);
|
|
@@ -258,7 +258,27 @@ export const renderEditField = <TData extends DataRecord>(
|
|
|
258
258
|
|
|
259
259
|
if (columnDef.fieldType === 'select' && columnDef.fieldOptions) {
|
|
260
260
|
const accessorKey = columnDef.editAccessorKey || column.id;
|
|
261
|
-
|
|
261
|
+
// CRITICAL FIX: Ensure we use the value from editingData first, then fall back to the passed value
|
|
262
|
+
// Convert to string to match Select component's string-based value system
|
|
263
|
+
// Always prioritize editingData[accessorKey] to ensure we use the most recent value
|
|
264
|
+
const rawValue = editingData[accessorKey] !== undefined && editingData[accessorKey] !== null
|
|
265
|
+
? editingData[accessorKey]
|
|
266
|
+
: (value !== undefined && value !== null ? value : '');
|
|
267
|
+
const currentValue = rawValue !== null && rawValue !== undefined ? String(rawValue) : '';
|
|
268
|
+
|
|
269
|
+
// Create onChange handler that immediately updates state
|
|
270
|
+
const handleValueChange = (newValue: CellValue) => {
|
|
271
|
+
// Store the new value - preserve original type if option values are numbers
|
|
272
|
+
// Check if any option has a numeric value to determine if we should convert
|
|
273
|
+
const hasNumericValues = columnDef.fieldOptions?.some((opt: any) =>
|
|
274
|
+
'value' in opt && !('type' in opt) && typeof opt.value === 'number'
|
|
275
|
+
);
|
|
276
|
+
const finalValue = hasNumericValues && !isNaN(Number(newValue)) && newValue !== ''
|
|
277
|
+
? Number(newValue)
|
|
278
|
+
: newValue;
|
|
279
|
+
// Immediately update state - this happens synchronously
|
|
280
|
+
onChange({ [accessorKey]: finalValue });
|
|
281
|
+
};
|
|
262
282
|
|
|
263
283
|
return (
|
|
264
284
|
<SelectEditField
|
|
@@ -266,7 +286,7 @@ export const renderEditField = <TData extends DataRecord>(
|
|
|
266
286
|
accessorKey={accessorKey}
|
|
267
287
|
currentValue={currentValue}
|
|
268
288
|
placeholder={placeholder}
|
|
269
|
-
onChange={
|
|
289
|
+
onChange={handleValueChange}
|
|
270
290
|
/>
|
|
271
291
|
);
|
|
272
292
|
}
|
|
@@ -51,7 +51,7 @@ function SelectEditField<TData extends DataRecord>({
|
|
|
51
51
|
// When selectSearchable is false, hide the search input (type-to-search still works via SelectContent internals)
|
|
52
52
|
const isSearchable = columnDef.selectSearchable !== false;
|
|
53
53
|
const isCreatable = columnDef.creatable === true;
|
|
54
|
-
const selectRef = React.useRef<
|
|
54
|
+
const selectRef = React.useRef<HTMLFieldSetElement>(null);
|
|
55
55
|
const [searchTerm, setSearchTerm] = React.useState('');
|
|
56
56
|
const [isOpen, setIsOpen] = React.useState(false);
|
|
57
57
|
const [showCreateOption, setShowCreateOption] = React.useState(false);
|
|
@@ -379,19 +379,18 @@ export function EditableRow<TData extends DataRecord>({
|
|
|
379
379
|
const isSystemColumn = cell.column.id === 'select' || cell.column.id === 'actions';
|
|
380
380
|
|
|
381
381
|
return (
|
|
382
|
-
<td key={cell.id} role="cell">
|
|
383
|
-
|
|
384
|
-
{isSystemColumn ? (
|
|
382
|
+
<td key={cell.id} role="cell" className={cell.column.columnDef.meta?.align === 'right' ? 'text-right' : ''}>
|
|
383
|
+
{isSystemColumn ? (
|
|
385
384
|
// System columns: render their normal cell content (checkbox for select, buttons for actions)
|
|
386
385
|
cell.column.id === 'actions' ? (
|
|
387
|
-
|
|
388
|
-
<Button onClick={onSave} size="sm" variant="default" aria-label="Save changes">
|
|
386
|
+
<>
|
|
387
|
+
<Button onClick={onSave} size="sm" variant="default" aria-label="Save changes" className="mr-1">
|
|
389
388
|
<Check className="size-4" />
|
|
390
389
|
</Button>
|
|
391
390
|
<Button onClick={onCancel} size="sm" variant="outline" aria-label="Cancel editing">
|
|
392
391
|
<X className="size-4" />
|
|
393
392
|
</Button>
|
|
394
|
-
|
|
393
|
+
</>
|
|
395
394
|
) : (
|
|
396
395
|
// Select column: render the checkbox normally
|
|
397
396
|
flexRender(cell.column.columnDef.cell, cell.getContext())
|
|
@@ -434,9 +433,14 @@ export function EditableRow<TData extends DataRecord>({
|
|
|
434
433
|
hasAssignedRef.current = true;
|
|
435
434
|
}
|
|
436
435
|
|
|
436
|
+
// CRITICAL FIX: Use the correct accessor key (editAccessorKey or column.id) to get the value
|
|
437
|
+
// This ensures that when editAccessorKey is different from column.id, we use the correct key
|
|
438
|
+
const accessorKey = columnDef.editAccessorKey || cell.column.id;
|
|
439
|
+
const currentValue = editingData[accessorKey] ?? (cell.getValue() as CellValue);
|
|
440
|
+
|
|
437
441
|
return renderEditField(
|
|
438
442
|
cell.column,
|
|
439
|
-
|
|
443
|
+
currentValue,
|
|
440
444
|
(value) => {
|
|
441
445
|
if (typeof value === 'object' && value !== null && !Array.isArray(value) && !(value instanceof Date)) {
|
|
442
446
|
onEditingDataChange({ ...editingData, ...(value as Record<string, CellValue>) });
|
|
@@ -450,7 +454,6 @@ export function EditableRow<TData extends DataRecord>({
|
|
|
450
454
|
);
|
|
451
455
|
})()
|
|
452
456
|
)}
|
|
453
|
-
</div>
|
|
454
457
|
</td>
|
|
455
458
|
);
|
|
456
459
|
})}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Database, Search, Plus, User } from 'lucide-react';
|
|
3
3
|
import { Button } from '../../Button/Button';
|
|
4
|
+
import { Alert, AlertTitle, AlertDescription } from '../../Alert/Alert';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Props for the EmptyState component.
|
|
@@ -38,10 +39,10 @@ export function EmptyState({
|
|
|
38
39
|
: "Get started by adding your first entry";
|
|
39
40
|
|
|
40
41
|
return (
|
|
41
|
-
<
|
|
42
|
+
<Alert
|
|
42
43
|
role="status"
|
|
43
44
|
aria-live="polite"
|
|
44
|
-
className="
|
|
45
|
+
className="grid place-items-center text-center max-w-lg mx-auto"
|
|
45
46
|
>
|
|
46
47
|
<Icon
|
|
47
48
|
role="img"
|
|
@@ -49,15 +50,15 @@ export function EmptyState({
|
|
|
49
50
|
className="size-12 text-muted-foreground mb-4"
|
|
50
51
|
data-testid={Icon === Database ? 'lucide-database' : Icon === User ? 'lucide-user' : 'custom-icon'}
|
|
51
52
|
/>
|
|
52
|
-
<
|
|
53
|
+
<AlertTitle className="text-lg font-semibold mb-2">
|
|
53
54
|
{title || defaultTitle}
|
|
54
|
-
</
|
|
55
|
-
<
|
|
55
|
+
</AlertTitle>
|
|
56
|
+
<AlertDescription className="text-sm text-muted-foreground mb-4 max-w-sm">
|
|
56
57
|
{description || defaultDescription}
|
|
57
|
-
</
|
|
58
|
+
</AlertDescription>
|
|
58
59
|
|
|
59
60
|
{(isFiltered && onClearFilters) || action ? (
|
|
60
|
-
|
|
61
|
+
<>
|
|
61
62
|
{isFiltered && onClearFilters && (
|
|
62
63
|
<Button variant="outline" onClick={onClearFilters}>
|
|
63
64
|
<Search className="size-4 mr-2" />
|
|
@@ -71,8 +72,8 @@ export function EmptyState({
|
|
|
71
72
|
{action.label}
|
|
72
73
|
</Button>
|
|
73
74
|
)}
|
|
74
|
-
|
|
75
|
+
</>
|
|
75
76
|
) : null}
|
|
76
|
-
</
|
|
77
|
+
</Alert>
|
|
77
78
|
);
|
|
78
79
|
}
|
|
@@ -121,7 +121,7 @@ export function FilterRow<TData>({ table, visibleColumns }: FilterRowProps<TData
|
|
|
121
121
|
return (
|
|
122
122
|
<td
|
|
123
123
|
key={header.id}
|
|
124
|
-
className="
|
|
124
|
+
className="p-1"
|
|
125
125
|
>
|
|
126
126
|
{canFilter ? (
|
|
127
127
|
<ColumnFilter
|
|
@@ -131,9 +131,7 @@ export function FilterRow<TData>({ table, visibleColumns }: FilterRowProps<TData
|
|
|
131
131
|
placeholder={`Filter ${getColumnHeaderText(column as unknown as Column<DataRecord, unknown>)}...`}
|
|
132
132
|
/>
|
|
133
133
|
) : (
|
|
134
|
-
|
|
135
|
-
No filter
|
|
136
|
-
</div>
|
|
134
|
+
<> </>
|
|
137
135
|
)}
|
|
138
136
|
</td>
|
|
139
137
|
);
|
|
@@ -36,10 +36,12 @@
|
|
|
36
36
|
* - Customizable text content
|
|
37
37
|
*/
|
|
38
38
|
import React, { useState, useRef, useEffect } from 'react';
|
|
39
|
-
import { Dialog, DialogContent, DialogHeader } from '../../Dialog';
|
|
39
|
+
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from '../../Dialog';
|
|
40
40
|
import { Button } from '../../Button/Button';
|
|
41
41
|
import { Input } from '../../Input/Input';
|
|
42
42
|
import { Progress } from '../../Progress';
|
|
43
|
+
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '../../Table/Table';
|
|
44
|
+
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '../../Card/Card';
|
|
43
45
|
import { Upload, FileText, AlertCircle } from 'lucide-react';
|
|
44
46
|
import { createLogger } from '../../../utils/core/logger';
|
|
45
47
|
|
|
@@ -372,150 +374,146 @@ export function ImportModal({ isOpen, onClose, onImport, config = {} }: ImportMo
|
|
|
372
374
|
|
|
373
375
|
return (
|
|
374
376
|
<Dialog open={isOpen} onOpenChange={handleClose}>
|
|
375
|
-
<DialogContent
|
|
377
|
+
<DialogContent
|
|
378
|
+
maxWidthPercent={95}
|
|
379
|
+
className="w-auto"
|
|
380
|
+
title={title}
|
|
381
|
+
description={description}
|
|
382
|
+
>
|
|
376
383
|
<DialogHeader>
|
|
377
|
-
<
|
|
378
|
-
<
|
|
384
|
+
<DialogTitle>{title}</DialogTitle>
|
|
385
|
+
<DialogDescription>{description}</DialogDescription>
|
|
379
386
|
</DialogHeader>
|
|
380
387
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
388
|
+
<Card className="text-center">
|
|
389
|
+
<CardHeader>
|
|
390
|
+
<FileText className="size-8 mx-auto text-sec-400 mb-2" />
|
|
391
|
+
</CardHeader>
|
|
392
|
+
<CardDescription>
|
|
385
393
|
{file ? `Selected: ${file.name}` : uploadText}
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
File selected, processing preview...
|
|
390
|
-
</p>
|
|
391
|
-
)}
|
|
392
|
-
<Button
|
|
393
|
-
variant="outline"
|
|
394
|
-
size="sm"
|
|
395
|
-
onClick={() => fileInputRef.current?.click()}
|
|
396
|
-
>
|
|
397
|
-
<Upload className="size-4 mr-2" />
|
|
398
|
-
{selectFileButtonText}
|
|
399
|
-
</Button>
|
|
400
|
-
<Input
|
|
401
|
-
ref={fileInputRef}
|
|
402
|
-
type="file"
|
|
403
|
-
accept=".csv"
|
|
404
|
-
onChange={handleFileSelect}
|
|
405
|
-
className="hidden"
|
|
406
|
-
/>
|
|
407
|
-
</div>
|
|
408
|
-
|
|
409
|
-
{error && (
|
|
410
|
-
<div className="flex items-center gap-2 p-3 bg-acc-50 border border-acc-200 rounded text-acc-700">
|
|
411
|
-
<AlertCircle className="size-4" />
|
|
412
|
-
<span className="text-sm">{error}</span>
|
|
413
|
-
</div>
|
|
414
|
-
)}
|
|
415
|
-
|
|
416
|
-
{validationErrors.length > 0 && (
|
|
417
|
-
<div className="space-y-2">
|
|
418
|
-
<div className="flex items-center gap-2 p-3 bg-acc-50 border border-acc-200 rounded text-acc-700">
|
|
419
|
-
<AlertCircle className="size-4" />
|
|
420
|
-
<span className="text-sm font-medium">
|
|
421
|
-
{validationErrors.length} validation error{validationErrors.length !== 1 ? 's' : ''} found
|
|
394
|
+
{file && (
|
|
395
|
+
<span className="block text-xs text-sec-500 mt-1">
|
|
396
|
+
File selected, processing preview...
|
|
422
397
|
</span>
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
398
|
+
)}
|
|
399
|
+
</CardDescription>
|
|
400
|
+
<CardContent className="text-center">
|
|
401
|
+
{error && (
|
|
402
|
+
<>
|
|
403
|
+
<AlertCircle className="inline-block size-4 mr-2" />
|
|
404
|
+
<span className="text-sm">{error}</span>
|
|
405
|
+
</>
|
|
406
|
+
)}
|
|
407
|
+
|
|
408
|
+
{validationErrors.length > 0 && (
|
|
409
|
+
<>
|
|
410
|
+
<AlertCircle className="size-4" />
|
|
411
|
+
<span className="text-sm font-medium">
|
|
412
|
+
{validationErrors.length} validation error{validationErrors.length !== 1 ? 's' : ''} found
|
|
413
|
+
</span>
|
|
414
|
+
{validationErrors.slice(0, 10).map((err, idx) => (
|
|
415
|
+
<p key={idx} className="text-xs text-acc-600 p-2 bg-acc-50 border border-acc-200 rounded">
|
|
416
|
+
<span className="font-medium">Row {err.row}</span> • {err.field}: {err.message}
|
|
417
|
+
</p>
|
|
418
|
+
))}
|
|
419
|
+
{validationErrors.length > 10 && (
|
|
420
|
+
<p className="text-xs text-sec-500 italic">
|
|
421
|
+
... and {validationErrors.length - 10} more errors
|
|
422
|
+
</p>
|
|
423
|
+
)}
|
|
424
|
+
</>
|
|
425
|
+
)}
|
|
439
426
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
427
|
+
{importProgress && isProcessing && (
|
|
428
|
+
<>
|
|
429
|
+
<span className="text-sm font-medium text-sec-900">
|
|
430
|
+
{importProgress.stage === 'parsing' ? 'Parsing CSV file...' : 'Importing data...'}
|
|
431
|
+
</span>
|
|
432
|
+
<span className="text-sm text-sec-600">
|
|
433
|
+
{importProgress.current.toLocaleString()} / {importProgress.total.toLocaleString()} rows
|
|
434
|
+
</span>
|
|
435
|
+
<Progress
|
|
436
|
+
value={importProgress.total > 0 ? (importProgress.current / importProgress.total) * 100 : 0}
|
|
437
|
+
className="h-2 bg-sec-200"
|
|
438
|
+
/>
|
|
439
|
+
<p className="text-xs text-sec-500">
|
|
440
|
+
{importProgress.total > 0 && importProgress.current < importProgress.total
|
|
441
|
+
? `${Math.round((importProgress.current / importProgress.total) * 100)}% complete`
|
|
442
|
+
: importProgress.stage === 'importing' && importProgress.current === 0
|
|
443
|
+
? 'Processing your data...'
|
|
444
|
+
: importProgress.current === importProgress.total
|
|
445
|
+
? 'Complete!'
|
|
446
|
+
: 'Processing...'}
|
|
447
|
+
</p>
|
|
448
|
+
</>
|
|
449
|
+
)}
|
|
450
|
+
</CardContent>
|
|
451
|
+
<CardFooter>
|
|
452
|
+
<Button
|
|
453
|
+
variant="outline"
|
|
454
|
+
size="sm"
|
|
455
|
+
onClick={() => fileInputRef.current?.click()}
|
|
456
|
+
>
|
|
457
|
+
<Upload className="size-4 mr-2" />
|
|
458
|
+
{selectFileButtonText}
|
|
459
|
+
</Button>
|
|
460
|
+
<Input
|
|
461
|
+
ref={fileInputRef}
|
|
462
|
+
type="file"
|
|
463
|
+
accept=".csv"
|
|
464
|
+
onChange={handleFileSelect}
|
|
465
|
+
className="hidden"
|
|
453
466
|
/>
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
? `${Math.round((importProgress.current / importProgress.total) * 100)}% complete`
|
|
457
|
-
: importProgress.stage === 'importing' && importProgress.current === 0
|
|
458
|
-
? 'Processing your data...'
|
|
459
|
-
: importProgress.current === importProgress.total
|
|
460
|
-
? 'Complete!'
|
|
461
|
-
: 'Processing...'}
|
|
462
|
-
</p>
|
|
463
|
-
</div>
|
|
464
|
-
)}
|
|
467
|
+
</CardFooter>
|
|
468
|
+
</Card>
|
|
465
469
|
|
|
466
470
|
{file && previewData && previewData.length > 0 && !isProcessing ? (
|
|
467
|
-
<
|
|
468
|
-
<
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
471
|
+
<Card>
|
|
472
|
+
<CardHeader>
|
|
473
|
+
<CardTitle>{previewHeaderText}</CardTitle>
|
|
474
|
+
</CardHeader>
|
|
475
|
+
<CardContent className="overflow-x-auto">
|
|
476
|
+
<Table className="text-xs min-w-full">
|
|
477
|
+
<TableHeader>
|
|
478
|
+
<TableRow>
|
|
474
479
|
{Object.keys(previewData[0]).map((header) => (
|
|
475
|
-
<
|
|
480
|
+
<TableHead key={header} >
|
|
476
481
|
{header}
|
|
477
|
-
</
|
|
482
|
+
</TableHead>
|
|
478
483
|
))}
|
|
479
|
-
</
|
|
480
|
-
</
|
|
481
|
-
<
|
|
484
|
+
</TableRow>
|
|
485
|
+
</TableHeader>
|
|
486
|
+
<TableBody>
|
|
482
487
|
{previewData.map((row, index) => (
|
|
483
|
-
<
|
|
488
|
+
<TableRow key={index} >
|
|
484
489
|
{Object.values(row).map((value, cellIndex) => (
|
|
485
|
-
<
|
|
490
|
+
<TableCell key={cellIndex} >
|
|
486
491
|
{String(value)}
|
|
487
|
-
</
|
|
492
|
+
</TableCell>
|
|
488
493
|
))}
|
|
489
|
-
</
|
|
494
|
+
</TableRow>
|
|
490
495
|
))}
|
|
491
|
-
</
|
|
492
|
-
</
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
</div>
|
|
499
|
-
) : !file ? (
|
|
500
|
-
<div className="border rounded-lg p-6 text-center bg-sec-50">
|
|
501
|
-
<p className="text-sec-500">
|
|
502
|
-
Select a CSV file to preview
|
|
503
|
-
</p>
|
|
504
|
-
</div>
|
|
496
|
+
</TableBody>
|
|
497
|
+
</Table>
|
|
498
|
+
</CardContent>
|
|
499
|
+
<CardFooter>
|
|
500
|
+
{totalRowsText.replace('{count}', totalCount.toString())}
|
|
501
|
+
</CardFooter>
|
|
502
|
+
</Card>
|
|
505
503
|
) : null}
|
|
506
504
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
</
|
|
518
|
-
</
|
|
505
|
+
|
|
506
|
+
<DialogFooter>
|
|
507
|
+
<Button variant="outline" onClick={handleClose}>
|
|
508
|
+
{cancelButtonText}
|
|
509
|
+
</Button>
|
|
510
|
+
<Button
|
|
511
|
+
onClick={handleImport}
|
|
512
|
+
disabled={!file || isProcessing}
|
|
513
|
+
>
|
|
514
|
+
{isProcessing ? importButtonProcessingText : importButtonText}
|
|
515
|
+
</Button>
|
|
516
|
+
</DialogFooter>
|
|
519
517
|
</DialogContent>
|
|
520
518
|
</Dialog>
|
|
521
519
|
);
|