@visns-studio/visns-components 5.15.8 → 5.15.10
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.
|
@@ -1082,6 +1082,20 @@ const GenericReportImproved = ({
|
|
|
1082
1082
|
exportUrl: '',
|
|
1083
1083
|
});
|
|
1084
1084
|
|
|
1085
|
+
// State for unique field selection and row exclusion
|
|
1086
|
+
const [uniqueFieldConfig, setUniqueFieldConfig] = useState({
|
|
1087
|
+
enabled: false,
|
|
1088
|
+
selectedField: '',
|
|
1089
|
+
});
|
|
1090
|
+
|
|
1091
|
+
// Debug logging for uniqueFieldConfig changes
|
|
1092
|
+
useEffect(() => {
|
|
1093
|
+
console.log('🔍 [EFFECT] uniqueFieldConfig changed:', uniqueFieldConfig);
|
|
1094
|
+
}, [uniqueFieldConfig]);
|
|
1095
|
+
const [excludedRows, setExcludedRows] = useState(new Set());
|
|
1096
|
+
const [showRowExclusionModal, setShowRowExclusionModal] = useState(false);
|
|
1097
|
+
const [exportType, setExportType] = useState('regular');
|
|
1098
|
+
|
|
1085
1099
|
// Note: Removed table search functionality to simplify user experience
|
|
1086
1100
|
|
|
1087
1101
|
// Extract additional settings with defaults
|
|
@@ -2291,6 +2305,17 @@ const GenericReportImproved = ({
|
|
|
2291
2305
|
let payload;
|
|
2292
2306
|
|
|
2293
2307
|
if (isDynamicTemplate) {
|
|
2308
|
+
// Enhanced unique field configuration for grouped templates
|
|
2309
|
+
const groupedUniqueConfig = uniqueFieldConfig.enabled && uniqueFieldConfig.selectedField ? {
|
|
2310
|
+
enabled: true,
|
|
2311
|
+
field: uniqueFieldConfig.selectedField,
|
|
2312
|
+
distinct: true,
|
|
2313
|
+
distinctField: uniqueFieldConfig.selectedField
|
|
2314
|
+
} : {
|
|
2315
|
+
enabled: false,
|
|
2316
|
+
distinct: false
|
|
2317
|
+
};
|
|
2318
|
+
|
|
2294
2319
|
// For dynamic templates, send the complete template configuration
|
|
2295
2320
|
payload = {
|
|
2296
2321
|
dynamic_template: template,
|
|
@@ -2299,7 +2324,16 @@ const GenericReportImproved = ({
|
|
|
2299
2324
|
joins: joins,
|
|
2300
2325
|
filters: flattenFilterCriteria(filterCriteria),
|
|
2301
2326
|
sorting: sortCriteria,
|
|
2327
|
+
// Enhanced unique field configuration
|
|
2328
|
+
unique: groupedUniqueConfig,
|
|
2302
2329
|
};
|
|
2330
|
+
|
|
2331
|
+
// Debug log for grouped reports
|
|
2332
|
+
if (uniqueFieldConfig.enabled) {
|
|
2333
|
+
console.group('🔍 [DEBUG] Grouped Report - Unique Field Configuration');
|
|
2334
|
+
console.log('Grouped unique config:', groupedUniqueConfig);
|
|
2335
|
+
console.groupEnd();
|
|
2336
|
+
}
|
|
2303
2337
|
} else {
|
|
2304
2338
|
// For predefined templates, use the existing approach
|
|
2305
2339
|
payload = {
|
|
@@ -2337,6 +2371,28 @@ const GenericReportImproved = ({
|
|
|
2337
2371
|
const page = Math.floor(skip / limit) + 1;
|
|
2338
2372
|
|
|
2339
2373
|
// Use the same payload format as GenericReport (with query wrapper)
|
|
2374
|
+
// Debug the unique field state at query time
|
|
2375
|
+
console.group('🔍 [DEBUG] DataSource - Unique Field State Check');
|
|
2376
|
+
console.log('uniqueFieldConfig:', uniqueFieldConfig);
|
|
2377
|
+
console.log('uniqueFieldConfig.enabled:', uniqueFieldConfig.enabled);
|
|
2378
|
+
console.log('uniqueFieldConfig.selectedField:', uniqueFieldConfig.selectedField);
|
|
2379
|
+
console.log('Condition evaluation:', uniqueFieldConfig.enabled && uniqueFieldConfig.selectedField);
|
|
2380
|
+
|
|
2381
|
+
// Check DOM state vs React state
|
|
2382
|
+
const checkboxes = document.querySelectorAll('input[type="checkbox"]');
|
|
2383
|
+
console.log('🔍 [DEBUG] All checkboxes in DOM:', Array.from(checkboxes).map((cb, i) => `${i}: ${cb.checked}`));
|
|
2384
|
+
console.groupEnd();
|
|
2385
|
+
|
|
2386
|
+
const uniqueConfig = uniqueFieldConfig.enabled && uniqueFieldConfig.selectedField ? {
|
|
2387
|
+
enabled: true,
|
|
2388
|
+
field: uniqueFieldConfig.selectedField,
|
|
2389
|
+
distinct: true, // Explicit DISTINCT flag
|
|
2390
|
+
distinctField: uniqueFieldConfig.selectedField
|
|
2391
|
+
} : {
|
|
2392
|
+
enabled: false,
|
|
2393
|
+
distinct: false
|
|
2394
|
+
};
|
|
2395
|
+
|
|
2340
2396
|
const queryConfig = {
|
|
2341
2397
|
mainTable: selectedTable,
|
|
2342
2398
|
columns: selectedColumns.map((col) => {
|
|
@@ -2368,8 +2424,20 @@ const GenericReportImproved = ({
|
|
|
2368
2424
|
})),
|
|
2369
2425
|
filters: flattenFilterCriteria(filterCriteria),
|
|
2370
2426
|
sorting: sortCriteria,
|
|
2427
|
+
// Enhanced unique field configuration
|
|
2428
|
+
unique: uniqueConfig,
|
|
2371
2429
|
};
|
|
2372
2430
|
|
|
2431
|
+
// Debug log for unique field configuration
|
|
2432
|
+
if (uniqueFieldConfig.enabled) {
|
|
2433
|
+
console.group('🔍 [DEBUG] Unique Field Configuration');
|
|
2434
|
+
console.log('Unique config enabled:', uniqueFieldConfig.enabled);
|
|
2435
|
+
console.log('Selected field:', uniqueFieldConfig.selectedField);
|
|
2436
|
+
console.log('Query unique config:', uniqueConfig);
|
|
2437
|
+
console.log('Expected SQL: SELECT DISTINCT', uniqueFieldConfig.selectedField, '...');
|
|
2438
|
+
console.groupEnd();
|
|
2439
|
+
}
|
|
2440
|
+
|
|
2373
2441
|
// Add sorting from DataGrid if provided
|
|
2374
2442
|
if (sortInfo) {
|
|
2375
2443
|
queryConfig.sorting = [
|
|
@@ -2461,6 +2529,11 @@ const GenericReportImproved = ({
|
|
|
2461
2529
|
executeUrl,
|
|
2462
2530
|
setting,
|
|
2463
2531
|
});
|
|
2532
|
+
|
|
2533
|
+
// CRITICAL DEBUG: Check uniqueFieldConfig state at execute time
|
|
2534
|
+
console.log('🚨 [CRITICAL] uniqueFieldConfig at executeReport start:', uniqueFieldConfig);
|
|
2535
|
+
console.log('🚨 [CRITICAL] uniqueFieldConfig.enabled:', uniqueFieldConfig.enabled);
|
|
2536
|
+
console.log('🚨 [CRITICAL] uniqueFieldConfig.selectedField:', uniqueFieldConfig.selectedField);
|
|
2464
2537
|
|
|
2465
2538
|
if (!selectedTable || selectedColumns.length === 0) {
|
|
2466
2539
|
toast.warning(
|
|
@@ -2885,6 +2958,12 @@ const GenericReportImproved = ({
|
|
|
2885
2958
|
});
|
|
2886
2959
|
}
|
|
2887
2960
|
|
|
2961
|
+
// Restore unique field configuration if it exists
|
|
2962
|
+
if (config.unique) {
|
|
2963
|
+
console.log('🔄 [RESTORE] Restoring unique field config:', config.unique);
|
|
2964
|
+
setUniqueFieldConfig(config.unique);
|
|
2965
|
+
}
|
|
2966
|
+
|
|
2888
2967
|
if (config.filters) {
|
|
2889
2968
|
// Ensure filters have the proper structure
|
|
2890
2969
|
if (config.filters.groups) {
|
|
@@ -4181,6 +4260,96 @@ const GenericReportImproved = ({
|
|
|
4181
4260
|
)}
|
|
4182
4261
|
</div>
|
|
4183
4262
|
)}
|
|
4263
|
+
|
|
4264
|
+
{/* Unique Field Configuration */}
|
|
4265
|
+
{selectedColumns.length > 0 && (
|
|
4266
|
+
<div className={styles.uniqueFieldConfig}>
|
|
4267
|
+
<div className={styles.configHeader}>
|
|
4268
|
+
<h4>
|
|
4269
|
+
<Filter size={16} />
|
|
4270
|
+
Remove Duplicates (Optional)
|
|
4271
|
+
</h4>
|
|
4272
|
+
<p>Use SQL DISTINCT to prevent duplicate rows based on a specific field</p>
|
|
4273
|
+
</div>
|
|
4274
|
+
<div className={styles.configContent}>
|
|
4275
|
+
<label className={styles.checkboxLabel}>
|
|
4276
|
+
<input
|
|
4277
|
+
type="checkbox"
|
|
4278
|
+
checked={uniqueFieldConfig.enabled}
|
|
4279
|
+
onChange={(e) => {
|
|
4280
|
+
console.log('🔍 [DEBUG] Unique field toggled:', e.target.checked);
|
|
4281
|
+
console.log('🔍 [DEBUG] Current uniqueFieldConfig before change:', uniqueFieldConfig);
|
|
4282
|
+
const newConfig = {
|
|
4283
|
+
...uniqueFieldConfig,
|
|
4284
|
+
enabled: e.target.checked,
|
|
4285
|
+
selectedField: e.target.checked ? uniqueFieldConfig.selectedField : ''
|
|
4286
|
+
};
|
|
4287
|
+
console.log('🔍 [DEBUG] New unique field config:', newConfig);
|
|
4288
|
+
setUniqueFieldConfig(newConfig);
|
|
4289
|
+
// Log immediately after setState
|
|
4290
|
+
setTimeout(() => {
|
|
4291
|
+
console.log('🔍 [DEBUG] State after setTimeout:', uniqueFieldConfig);
|
|
4292
|
+
}, 100);
|
|
4293
|
+
}}
|
|
4294
|
+
/>
|
|
4295
|
+
<span className={styles.checkboxText}>
|
|
4296
|
+
Enable DISTINCT filtering
|
|
4297
|
+
{uniqueFieldConfig.enabled && uniqueFieldConfig.selectedField && (
|
|
4298
|
+
<span className={styles.activeIndicator}>
|
|
4299
|
+
<CircleCheck size={12} />
|
|
4300
|
+
Active on {uniqueFieldConfig.selectedField}
|
|
4301
|
+
</span>
|
|
4302
|
+
)}
|
|
4303
|
+
</span>
|
|
4304
|
+
</label>
|
|
4305
|
+
|
|
4306
|
+
{uniqueFieldConfig.enabled && (
|
|
4307
|
+
<div className={styles.uniqueFieldSelector}>
|
|
4308
|
+
<label className={styles.fieldLabel}>
|
|
4309
|
+
Select field to make unique:
|
|
4310
|
+
</label>
|
|
4311
|
+
<select
|
|
4312
|
+
value={uniqueFieldConfig.selectedField}
|
|
4313
|
+
onChange={(e) => {
|
|
4314
|
+
console.log('🔍 [DEBUG] Unique field selected:', e.target.value);
|
|
4315
|
+
console.log('🔍 [DEBUG] Available dropdown options:', Array.from(e.target.options).map(opt => ({value: opt.value, text: opt.text})));
|
|
4316
|
+
console.log('🔍 [DEBUG] Selected option text:', e.target.options[e.target.selectedIndex]?.text);
|
|
4317
|
+
console.log('🔍 [DEBUG] Current uniqueFieldConfig before field change:', uniqueFieldConfig);
|
|
4318
|
+
console.log('🔍 [DEBUG] Current selectedColumns:', selectedColumns);
|
|
4319
|
+
const newConfig = {
|
|
4320
|
+
...uniqueFieldConfig,
|
|
4321
|
+
selectedField: e.target.value
|
|
4322
|
+
};
|
|
4323
|
+
console.log('🔍 [DEBUG] Updated unique field config with selected field:', newConfig);
|
|
4324
|
+
setUniqueFieldConfig(newConfig);
|
|
4325
|
+
// Log immediately after setState
|
|
4326
|
+
setTimeout(() => {
|
|
4327
|
+
console.log('🔍 [DEBUG] Field state after setTimeout:', uniqueFieldConfig);
|
|
4328
|
+
}, 100);
|
|
4329
|
+
}}
|
|
4330
|
+
className={styles.fieldSelect}
|
|
4331
|
+
required
|
|
4332
|
+
>
|
|
4333
|
+
<option value="">Choose a field...</option>
|
|
4334
|
+
{selectedColumns.map((col) => (
|
|
4335
|
+
<option
|
|
4336
|
+
key={`${col.table}-${col.column}`}
|
|
4337
|
+
value={`${col.table}.${col.column}`}
|
|
4338
|
+
>
|
|
4339
|
+
{col.displayName || col.column} ({col.table})
|
|
4340
|
+
</option>
|
|
4341
|
+
))}
|
|
4342
|
+
</select>
|
|
4343
|
+
<div className={styles.fieldHelp}>
|
|
4344
|
+
<strong>SQL Impact:</strong> This will add DISTINCT to your query based on the selected field.
|
|
4345
|
+
<br />
|
|
4346
|
+
<code>SELECT DISTINCT {uniqueFieldConfig.selectedField || '[field]'}, ... FROM {selectedTable}</code>
|
|
4347
|
+
</div>
|
|
4348
|
+
</div>
|
|
4349
|
+
)}
|
|
4350
|
+
</div>
|
|
4351
|
+
</div>
|
|
4352
|
+
)}
|
|
4184
4353
|
</div>
|
|
4185
4354
|
);
|
|
4186
4355
|
};
|
|
@@ -6483,6 +6652,17 @@ const GenericReportImproved = ({
|
|
|
6483
6652
|
|
|
6484
6653
|
try {
|
|
6485
6654
|
// Use exact same payload format as GenericReport
|
|
6655
|
+
// Enhanced unique field configuration for exports
|
|
6656
|
+
const exportUniqueConfig = uniqueFieldConfig.enabled && uniqueFieldConfig.selectedField ? {
|
|
6657
|
+
enabled: true,
|
|
6658
|
+
field: uniqueFieldConfig.selectedField,
|
|
6659
|
+
distinct: true,
|
|
6660
|
+
distinctField: uniqueFieldConfig.selectedField
|
|
6661
|
+
} : {
|
|
6662
|
+
enabled: false,
|
|
6663
|
+
distinct: false
|
|
6664
|
+
};
|
|
6665
|
+
|
|
6486
6666
|
const queryConfig = {
|
|
6487
6667
|
mainTable: selectedTable,
|
|
6488
6668
|
columns: selectedColumns.map((col) => ({
|
|
@@ -6503,8 +6683,21 @@ const GenericReportImproved = ({
|
|
|
6503
6683
|
})),
|
|
6504
6684
|
filters: flattenFilterCriteria(filterCriteria),
|
|
6505
6685
|
sorting: sortCriteria,
|
|
6686
|
+
// Enhanced unique field configuration
|
|
6687
|
+
unique: exportUniqueConfig,
|
|
6688
|
+
// Add excluded rows for server-side filtering
|
|
6689
|
+
excludedRows: Array.from(excludedRows),
|
|
6506
6690
|
};
|
|
6507
6691
|
|
|
6692
|
+
// Debug log for exports
|
|
6693
|
+
if (uniqueFieldConfig.enabled) {
|
|
6694
|
+
console.group('🔍 [DEBUG] Export - Unique Field Configuration');
|
|
6695
|
+
console.log('Export format:', format);
|
|
6696
|
+
console.log('Export unique config:', exportUniqueConfig);
|
|
6697
|
+
console.log('Query config:', queryConfig);
|
|
6698
|
+
console.groupEnd();
|
|
6699
|
+
}
|
|
6700
|
+
|
|
6508
6701
|
const exportData = {
|
|
6509
6702
|
query: queryConfig,
|
|
6510
6703
|
format: format === 'excel' ? 'xlsx' : format, // Convert excel to xlsx
|
|
@@ -6663,23 +6856,78 @@ const GenericReportImproved = ({
|
|
|
6663
6856
|
}
|
|
6664
6857
|
};
|
|
6665
6858
|
|
|
6666
|
-
// Handle
|
|
6667
|
-
const
|
|
6859
|
+
// Handle row exclusion modal
|
|
6860
|
+
const handleExportWithExclusion = (exportType = 'regular') => {
|
|
6668
6861
|
if (previewData.length === 0) {
|
|
6669
6862
|
toast.error('No data available to export');
|
|
6670
6863
|
return;
|
|
6671
6864
|
}
|
|
6672
6865
|
|
|
6866
|
+
setShowRowExclusionModal(true);
|
|
6867
|
+
setExportType(exportType);
|
|
6868
|
+
};
|
|
6869
|
+
|
|
6870
|
+
const confirmExportWithExclusion = async () => {
|
|
6871
|
+
setShowRowExclusionModal(false);
|
|
6872
|
+
|
|
6873
|
+
if (exportType === 'grouped') {
|
|
6874
|
+
await performGroupedExport();
|
|
6875
|
+
} else {
|
|
6876
|
+
await performRegularExport();
|
|
6877
|
+
}
|
|
6878
|
+
};
|
|
6879
|
+
|
|
6880
|
+
// Handle grouped report export to Excel
|
|
6881
|
+
const handleRegularExport = async () => {
|
|
6882
|
+
handleExportWithExclusion('regular');
|
|
6883
|
+
};
|
|
6884
|
+
|
|
6885
|
+
// Filter out excluded rows from preview data
|
|
6886
|
+
const getFilteredPreviewData = () => {
|
|
6887
|
+
if (excludedRows.size === 0) {
|
|
6888
|
+
return previewData;
|
|
6889
|
+
}
|
|
6890
|
+
|
|
6891
|
+
return previewData.filter((row, index) => {
|
|
6892
|
+
const rowId = row.id || `preview-row-${index}`;
|
|
6893
|
+
return !excludedRows.has(rowId);
|
|
6894
|
+
});
|
|
6895
|
+
};
|
|
6896
|
+
|
|
6897
|
+
// Perform the actual regular export
|
|
6898
|
+
const performRegularExport = async () => {
|
|
6899
|
+
const filteredData = getFilteredPreviewData();
|
|
6900
|
+
|
|
6901
|
+
if (filteredData.length === 0) {
|
|
6902
|
+
toast.error('No data available to export after exclusions');
|
|
6903
|
+
return;
|
|
6904
|
+
}
|
|
6905
|
+
|
|
6673
6906
|
try {
|
|
6907
|
+
// Temporarily replace previewData with filtered data for export
|
|
6908
|
+
const originalPreviewData = previewData;
|
|
6909
|
+
setPreviewData(filteredData);
|
|
6910
|
+
|
|
6674
6911
|
// Use the existing client-side Excel export functionality
|
|
6675
6912
|
await exportReport('excel');
|
|
6913
|
+
|
|
6914
|
+
// Restore original data
|
|
6915
|
+
setPreviewData(originalPreviewData);
|
|
6676
6916
|
} catch (error) {
|
|
6677
6917
|
console.error('Regular export failed:', error);
|
|
6678
6918
|
toast.error('Export failed. Please try again.');
|
|
6919
|
+
|
|
6920
|
+
// Restore original data on error as well
|
|
6921
|
+
setPreviewData(previewData);
|
|
6679
6922
|
}
|
|
6680
6923
|
};
|
|
6681
6924
|
|
|
6682
6925
|
const handleGroupedExport = async () => {
|
|
6926
|
+
handleExportWithExclusion('grouped');
|
|
6927
|
+
};
|
|
6928
|
+
|
|
6929
|
+
// Perform the actual grouped export
|
|
6930
|
+
const performGroupedExport = async () => {
|
|
6683
6931
|
if (!selectedTemplate) {
|
|
6684
6932
|
toast.error('No template selected for export');
|
|
6685
6933
|
return;
|
|
@@ -6830,9 +7078,17 @@ const GenericReportImproved = ({
|
|
|
6830
7078
|
groupHeaderRow[0] = `${groupDisplayName}: ${group.groupDisplayName}`;
|
|
6831
7079
|
worksheetData.push(groupHeaderRow);
|
|
6832
7080
|
|
|
6833
|
-
// Add data rows for this group
|
|
7081
|
+
// Add data rows for this group (excluding excluded rows)
|
|
6834
7082
|
const allRows = [...group.rows, ...(group.emptyRows || [])];
|
|
6835
|
-
allRows.forEach((row) => {
|
|
7083
|
+
allRows.forEach((row, rowIndex) => {
|
|
7084
|
+
// Create a unique identifier for the row
|
|
7085
|
+
const rowId = row.id || `group-${groupIndex}-row-${rowIndex}`;
|
|
7086
|
+
|
|
7087
|
+
// Skip excluded rows
|
|
7088
|
+
if (excludedRows.has(rowId)) {
|
|
7089
|
+
return;
|
|
7090
|
+
}
|
|
7091
|
+
|
|
6836
7092
|
const dataRow = selectedColumns.map((column) =>
|
|
6837
7093
|
getCellValue(row, column)
|
|
6838
7094
|
);
|
|
@@ -6977,6 +7233,7 @@ const GenericReportImproved = ({
|
|
|
6977
7233
|
isGrouped: groupingConfig.enabled,
|
|
6978
7234
|
customCalculatedFields: customCalculatedFields,
|
|
6979
7235
|
customUrls: customUrls,
|
|
7236
|
+
unique: uniqueFieldConfig,
|
|
6980
7237
|
},
|
|
6981
7238
|
};
|
|
6982
7239
|
|
|
@@ -7400,7 +7657,7 @@ const GenericReportImproved = ({
|
|
|
7400
7657
|
className={`${styles.btn} ${styles.btnPrimary}`}
|
|
7401
7658
|
onClick={() => {
|
|
7402
7659
|
resetPagination();
|
|
7403
|
-
|
|
7660
|
+
// Don't reset hasAutoExecuted to avoid triggering useEffect
|
|
7404
7661
|
executeReport();
|
|
7405
7662
|
}}
|
|
7406
7663
|
disabled={isLoading}
|
|
@@ -8597,6 +8854,123 @@ const GenericReportImproved = ({
|
|
|
8597
8854
|
</div>
|
|
8598
8855
|
</div>
|
|
8599
8856
|
)}
|
|
8857
|
+
|
|
8858
|
+
{/* Row Exclusion Modal */}
|
|
8859
|
+
{showRowExclusionModal && (
|
|
8860
|
+
<div className={styles.modalOverlay}>
|
|
8861
|
+
<div className={styles.rowExclusionModal}>
|
|
8862
|
+
<div className={styles.modalHeader}>
|
|
8863
|
+
<h3>Select Rows to Exclude</h3>
|
|
8864
|
+
<p>Choose which rows you don't want to include in the export</p>
|
|
8865
|
+
<button
|
|
8866
|
+
className={styles.modalCloseButton}
|
|
8867
|
+
onClick={() => setShowRowExclusionModal(false)}
|
|
8868
|
+
>
|
|
8869
|
+
✕
|
|
8870
|
+
</button>
|
|
8871
|
+
</div>
|
|
8872
|
+
|
|
8873
|
+
<div className={styles.modalBody}>
|
|
8874
|
+
<div className={styles.rowExclusionList}>
|
|
8875
|
+
{(exportType === 'grouped' && groupedData?.groupedData?.groups ?
|
|
8876
|
+
groupedData.groupedData.groups.flatMap((group, groupIndex) =>
|
|
8877
|
+
[...group.rows, ...(group.emptyRows || [])].map((row, rowIndex) => {
|
|
8878
|
+
const rowId = row.id || `group-${groupIndex}-row-${rowIndex}`;
|
|
8879
|
+
const isExcluded = excludedRows.has(rowId);
|
|
8880
|
+
|
|
8881
|
+
return (
|
|
8882
|
+
<label key={rowId} className={styles.rowExclusionItem}>
|
|
8883
|
+
<input
|
|
8884
|
+
type="checkbox"
|
|
8885
|
+
checked={isExcluded}
|
|
8886
|
+
onChange={(e) => {
|
|
8887
|
+
const newExcludedRows = new Set(excludedRows);
|
|
8888
|
+
if (e.target.checked) {
|
|
8889
|
+
newExcludedRows.add(rowId);
|
|
8890
|
+
} else {
|
|
8891
|
+
newExcludedRows.delete(rowId);
|
|
8892
|
+
}
|
|
8893
|
+
setExcludedRows(newExcludedRows);
|
|
8894
|
+
}}
|
|
8895
|
+
/>
|
|
8896
|
+
<div className={styles.rowPreview}>
|
|
8897
|
+
{selectedColumns.slice(0, 3).map((col) => {
|
|
8898
|
+
const value = row[col.displayName] || row[col.column] || row[`${col.table}_${col.column}`] || '';
|
|
8899
|
+
return (
|
|
8900
|
+
<span key={col.column} className={styles.rowValue}>
|
|
8901
|
+
{String(value).substring(0, 50)}{String(value).length > 50 ? '...' : ''}
|
|
8902
|
+
</span>
|
|
8903
|
+
);
|
|
8904
|
+
})}
|
|
8905
|
+
</div>
|
|
8906
|
+
</label>
|
|
8907
|
+
);
|
|
8908
|
+
})
|
|
8909
|
+
)
|
|
8910
|
+
:
|
|
8911
|
+
previewData.map((row, index) => {
|
|
8912
|
+
const rowId = row.id || `preview-row-${index}`;
|
|
8913
|
+
const isExcluded = excludedRows.has(rowId);
|
|
8914
|
+
|
|
8915
|
+
return (
|
|
8916
|
+
<label key={rowId} className={styles.rowExclusionItem}>
|
|
8917
|
+
<input
|
|
8918
|
+
type="checkbox"
|
|
8919
|
+
checked={isExcluded}
|
|
8920
|
+
onChange={(e) => {
|
|
8921
|
+
const newExcludedRows = new Set(excludedRows);
|
|
8922
|
+
if (e.target.checked) {
|
|
8923
|
+
newExcludedRows.add(rowId);
|
|
8924
|
+
} else {
|
|
8925
|
+
newExcludedRows.delete(rowId);
|
|
8926
|
+
}
|
|
8927
|
+
setExcludedRows(newExcludedRows);
|
|
8928
|
+
}}
|
|
8929
|
+
/>
|
|
8930
|
+
<div className={styles.rowPreview}>
|
|
8931
|
+
{selectedColumns.slice(0, 3).map((col) => {
|
|
8932
|
+
const value = row[col.displayName] || row[col.column] || row[`${col.table}_${col.column}`] || '';
|
|
8933
|
+
return (
|
|
8934
|
+
<span key={col.column} className={styles.rowValue}>
|
|
8935
|
+
{String(value).substring(0, 50)}{String(value).length > 50 ? '...' : ''}
|
|
8936
|
+
</span>
|
|
8937
|
+
);
|
|
8938
|
+
})}
|
|
8939
|
+
</div>
|
|
8940
|
+
</label>
|
|
8941
|
+
);
|
|
8942
|
+
})
|
|
8943
|
+
)}
|
|
8944
|
+
</div>
|
|
8945
|
+
|
|
8946
|
+
<div className={styles.exclusionSummary}>
|
|
8947
|
+
<p>
|
|
8948
|
+
{excludedRows.size} of {(exportType === 'grouped' && groupedData?.groupedData?.groups ?
|
|
8949
|
+
groupedData.groupedData.groups.reduce((total, group) => total + group.rows.length + (group.emptyRows?.length || 0), 0)
|
|
8950
|
+
: previewData.length)} rows will be excluded from export
|
|
8951
|
+
</p>
|
|
8952
|
+
</div>
|
|
8953
|
+
</div>
|
|
8954
|
+
|
|
8955
|
+
<div className={styles.modalFooter}>
|
|
8956
|
+
<button
|
|
8957
|
+
className={styles.cancelButton}
|
|
8958
|
+
onClick={() => setShowRowExclusionModal(false)}
|
|
8959
|
+
>
|
|
8960
|
+
Cancel
|
|
8961
|
+
</button>
|
|
8962
|
+
<button
|
|
8963
|
+
className={styles.confirmButton}
|
|
8964
|
+
onClick={confirmExportWithExclusion}
|
|
8965
|
+
>
|
|
8966
|
+
Export ({(exportType === 'grouped' && groupedData?.groupedData?.groups ?
|
|
8967
|
+
groupedData.groupedData.groups.reduce((total, group) => total + group.rows.length + (group.emptyRows?.length || 0), 0) - excludedRows.size
|
|
8968
|
+
: previewData.length - excludedRows.size)} rows)
|
|
8969
|
+
</button>
|
|
8970
|
+
</div>
|
|
8971
|
+
</div>
|
|
8972
|
+
</div>
|
|
8973
|
+
)}
|
|
8600
8974
|
</div>
|
|
8601
8975
|
);
|
|
8602
8976
|
};
|