@jmruthers/pace-core 0.5.93 → 0.5.95
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{DataTable-HC5S4RKB.js → DataTable-XENXNMCP.js} +6 -6
- package/dist/{PublicLoadingSpinner-n74JgA9h.d.ts → PublicLoadingSpinner-B84QWsvB.d.ts} +31 -3
- package/dist/{UnifiedAuthProvider-ZM7VUC45.js → UnifiedAuthProvider-H7RI4KYD.js} +3 -3
- package/dist/{chunk-AZ2QJYKU.js → chunk-2KLAOD4M.js} +3 -3
- package/dist/{chunk-HW5BGOWB.js → chunk-2ZYHCFUO.js} +4 -4
- package/dist/{chunk-AAM57AEU.js → chunk-5RYPBJYL.js} +16 -19
- package/dist/chunk-5RYPBJYL.js.map +1 -0
- package/dist/{chunk-XIBSVWJW.js → chunk-7TQDRDSM.js} +5 -5
- package/dist/{chunk-TZXYSZT3.js → chunk-EPKHU5SS.js} +314 -245
- package/dist/{chunk-TZXYSZT3.js.map → chunk-EPKHU5SS.js.map} +1 -1
- package/dist/{chunk-GP3HU6WS.js → chunk-G7UUVEAP.js} +3 -3
- package/dist/{chunk-M52CQP5W.js → chunk-MKMKUCPF.js} +762 -12
- package/dist/chunk-MKMKUCPF.js.map +1 -0
- package/dist/{chunk-OXFOS62D.js → chunk-MVNOAHOP.js} +2 -2
- package/dist/{chunk-AYC2P377.js → chunk-ORACUZ7H.js} +2 -2
- package/dist/{chunk-SVMPR5IV.js → chunk-V5CTX4FR.js} +963 -788
- package/dist/chunk-V5CTX4FR.js.map +1 -0
- package/dist/{chunk-6WFM22A4.js → chunk-ZGCVJ7WW.js} +2 -2
- package/dist/components.d.ts +1 -1
- package/dist/components.js +8 -8
- package/dist/hooks.d.ts +94 -3
- package/dist/hooks.js +20 -8
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +17 -11
- package/dist/index.js.map +1 -1
- package/dist/providers.js +2 -2
- package/dist/rbac/index.js +7 -7
- package/dist/{usePublicRouteParams-BlgwXweB.d.ts → usePublicRouteParams-BwMR2uub.d.ts} +93 -1
- package/dist/utils.js +1 -1
- package/docs/api/classes/ColumnFactory.md +1 -1
- package/docs/api/classes/ErrorBoundary.md +1 -1
- package/docs/api/classes/InvalidScopeError.md +1 -1
- package/docs/api/classes/MissingUserContextError.md +1 -1
- package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
- package/docs/api/classes/PermissionDeniedError.md +1 -1
- package/docs/api/classes/PublicErrorBoundary.md +1 -1
- package/docs/api/classes/RBACAuditManager.md +1 -1
- package/docs/api/classes/RBACCache.md +1 -1
- package/docs/api/classes/RBACEngine.md +1 -1
- package/docs/api/classes/RBACError.md +1 -1
- package/docs/api/classes/RBACNotInitializedError.md +1 -1
- package/docs/api/classes/SecureSupabaseClient.md +1 -1
- package/docs/api/classes/StorageUtils.md +1 -1
- package/docs/api/enums/FileCategory.md +1 -1
- package/docs/api/interfaces/AggregateConfig.md +1 -1
- package/docs/api/interfaces/ButtonProps.md +1 -1
- package/docs/api/interfaces/CardProps.md +1 -1
- package/docs/api/interfaces/ColorPalette.md +1 -1
- package/docs/api/interfaces/ColorShade.md +1 -1
- package/docs/api/interfaces/DataAccessRecord.md +1 -1
- package/docs/api/interfaces/DataRecord.md +1 -1
- package/docs/api/interfaces/DataTableAction.md +1 -1
- package/docs/api/interfaces/DataTableColumn.md +1 -1
- package/docs/api/interfaces/DataTableProps.md +1 -1
- package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
- package/docs/api/interfaces/EmptyStateConfig.md +1 -1
- package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
- package/docs/api/interfaces/EventLogoProps.md +1 -1
- package/docs/api/interfaces/FileDisplayProps.md +52 -11
- package/docs/api/interfaces/FileMetadata.md +1 -1
- package/docs/api/interfaces/FileReference.md +1 -1
- package/docs/api/interfaces/FileSizeLimits.md +1 -1
- package/docs/api/interfaces/FileUploadOptions.md +1 -1
- package/docs/api/interfaces/FileUploadProps.md +1 -1
- package/docs/api/interfaces/FooterProps.md +1 -1
- package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
- package/docs/api/interfaces/InputProps.md +1 -1
- package/docs/api/interfaces/LabelProps.md +1 -1
- package/docs/api/interfaces/LoginFormProps.md +1 -1
- package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
- package/docs/api/interfaces/NavigationContextType.md +1 -1
- package/docs/api/interfaces/NavigationGuardProps.md +1 -1
- package/docs/api/interfaces/NavigationItem.md +1 -1
- package/docs/api/interfaces/NavigationMenuProps.md +1 -1
- package/docs/api/interfaces/NavigationProviderProps.md +1 -1
- package/docs/api/interfaces/Organisation.md +1 -1
- package/docs/api/interfaces/OrganisationContextType.md +1 -1
- package/docs/api/interfaces/OrganisationMembership.md +1 -1
- package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
- package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
- package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
- package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
- package/docs/api/interfaces/PageAccessRecord.md +1 -1
- package/docs/api/interfaces/PagePermissionContextType.md +1 -1
- package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
- package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
- package/docs/api/interfaces/PaletteData.md +1 -1
- package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
- package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
- package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
- package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
- package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
- package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
- package/docs/api/interfaces/PublicPageHeaderProps.md +24 -11
- package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
- package/docs/api/interfaces/RBACConfig.md +1 -1
- package/docs/api/interfaces/RBACLogger.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
- package/docs/api/interfaces/RouteAccessRecord.md +1 -1
- package/docs/api/interfaces/RouteConfig.md +1 -1
- package/docs/api/interfaces/SecureDataContextType.md +1 -1
- package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
- package/docs/api/interfaces/StorageConfig.md +1 -1
- package/docs/api/interfaces/StorageFileInfo.md +1 -1
- package/docs/api/interfaces/StorageFileMetadata.md +1 -1
- package/docs/api/interfaces/StorageListOptions.md +1 -1
- package/docs/api/interfaces/StorageListResult.md +1 -1
- package/docs/api/interfaces/StorageUploadOptions.md +1 -1
- package/docs/api/interfaces/StorageUploadResult.md +1 -1
- package/docs/api/interfaces/StorageUrlOptions.md +1 -1
- package/docs/api/interfaces/StyleImport.md +1 -1
- package/docs/api/interfaces/SwitchProps.md +1 -1
- package/docs/api/interfaces/ToastActionElement.md +1 -1
- package/docs/api/interfaces/ToastProps.md +1 -1
- package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
- package/docs/api/interfaces/UseEventLogoOptions.md +1 -1
- package/docs/api/interfaces/UseEventLogoReturn.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventLogoOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
- package/docs/api/interfaces/UsePublicFileDisplayOptions.md +47 -0
- package/docs/api/interfaces/UsePublicFileDisplayReturn.md +120 -0
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
- package/docs/api/interfaces/UserEventAccess.md +1 -1
- package/docs/api/interfaces/UserMenuProps.md +1 -1
- package/docs/api/interfaces/UserProfile.md +1 -1
- package/docs/api/modules.md +102 -16
- package/docs/implementation-guides/file-reference-system.md +15 -0
- package/docs/implementation-guides/file-upload-storage.md +16 -0
- package/package.json +1 -1
- package/src/components/DataTable/__tests__/DataTableCore.test.tsx +9 -7
- package/src/components/DataTable/components/DataTableCore.tsx +35 -10
- package/src/components/DataTable/components/EditableRow.tsx +62 -22
- package/src/components/DataTable/components/UnifiedTableBody.tsx +25 -101
- package/src/components/FileDisplay/FileDisplay.test.tsx +263 -39
- package/src/components/FileDisplay/FileDisplay.tsx +667 -103
- package/src/components/PublicLayout/PublicPageHeader.tsx +15 -8
- package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +71 -28
- package/src/components/Select/Select.test.tsx +83 -6
- package/src/components/Select/Select.tsx +236 -16
- package/src/examples/CorrectPublicPageImplementation.tsx +16 -13
- package/src/examples/PublicEventPage.tsx +9 -6
- package/src/examples/PublicPageApp.tsx +9 -6
- package/src/examples/PublicPageUsageExample.tsx +9 -7
- package/src/hooks/index.ts +4 -0
- package/src/hooks/public/index.ts +2 -0
- package/src/hooks/public/usePublicFileDisplay.ts +355 -0
- package/src/hooks/useFileDisplay.ts +370 -0
- package/src/hooks/useFileUrl.ts +130 -0
- package/src/services/AuthService.ts +19 -22
- package/dist/chunk-AAM57AEU.js.map +0 -1
- package/dist/chunk-M52CQP5W.js.map +0 -1
- package/dist/chunk-SVMPR5IV.js.map +0 -1
- /package/dist/{DataTable-HC5S4RKB.js.map → DataTable-XENXNMCP.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-ZM7VUC45.js.map → UnifiedAuthProvider-H7RI4KYD.js.map} +0 -0
- /package/dist/{chunk-AZ2QJYKU.js.map → chunk-2KLAOD4M.js.map} +0 -0
- /package/dist/{chunk-HW5BGOWB.js.map → chunk-2ZYHCFUO.js.map} +0 -0
- /package/dist/{chunk-XIBSVWJW.js.map → chunk-7TQDRDSM.js.map} +0 -0
- /package/dist/{chunk-GP3HU6WS.js.map → chunk-G7UUVEAP.js.map} +0 -0
- /package/dist/{chunk-OXFOS62D.js.map → chunk-MVNOAHOP.js.map} +0 -0
- /package/dist/{chunk-AYC2P377.js.map → chunk-ORACUZ7H.js.map} +0 -0
- /package/dist/{chunk-6WFM22A4.js.map → chunk-ZGCVJ7WW.js.map} +0 -0
|
@@ -571,16 +571,21 @@ function DataTableInternal<TData extends DataRecord>({
|
|
|
571
571
|
* from the beginning. This provides a better user experience when searching
|
|
572
572
|
* large datasets.
|
|
573
573
|
*
|
|
574
|
+
* CRITICAL: Must sync both state.searchQuery (used by state management) and
|
|
575
|
+
* performance hook's searchQuery (used by table filtering and search index).
|
|
576
|
+
*
|
|
574
577
|
* @param value - The search query string
|
|
575
578
|
*/
|
|
576
579
|
const handleSearch = useCallback((value: string) => {
|
|
580
|
+
// Update both search query states to keep them in sync
|
|
577
581
|
stateActions.setSearchQuery(value);
|
|
582
|
+
setSearchQuery(value);
|
|
578
583
|
|
|
579
584
|
// Reset to first page when searching to show results from the beginning
|
|
580
585
|
if (secureFeatures.pagination) {
|
|
581
586
|
stateActions.setPagination({ ...state.pagination, pageIndex: 0 });
|
|
582
587
|
}
|
|
583
|
-
}, [stateActions, secureFeatures.pagination, state.pagination]);
|
|
588
|
+
}, [stateActions, setSearchQuery, secureFeatures.pagination, state.pagination]);
|
|
584
589
|
|
|
585
590
|
// ============================================================================
|
|
586
591
|
// SERVER-SIDE DATA FETCHING - ALWAYS call these hooks
|
|
@@ -967,16 +972,34 @@ function DataTableInternal<TData extends DataRecord>({
|
|
|
967
972
|
// Get the current filtered/paginated data (what's actually visible)
|
|
968
973
|
const currentData = table.getFilteredRowModel().rows.map(row => row.original);
|
|
969
974
|
|
|
970
|
-
// Get only visible columns
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
+
// Get only visible columns by checking the actual table columns
|
|
976
|
+
// This approach is more reliable because it uses the table's actual column registry
|
|
977
|
+
const tableColumns = table.getAllColumns();
|
|
978
|
+
const visibleTableColumns = tableColumns.filter(col => {
|
|
979
|
+
// Exclude system columns (selection, actions) and only include data columns
|
|
980
|
+
const isSystemColumn = col.id === 'select' || col.id === 'actions';
|
|
981
|
+
return !isSystemColumn && col.getIsVisible();
|
|
982
|
+
});
|
|
983
|
+
|
|
984
|
+
// Map table columns back to original column definitions for export
|
|
985
|
+
const visibleColumns = visibleTableColumns
|
|
986
|
+
.map(tableCol => {
|
|
987
|
+
// Find the original column definition that matches this table column
|
|
988
|
+
const originalCol = columns.find(col => {
|
|
989
|
+
const colId = col.id || col.accessorKey;
|
|
990
|
+
return colId && String(colId) === tableCol.id;
|
|
991
|
+
});
|
|
992
|
+
|
|
993
|
+
if (!originalCol) return null;
|
|
994
|
+
|
|
995
|
+
return {
|
|
996
|
+
...originalCol,
|
|
997
|
+
header: typeof originalCol.header === 'string'
|
|
998
|
+
? originalCol.header
|
|
999
|
+
: originalCol.accessorKey || tableCol.id || 'Column',
|
|
1000
|
+
};
|
|
975
1001
|
})
|
|
976
|
-
.
|
|
977
|
-
...col,
|
|
978
|
-
header: typeof col.header === 'string' ? col.header : col.accessorKey || 'Column',
|
|
979
|
-
}));
|
|
1002
|
+
.filter((col): col is NonNullable<typeof col> => col !== null);
|
|
980
1003
|
|
|
981
1004
|
// Generate filename with timestamp
|
|
982
1005
|
const timestamp = new Date().toISOString().split('T')[0];
|
|
@@ -1179,7 +1202,9 @@ function DataTableInternal<TData extends DataRecord>({
|
|
|
1179
1202
|
emptyState={React.isValidElement(emptyState) ? undefined : emptyState as any}
|
|
1180
1203
|
isFiltered={searchQuery !== '' || state.columnFilters.length > 0}
|
|
1181
1204
|
onClearFilters={() => {
|
|
1205
|
+
// Clear both search query states to keep them in sync
|
|
1182
1206
|
stateActions.setSearchQuery('');
|
|
1207
|
+
setSearchQuery('');
|
|
1183
1208
|
stateActions.setColumnFilters([]);
|
|
1184
1209
|
}}
|
|
1185
1210
|
enableFiltering={secureFeatures.filtering}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { flexRender, type Row, type Column } from '@tanstack/react-table';
|
|
3
|
+
import { X, Check } from 'lucide-react';
|
|
3
4
|
|
|
4
5
|
import { Button } from '../../Button/Button';
|
|
5
6
|
import { Input } from '../../Input/Input';
|
|
@@ -29,7 +30,9 @@ const renderEditField = <TData extends DataRecord>(
|
|
|
29
30
|
column: Column<TData, unknown>,
|
|
30
31
|
value: CellValue,
|
|
31
32
|
onChange: (value: CellValue | Record<string, CellValue>) => void,
|
|
32
|
-
editingData: Record<string, CellValue> = {}
|
|
33
|
+
editingData: Record<string, CellValue> = {},
|
|
34
|
+
placeholder?: string,
|
|
35
|
+
inputRef?: React.Ref<HTMLInputElement>
|
|
33
36
|
) => {
|
|
34
37
|
const columnDef = column.columnDef as EditableColumnDef<TData>;
|
|
35
38
|
|
|
@@ -63,6 +66,7 @@ const renderEditField = <TData extends DataRecord>(
|
|
|
63
66
|
if (columnDef.fieldType === 'date') {
|
|
64
67
|
return (
|
|
65
68
|
<Input
|
|
69
|
+
ref={inputRef}
|
|
66
70
|
type="date"
|
|
67
71
|
value={String(value ?? '')}
|
|
68
72
|
onChange={(e) => onChange(e.target.value as unknown as CellValue)}
|
|
@@ -74,6 +78,7 @@ const renderEditField = <TData extends DataRecord>(
|
|
|
74
78
|
if (columnDef.fieldType === 'number') {
|
|
75
79
|
return (
|
|
76
80
|
<Input
|
|
81
|
+
ref={inputRef}
|
|
77
82
|
type="number"
|
|
78
83
|
value={String(value ?? '')}
|
|
79
84
|
onChange={(e) => onChange(e.target.value as unknown as CellValue)}
|
|
@@ -84,11 +89,12 @@ const renderEditField = <TData extends DataRecord>(
|
|
|
84
89
|
|
|
85
90
|
return (
|
|
86
91
|
<Input
|
|
92
|
+
ref={inputRef}
|
|
87
93
|
type="text"
|
|
88
94
|
value={String(value ?? '')}
|
|
89
95
|
onChange={(e) => onChange(e.target.value as unknown as CellValue)}
|
|
90
96
|
className="w-full h-7"
|
|
91
|
-
placeholder={`Enter ${column.id}`}
|
|
97
|
+
placeholder={placeholder || `Enter ${column.id}`}
|
|
92
98
|
/>
|
|
93
99
|
);
|
|
94
100
|
};
|
|
@@ -105,6 +111,16 @@ export function EditableRow<TData extends DataRecord>({
|
|
|
105
111
|
hierarchical = false,
|
|
106
112
|
}: EditableRowProps<TData>) {
|
|
107
113
|
const rowId = getRowId ? getRowId(row.original, row.index) : String(row.id);
|
|
114
|
+
const firstInputRef = React.useRef<HTMLInputElement>(null);
|
|
115
|
+
const hasAssignedRef = React.useRef(false);
|
|
116
|
+
|
|
117
|
+
// Auto-focus first input field when entering edit mode
|
|
118
|
+
React.useEffect(() => {
|
|
119
|
+
if (firstInputRef.current) {
|
|
120
|
+
firstInputRef.current.focus();
|
|
121
|
+
firstInputRef.current.select();
|
|
122
|
+
}
|
|
123
|
+
}, []);
|
|
108
124
|
|
|
109
125
|
return (
|
|
110
126
|
<tr
|
|
@@ -116,34 +132,58 @@ export function EditableRow<TData extends DataRecord>({
|
|
|
116
132
|
<td key={cell.id} role="cell">
|
|
117
133
|
<div className={cell.column.columnDef.meta?.align === 'right' ? 'text-right' : ''}>
|
|
118
134
|
{cell.column.id !== 'actions' ? (
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
135
|
+
// In edit mode, always use renderEditField for editable columns
|
|
136
|
+
// Custom cell renderers are for display mode only
|
|
137
|
+
(() => {
|
|
138
|
+
const columnDef = cell.column.columnDef as EditableColumnDef<TData>;
|
|
139
|
+
// If column is explicitly marked as not editable, check if custom cell renderer handles editing
|
|
140
|
+
if (columnDef.editable === false) {
|
|
141
|
+
// Not editable - use custom cell renderer if available, otherwise show static value
|
|
142
|
+
return cell.column.columnDef.cell ? (
|
|
143
|
+
flexRender(cell.column.columnDef.cell, {
|
|
144
|
+
...cell.getContext(),
|
|
145
|
+
getIsEditing: () => true,
|
|
146
|
+
setValue: (value: CellValue | Record<string, CellValue>) => {
|
|
147
|
+
if (typeof value === 'object' && value !== null && !Array.isArray(value) && !(value instanceof Date)) {
|
|
148
|
+
onEditingDataChange({ ...editingData, ...(value as Record<string, CellValue>) });
|
|
149
|
+
} else {
|
|
150
|
+
onEditingDataChange({ ...editingData, [cell.column.id]: value as CellValue });
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
})
|
|
154
|
+
) : (
|
|
155
|
+
<span className="text-sm text-gray-600">{String(cell.getValue() ?? '')}</span>
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Column is editable - always use renderEditField in EditableRow
|
|
160
|
+
const shouldGetRef = !hasAssignedRef.current;
|
|
161
|
+
if (shouldGetRef) {
|
|
162
|
+
hasAssignedRef.current = true;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return renderEditField(
|
|
166
|
+
cell.column,
|
|
167
|
+
editingData[cell.column.id] ?? (cell.getValue() as CellValue),
|
|
168
|
+
(value) => {
|
|
124
169
|
if (typeof value === 'object' && value !== null && !Array.isArray(value) && !(value instanceof Date)) {
|
|
125
170
|
onEditingDataChange({ ...editingData, ...(value as Record<string, CellValue>) });
|
|
126
171
|
} else {
|
|
127
172
|
onEditingDataChange({ ...editingData, [cell.column.id]: value as CellValue });
|
|
128
173
|
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
} else {
|
|
136
|
-
onEditingDataChange({ ...editingData, [cell.column.id]: value as CellValue });
|
|
137
|
-
}
|
|
138
|
-
}, editingData)
|
|
139
|
-
)
|
|
174
|
+
},
|
|
175
|
+
editingData,
|
|
176
|
+
undefined, // placeholder
|
|
177
|
+
shouldGetRef ? firstInputRef : undefined
|
|
178
|
+
);
|
|
179
|
+
})()
|
|
140
180
|
) : (
|
|
141
181
|
<div className="flex gap-1">
|
|
142
|
-
<Button onClick={onSave} size="sm" variant="default">
|
|
143
|
-
|
|
182
|
+
<Button onClick={onSave} size="sm" variant="default" aria-label="Save changes">
|
|
183
|
+
<Check className="h-4 w-4" />
|
|
144
184
|
</Button>
|
|
145
|
-
<Button onClick={onCancel} size="sm" variant="outline">
|
|
146
|
-
|
|
185
|
+
<Button onClick={onCancel} size="sm" variant="outline" aria-label="Cancel editing">
|
|
186
|
+
<X className="h-4 w-4" />
|
|
147
187
|
</Button>
|
|
148
188
|
</div>
|
|
149
189
|
)}
|
|
@@ -319,109 +319,33 @@ const RowComponent = React.memo(({
|
|
|
319
319
|
const subRowsCount = row.subRows?.length || 0;
|
|
320
320
|
const isExpanded = row.getIsExpanded();
|
|
321
321
|
|
|
322
|
+
// Only render the group header row - sub-rows will be rendered by the standard rendering loop
|
|
322
323
|
return (
|
|
323
|
-
<
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
className
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
324
|
+
<tr className="bg-sec-50 hover:bg-sec-100" style={style}>
|
|
325
|
+
<td
|
|
326
|
+
className={getTableCellClasses({
|
|
327
|
+
isCompact: true,
|
|
328
|
+
className: "px-3 py-2 flex items-center font-medium"
|
|
329
|
+
})}
|
|
330
|
+
colSpan={row.getAllCells().length}
|
|
331
|
+
>
|
|
332
|
+
<Button
|
|
333
|
+
variant="ghost"
|
|
334
|
+
size="sm"
|
|
335
|
+
onClick={() => row.toggleExpanded()}
|
|
336
|
+
className="p-0 h-auto mr-2"
|
|
332
337
|
>
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
</Button>
|
|
345
|
-
<span className="text-sm">
|
|
346
|
-
{String(groupValue)} ({subRowsCount} items)
|
|
347
|
-
</span>
|
|
348
|
-
</td>
|
|
349
|
-
</tr>
|
|
350
|
-
|
|
351
|
-
{/* Render sub-rows if expanded */}
|
|
352
|
-
{isExpanded && row.subRows?.map((subRow: any) => {
|
|
353
|
-
const subRowId = getRowId ? getRowId(subRow.original, subRow.index) : String(subRow.index);
|
|
354
|
-
const isSubRowEditing = editingRowId === subRowId;
|
|
355
|
-
|
|
356
|
-
return (
|
|
357
|
-
<tr key={subRow.id} className="border-l-2 border-l-blue-200" style={style}>
|
|
358
|
-
{subRow.getVisibleCells().map((cell: any) => (
|
|
359
|
-
<td
|
|
360
|
-
key={cell.id}
|
|
361
|
-
className={getTableCellClasses({
|
|
362
|
-
isCompact: true,
|
|
363
|
-
className: `px-3 py-2 pl-8 ${cell.column.id === 'actions' ? 'whitespace-nowrap' : 'whitespace-normal break-words'} ${cell.column.columnDef.meta?.align === 'right' ? 'text-right' : ''}`
|
|
364
|
-
})}
|
|
365
|
-
>
|
|
366
|
-
{isSubRowEditing && cell.column.id !== 'actions' ? (
|
|
367
|
-
// Check if column has a custom cell renderer - if so, use it in edit mode
|
|
368
|
-
cell.column.columnDef.cell ? (
|
|
369
|
-
flexRender(cell.column.columnDef.cell, {
|
|
370
|
-
...cell.getContext(),
|
|
371
|
-
hierarchical: hierarchical,
|
|
372
|
-
isParent: false,
|
|
373
|
-
isChild: true,
|
|
374
|
-
isHierarchical: false,
|
|
375
|
-
rowId: subRowId,
|
|
376
|
-
isExpanded: false,
|
|
377
|
-
hasChildren: false,
|
|
378
|
-
getIsEditing: () => true, // Always true in edit mode
|
|
379
|
-
setValue: (value: any) => {
|
|
380
|
-
if (typeof value === 'object' && value !== null) {
|
|
381
|
-
onEditingDataChange?.({ ...editingData, ...value });
|
|
382
|
-
} else {
|
|
383
|
-
onEditingDataChange?.({ ...editingData, [cell.column.id]: value });
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
})
|
|
387
|
-
) : (
|
|
388
|
-
// Fall back to default edit field rendering when no custom cell renderer
|
|
389
|
-
renderEditField(cell.column, editingData?.[cell.column.id], (value) => {
|
|
390
|
-
if (typeof value === 'object' && value !== null) {
|
|
391
|
-
onEditingDataChange?.({ ...editingData, ...value });
|
|
392
|
-
} else {
|
|
393
|
-
onEditingDataChange?.({ ...editingData, [cell.column.id]: value });
|
|
394
|
-
}
|
|
395
|
-
}, editingData)
|
|
396
|
-
)
|
|
397
|
-
) : cell.column.id === 'actions' ? (
|
|
398
|
-
<ActionButtons
|
|
399
|
-
row={row}
|
|
400
|
-
actions={actions}
|
|
401
|
-
isEditing={isEditing}
|
|
402
|
-
isParent={isParent}
|
|
403
|
-
hierarchical={!!hierarchical}
|
|
404
|
-
rbac={rbac}
|
|
405
|
-
permissions={permissions}
|
|
406
|
-
/>
|
|
407
|
-
) : (
|
|
408
|
-
flexRender(cell.column.columnDef.cell, {
|
|
409
|
-
...cell.getContext(),
|
|
410
|
-
hierarchical: hierarchical,
|
|
411
|
-
isParent: false,
|
|
412
|
-
isChild: true,
|
|
413
|
-
isHierarchical: false,
|
|
414
|
-
rowId: subRowId,
|
|
415
|
-
isExpanded: false,
|
|
416
|
-
hasChildren: false
|
|
417
|
-
})
|
|
418
|
-
)}
|
|
419
|
-
</td>
|
|
420
|
-
))}
|
|
421
|
-
</tr>
|
|
422
|
-
);
|
|
423
|
-
})}
|
|
424
|
-
</React.Fragment>
|
|
338
|
+
{isExpanded ? (
|
|
339
|
+
<ChevronDown className="h-4 w-4" />
|
|
340
|
+
) : (
|
|
341
|
+
<ChevronRight className="h-4 w-4" />
|
|
342
|
+
)}
|
|
343
|
+
</Button>
|
|
344
|
+
<span className="text-sm">
|
|
345
|
+
{String(groupValue)} ({subRowsCount} items)
|
|
346
|
+
</span>
|
|
347
|
+
</td>
|
|
348
|
+
</tr>
|
|
425
349
|
);
|
|
426
350
|
}
|
|
427
351
|
|