@visns-studio/visns-components 5.11.10 → 5.11.12
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/README.md +128 -0
- package/package.json +4 -4
- package/src/components/cms/DataGrid.jsx +22 -4
- package/src/components/crm/Autocomplete.jsx +3 -3
- package/src/components/crm/DataGrid.jsx +26 -4
- package/src/components/crm/Field.jsx +66 -21
- package/src/components/crm/columns/ColumnRenderers.jsx +73 -8
- package/src/components/crm/generic/GenericGrid.jsx +52 -60
- package/src/components/crm/generic/styles/GenericIndex.module.scss +52 -0
- package/src/utils/columnsMetadataUtils.js +277 -0
- package/src/utils/relationshipSortingFallback.js +37 -0
- package/src/utils/relationshipSortingUtils.js +289 -0
- package/src/utils/relationshipSortingUtilsSimple.js +51 -0
|
@@ -13,6 +13,7 @@ import { showContactSelectorModal } from './ContactSelectorModal';
|
|
|
13
13
|
import { showDateRangeSelectorModal } from './DateRangeSelectorModal';
|
|
14
14
|
import { showAlternativeActionModal } from './AlternativeActionModal';
|
|
15
15
|
import { showReasonCollectorModal } from './ReasonCollectorModal';
|
|
16
|
+
import { processGridHeaders, getColumnHeaderClasses, getColumnHeaderStyles, getColumnHeaderTooltip } from '../../../utils/columnsMetadataUtils';
|
|
16
17
|
import styles from './styles/GenericIndex.module.scss';
|
|
17
18
|
|
|
18
19
|
// ContactTooltip component for enhanced contact display
|
|
@@ -825,6 +826,14 @@ const GenericGrid = ({
|
|
|
825
826
|
|
|
826
827
|
// Handle sort request
|
|
827
828
|
const requestSort = useCallback((key) => {
|
|
829
|
+
// Find the header configuration for this key to check if it's sortable
|
|
830
|
+
const header = gridHeaders.find((h) => h.key === key);
|
|
831
|
+
|
|
832
|
+
// If the column is not sortable, don't proceed with sorting
|
|
833
|
+
if (header && header.sortable === false) {
|
|
834
|
+
return;
|
|
835
|
+
}
|
|
836
|
+
|
|
828
837
|
// If clicking the same column, toggle direction
|
|
829
838
|
// Otherwise, start with ascending sort for the new column
|
|
830
839
|
setSortConfig((prevConfig) => {
|
|
@@ -835,7 +844,7 @@ const GenericGrid = ({
|
|
|
835
844
|
|
|
836
845
|
return { key, direction: newDirection };
|
|
837
846
|
});
|
|
838
|
-
}, []);
|
|
847
|
+
}, [gridHeaders]);
|
|
839
848
|
|
|
840
849
|
// Function to filter data based on filter values
|
|
841
850
|
const filterData = useCallback(
|
|
@@ -975,24 +984,16 @@ const GenericGrid = ({
|
|
|
975
984
|
const staticData = settings.staticData;
|
|
976
985
|
|
|
977
986
|
if (staticData.header && staticData.rows) {
|
|
978
|
-
//
|
|
979
|
-
const
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
key,
|
|
983
|
-
label: config.label || key,
|
|
984
|
-
sort: config.sort || key,
|
|
985
|
-
type: config.type || 'text',
|
|
986
|
-
filter: config.filter || null,
|
|
987
|
-
onClick: config.onClick || null,
|
|
988
|
-
}))
|
|
989
|
-
);
|
|
987
|
+
// Process static headers using the metadata utilities
|
|
988
|
+
const mockResponse = { data: { data: staticData } };
|
|
989
|
+
const processedHeaders = processGridHeaders(mockResponse);
|
|
990
|
+
setGridHeaders(processedHeaders);
|
|
990
991
|
|
|
991
992
|
// Initialize filter values
|
|
992
993
|
const initialFilterValues = {};
|
|
993
|
-
|
|
994
|
-
if (
|
|
995
|
-
initialFilterValues[key] = '';
|
|
994
|
+
processedHeaders.forEach((header) => {
|
|
995
|
+
if (header.filter) {
|
|
996
|
+
initialFilterValues[header.key] = '';
|
|
996
997
|
}
|
|
997
998
|
});
|
|
998
999
|
setFilterValues(initialFilterValues);
|
|
@@ -1046,26 +1047,15 @@ const GenericGrid = ({
|
|
|
1046
1047
|
if (response.data.data) {
|
|
1047
1048
|
// Check if the response has the expected structure with header and rows
|
|
1048
1049
|
if (response.data.data.header && response.data.data.rows) {
|
|
1049
|
-
//
|
|
1050
|
-
const
|
|
1051
|
-
|
|
1052
|
-
);
|
|
1053
|
-
setGridHeaders(
|
|
1054
|
-
headerEntries.map(([key, config]) => ({
|
|
1055
|
-
key,
|
|
1056
|
-
label: config.label || key,
|
|
1057
|
-
sort: config.sort || key,
|
|
1058
|
-
type: config.type || 'text',
|
|
1059
|
-
filter: config.filter || null,
|
|
1060
|
-
onClick: config.onClick || null,
|
|
1061
|
-
}))
|
|
1062
|
-
);
|
|
1050
|
+
// Process headers using the metadata utilities
|
|
1051
|
+
const processedHeaders = processGridHeaders(response.data);
|
|
1052
|
+
setGridHeaders(processedHeaders);
|
|
1063
1053
|
|
|
1064
1054
|
// Initialize filter values
|
|
1065
1055
|
const initialFilterValues = {};
|
|
1066
|
-
|
|
1067
|
-
if (
|
|
1068
|
-
initialFilterValues[key] = '';
|
|
1056
|
+
processedHeaders.forEach((header) => {
|
|
1057
|
+
if (header.filter) {
|
|
1058
|
+
initialFilterValues[header.key] = '';
|
|
1069
1059
|
}
|
|
1070
1060
|
});
|
|
1071
1061
|
setFilterValues(initialFilterValues);
|
|
@@ -2627,34 +2617,36 @@ const GenericGrid = ({
|
|
|
2627
2617
|
<tr>
|
|
2628
2618
|
{/* Use gridHeaders if available, otherwise fall back to headers from columns */}
|
|
2629
2619
|
{gridHeaders.length > 0
|
|
2630
|
-
? gridHeaders.map((header, index) =>
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
{
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
}
|
|
2645
|
-
|
|
2646
|
-
|
|
2620
|
+
? gridHeaders.map((header, index) => {
|
|
2621
|
+
const headerClasses = getColumnHeaderClasses(header);
|
|
2622
|
+
const headerStyles = getColumnHeaderStyles(header);
|
|
2623
|
+
const tooltip = getColumnHeaderTooltip(header);
|
|
2624
|
+
|
|
2625
|
+
return (
|
|
2626
|
+
<th
|
|
2627
|
+
key={`header-${index}`}
|
|
2628
|
+
className={`${styles.gridHeader} ${headerClasses.join(' ')}`}
|
|
2629
|
+
onClick={header.sortable !== false ? () => requestSort(header.key) : undefined}
|
|
2630
|
+
style={headerStyles}
|
|
2631
|
+
title={tooltip}
|
|
2632
|
+
>
|
|
2633
|
+
<div className={styles.headerContent}>
|
|
2634
|
+
{header.label}
|
|
2635
|
+
{header.sortable !== false && (
|
|
2636
|
+
<span
|
|
2637
|
+
className={styles.sortIndicator}
|
|
2638
|
+
style={getSortIndicatorStyle(header.key)}
|
|
2639
|
+
>
|
|
2640
|
+
{sortConfig.key === header.key &&
|
|
2641
|
+
sortConfig.direction === 'asc'
|
|
2642
|
+
? ' ▲'
|
|
2643
|
+
: ' ▼'}
|
|
2644
|
+
</span>
|
|
2647
2645
|
)}
|
|
2648
|
-
>
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
? ' ▲'
|
|
2653
|
-
: ' ▼'}
|
|
2654
|
-
</span>
|
|
2655
|
-
</div>
|
|
2656
|
-
</th>
|
|
2657
|
-
))
|
|
2646
|
+
</div>
|
|
2647
|
+
</th>
|
|
2648
|
+
);
|
|
2649
|
+
})
|
|
2658
2650
|
: headers.map((header, index) => (
|
|
2659
2651
|
<th
|
|
2660
2652
|
key={`header-${index}`}
|
|
@@ -502,6 +502,58 @@
|
|
|
502
502
|
}
|
|
503
503
|
}
|
|
504
504
|
|
|
505
|
+
// Non-sortable column styles
|
|
506
|
+
.non-sortable {
|
|
507
|
+
cursor: default !important;
|
|
508
|
+
opacity: 0.8;
|
|
509
|
+
user-select: none;
|
|
510
|
+
|
|
511
|
+
&:hover {
|
|
512
|
+
background-color: var(--primary-color, #007bff) !important;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
.headerContent {
|
|
516
|
+
opacity: 0.9;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// Virtual column styles
|
|
521
|
+
.virtual-column {
|
|
522
|
+
position: relative;
|
|
523
|
+
|
|
524
|
+
&::after {
|
|
525
|
+
content: '🔗';
|
|
526
|
+
position: absolute;
|
|
527
|
+
top: 4px;
|
|
528
|
+
right: 4px;
|
|
529
|
+
font-size: 0.7em;
|
|
530
|
+
opacity: 0.6;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// Computed column styles
|
|
535
|
+
.computed-column {
|
|
536
|
+
position: relative;
|
|
537
|
+
|
|
538
|
+
&::after {
|
|
539
|
+
content: '🧮';
|
|
540
|
+
position: absolute;
|
|
541
|
+
top: 4px;
|
|
542
|
+
right: 4px;
|
|
543
|
+
font-size: 0.7em;
|
|
544
|
+
opacity: 0.6;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
// Column type indicators
|
|
549
|
+
.column-type-virtual {
|
|
550
|
+
border-left: 3px solid rgba(255, 193, 7, 0.7);
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
.column-type-computed {
|
|
554
|
+
border-left: 3px solid rgba(40, 167, 69, 0.7);
|
|
555
|
+
}
|
|
556
|
+
|
|
505
557
|
.headerContent {
|
|
506
558
|
display: flex;
|
|
507
559
|
align-items: center;
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utilities for handling columns_metadata from API responses
|
|
3
|
+
*
|
|
4
|
+
* This module provides functions to parse and apply metadata from the backend
|
|
5
|
+
* that controls column behavior, especially for virtual columns that should not be sortable.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Extracts and normalizes columns metadata from API response
|
|
10
|
+
*
|
|
11
|
+
* @param {Object} response - API response object
|
|
12
|
+
* @returns {Object} - Normalized metadata object with column keys as properties
|
|
13
|
+
*/
|
|
14
|
+
export const extractColumnsMetadata = (response) => {
|
|
15
|
+
// Handle different possible response structures
|
|
16
|
+
const metadata = response?.data?.columns_metadata ||
|
|
17
|
+
response?.columns_metadata ||
|
|
18
|
+
response?.metadata?.columns ||
|
|
19
|
+
{};
|
|
20
|
+
|
|
21
|
+
// Ensure we have a valid object
|
|
22
|
+
if (!metadata || typeof metadata !== 'object') {
|
|
23
|
+
return {};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return metadata;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Checks if a column is sortable based on metadata
|
|
31
|
+
*
|
|
32
|
+
* @param {string} columnKey - The column key/identifier
|
|
33
|
+
* @param {Object} metadata - Columns metadata object
|
|
34
|
+
* @returns {boolean} - Whether the column is sortable
|
|
35
|
+
*/
|
|
36
|
+
export const isColumnSortable = (columnKey, metadata) => {
|
|
37
|
+
// If no metadata available, assume sortable (backward compatibility)
|
|
38
|
+
if (!metadata || typeof metadata !== 'object') {
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const columnMeta = metadata[columnKey];
|
|
43
|
+
|
|
44
|
+
// If no specific metadata for this column, assume sortable
|
|
45
|
+
if (!columnMeta || typeof columnMeta !== 'object') {
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Check the sortable property, default to true if not specified
|
|
50
|
+
return columnMeta.sortable !== false;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Gets the display type for a column based on metadata
|
|
55
|
+
*
|
|
56
|
+
* @param {string} columnKey - The column key/identifier
|
|
57
|
+
* @param {Object} metadata - Columns metadata object
|
|
58
|
+
* @returns {string} - Column display type (e.g., 'virtual', 'computed', 'regular')
|
|
59
|
+
*/
|
|
60
|
+
export const getColumnDisplayType = (columnKey, metadata) => {
|
|
61
|
+
if (!metadata || typeof metadata !== 'object') {
|
|
62
|
+
return 'regular';
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const columnMeta = metadata[columnKey];
|
|
66
|
+
|
|
67
|
+
if (!columnMeta || typeof columnMeta !== 'object') {
|
|
68
|
+
return 'regular';
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return columnMeta.type || 'regular';
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Gets additional column properties from metadata
|
|
76
|
+
*
|
|
77
|
+
* @param {string} columnKey - The column key/identifier
|
|
78
|
+
* @param {Object} metadata - Columns metadata object
|
|
79
|
+
* @returns {Object} - Additional properties like tooltip, description, etc.
|
|
80
|
+
*/
|
|
81
|
+
export const getColumnProperties = (columnKey, metadata) => {
|
|
82
|
+
if (!metadata || typeof metadata !== 'object') {
|
|
83
|
+
return {};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const columnMeta = metadata[columnKey];
|
|
87
|
+
|
|
88
|
+
if (!columnMeta || typeof columnMeta !== 'object') {
|
|
89
|
+
return {};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
tooltip: columnMeta.tooltip || null,
|
|
94
|
+
description: columnMeta.description || null,
|
|
95
|
+
virtual: columnMeta.virtual === true,
|
|
96
|
+
computed: columnMeta.computed === true,
|
|
97
|
+
searchable: columnMeta.searchable !== false,
|
|
98
|
+
filterable: columnMeta.filterable !== false
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Merges column configuration with metadata to create enhanced column objects
|
|
104
|
+
*
|
|
105
|
+
* @param {Array} columns - Original column configuration array
|
|
106
|
+
* @param {Object} metadata - Columns metadata object
|
|
107
|
+
* @returns {Array} - Enhanced column array with metadata applied
|
|
108
|
+
*/
|
|
109
|
+
export const mergeColumnsWithMetadata = (columns, metadata) => {
|
|
110
|
+
if (!Array.isArray(columns)) {
|
|
111
|
+
return [];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (!metadata || typeof metadata !== 'object') {
|
|
115
|
+
return columns;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return columns.map(column => {
|
|
119
|
+
const columnKey = column.key || column.id || column.name;
|
|
120
|
+
|
|
121
|
+
if (!columnKey) {
|
|
122
|
+
return column;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const columnProperties = getColumnProperties(columnKey, metadata);
|
|
126
|
+
const isSortable = isColumnSortable(columnKey, metadata);
|
|
127
|
+
const displayType = getColumnDisplayType(columnKey, metadata);
|
|
128
|
+
|
|
129
|
+
return {
|
|
130
|
+
...column,
|
|
131
|
+
sortable: isSortable,
|
|
132
|
+
displayType,
|
|
133
|
+
virtual: columnProperties.virtual,
|
|
134
|
+
computed: columnProperties.computed,
|
|
135
|
+
tooltip: columnProperties.tooltip,
|
|
136
|
+
description: columnProperties.description,
|
|
137
|
+
searchable: columnProperties.searchable,
|
|
138
|
+
filterable: columnProperties.filterable,
|
|
139
|
+
// Keep original metadata for reference
|
|
140
|
+
_metadata: metadata[columnKey] || {}
|
|
141
|
+
};
|
|
142
|
+
});
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Processes grid headers from API response and applies metadata
|
|
147
|
+
*
|
|
148
|
+
* @param {Object} response - API response containing headers and metadata
|
|
149
|
+
* @returns {Array} - Processed headers with metadata applied
|
|
150
|
+
*/
|
|
151
|
+
export const processGridHeaders = (response) => {
|
|
152
|
+
// Extract headers from different possible response structures
|
|
153
|
+
const headers = response?.data?.data?.header ||
|
|
154
|
+
response?.data?.header ||
|
|
155
|
+
response?.header ||
|
|
156
|
+
{};
|
|
157
|
+
|
|
158
|
+
const metadata = extractColumnsMetadata(response);
|
|
159
|
+
|
|
160
|
+
if (!headers || typeof headers !== 'object') {
|
|
161
|
+
return [];
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Convert headers object to array format expected by components
|
|
165
|
+
const headerEntries = Object.entries(headers);
|
|
166
|
+
|
|
167
|
+
return headerEntries.map(([key, config]) => {
|
|
168
|
+
const isSortable = isColumnSortable(key, metadata);
|
|
169
|
+
const displayType = getColumnDisplayType(key, metadata);
|
|
170
|
+
const properties = getColumnProperties(key, metadata);
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
key,
|
|
174
|
+
label: config.label || key,
|
|
175
|
+
sort: config.sort || key,
|
|
176
|
+
type: config.type || 'text',
|
|
177
|
+
filter: config.filter || null,
|
|
178
|
+
onClick: config.onClick || null,
|
|
179
|
+
// Apply metadata
|
|
180
|
+
sortable: isSortable,
|
|
181
|
+
displayType,
|
|
182
|
+
virtual: properties.virtual,
|
|
183
|
+
computed: properties.computed,
|
|
184
|
+
tooltip: properties.tooltip,
|
|
185
|
+
description: properties.description,
|
|
186
|
+
searchable: properties.searchable,
|
|
187
|
+
filterable: properties.filterable,
|
|
188
|
+
// Keep original metadata for reference
|
|
189
|
+
_metadata: metadata[key] || {}
|
|
190
|
+
};
|
|
191
|
+
});
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Gets CSS classes for a column header based on its metadata
|
|
196
|
+
*
|
|
197
|
+
* @param {Object} header - Header configuration object with metadata
|
|
198
|
+
* @returns {Array} - Array of CSS class names
|
|
199
|
+
*/
|
|
200
|
+
export const getColumnHeaderClasses = (header) => {
|
|
201
|
+
const classes = [];
|
|
202
|
+
|
|
203
|
+
if (header.sortable === false) {
|
|
204
|
+
classes.push('non-sortable');
|
|
205
|
+
} else {
|
|
206
|
+
classes.push('sortable');
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (header.virtual) {
|
|
210
|
+
classes.push('virtual-column');
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (header.computed) {
|
|
214
|
+
classes.push('computed-column');
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (header.displayType) {
|
|
218
|
+
classes.push(`column-type-${header.displayType}`);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return classes;
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Gets inline styles for a column header based on its metadata
|
|
226
|
+
*
|
|
227
|
+
* @param {Object} header - Header configuration object with metadata
|
|
228
|
+
* @returns {Object} - Style object for the header
|
|
229
|
+
*/
|
|
230
|
+
export const getColumnHeaderStyles = (header) => {
|
|
231
|
+
const styles = {};
|
|
232
|
+
|
|
233
|
+
if (header.sortable === false) {
|
|
234
|
+
styles.cursor = 'default';
|
|
235
|
+
styles.opacity = 0.7;
|
|
236
|
+
} else {
|
|
237
|
+
styles.cursor = 'pointer';
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return styles;
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Gets tooltip text for a column header based on its metadata
|
|
245
|
+
*
|
|
246
|
+
* @param {Object} header - Header configuration object with metadata
|
|
247
|
+
* @returns {string|null} - Tooltip text or null if no tooltip needed
|
|
248
|
+
*/
|
|
249
|
+
export const getColumnHeaderTooltip = (header) => {
|
|
250
|
+
if (header.tooltip) {
|
|
251
|
+
return header.tooltip;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (header.sortable === false) {
|
|
255
|
+
if (header.virtual) {
|
|
256
|
+
return 'This is a virtual column and cannot be sorted';
|
|
257
|
+
}
|
|
258
|
+
if (header.computed) {
|
|
259
|
+
return 'This is a computed column and cannot be sorted';
|
|
260
|
+
}
|
|
261
|
+
return 'This column cannot be sorted';
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return null;
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
export default {
|
|
268
|
+
extractColumnsMetadata,
|
|
269
|
+
isColumnSortable,
|
|
270
|
+
getColumnDisplayType,
|
|
271
|
+
getColumnProperties,
|
|
272
|
+
mergeColumnsWithMetadata,
|
|
273
|
+
processGridHeaders,
|
|
274
|
+
getColumnHeaderClasses,
|
|
275
|
+
getColumnHeaderStyles,
|
|
276
|
+
getColumnHeaderTooltip
|
|
277
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fallback version that restores original behavior
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export const DEFAULT_INTELLIGENT_SORTING_CONFIG = {
|
|
6
|
+
enableIntelligentSorting: false, // Disabled by default for safety
|
|
7
|
+
maxRelationshipDepth: 3,
|
|
8
|
+
customSortableFields: [],
|
|
9
|
+
customUnsortableFields: [],
|
|
10
|
+
respectExplicitSortable: true,
|
|
11
|
+
logAnalysis: false
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const isRelationshipColumnSortable = (column, options = {}) => {
|
|
15
|
+
// If intelligent sorting is disabled, use original behavior
|
|
16
|
+
if (options.enableIntelligentSorting === false) {
|
|
17
|
+
// Original behavior: return false for relation columns unless explicitly set
|
|
18
|
+
return column.sortable === true;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Respect explicit configuration
|
|
22
|
+
if (column.hasOwnProperty('sortable')) {
|
|
23
|
+
return column.sortable === true;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Default to false (original behavior) for safety
|
|
27
|
+
return false;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const getRelationshipPath = (column) => {
|
|
31
|
+
if (!Array.isArray(column.id)) {
|
|
32
|
+
return column.nameFrom || 'unknown';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const relationPath = column.id.join('.');
|
|
36
|
+
return column.nameFrom ? `${relationPath}.${column.nameFrom}` : relationPath;
|
|
37
|
+
};
|