@jmruthers/pace-core 0.6.6 → 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/{scripts/audit/audit-dependencies.cjs → audit-tool/00-dependencies.cjs} +12 -13
- 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/cursor-rules/00-standards-overview.mdc +156 -0
- package/cursor-rules/{00-pace-core-compliance.mdc → 01-pace-core-compliance.mdc} +187 -34
- package/cursor-rules/02-project-structure.mdc +37 -5
- package/cursor-rules/{03-solid-principles.mdc → 03-architecture.mdc} +125 -11
- package/cursor-rules/04-code-quality.mdc +419 -0
- package/cursor-rules/{08-markup-quality.mdc → 05-styling.mdc} +55 -10
- package/cursor-rules/{09-rbac-compliance.mdc → 06-security-rbac.mdc} +62 -6
- 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/DataTable-7PMH7XN7.js +15 -0
- package/dist/{DataTable-2N_tqbfq.d.ts → DataTable-DRUIgtUH.d.ts} +1 -1
- package/dist/{PublicPageProvider-BBH6Vqg7.d.ts → PublicPageProvider-DlsCaR5v.d.ts} +26 -16
- package/dist/{chunk-FENMYN2U.js → chunk-5X4QLXRG.js} +1 -3
- package/dist/{chunk-4T7OBVTU.js → chunk-6F3IILHI.js} +1 -1
- package/dist/{chunk-SD6WQY43.js → chunk-7ILTDCL2.js} +9 -1
- package/dist/{chunk-3QC3KRHK.js → chunk-A3W6LW53.js} +16 -1
- package/dist/{chunk-7TYHROIV.js → chunk-BM4CQ5P3.js} +50 -8
- package/dist/{chunk-2HGJFNAH.js → chunk-FEJLJNWA.js} +1 -15
- package/dist/{chunk-OHIK3MIO.js → chunk-GHYHJTYV.js} +2 -2
- package/dist/{chunk-UIYSCEV7.js → chunk-IUBRCBSY.js} +1 -1
- package/dist/{chunk-LAZMKTTF.js → chunk-JGWDVX64.js} +281 -347
- package/dist/{chunk-MAGBIDNS.js → chunk-L4XMVJKY.js} +2 -2
- package/dist/{chunk-A55DK444.js → chunk-OJ4SKRSV.js} +1 -7
- package/dist/{chunk-ZS5VO5JB.js → chunk-Q7Q7V5NV.js} +406 -451
- package/dist/{chunk-3O3WHILE.js → chunk-VBCS3DUA.js} +236 -60
- package/dist/{chunk-BVP2BCJF.js → chunk-ZKAWKYT4.js} +8 -8
- package/dist/components.d.ts +5 -4
- package/dist/components.js +27 -32
- package/dist/eslint-rules/index.cjs +22 -9
- package/{src/eslint-rules/rules/compliance.cjs → dist/eslint-rules/rules/01-pace-core-compliance.cjs} +184 -23
- 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/{rbac.cjs → 06-security-rbac.cjs} +26 -10
- package/dist/eslint-rules/rules/07-api-tech-stack.cjs +263 -0
- package/dist/eslint-rules/rules/08-testing.cjs +94 -0
- package/dist/hooks.d.ts +5 -5
- package/dist/hooks.js +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +18 -17
- package/dist/rbac/index.js +6 -6
- package/dist/theming/runtime.d.ts +14 -1
- package/dist/theming/runtime.js +1 -1
- package/dist/{types-B-K_5VnO.d.ts → types-DXstZpNI.d.ts} +0 -17
- package/dist/{usePublicRouteParams-COZ28Mvq.d.ts → usePublicRouteParams-MamNgwqe.d.ts} +19 -19
- package/dist/utils.d.ts +2 -2
- package/dist/utils.js +8 -8
- package/docs/README.md +1 -1
- package/docs/api/modules.md +47 -31
- package/docs/api-reference/components.md +18 -20
- package/docs/api-reference/hooks.md +80 -80
- 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/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/quick-reference.md +4 -4
- 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 +1 -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/README.md +5 -5
- package/docs/rbac/advanced-patterns.md +6 -6
- package/docs/rbac/api-reference.md +20 -20
- 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 -1
- 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/{00-pace-core-compliance.md → 1-pace-core-compliance-standards.md} +204 -185
- package/docs/standards/{02-project-structure.md → 2-project-structure-standards.md} +11 -47
- package/docs/standards/3-architecture-standards.md +606 -0
- package/docs/standards/4-code-quality-standards.md +728 -0
- package/docs/standards/{08-markup-quality.md → 5-styling-standards.md} +12 -9
- package/docs/standards/{09-rbac-compliance.md → 6-security-rbac-standards.md} +126 -18
- 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 +203 -104
- 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/eslint-config-pace-core.cjs +21 -10
- package/package.json +6 -5
- package/scripts/install-cursor-rules.cjs +11 -243
- package/scripts/install-eslint-config.cjs +284 -0
- package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +2 -2
- package/src/__tests__/helpers/__tests__/test-providers.test.tsx +2 -2
- package/src/__tests__/helpers/__tests__/test-utils.test.tsx +10 -10
- package/src/__tests__/integration/UserProfile.test.tsx +14 -14
- 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/Calendar/Calendar.tsx +201 -47
- package/src/components/ContextSelector/ContextSelector.tsx +137 -153
- 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/DataTableErrorBoundary.tsx +9 -11
- package/src/components/DataTable/components/DataTableLayout.tsx +5 -16
- package/src/components/DataTable/components/EditableRow.tsx +5 -7
- 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/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/index.ts +2 -1
- package/src/components/DataTable/types.ts +0 -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 +7 -8
- package/src/components/Dialog/Dialog.test.tsx +1 -0
- package/src/components/Dialog/Dialog.tsx +25 -8
- package/src/components/ErrorBoundary/ErrorBoundary.tsx +77 -79
- package/src/components/FileUpload/FileUpload.test.tsx +52 -14
- package/src/components/FileUpload/FileUpload.tsx +112 -130
- package/src/components/Progress/Progress.tsx +2 -4
- package/src/components/ProtectedRoute/ProtectedRoute.tsx +8 -8
- package/src/components/Select/Select.tsx +86 -77
- package/src/components/Select/types.ts +3 -0
- package/src/hooks/__tests__/ServiceHooks.test.tsx +16 -16
- package/src/hooks/__tests__/hooks.integration.test.tsx +49 -49
- package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +97 -97
- package/src/hooks/public/usePublicEvent.ts +5 -5
- package/src/hooks/public/usePublicEventLogo.ts +5 -5
- package/src/hooks/public/usePublicFileDisplay.ts +2 -2
- package/src/hooks/public/usePublicRouteParams.ts +5 -5
- package/src/hooks/useAppConfig.ts +2 -2
- package/src/hooks/useEventTheme.test.ts +7 -7
- package/src/hooks/useEventTheme.ts +1 -4
- package/src/hooks/useFileDisplay.ts +2 -2
- 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/__tests__/AuthServiceProvider.integration.test.tsx +7 -7
- package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +10 -10
- 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/utils/__tests__/lazyLoad.unit.test.tsx +42 -39
- package/src/utils/storage/README.md +1 -1
- package/cursor-rules/01-standards-compliance.mdc +0 -285
- package/cursor-rules/04-testing-standards.mdc +0 -270
- package/cursor-rules/05-bug-reports-and-features.mdc +0 -248
- package/cursor-rules/06-code-quality.mdc +0 -311
- package/cursor-rules/07-tech-stack-compliance.mdc +0 -216
- package/cursor-rules/10-error-handling-patterns.mdc +0 -179
- package/cursor-rules/11-performance-optimization.mdc +0 -169
- package/cursor-rules/12-ci-cd-integration.mdc +0 -150
- package/dist/DataTable-LRJL4IRV.js +0 -15
- package/dist/eslint-rules/rules/compliance.cjs +0 -348
- package/dist/eslint-rules/rules/components.cjs +0 -113
- package/dist/eslint-rules/rules/imports.cjs +0 -102
- package/docs/best-practices/README.md +0 -472
- package/docs/best-practices/accessibility.md +0 -604
- 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-standards-compliance.md +0 -188
- package/docs/standards/03-solid-principles.md +0 -39
- package/docs/standards/04-testing-standards.md +0 -36
- package/docs/standards/05-bug-reports-and-features.md +0 -27
- package/docs/standards/06-code-quality.md +0 -34
- package/docs/standards/07-tech-stack-compliance.md +0 -30
- package/docs/standards/10-error-handling-patterns.md +0 -401
- package/docs/standards/11-performance-optimization.md +0 -348
- package/docs/standards/12-ci-cd-integration.md +0 -370
- package/docs/standards/ALIGNMENT_REVIEW_SUMMARY.md +0 -192
- package/scripts/audit/audit-compliance.cjs +0 -1295
- package/scripts/audit/audit-components.cjs +0 -260
- package/scripts/audit/audit-rbac.cjs +0 -954
- package/scripts/audit/audit-standards.cjs +0 -1268
- package/scripts/audit/index.cjs +0 -1927
- package/src/components/DataTable/components/DataTableBody.tsx +0 -478
- 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/index.cjs +0 -22
- package/src/eslint-rules/rules/components.cjs +0 -113
- package/src/eslint-rules/rules/imports.cjs +0 -102
- package/src/eslint-rules/rules/rbac.cjs +0 -790
- package/src/eslint-rules/utils/helpers.cjs +0 -42
- package/src/eslint-rules/utils/manifest-loader.cjs +0 -75
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Enforce error handling patterns, performance optimization, and CI/CD integration patterns
|
|
3
|
+
globs: ["src/**/*.{ts,tsx,js,jsx}", "supabase/migrations/**/*.sql", ".github/workflows/**/*.{yml,yaml}", "package.json"]
|
|
4
|
+
alwaysApply: false
|
|
5
|
+
paceCoreVersion: "0.6.x"
|
|
6
|
+
rulesVersion: "2025-01-28"
|
|
7
|
+
---
|
|
8
|
+
# Operations Standards Guide
|
|
9
|
+
|
|
10
|
+
**📚 Human-Readable Standard**: See [9-operations-standards.md](../../packages/core/docs/standards/9-operations-standards.md) for complete documentation.
|
|
11
|
+
|
|
12
|
+
This guide enforces error handling patterns, performance optimization strategies, and CI/CD integration patterns.
|
|
13
|
+
|
|
14
|
+
## AI Agent Instructions
|
|
15
|
+
|
|
16
|
+
**When writing or modifying code, ALWAYS:**
|
|
17
|
+
1. **Use type-safe errors** - Never use `any` for errors, always use type guards or Result types
|
|
18
|
+
2. **Never expose internals** - User-facing errors must be friendly, never show SQL, stack traces, or file paths
|
|
19
|
+
3. **Log with context** - Always log errors with context, but never log sensitive data (passwords, tokens, PII)
|
|
20
|
+
4. **Memoize expensive operations** - Use `useMemo` for expensive computations, `useCallback` for stable references
|
|
21
|
+
5. **Avoid new objects in render** - Never create new objects/arrays in render, memoize them with `useMemo`
|
|
22
|
+
6. **Use helper functions in RLS** - Always use STABLE SECURITY DEFINER helper functions, never subqueries
|
|
23
|
+
7. **Provide recovery paths** - When possible, provide retry logic or fallback values
|
|
24
|
+
|
|
25
|
+
**Decision Tree: Error Handling**
|
|
26
|
+
```
|
|
27
|
+
1. What type of error is this?
|
|
28
|
+
├─ API Error → Use ApiResult shape, user-friendly message
|
|
29
|
+
├─ Validation Error → Use Zod errors, field-specific messages
|
|
30
|
+
├─ Network Error → Retry logic, connection message
|
|
31
|
+
└─ Unknown Error → Generic user message, detailed log
|
|
32
|
+
|
|
33
|
+
2. Should user see this error?
|
|
34
|
+
├─ YES → User-friendly message (no internals)
|
|
35
|
+
└─ NO → Log only, show generic message
|
|
36
|
+
|
|
37
|
+
3. Can we recover?
|
|
38
|
+
├─ YES → Retry logic or fallback value
|
|
39
|
+
└─ NO → Show error, allow user to retry
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**Decision Tree: Performance**
|
|
43
|
+
```
|
|
44
|
+
1. Is this expensive computation?
|
|
45
|
+
├─ YES → Use useMemo
|
|
46
|
+
└─ NO → Don't memoize (overhead not worth it)
|
|
47
|
+
|
|
48
|
+
2. Is this function passed as prop?
|
|
49
|
+
├─ YES → Use useCallback
|
|
50
|
+
└─ NO → Regular function is fine
|
|
51
|
+
|
|
52
|
+
3. Is this creating new object/array in render?
|
|
53
|
+
├─ YES → Memoize with useMemo
|
|
54
|
+
└─ NO → Continue
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Error Handling Patterns
|
|
58
|
+
|
|
59
|
+
### MUST: Use Type-Safe Error Handling
|
|
60
|
+
|
|
61
|
+
**MUST use type guards or Result types, NEVER use `any`:**
|
|
62
|
+
|
|
63
|
+
```tsx
|
|
64
|
+
// ❌ WRONG: Using any
|
|
65
|
+
catch (error: any) {
|
|
66
|
+
console.log(error.message);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// ✅ CORRECT: Type guard
|
|
70
|
+
function isApiError(error: unknown): error is ApiError {
|
|
71
|
+
return typeof error === 'object' && error !== null && 'ok' in error && (error as ApiError).ok === false;
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
if (isApiError(error)) {
|
|
75
|
+
handleApiError(error);
|
|
76
|
+
} else {
|
|
77
|
+
handleUnknownError(error);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// ✅ CORRECT: Result type
|
|
82
|
+
type Result<T> = { ok: true; data: T } | { ok: false; error: ApiError };
|
|
83
|
+
const result = await fetchData();
|
|
84
|
+
if (result.ok) {
|
|
85
|
+
useData(result.data);
|
|
86
|
+
} else {
|
|
87
|
+
showError(result.error.message);
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### MUST: Never Expose Internal Details
|
|
92
|
+
|
|
93
|
+
**MUST NOT expose SQL, stack traces, file paths, or internal errors to users:**
|
|
94
|
+
|
|
95
|
+
```tsx
|
|
96
|
+
// ❌ WRONG: Exposing internal details
|
|
97
|
+
toast.error(error.message); // May contain SQL, stack traces
|
|
98
|
+
|
|
99
|
+
// ✅ CORRECT: User-friendly message
|
|
100
|
+
toast.error('Unable to save changes. Please try again.');
|
|
101
|
+
logger.error('Save failed', { error: error.message, context: 'saveUser' });
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### MUST: Use Consistent Error Shapes
|
|
105
|
+
|
|
106
|
+
**MUST use ApiResult shape for API errors:**
|
|
107
|
+
|
|
108
|
+
```tsx
|
|
109
|
+
// ✅ CORRECT: Consistent error shape
|
|
110
|
+
type ApiError = {
|
|
111
|
+
ok: false;
|
|
112
|
+
error: {
|
|
113
|
+
code: string;
|
|
114
|
+
message: string; // User-friendly
|
|
115
|
+
details?: object; // Non-sensitive context
|
|
116
|
+
};
|
|
117
|
+
};
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### MUST: Log Errors with Context
|
|
121
|
+
|
|
122
|
+
**MUST log errors with context, but NEVER log sensitive data:**
|
|
123
|
+
|
|
124
|
+
```tsx
|
|
125
|
+
// ✅ CORRECT: Log with context, no sensitive data
|
|
126
|
+
logger.error('Failed to save user', {
|
|
127
|
+
userId: user.id,
|
|
128
|
+
operation: 'updateUser',
|
|
129
|
+
errorCode: error.code,
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// ❌ WRONG: Logging sensitive data
|
|
133
|
+
logger.error('Failed to save user', {
|
|
134
|
+
password: user.password, // NEVER
|
|
135
|
+
token: authToken, // NEVER
|
|
136
|
+
});
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### SHOULD: Provide Recovery Paths
|
|
140
|
+
|
|
141
|
+
**SHOULD provide retry logic or fallback values when appropriate:**
|
|
142
|
+
|
|
143
|
+
```tsx
|
|
144
|
+
// ✅ CORRECT: Retry with exponential backoff
|
|
145
|
+
async function fetchWithRetry<T>(fn: () => Promise<Result<T>>, maxRetries = 3): Promise<Result<T>> {
|
|
146
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
147
|
+
const result = await fn();
|
|
148
|
+
if (result.ok) return result;
|
|
149
|
+
if (result.error.code?.startsWith('4')) return result; // Don't retry 4xx
|
|
150
|
+
await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 1000));
|
|
151
|
+
}
|
|
152
|
+
return { ok: false, error: { code: 'MAX_RETRIES', message: 'Operation failed after retries' } };
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Performance Optimization Patterns
|
|
157
|
+
|
|
158
|
+
### MUST: Optimize React Re-renders
|
|
159
|
+
|
|
160
|
+
**MUST use memoization for expensive computations and stable references:**
|
|
161
|
+
|
|
162
|
+
```tsx
|
|
163
|
+
// ✅ CORRECT - Memoize expensive computation
|
|
164
|
+
const expensiveValue = useMemo(() => computeExpensiveValue(data), [data]);
|
|
165
|
+
|
|
166
|
+
// ✅ CORRECT - Stable callback reference
|
|
167
|
+
const handleClick = useCallback(() => doSomething(id), [id]);
|
|
168
|
+
|
|
169
|
+
// ✅ CORRECT - Memoize component
|
|
170
|
+
const ExpensiveComponent = React.memo(({ data }) => <div>{/* ... */}</div>);
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### MUST: Avoid Creating New Objects in Render
|
|
174
|
+
|
|
175
|
+
**MUST NOT create new objects/arrays in render:**
|
|
176
|
+
|
|
177
|
+
```tsx
|
|
178
|
+
// ❌ WRONG - New object on every render
|
|
179
|
+
function Component({ items }) {
|
|
180
|
+
const config = { items, enabled: true };
|
|
181
|
+
return <Child config={config} />;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// ✅ CORRECT - Memoize object
|
|
185
|
+
function Component({ items }) {
|
|
186
|
+
const config = useMemo(() => ({ items, enabled: true }), [items]);
|
|
187
|
+
return <Child config={config} />;
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### MUST: Use Helper Functions in RLS Policies
|
|
192
|
+
|
|
193
|
+
**MUST use STABLE SECURITY DEFINER helper functions (never subqueries):**
|
|
194
|
+
|
|
195
|
+
```sql
|
|
196
|
+
-- ✅ CORRECT - Helper function (evaluated once)
|
|
197
|
+
CREATE POLICY "rbac_select_users" ON users FOR SELECT USING (
|
|
198
|
+
check_user_organisation_access(organisation_id)
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
-- ❌ WRONG - Subquery (N+1 performance issue)
|
|
202
|
+
CREATE POLICY "rbac_select_users" ON users FOR SELECT USING (
|
|
203
|
+
organisation_id IN (SELECT organisation_id FROM organisation_memberships WHERE user_id = auth.uid())
|
|
204
|
+
);
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### SHOULD: Lazy Load Heavy Components
|
|
208
|
+
|
|
209
|
+
**SHOULD lazy load heavy components:**
|
|
210
|
+
|
|
211
|
+
```tsx
|
|
212
|
+
// ✅ CORRECT - Lazy load
|
|
213
|
+
import { lazy, Suspense } from 'react';
|
|
214
|
+
const HeavyComponent = lazy(() => import('./HeavyComponent'));
|
|
215
|
+
<Suspense fallback={<Loading />}><HeavyComponent /></Suspense>
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### SHOULD: Configure TanStack Query Cache
|
|
219
|
+
|
|
220
|
+
**SHOULD configure appropriate cache times:**
|
|
221
|
+
|
|
222
|
+
```tsx
|
|
223
|
+
// ✅ CORRECT - Configure cache
|
|
224
|
+
const queryClient = new QueryClient({
|
|
225
|
+
defaultOptions: {
|
|
226
|
+
queries: {
|
|
227
|
+
staleTime: 5 * 60 * 1000,
|
|
228
|
+
cacheTime: 10 * 60 * 1000,
|
|
229
|
+
retry: 1,
|
|
230
|
+
refetchOnWindowFocus: false,
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
});
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## CI/CD Integration Patterns
|
|
237
|
+
|
|
238
|
+
### MUST: Include Required CI Checks
|
|
239
|
+
|
|
240
|
+
**MUST run these checks in every CI pipeline:**
|
|
241
|
+
|
|
242
|
+
```yaml
|
|
243
|
+
# ✅ CORRECT - Required checks
|
|
244
|
+
jobs:
|
|
245
|
+
quality-checks:
|
|
246
|
+
steps:
|
|
247
|
+
- name: Lint
|
|
248
|
+
run: npm run lint
|
|
249
|
+
- name: Type check
|
|
250
|
+
run: npx tsc --noEmit
|
|
251
|
+
- name: Run tests
|
|
252
|
+
run: npm run test
|
|
253
|
+
- name: Build
|
|
254
|
+
run: npm run build
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### MUST: Have Required Scripts
|
|
258
|
+
|
|
259
|
+
**MUST have these scripts in package.json:**
|
|
260
|
+
|
|
261
|
+
```json
|
|
262
|
+
// ✅ CORRECT - Required scripts
|
|
263
|
+
{
|
|
264
|
+
"scripts": {
|
|
265
|
+
"lint": "eslint .",
|
|
266
|
+
"type-check": "tsc --noEmit",
|
|
267
|
+
"test": "vitest run",
|
|
268
|
+
"build": "vite build"
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### MUST: Use Secrets for Sensitive Data
|
|
274
|
+
|
|
275
|
+
**MUST NOT commit secrets to repository:**
|
|
276
|
+
|
|
277
|
+
```yaml
|
|
278
|
+
# ✅ CORRECT - Use secrets
|
|
279
|
+
env:
|
|
280
|
+
SUPABASE_URL: ${{ secrets.SUPABASE_URL }}
|
|
281
|
+
VITE_SUPABASE_ANON_KEY: ${{ secrets.VITE_SUPABASE_ANON_KEY }}
|
|
282
|
+
|
|
283
|
+
# ❌ WRONG - Hardcoded secrets
|
|
284
|
+
env:
|
|
285
|
+
SUPABASE_URL: "https://hardcoded-url.supabase.co"
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### SHOULD: Deploy to Staging First
|
|
289
|
+
|
|
290
|
+
**SHOULD deploy to staging before production:**
|
|
291
|
+
|
|
292
|
+
```yaml
|
|
293
|
+
# ✅ CORRECT - Staging first
|
|
294
|
+
deploy-staging:
|
|
295
|
+
if: github.ref == 'refs/heads/develop'
|
|
296
|
+
environment: staging
|
|
297
|
+
|
|
298
|
+
deploy-production:
|
|
299
|
+
needs: deploy-staging
|
|
300
|
+
if: github.ref == 'refs/heads/main'
|
|
301
|
+
environment: production
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
## Common Mistakes to Avoid
|
|
305
|
+
|
|
306
|
+
**When writing code, NEVER:**
|
|
307
|
+
1. **Use `any` for errors** - Always use type guards or Result types
|
|
308
|
+
```tsx
|
|
309
|
+
// ❌ WRONG
|
|
310
|
+
catch (error: any) {
|
|
311
|
+
toast.error(error.message);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// ✅ CORRECT
|
|
315
|
+
catch (error: unknown) {
|
|
316
|
+
if (isApiError(error)) {
|
|
317
|
+
toast.error(error.error.message);
|
|
318
|
+
} else {
|
|
319
|
+
toast.error('An unexpected error occurred');
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
2. **Expose internal details in errors** - Always use user-friendly messages
|
|
325
|
+
3. **Create new objects in render** - Always memoize with useMemo
|
|
326
|
+
4. **Skip memoization for expensive operations** - Always use useMemo/useCallback
|
|
327
|
+
5. **Use subqueries in RLS policies** - Always use STABLE SECURITY DEFINER helper functions
|
|
328
|
+
6. **Log sensitive data** - Never log passwords, tokens, or PII
|
|
329
|
+
|
|
330
|
+
## Operations Checklist
|
|
331
|
+
|
|
332
|
+
Before committing, verify:
|
|
333
|
+
|
|
334
|
+
**Error Handling:**
|
|
335
|
+
- [ ] Type-safe error handling (no `any`)
|
|
336
|
+
- [ ] User-friendly error messages (no internals)
|
|
337
|
+
- [ ] Errors logged with context (no sensitive data)
|
|
338
|
+
- [ ] Recovery paths provided when possible
|
|
339
|
+
- [ ] Consistent error shapes used
|
|
340
|
+
|
|
341
|
+
**Performance:**
|
|
342
|
+
- [ ] Expensive computations memoized
|
|
343
|
+
- [ ] Callbacks stable with useCallback
|
|
344
|
+
- [ ] Components memoized when appropriate
|
|
345
|
+
- [ ] No new objects/arrays in render
|
|
346
|
+
- [ ] Heavy components lazy loaded
|
|
347
|
+
- [ ] RLS policies use helper functions
|
|
348
|
+
- [ ] TanStack Query configured properly
|
|
349
|
+
|
|
350
|
+
**CI/CD:**
|
|
351
|
+
- [ ] Lint check configured
|
|
352
|
+
- [ ] Type check configured
|
|
353
|
+
- [ ] Tests run in CI
|
|
354
|
+
- [ ] Build succeeds in CI
|
|
355
|
+
- [ ] Environment variables set as secrets
|
|
356
|
+
- [ ] Staging deployment configured
|
|
357
|
+
- [ ] Production deployment configured
|
|
358
|
+
|
|
359
|
+
## Reference
|
|
360
|
+
|
|
361
|
+
**Note**: CI/CD configuration validation and performance metric thresholds are handled by CI/audit tool. See [9-operations-standards.md](../../packages/core/docs/standards/9-operations-standards.md) for complete enforcement details.
|
|
362
|
+
|
|
363
|
+
- Error Handling: [9-operations-standards.md](../../packages/core/docs/standards/9-operations-standards.md#error-handling-patterns)
|
|
364
|
+
- Performance: [9-operations-standards.md](../../packages/core/docs/standards/9-operations-standards.md#performance-optimization)
|
|
365
|
+
- CI/CD: [9-operations-standards.md](../../packages/core/docs/standards/9-operations-standards.md#cicd-integration)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export { ActionButtons, BulkOperationsDropdown, ColumnFactory, ColumnVisibilityDropdown, DataTable, DataTableCore, DataTableErrorBoundary, DataTableModals, DataTableToolbar, EditableRow, EmptyState, EnhancedPaginationControls, GroupingDropdown, ImportModal, LoadingState, PaginationControls, SortIndicator, UnifiedTableBody, announce, announceBulkOperation, announceFilterChange, announceLoadingState, announcePaginationChange, announceSearchResults, announceSelectionChange, announceSortChange, average, calculateAllDepths, calculateAllIndentation, calculateIndentation, calculateOptimalPageSize, cleanupLiveRegion, count, createHierarchicalStructure, defaultDataTableFeatures, exportToCSV, exportToCSVWithTableRows, generateCSVContent, getAriaSortState, getAriaSortValue, getCellRenderer, getColumnHeaderText, getHierarchicalSortConfig, getPageSizeOptions, getPaginationBinding, getRowDepth, getRowDescription, getRowIdSafe, getSortButtonLabel, groupHierarchicalData, hasValidRowId, initializeLiveRegion, isHierarchicalSortableColumn, max, min, normalizeDataTableFeatures, shouldShowColumnForRow, sortHierarchicalDataByStructure, sortHierarchicalDataWithSorting, sum, validateHierarchicalData, validatePaginationConfig } from './chunk-Q7Q7V5NV.js';
|
|
2
|
+
import './chunk-BM4CQ5P3.js';
|
|
3
|
+
export { CircuitBreaker, DEFAULT_FALLBACK_CONFIG, DataChunkManager, DataTableError, DataTableErrorType, ErrorRecoveryManager, MemoryMonitor, SearchIndex, VisibilityTracker, chunkData, debounce, determinePaginationMode, getOptimalPageSizeOptions, safeExecute, throttle, useDataTablePerformance } from './chunk-S7DKJPLT.js';
|
|
4
|
+
import './chunk-VBCS3DUA.js';
|
|
5
|
+
import './chunk-C7NSAPTL.js';
|
|
6
|
+
import './chunk-FTCRZOG2.js';
|
|
7
|
+
import './chunk-ZFYPMX46.js';
|
|
8
|
+
import './chunk-AHU7G2R5.js';
|
|
9
|
+
import './chunk-4SXLQIZO.js';
|
|
10
|
+
import './chunk-A3W6LW53.js';
|
|
11
|
+
import './chunk-OJ4SKRSV.js';
|
|
12
|
+
import './chunk-7ILTDCL2.js';
|
|
13
|
+
import './chunk-HF6O3O37.js';
|
|
14
|
+
import './chunk-TTRFSOKR.js';
|
|
15
|
+
import './chunk-3RG5ZIWI.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { d as DataRecord, D as DataTableColumn, e as DataTableRBACConfig, f as DataTableFeatureConfig, H as HierarchicalConfig, g as PerformanceConfig, S as ServerSideConfig, h as PaginationMode, C as ChunkingConfig, i as SearchIndexConfig, j as ExportOptions, G as GetRowId, E as EmptyStateConfig, c as AggregateConfig, a as DataTableAction } from './types-
|
|
2
|
+
import { d as DataRecord, D as DataTableColumn, e as DataTableRBACConfig, f as DataTableFeatureConfig, H as HierarchicalConfig, g as PerformanceConfig, S as ServerSideConfig, h as PaginationMode, C as ChunkingConfig, i as SearchIndexConfig, j as ExportOptions, G as GetRowId, E as EmptyStateConfig, c as AggregateConfig, a as DataTableAction } from './types-DXstZpNI.js';
|
|
3
3
|
import React__default from 'react';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React$1 from 'react';
|
|
2
2
|
import React__default, { ReactNode, Component } from 'react';
|
|
3
3
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
4
|
-
import { P as ParsedAddress, A as AutocompleteOptions } from './types-
|
|
4
|
+
import { P as ParsedAddress, A as AutocompleteOptions } from './types-DXstZpNI.js';
|
|
5
5
|
import * as LabelPrimitive from '@radix-ui/react-label';
|
|
6
6
|
import { F as FileCategory, e as FileUploadResult, U as UploadProgress, c as FileUploadOptions, a as FileReference } from './file-reference-BavO2eQj.js';
|
|
7
7
|
import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
|
|
@@ -912,9 +912,9 @@ interface DialogContentProps extends React$1.HTMLAttributes<HTMLDialogElement> {
|
|
|
912
912
|
minHeight?: string;
|
|
913
913
|
/** Minimum width in CSS units */
|
|
914
914
|
minWidth?: string;
|
|
915
|
-
/** Dialog title
|
|
915
|
+
/** Dialog title - sets native title attribute and aria-labelledby */
|
|
916
916
|
title?: string;
|
|
917
|
-
/** Dialog description
|
|
917
|
+
/** Dialog description - sets native aria-description attribute */
|
|
918
918
|
description?: string;
|
|
919
919
|
/** Whether to persist open state across tab switches */
|
|
920
920
|
persistOpenState?: boolean;
|
|
@@ -926,12 +926,6 @@ interface DialogContentProps extends React$1.HTMLAttributes<HTMLDialogElement> {
|
|
|
926
926
|
interface DialogPortalProps {
|
|
927
927
|
children: React$1.ReactNode;
|
|
928
928
|
}
|
|
929
|
-
/**
|
|
930
|
-
* Props for the DialogClose component
|
|
931
|
-
* @public
|
|
932
|
-
*/
|
|
933
|
-
interface DialogCloseProps extends React$1.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
934
|
-
}
|
|
935
929
|
/**
|
|
936
930
|
* Props for the DialogHeader component (semantic header element)
|
|
937
931
|
* @public
|
|
@@ -1008,6 +1002,20 @@ declare const DialogPortal: React$1.FC<DialogPortalProps>;
|
|
|
1008
1002
|
* @returns JSX.Element - The semantic dialog content with overlay and optional close button
|
|
1009
1003
|
*/
|
|
1010
1004
|
declare const DialogContent: React$1.ForwardRefExoticComponent<DialogContentProps & React$1.RefAttributes<HTMLDialogElement>>;
|
|
1005
|
+
/**
|
|
1006
|
+
* Props for the DialogClose component
|
|
1007
|
+
* @public
|
|
1008
|
+
*/
|
|
1009
|
+
interface DialogCloseProps extends React$1.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
1010
|
+
}
|
|
1011
|
+
/**
|
|
1012
|
+
* Props for the DialogClose component
|
|
1013
|
+
* @public
|
|
1014
|
+
*/
|
|
1015
|
+
interface DialogCloseProps extends React$1.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
1016
|
+
/** Whether to merge props with child element instead of rendering a button */
|
|
1017
|
+
asChild?: boolean;
|
|
1018
|
+
}
|
|
1011
1019
|
/**
|
|
1012
1020
|
* DialogClose component
|
|
1013
1021
|
* Button to close the dialog
|
|
@@ -1073,6 +1081,7 @@ interface SelectProps extends Omit<React$1.HTMLAttributes<HTMLFieldSetElement>,
|
|
|
1073
1081
|
children: React$1.ReactNode;
|
|
1074
1082
|
className?: string;
|
|
1075
1083
|
direction?: SelectDirection;
|
|
1084
|
+
showCheckmark?: boolean;
|
|
1076
1085
|
}
|
|
1077
1086
|
/**
|
|
1078
1087
|
* Props for the SelectTrigger component.
|
|
@@ -1108,6 +1117,7 @@ interface SelectItemProps {
|
|
|
1108
1117
|
disabled?: boolean;
|
|
1109
1118
|
className?: string;
|
|
1110
1119
|
onClick?: (e: React$1.MouseEvent) => void;
|
|
1120
|
+
showCheckmark?: boolean;
|
|
1111
1121
|
}
|
|
1112
1122
|
|
|
1113
1123
|
/**
|
|
@@ -1171,39 +1181,39 @@ declare const SelectContent: React$1.ForwardRefExoticComponent<SelectContentProp
|
|
|
1171
1181
|
declare const SelectItem: React$1.ForwardRefExoticComponent<SelectItemProps & React$1.RefAttributes<HTMLLIElement>>;
|
|
1172
1182
|
/**
|
|
1173
1183
|
* Select group component.
|
|
1174
|
-
* Groups related select items together.
|
|
1184
|
+
* Groups related select items together using a nested list structure.
|
|
1175
1185
|
*
|
|
1176
1186
|
* @param props - Select group configuration
|
|
1177
|
-
* @param ref - Forwarded ref to the
|
|
1187
|
+
* @param ref - Forwarded ref to the ul element
|
|
1178
1188
|
* @returns The rendered select group
|
|
1179
1189
|
*/
|
|
1180
1190
|
declare const SelectGroup: React$1.ForwardRefExoticComponent<{
|
|
1181
1191
|
children: React$1.ReactNode;
|
|
1182
1192
|
className?: string;
|
|
1183
|
-
} & React$1.RefAttributes<
|
|
1193
|
+
} & React$1.RefAttributes<HTMLUListElement>>;
|
|
1184
1194
|
/**
|
|
1185
1195
|
* Select label component.
|
|
1186
1196
|
* Provides a label for a group of select items.
|
|
1187
1197
|
*
|
|
1188
1198
|
* @param props - Select label configuration
|
|
1189
|
-
* @param ref - Forwarded ref to the
|
|
1199
|
+
* @param ref - Forwarded ref to the li element
|
|
1190
1200
|
* @returns The rendered select label
|
|
1191
1201
|
*/
|
|
1192
1202
|
declare const SelectLabel: React$1.ForwardRefExoticComponent<{
|
|
1193
1203
|
children: React$1.ReactNode;
|
|
1194
1204
|
className?: string;
|
|
1195
|
-
} & React$1.RefAttributes<
|
|
1205
|
+
} & React$1.RefAttributes<HTMLLIElement>>;
|
|
1196
1206
|
/**
|
|
1197
1207
|
* Select separator component.
|
|
1198
1208
|
* Provides visual separation between groups of select items.
|
|
1199
1209
|
*
|
|
1200
1210
|
* @param props - Select separator configuration
|
|
1201
|
-
* @param ref - Forwarded ref to the
|
|
1211
|
+
* @param ref - Forwarded ref to the hr element
|
|
1202
1212
|
* @returns The rendered select separator
|
|
1203
1213
|
*/
|
|
1204
1214
|
declare const SelectSeparator: React$1.ForwardRefExoticComponent<{
|
|
1205
1215
|
className?: string;
|
|
1206
|
-
} & React$1.RefAttributes<
|
|
1216
|
+
} & React$1.RefAttributes<HTMLHRElement>>;
|
|
1207
1217
|
|
|
1208
1218
|
/**
|
|
1209
1219
|
* @file Tabs Component System
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { clearPalette, parseAndNormalizeEventColours, applyPalette } from './chunk-
|
|
1
|
+
import { clearPalette, parseAndNormalizeEventColours, applyPalette } from './chunk-ZKAWKYT4.js';
|
|
2
2
|
import { EventServiceContext } from './chunk-FTCRZOG2.js';
|
|
3
3
|
import { assertAppId } from './chunk-4SXLQIZO.js';
|
|
4
4
|
import { fetchPlaceDetails, createAddressFromPlaceResult, getAddressByPlaceId, fetchPlaceAutocomplete, setOrganisationContext } from './chunk-FYHN4DD5.js';
|
|
@@ -2087,7 +2087,6 @@ function invalidateFileDisplayCache(table_name, record_id, organisation_id, cate
|
|
|
2087
2087
|
authenticatedFileCache.delete(allCategoryKey);
|
|
2088
2088
|
}
|
|
2089
2089
|
}
|
|
2090
|
-
var log4 = createLogger("useEventTheme");
|
|
2091
2090
|
function useEventTheme(event) {
|
|
2092
2091
|
const location = useLocation();
|
|
2093
2092
|
const eventServiceContext = useContext(EventServiceContext);
|
|
@@ -2112,7 +2111,6 @@ function useEventTheme(event) {
|
|
|
2112
2111
|
try {
|
|
2113
2112
|
applyPalette(normalized);
|
|
2114
2113
|
} catch (error) {
|
|
2115
|
-
log4.error("Failed to apply event palette:", error);
|
|
2116
2114
|
}
|
|
2117
2115
|
return () => {
|
|
2118
2116
|
};
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
import { clsx } from 'clsx';
|
|
2
|
+
import { twMerge } from 'tailwind-merge';
|
|
3
|
+
|
|
4
|
+
// src/utils/core/cn.ts
|
|
5
|
+
function cn(...inputs) {
|
|
6
|
+
return twMerge(clsx(inputs));
|
|
7
|
+
}
|
|
8
|
+
|
|
1
9
|
// src/utils/performance/performanceBudgets.ts
|
|
2
10
|
var PERFORMANCE_BUDGETS = {
|
|
3
11
|
COMPONENT_RENDER: { threshold: 50 },
|
|
@@ -69,4 +77,4 @@ performanceBudgetMonitor.setBudget("CHUNK_COUNT", 10, "warning");
|
|
|
69
77
|
performanceBudgetMonitor.setBudget("TREESHAKING_SCORE", 70, "warning");
|
|
70
78
|
performanceBudgetMonitor.setBudget("ERROR_BOUNDARY_TRIGGER", 5, "error");
|
|
71
79
|
|
|
72
|
-
export { PERFORMANCE_BUDGETS, performanceBudgetMonitor };
|
|
80
|
+
export { PERFORMANCE_BUDGETS, cn, performanceBudgetMonitor };
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
|
|
1
3
|
// src/utils/validation/htmlSanitization.ts
|
|
2
4
|
function sanitizeHtml(html) {
|
|
3
5
|
if (!html || typeof html !== "string") {
|
|
@@ -51,5 +53,18 @@ function renderSafeHtml(html, options = {}) {
|
|
|
51
53
|
warnings: validation.warnings
|
|
52
54
|
};
|
|
53
55
|
}
|
|
56
|
+
var LoadingSpinner = ({
|
|
57
|
+
size = "md",
|
|
58
|
+
className = ""
|
|
59
|
+
}) => {
|
|
60
|
+
const sizeClasses = {
|
|
61
|
+
sm: "size-4",
|
|
62
|
+
md: "size-6",
|
|
63
|
+
lg: "size-8"
|
|
64
|
+
};
|
|
65
|
+
const validSize = size && size in sizeClasses ? size : "md";
|
|
66
|
+
const sizeClass = sizeClasses[validSize];
|
|
67
|
+
return /* @__PURE__ */ jsx("canvas", { className: `inline-block animate-spin rounded-full border-2 border-solid border-current border-r-transparent motion-reduce:animate-[spin_1.5s_linear_infinite] ${sizeClass} ${className}`.trim(), role: "status", children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Loading..." }) });
|
|
68
|
+
};
|
|
54
69
|
|
|
55
|
-
export { renderSafeHtml, sanitizeHtml, validateHtml };
|
|
70
|
+
export { LoadingSpinner, renderSafeHtml, sanitizeHtml, validateHtml };
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { useAppConfig, useOrganisationSecurity } from './chunk-
|
|
1
|
+
import { useAppConfig, useOrganisationSecurity } from './chunk-VBCS3DUA.js';
|
|
2
2
|
import { useEventService, useUnifiedAuth, useOrganisations } from './chunk-FTCRZOG2.js';
|
|
3
3
|
import { OrganisationContextRequiredError, getRBACLogger, resolveAppContext, getPageScopeType, ContextValidator, getPermissionMap, getRoleContext, getAccessLevel, isPermittedCached, isPermitted, isSuperAdmin } from './chunk-ZFYPMX46.js';
|
|
4
|
-
import {
|
|
4
|
+
import { getCurrentAppName } from './chunk-OJ4SKRSV.js';
|
|
5
|
+
import { cn } from './chunk-7ILTDCL2.js';
|
|
5
6
|
import { createLogger, logger } from './chunk-TTRFSOKR.js';
|
|
6
|
-
import * as
|
|
7
|
+
import * as React2 from 'react';
|
|
7
8
|
import { useRef, useMemo, useState, useCallback, useEffect } from 'react';
|
|
8
9
|
import * as TooltipPrimitive from '@radix-ui/react-tooltip';
|
|
9
10
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
@@ -52,7 +53,7 @@ function useEvents() {
|
|
|
52
53
|
var TooltipProvider = TooltipPrimitive.Provider;
|
|
53
54
|
var TooltipRoot = TooltipPrimitive.Root;
|
|
54
55
|
var TooltipTrigger = TooltipPrimitive.Trigger;
|
|
55
|
-
var TooltipContent =
|
|
56
|
+
var TooltipContent = React2.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
56
57
|
TooltipPrimitive.Content,
|
|
57
58
|
{
|
|
58
59
|
ref,
|
|
@@ -65,7 +66,7 @@ var TooltipContent = React.forwardRef(({ className, sideOffset = 4, ...props },
|
|
|
65
66
|
}
|
|
66
67
|
));
|
|
67
68
|
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
|
|
68
|
-
var Tooltip =
|
|
69
|
+
var Tooltip = React2.forwardRef(({ children, content, delayDuration = 200 }, ref) => /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(TooltipRoot, { delayDuration, children: [
|
|
69
70
|
/* @__PURE__ */ jsx(TooltipTrigger, { ref, asChild: true, children: /* @__PURE__ */ jsx("span", { children }) }),
|
|
70
71
|
/* @__PURE__ */ jsx(TooltipContent, { children: content })
|
|
71
72
|
] }) }));
|
|
@@ -88,7 +89,7 @@ function getButtonClasses(variant = "default", size = "default") {
|
|
|
88
89
|
};
|
|
89
90
|
return `${baseClasses} ${variantClasses[variant]} ${sizeClasses[size]}`;
|
|
90
91
|
}
|
|
91
|
-
var Button =
|
|
92
|
+
var Button = React2.forwardRef(
|
|
92
93
|
({ className, variant, size, asChild = false, type = "button", disabled, ...props }, ref) => {
|
|
93
94
|
const Comp = asChild ? Slot : "button";
|
|
94
95
|
return /* @__PURE__ */ jsx(
|
|
@@ -105,7 +106,48 @@ var Button = React.forwardRef(
|
|
|
105
106
|
}
|
|
106
107
|
);
|
|
107
108
|
Button.displayName = "Button";
|
|
108
|
-
|
|
109
|
+
function ButtonGroup({
|
|
110
|
+
children,
|
|
111
|
+
orientation = "horizontal",
|
|
112
|
+
variant,
|
|
113
|
+
size,
|
|
114
|
+
className,
|
|
115
|
+
spacing = "sm"
|
|
116
|
+
}) {
|
|
117
|
+
const spacingClasses = {
|
|
118
|
+
none: "",
|
|
119
|
+
sm: orientation === "horizontal" ? "space-x-1" : "space-y-1",
|
|
120
|
+
md: orientation === "horizontal" ? "space-x-2" : "space-y-2",
|
|
121
|
+
lg: orientation === "horizontal" ? "space-x-4" : "space-y-4"
|
|
122
|
+
};
|
|
123
|
+
return /* @__PURE__ */ jsx(
|
|
124
|
+
"fieldset",
|
|
125
|
+
{
|
|
126
|
+
className: cn(
|
|
127
|
+
"flex",
|
|
128
|
+
orientation === "horizontal" ? "flex-row items-center" : "flex-col",
|
|
129
|
+
spacingClasses[spacing],
|
|
130
|
+
className
|
|
131
|
+
),
|
|
132
|
+
role: "group",
|
|
133
|
+
children: React2.Children.map(children, (child) => {
|
|
134
|
+
if (React2.isValidElement(child) && child.type) {
|
|
135
|
+
const componentType = child.type;
|
|
136
|
+
if (componentType.displayName === "Button") {
|
|
137
|
+
const childProps = child.props;
|
|
138
|
+
return React2.cloneElement(child, {
|
|
139
|
+
variant: childProps.variant || variant,
|
|
140
|
+
size: childProps.size || size,
|
|
141
|
+
...childProps
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return child;
|
|
146
|
+
})
|
|
147
|
+
}
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
var IconButton = React2.forwardRef(
|
|
109
151
|
({ icon, className, size = "icon", "aria-label": ariaLabel, tooltip, ...props }, ref) => {
|
|
110
152
|
const button = /* @__PURE__ */ jsx(
|
|
111
153
|
Button,
|
|
@@ -1958,4 +2000,4 @@ function useSecureSupabase(baseClient) {
|
|
|
1958
2000
|
]);
|
|
1959
2001
|
}
|
|
1960
2002
|
|
|
1961
|
-
export { Button, SECURE_CLIENT_SYMBOL, SecureSupabaseClient, Tooltip, TooltipContent, TooltipProvider, TooltipRoot, TooltipTrigger, createSecureClient, fromSupabaseClient, isSecureClient, scopeEqual, useAccessLevel, useCan, useEvents, useMultiplePermissions, usePermissions, useRBAC, useResolvedScope, useResourcePermissions, useRoleManagement, useSecureSupabase, warnIfInsecureClient };
|
|
2003
|
+
export { Button, ButtonGroup, SECURE_CLIENT_SYMBOL, SecureSupabaseClient, Tooltip, TooltipContent, TooltipProvider, TooltipRoot, TooltipTrigger, createSecureClient, fromSupabaseClient, isSecureClient, scopeEqual, useAccessLevel, useCan, useEvents, useMultiplePermissions, usePermissions, useRBAC, useResolvedScope, useResourcePermissions, useRoleManagement, useSecureSupabase, warnIfInsecureClient };
|