@visns-studio/visns-components 5.6.3 → 5.6.5
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.
|
@@ -177,6 +177,96 @@ const isJsonValue = (value) => {
|
|
|
177
177
|
return typeof value === 'object' && value !== null;
|
|
178
178
|
};
|
|
179
179
|
|
|
180
|
+
// Helper function to validate filter criteria
|
|
181
|
+
const validateFilterCriteria = (filterCriteria) => {
|
|
182
|
+
// If it's already a flat array (legacy format)
|
|
183
|
+
if (Array.isArray(filterCriteria)) {
|
|
184
|
+
// Check each filter in the array
|
|
185
|
+
for (let i = 0; i < filterCriteria.length; i++) {
|
|
186
|
+
const filter = filterCriteria[i];
|
|
187
|
+
|
|
188
|
+
// Skip validation for IS NULL and IS NOT NULL operators which don't need a value
|
|
189
|
+
if (
|
|
190
|
+
filter.operator === 'IS NULL' ||
|
|
191
|
+
filter.operator === 'IS NOT NULL'
|
|
192
|
+
) {
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Check if any required field is missing
|
|
197
|
+
if (
|
|
198
|
+
!filter.table ||
|
|
199
|
+
!filter.column ||
|
|
200
|
+
!filter.operator ||
|
|
201
|
+
filter.value === undefined ||
|
|
202
|
+
filter.value === null ||
|
|
203
|
+
filter.value === ''
|
|
204
|
+
) {
|
|
205
|
+
return {
|
|
206
|
+
valid: false,
|
|
207
|
+
message: `Filter #${
|
|
208
|
+
i + 1
|
|
209
|
+
} is missing required fields (table, column, operator, or value)`,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return { valid: true };
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// If it's the new structure with groups and operators
|
|
217
|
+
if (filterCriteria.groups && Array.isArray(filterCriteria.groups)) {
|
|
218
|
+
// Process each group
|
|
219
|
+
for (
|
|
220
|
+
let groupIndex = 0;
|
|
221
|
+
groupIndex < filterCriteria.groups.length;
|
|
222
|
+
groupIndex++
|
|
223
|
+
) {
|
|
224
|
+
const group = filterCriteria.groups[groupIndex];
|
|
225
|
+
|
|
226
|
+
// Only validate non-empty groups
|
|
227
|
+
if (group.filters && group.filters.length > 0) {
|
|
228
|
+
// Check all filters in this group
|
|
229
|
+
for (
|
|
230
|
+
let filterIndex = 0;
|
|
231
|
+
filterIndex < group.filters.length;
|
|
232
|
+
filterIndex++
|
|
233
|
+
) {
|
|
234
|
+
const filter = group.filters[filterIndex];
|
|
235
|
+
|
|
236
|
+
// Skip validation for IS NULL and IS NOT NULL operators which don't need a value
|
|
237
|
+
if (
|
|
238
|
+
filter.operator === 'IS NULL' ||
|
|
239
|
+
filter.operator === 'IS NOT NULL'
|
|
240
|
+
) {
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Check if any required field is missing
|
|
245
|
+
if (
|
|
246
|
+
!filter.table ||
|
|
247
|
+
!filter.column ||
|
|
248
|
+
!filter.operator ||
|
|
249
|
+
filter.value === undefined ||
|
|
250
|
+
filter.value === null ||
|
|
251
|
+
filter.value === ''
|
|
252
|
+
) {
|
|
253
|
+
return {
|
|
254
|
+
valid: false,
|
|
255
|
+
message: `Filter #${filterIndex + 1} in group #${
|
|
256
|
+
groupIndex + 1
|
|
257
|
+
} is missing required fields (table, column, operator, or value)`,
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return { valid: true };
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// If it's neither a flat array nor the new structure, consider it valid (empty)
|
|
267
|
+
return { valid: true };
|
|
268
|
+
};
|
|
269
|
+
|
|
180
270
|
// Helper function to convert the enhanced filter structure to a flat array for the backend
|
|
181
271
|
const flattenFilterCriteria = (filterCriteria) => {
|
|
182
272
|
// If it's already a flat array (legacy format), return it as is
|
|
@@ -750,9 +840,40 @@ const GenericReport = ({ setting = {} }) => {
|
|
|
750
840
|
setSelectedColumns(updatedColumns);
|
|
751
841
|
};
|
|
752
842
|
|
|
843
|
+
// Start editing a column name
|
|
844
|
+
const handleStartEditColumn = (index) => {
|
|
845
|
+
const column = selectedColumns[index];
|
|
846
|
+
setEditingColumnIndex(index);
|
|
847
|
+
setEditingColumnName(column.alias || column.displayName);
|
|
848
|
+
};
|
|
849
|
+
|
|
850
|
+
// Save the edited column name
|
|
851
|
+
const handleSaveColumnName = () => {
|
|
852
|
+
if (editingColumnIndex !== null) {
|
|
853
|
+
const updatedColumns = [...selectedColumns];
|
|
854
|
+
updatedColumns[editingColumnIndex] = {
|
|
855
|
+
...updatedColumns[editingColumnIndex],
|
|
856
|
+
alias: editingColumnName,
|
|
857
|
+
};
|
|
858
|
+
setSelectedColumns(updatedColumns);
|
|
859
|
+
setEditingColumnIndex(null);
|
|
860
|
+
setEditingColumnName('');
|
|
861
|
+
}
|
|
862
|
+
};
|
|
863
|
+
|
|
864
|
+
// Cancel column name editing
|
|
865
|
+
const handleCancelEditColumn = () => {
|
|
866
|
+
setEditingColumnIndex(null);
|
|
867
|
+
setEditingColumnName('');
|
|
868
|
+
};
|
|
869
|
+
|
|
753
870
|
// State for drag and drop
|
|
754
871
|
const [draggedItemIndex, setDraggedItemIndex] = useState(null);
|
|
755
872
|
|
|
873
|
+
// State for column renaming
|
|
874
|
+
const [editingColumnIndex, setEditingColumnIndex] = useState(null);
|
|
875
|
+
const [editingColumnName, setEditingColumnName] = useState('');
|
|
876
|
+
|
|
756
877
|
// Handle drag start for column reordering
|
|
757
878
|
const handleDragStart = (e, index) => {
|
|
758
879
|
setDraggedItemIndex(index);
|
|
@@ -1336,7 +1457,7 @@ const GenericReport = ({ setting = {} }) => {
|
|
|
1336
1457
|
}
|
|
1337
1458
|
};
|
|
1338
1459
|
|
|
1339
|
-
// Export report as CSV or
|
|
1460
|
+
// Export report as CSV, Excel or PDF
|
|
1340
1461
|
const handleExportReport = async (format = 'csv') => {
|
|
1341
1462
|
if (selectedColumns.length === 0) {
|
|
1342
1463
|
toast.error('Please select at least one column for your report');
|
|
@@ -1348,6 +1469,15 @@ const GenericReport = ({ setting = {} }) => {
|
|
|
1348
1469
|
return;
|
|
1349
1470
|
}
|
|
1350
1471
|
|
|
1472
|
+
// Validate filter criteria
|
|
1473
|
+
if (filterCriteria) {
|
|
1474
|
+
const validationResult = validateFilterCriteria(filterCriteria);
|
|
1475
|
+
if (!validationResult.valid) {
|
|
1476
|
+
toast.error(validationResult.message);
|
|
1477
|
+
return;
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1351
1481
|
setIsLoading(true);
|
|
1352
1482
|
const toastId = toast.loading(
|
|
1353
1483
|
`Exporting report as ${format.toUpperCase()}...`
|
|
@@ -1368,8 +1498,8 @@ const GenericReport = ({ setting = {} }) => {
|
|
|
1368
1498
|
sourceColumn: join.sourceColumn,
|
|
1369
1499
|
targetColumn: join.targetColumn,
|
|
1370
1500
|
})),
|
|
1371
|
-
filters:
|
|
1372
|
-
sorting:
|
|
1501
|
+
filters: flattenFilterCriteria(filterCriteria),
|
|
1502
|
+
sorting: sortCriteria,
|
|
1373
1503
|
};
|
|
1374
1504
|
|
|
1375
1505
|
// Prepare export request data
|
|
@@ -1395,16 +1525,66 @@ const GenericReport = ({ setting = {} }) => {
|
|
|
1395
1525
|
const date = moment().format('YYYYMMDD');
|
|
1396
1526
|
const fileName = `${date}_${reportName}.${format}`;
|
|
1397
1527
|
|
|
1398
|
-
//
|
|
1399
|
-
|
|
1528
|
+
// For PDF (HTML) format, open in a new window for printing
|
|
1529
|
+
if (format === 'pdf') {
|
|
1530
|
+
// Convert blob to URL
|
|
1531
|
+
const blob = new Blob([res.data], { type: 'text/html' });
|
|
1532
|
+
const url = URL.createObjectURL(blob);
|
|
1533
|
+
|
|
1534
|
+
// Open in a new window
|
|
1535
|
+
const printWindow = window.open(url, '_blank');
|
|
1536
|
+
|
|
1537
|
+
// Add print instructions
|
|
1538
|
+
if (printWindow) {
|
|
1539
|
+
printWindow.onload = function () {
|
|
1540
|
+
// Add print button at the top
|
|
1541
|
+
const printButton =
|
|
1542
|
+
printWindow.document.createElement('button');
|
|
1543
|
+
printButton.innerHTML = 'Print PDF';
|
|
1544
|
+
printButton.style.position = 'fixed';
|
|
1545
|
+
printButton.style.top = '10px';
|
|
1546
|
+
printButton.style.right = '10px';
|
|
1547
|
+
printButton.style.zIndex = '9999';
|
|
1548
|
+
printButton.style.padding = '8px 16px';
|
|
1549
|
+
printButton.style.backgroundColor = '#4CAF50';
|
|
1550
|
+
printButton.style.color = 'white';
|
|
1551
|
+
printButton.style.border = 'none';
|
|
1552
|
+
printButton.style.borderRadius = '4px';
|
|
1553
|
+
printButton.style.cursor = 'pointer';
|
|
1554
|
+
|
|
1555
|
+
printButton.onclick = function () {
|
|
1556
|
+
// Hide the button before printing
|
|
1557
|
+
this.style.display = 'none';
|
|
1558
|
+
printWindow.print();
|
|
1559
|
+
this.style.display = 'block';
|
|
1560
|
+
};
|
|
1561
|
+
|
|
1562
|
+
printWindow.document.body.insertBefore(
|
|
1563
|
+
printButton,
|
|
1564
|
+
printWindow.document.body.firstChild
|
|
1565
|
+
);
|
|
1566
|
+
};
|
|
1567
|
+
}
|
|
1400
1568
|
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1569
|
+
toast.update(toastId, {
|
|
1570
|
+
render: `Report opened in a new window. Use browser's print function to save as PDF.`,
|
|
1571
|
+
type: 'success',
|
|
1572
|
+
isLoading: false,
|
|
1573
|
+
autoClose: 5000,
|
|
1574
|
+
closeButton: true,
|
|
1575
|
+
});
|
|
1576
|
+
} else {
|
|
1577
|
+
// Use FileSaver.js to save the file for CSV and Excel
|
|
1578
|
+
saveAs(res.data, fileName);
|
|
1579
|
+
|
|
1580
|
+
toast.update(toastId, {
|
|
1581
|
+
render: `Report exported successfully as ${format.toUpperCase()}`,
|
|
1582
|
+
type: 'success',
|
|
1583
|
+
isLoading: false,
|
|
1584
|
+
autoClose: 5000,
|
|
1585
|
+
closeButton: true,
|
|
1586
|
+
});
|
|
1587
|
+
}
|
|
1408
1588
|
} else {
|
|
1409
1589
|
throw new Error('Invalid response format');
|
|
1410
1590
|
}
|
|
@@ -1666,6 +1846,15 @@ const GenericReport = ({ setting = {} }) => {
|
|
|
1666
1846
|
return;
|
|
1667
1847
|
}
|
|
1668
1848
|
|
|
1849
|
+
// Validate filter criteria
|
|
1850
|
+
if (filterCriteria) {
|
|
1851
|
+
const validationResult = validateFilterCriteria(filterCriteria);
|
|
1852
|
+
if (!validationResult.valid) {
|
|
1853
|
+
toast.error(validationResult.message);
|
|
1854
|
+
return;
|
|
1855
|
+
}
|
|
1856
|
+
}
|
|
1857
|
+
|
|
1669
1858
|
setIsLoading(true);
|
|
1670
1859
|
toast.info('Executing query...');
|
|
1671
1860
|
|
|
@@ -1845,6 +2034,15 @@ const GenericReport = ({ setting = {} }) => {
|
|
|
1845
2034
|
return;
|
|
1846
2035
|
}
|
|
1847
2036
|
|
|
2037
|
+
// Validate filter criteria
|
|
2038
|
+
if (filterCriteria) {
|
|
2039
|
+
const validationResult = validateFilterCriteria(filterCriteria);
|
|
2040
|
+
if (!validationResult.valid) {
|
|
2041
|
+
toast.error(validationResult.message);
|
|
2042
|
+
return;
|
|
2043
|
+
}
|
|
2044
|
+
}
|
|
2045
|
+
|
|
1848
2046
|
setIsLoading(true);
|
|
1849
2047
|
|
|
1850
2048
|
try {
|
|
@@ -2248,7 +2446,12 @@ const GenericReport = ({ setting = {} }) => {
|
|
|
2248
2446
|
)}
|
|
2249
2447
|
</div>
|
|
2250
2448
|
|
|
2251
|
-
<
|
|
2449
|
+
<div className={styles.columnSectionHeader}>
|
|
2450
|
+
<h3>Selected Columns</h3>
|
|
2451
|
+
<span className={styles.instructionText}>
|
|
2452
|
+
Click the pencil icon (✎) to rename columns
|
|
2453
|
+
</span>
|
|
2454
|
+
</div>
|
|
2252
2455
|
{selectedColumns.length > 0 ? (
|
|
2253
2456
|
<div className={styles.selectedColumns}>
|
|
2254
2457
|
{selectedColumns.map((column, index) => (
|
|
@@ -2276,10 +2479,86 @@ const GenericReport = ({ setting = {} }) => {
|
|
|
2276
2479
|
>
|
|
2277
2480
|
⋮⋮
|
|
2278
2481
|
</div>
|
|
2279
|
-
<span>
|
|
2482
|
+
<span>
|
|
2483
|
+
{editingColumnIndex ===
|
|
2484
|
+
index ? (
|
|
2485
|
+
<div
|
|
2486
|
+
className={
|
|
2487
|
+
styles.inlineEditContainer
|
|
2488
|
+
}
|
|
2489
|
+
>
|
|
2490
|
+
<input
|
|
2491
|
+
type="text"
|
|
2492
|
+
className={
|
|
2493
|
+
styles.columnNameInput
|
|
2494
|
+
}
|
|
2495
|
+
value={
|
|
2496
|
+
editingColumnName
|
|
2497
|
+
}
|
|
2498
|
+
onChange={(e) =>
|
|
2499
|
+
setEditingColumnName(
|
|
2500
|
+
e.target
|
|
2501
|
+
.value
|
|
2502
|
+
)
|
|
2503
|
+
}
|
|
2504
|
+
autoFocus
|
|
2505
|
+
onKeyDown={(e) => {
|
|
2506
|
+
if (
|
|
2507
|
+
e.key ===
|
|
2508
|
+
'Enter'
|
|
2509
|
+
) {
|
|
2510
|
+
handleSaveColumnName();
|
|
2511
|
+
} else if (
|
|
2512
|
+
e.key ===
|
|
2513
|
+
'Escape'
|
|
2514
|
+
) {
|
|
2515
|
+
handleCancelEditColumn();
|
|
2516
|
+
}
|
|
2517
|
+
}}
|
|
2518
|
+
/>
|
|
2519
|
+
<button
|
|
2520
|
+
className={
|
|
2521
|
+
styles.saveBtn
|
|
2522
|
+
}
|
|
2523
|
+
onClick={
|
|
2524
|
+
handleSaveColumnName
|
|
2525
|
+
}
|
|
2526
|
+
title="Save"
|
|
2527
|
+
>
|
|
2528
|
+
✓
|
|
2529
|
+
</button>
|
|
2530
|
+
<button
|
|
2531
|
+
className={
|
|
2532
|
+
styles.cancelBtn
|
|
2533
|
+
}
|
|
2534
|
+
onClick={
|
|
2535
|
+
handleCancelEditColumn
|
|
2536
|
+
}
|
|
2537
|
+
title="Cancel"
|
|
2538
|
+
>
|
|
2539
|
+
✕
|
|
2540
|
+
</button>
|
|
2541
|
+
</div>
|
|
2542
|
+
) : (
|
|
2543
|
+
column.alias ||
|
|
2544
|
+
column.displayName
|
|
2545
|
+
)}
|
|
2546
|
+
</span>
|
|
2280
2547
|
<div
|
|
2281
2548
|
className={styles.columnActions}
|
|
2282
2549
|
>
|
|
2550
|
+
<button
|
|
2551
|
+
className={styles.editBtn}
|
|
2552
|
+
onClick={() =>
|
|
2553
|
+
handleStartEditColumn(
|
|
2554
|
+
index
|
|
2555
|
+
)
|
|
2556
|
+
}
|
|
2557
|
+
aria-label="Edit column name"
|
|
2558
|
+
title="Edit name"
|
|
2559
|
+
>
|
|
2560
|
+
✎
|
|
2561
|
+
</button>
|
|
2283
2562
|
<button
|
|
2284
2563
|
className={styles.removeBtn}
|
|
2285
2564
|
onClick={() =>
|
|
@@ -2307,338 +2586,351 @@ const GenericReport = ({ setting = {} }) => {
|
|
|
2307
2586
|
<div className={styles.reportSection}>
|
|
2308
2587
|
<div
|
|
2309
2588
|
className={styles.sectionHeader}
|
|
2310
|
-
onClick={() =>
|
|
2311
|
-
setShowJoinTables(!showJoinTables)
|
|
2312
|
-
}
|
|
2313
|
-
style={{ cursor: 'pointer' }}
|
|
2314
2589
|
title={
|
|
2315
2590
|
showJoinTables
|
|
2316
2591
|
? 'Hide join tables'
|
|
2317
2592
|
: 'Show join tables'
|
|
2318
2593
|
}
|
|
2319
2594
|
>
|
|
2320
|
-
<h3
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
: ''
|
|
2326
|
-
}`}
|
|
2595
|
+
<h3
|
|
2596
|
+
onClick={() =>
|
|
2597
|
+
setShowJoinTables(!showJoinTables)
|
|
2598
|
+
}
|
|
2599
|
+
style={{ cursor: 'pointer' }}
|
|
2327
2600
|
>
|
|
2328
|
-
|
|
2329
|
-
</
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2601
|
+
Join Tables
|
|
2602
|
+
</h3>
|
|
2603
|
+
<div className={styles.sectionHeaderActions}>
|
|
2604
|
+
<button
|
|
2605
|
+
className={styles.btn}
|
|
2606
|
+
onClick={handleAddJoin}
|
|
2607
|
+
>
|
|
2608
|
+
Add Manual Relationship
|
|
2609
|
+
</button>
|
|
2334
2610
|
<div
|
|
2335
|
-
className={
|
|
2336
|
-
|
|
2611
|
+
className={`${styles.toggleBtn} ${
|
|
2612
|
+
showJoinTables
|
|
2613
|
+
? styles.toggleBtnActive
|
|
2614
|
+
: ''
|
|
2615
|
+
}`}
|
|
2616
|
+
onClick={() =>
|
|
2617
|
+
setShowJoinTables(!showJoinTables)
|
|
2337
2618
|
}
|
|
2619
|
+
style={{ cursor: 'pointer' }}
|
|
2338
2620
|
>
|
|
2339
|
-
|
|
2340
|
-
className={styles.btn}
|
|
2341
|
-
onClick={handleAddJoin}
|
|
2342
|
-
>
|
|
2343
|
-
Add Manual Relationship
|
|
2344
|
-
</button>
|
|
2621
|
+
{showJoinTables ? '▲' : '▼'}
|
|
2345
2622
|
</div>
|
|
2623
|
+
</div>
|
|
2624
|
+
</div>
|
|
2346
2625
|
|
|
2626
|
+
{showJoinTables && selectedTable && (
|
|
2627
|
+
<>
|
|
2347
2628
|
{joins.length > 0 && (
|
|
2348
|
-
<div
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
key={index}
|
|
2356
|
-
className={
|
|
2357
|
-
styles.joinSection
|
|
2358
|
-
}
|
|
2359
|
-
>
|
|
2629
|
+
<div className={styles.filterGroup}>
|
|
2630
|
+
<div
|
|
2631
|
+
className={
|
|
2632
|
+
styles.joinTablesContainer
|
|
2633
|
+
}
|
|
2634
|
+
>
|
|
2635
|
+
{joins.map((join, index) => (
|
|
2360
2636
|
<div
|
|
2637
|
+
key={index}
|
|
2361
2638
|
className={
|
|
2362
|
-
styles.
|
|
2639
|
+
styles.joinSection
|
|
2363
2640
|
}
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
{join.targetTable
|
|
2367
|
-
? `${formatName(
|
|
2368
|
-
join.sourceTable
|
|
2369
|
-
)} ${join.joinType.replace(
|
|
2370
|
-
' JOIN',
|
|
2371
|
-
''
|
|
2372
|
-
)} ${formatName(
|
|
2373
|
-
join.targetTable
|
|
2374
|
-
)}`
|
|
2375
|
-
: `Join #${
|
|
2376
|
-
index + 1
|
|
2377
|
-
}`}
|
|
2378
|
-
</h4>
|
|
2379
|
-
<button
|
|
2380
|
-
className={
|
|
2381
|
-
styles.removeJoinBtn
|
|
2382
|
-
}
|
|
2383
|
-
onClick={() =>
|
|
2384
|
-
handleRemoveJoin(
|
|
2385
|
-
index
|
|
2386
|
-
)
|
|
2387
|
-
}
|
|
2388
|
-
title="Remove Join"
|
|
2389
|
-
>
|
|
2390
|
-
×
|
|
2391
|
-
</button>
|
|
2392
|
-
</div>
|
|
2393
|
-
|
|
2394
|
-
<div
|
|
2395
|
-
className={
|
|
2396
|
-
styles.joinGrid
|
|
2641
|
+
data-join-index={
|
|
2642
|
+
index + 1
|
|
2397
2643
|
}
|
|
2398
2644
|
>
|
|
2399
2645
|
<div
|
|
2400
2646
|
className={
|
|
2401
|
-
styles.
|
|
2647
|
+
styles.joinHeader
|
|
2402
2648
|
}
|
|
2403
2649
|
>
|
|
2404
|
-
<
|
|
2405
|
-
|
|
2406
|
-
|
|
2650
|
+
<h4
|
|
2651
|
+
data-join-index={
|
|
2652
|
+
index + 1
|
|
2407
2653
|
}
|
|
2408
2654
|
>
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
'joinType',
|
|
2425
|
-
e
|
|
2426
|
-
.target
|
|
2427
|
-
.value
|
|
2428
|
-
)
|
|
2429
|
-
}
|
|
2430
|
-
>
|
|
2431
|
-
<option value="INNER JOIN">
|
|
2432
|
-
INNER
|
|
2433
|
-
JOIN
|
|
2434
|
-
</option>
|
|
2435
|
-
<option value="LEFT JOIN">
|
|
2436
|
-
LEFT
|
|
2437
|
-
JOIN
|
|
2438
|
-
</option>
|
|
2439
|
-
<option value="RIGHT JOIN">
|
|
2440
|
-
RIGHT
|
|
2441
|
-
JOIN
|
|
2442
|
-
</option>
|
|
2443
|
-
<option value="FULL JOIN">
|
|
2444
|
-
FULL
|
|
2445
|
-
JOIN
|
|
2446
|
-
</option>
|
|
2447
|
-
</select>
|
|
2448
|
-
</div>
|
|
2449
|
-
|
|
2450
|
-
<div
|
|
2655
|
+
{join.targetTable
|
|
2656
|
+
? `${formatName(
|
|
2657
|
+
join.sourceTable
|
|
2658
|
+
)} ${join.joinType.replace(
|
|
2659
|
+
' JOIN',
|
|
2660
|
+
''
|
|
2661
|
+
)} ${formatName(
|
|
2662
|
+
join.targetTable
|
|
2663
|
+
)}`
|
|
2664
|
+
: `Join #${
|
|
2665
|
+
index +
|
|
2666
|
+
1
|
|
2667
|
+
}`}
|
|
2668
|
+
</h4>
|
|
2669
|
+
<button
|
|
2451
2670
|
className={
|
|
2452
|
-
styles.
|
|
2671
|
+
styles.removeJoinBtn
|
|
2453
2672
|
}
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
</label>
|
|
2459
|
-
<input
|
|
2460
|
-
type="text"
|
|
2461
|
-
className={
|
|
2462
|
-
styles.formControl
|
|
2463
|
-
}
|
|
2464
|
-
value={formatName(
|
|
2465
|
-
join.sourceTable
|
|
2466
|
-
)}
|
|
2467
|
-
readOnly
|
|
2468
|
-
/>
|
|
2469
|
-
</div>
|
|
2470
|
-
|
|
2471
|
-
<div
|
|
2472
|
-
className={
|
|
2473
|
-
styles.joinField
|
|
2673
|
+
onClick={() =>
|
|
2674
|
+
handleRemoveJoin(
|
|
2675
|
+
index
|
|
2676
|
+
)
|
|
2474
2677
|
}
|
|
2678
|
+
title="Remove Join"
|
|
2475
2679
|
>
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
Column:
|
|
2479
|
-
</label>
|
|
2480
|
-
<select
|
|
2481
|
-
className={
|
|
2482
|
-
styles.selectControl
|
|
2483
|
-
}
|
|
2484
|
-
value={
|
|
2485
|
-
join.sourceColumn
|
|
2486
|
-
}
|
|
2487
|
-
onChange={(
|
|
2488
|
-
e
|
|
2489
|
-
) =>
|
|
2490
|
-
handleJoinChange(
|
|
2491
|
-
index,
|
|
2492
|
-
'sourceColumn',
|
|
2493
|
-
e
|
|
2494
|
-
.target
|
|
2495
|
-
.value
|
|
2496
|
-
)
|
|
2497
|
-
}
|
|
2498
|
-
>
|
|
2499
|
-
<option value="">
|
|
2500
|
-
Select
|
|
2501
|
-
Column
|
|
2502
|
-
</option>
|
|
2503
|
-
{tableColumns.map(
|
|
2504
|
-
(
|
|
2505
|
-
column
|
|
2506
|
-
) => (
|
|
2507
|
-
<option
|
|
2508
|
-
key={
|
|
2509
|
-
column.name
|
|
2510
|
-
}
|
|
2511
|
-
value={
|
|
2512
|
-
column.name
|
|
2513
|
-
}
|
|
2514
|
-
>
|
|
2515
|
-
{formatName(
|
|
2516
|
-
column.name
|
|
2517
|
-
)}
|
|
2518
|
-
</option>
|
|
2519
|
-
)
|
|
2520
|
-
)}
|
|
2521
|
-
</select>
|
|
2522
|
-
</div>
|
|
2680
|
+
×
|
|
2681
|
+
</button>
|
|
2523
2682
|
</div>
|
|
2524
2683
|
|
|
2525
2684
|
<div
|
|
2526
2685
|
className={
|
|
2527
|
-
styles.
|
|
2686
|
+
styles.joinGrid
|
|
2528
2687
|
}
|
|
2529
2688
|
>
|
|
2530
2689
|
<div
|
|
2531
2690
|
className={
|
|
2532
|
-
styles.
|
|
2691
|
+
styles.joinGridColumn
|
|
2533
2692
|
}
|
|
2534
2693
|
>
|
|
2535
|
-
<
|
|
2536
|
-
Target
|
|
2537
|
-
Table:
|
|
2538
|
-
</label>
|
|
2539
|
-
<select
|
|
2694
|
+
<div
|
|
2540
2695
|
className={
|
|
2541
|
-
styles.
|
|
2542
|
-
}
|
|
2543
|
-
value={
|
|
2544
|
-
join.targetTable
|
|
2545
|
-
}
|
|
2546
|
-
onChange={(
|
|
2547
|
-
e
|
|
2548
|
-
) =>
|
|
2549
|
-
handleJoinChange(
|
|
2550
|
-
index,
|
|
2551
|
-
'targetTable',
|
|
2552
|
-
e
|
|
2553
|
-
.target
|
|
2554
|
-
.value
|
|
2555
|
-
)
|
|
2696
|
+
styles.joinField
|
|
2556
2697
|
}
|
|
2557
2698
|
>
|
|
2558
|
-
<
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
</
|
|
2562
|
-
|
|
2563
|
-
(
|
|
2564
|
-
table
|
|
2565
|
-
) => (
|
|
2566
|
-
<option
|
|
2567
|
-
key={
|
|
2568
|
-
table.name
|
|
2569
|
-
}
|
|
2570
|
-
value={
|
|
2571
|
-
table.name
|
|
2572
|
-
}
|
|
2573
|
-
>
|
|
2574
|
-
{formatName(
|
|
2575
|
-
table.name
|
|
2576
|
-
)}
|
|
2577
|
-
</option>
|
|
2578
|
-
)
|
|
2579
|
-
)}
|
|
2580
|
-
</select>
|
|
2581
|
-
</div>
|
|
2582
|
-
|
|
2583
|
-
{join.targetTable &&
|
|
2584
|
-
join.availableColumns && (
|
|
2585
|
-
<div
|
|
2699
|
+
<label>
|
|
2700
|
+
Join
|
|
2701
|
+
Type:
|
|
2702
|
+
</label>
|
|
2703
|
+
<select
|
|
2586
2704
|
className={
|
|
2587
|
-
styles.
|
|
2705
|
+
styles.selectControl
|
|
2588
2706
|
}
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
value={
|
|
2599
|
-
join.targetColumn
|
|
2600
|
-
}
|
|
2601
|
-
onChange={(
|
|
2707
|
+
value={
|
|
2708
|
+
join.joinType
|
|
2709
|
+
}
|
|
2710
|
+
onChange={(
|
|
2711
|
+
e
|
|
2712
|
+
) =>
|
|
2713
|
+
handleJoinChange(
|
|
2714
|
+
index,
|
|
2715
|
+
'joinType',
|
|
2602
2716
|
e
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2717
|
+
.target
|
|
2718
|
+
.value
|
|
2719
|
+
)
|
|
2720
|
+
}
|
|
2721
|
+
>
|
|
2722
|
+
<option value="INNER JOIN">
|
|
2723
|
+
INNER
|
|
2724
|
+
JOIN
|
|
2725
|
+
</option>
|
|
2726
|
+
<option value="LEFT JOIN">
|
|
2727
|
+
LEFT
|
|
2728
|
+
JOIN
|
|
2729
|
+
</option>
|
|
2730
|
+
<option value="RIGHT JOIN">
|
|
2731
|
+
RIGHT
|
|
2732
|
+
JOIN
|
|
2733
|
+
</option>
|
|
2734
|
+
<option value="FULL JOIN">
|
|
2735
|
+
FULL
|
|
2736
|
+
JOIN
|
|
2737
|
+
</option>
|
|
2738
|
+
</select>
|
|
2739
|
+
</div>
|
|
2740
|
+
|
|
2741
|
+
<div
|
|
2742
|
+
className={
|
|
2743
|
+
styles.joinField
|
|
2744
|
+
}
|
|
2745
|
+
>
|
|
2746
|
+
<label>
|
|
2747
|
+
Source
|
|
2748
|
+
Table:
|
|
2749
|
+
</label>
|
|
2750
|
+
<input
|
|
2751
|
+
type="text"
|
|
2752
|
+
className={
|
|
2753
|
+
styles.formControl
|
|
2754
|
+
}
|
|
2755
|
+
value={formatName(
|
|
2756
|
+
join.sourceTable
|
|
2757
|
+
)}
|
|
2758
|
+
readOnly
|
|
2759
|
+
/>
|
|
2760
|
+
</div>
|
|
2761
|
+
|
|
2762
|
+
<div
|
|
2763
|
+
className={
|
|
2764
|
+
styles.joinField
|
|
2765
|
+
}
|
|
2766
|
+
>
|
|
2767
|
+
<label>
|
|
2768
|
+
Source
|
|
2769
|
+
Column:
|
|
2770
|
+
</label>
|
|
2771
|
+
<select
|
|
2772
|
+
className={
|
|
2773
|
+
styles.selectControl
|
|
2774
|
+
}
|
|
2775
|
+
value={
|
|
2776
|
+
join.sourceColumn
|
|
2777
|
+
}
|
|
2778
|
+
onChange={(
|
|
2779
|
+
e
|
|
2780
|
+
) =>
|
|
2781
|
+
handleJoinChange(
|
|
2782
|
+
index,
|
|
2783
|
+
'sourceColumn',
|
|
2784
|
+
e
|
|
2785
|
+
.target
|
|
2786
|
+
.value
|
|
2787
|
+
)
|
|
2788
|
+
}
|
|
2789
|
+
>
|
|
2790
|
+
<option value="">
|
|
2791
|
+
Select
|
|
2792
|
+
Column
|
|
2793
|
+
</option>
|
|
2794
|
+
{tableColumns.map(
|
|
2795
|
+
(
|
|
2796
|
+
column
|
|
2797
|
+
) => (
|
|
2798
|
+
<option
|
|
2799
|
+
key={
|
|
2800
|
+
column.name
|
|
2801
|
+
}
|
|
2802
|
+
value={
|
|
2803
|
+
column.name
|
|
2804
|
+
}
|
|
2805
|
+
>
|
|
2806
|
+
{formatName(
|
|
2807
|
+
column.name
|
|
2808
|
+
)}
|
|
2809
|
+
</option>
|
|
2810
|
+
)
|
|
2811
|
+
)}
|
|
2812
|
+
</select>
|
|
2813
|
+
</div>
|
|
2814
|
+
</div>
|
|
2815
|
+
|
|
2816
|
+
<div
|
|
2817
|
+
className={
|
|
2818
|
+
styles.joinGridColumn
|
|
2819
|
+
}
|
|
2820
|
+
>
|
|
2821
|
+
<div
|
|
2822
|
+
className={
|
|
2823
|
+
styles.joinField
|
|
2824
|
+
}
|
|
2825
|
+
>
|
|
2826
|
+
<label>
|
|
2827
|
+
Target
|
|
2828
|
+
Table:
|
|
2829
|
+
</label>
|
|
2830
|
+
<select
|
|
2831
|
+
className={
|
|
2832
|
+
styles.selectControl
|
|
2833
|
+
}
|
|
2834
|
+
value={
|
|
2835
|
+
join.targetTable
|
|
2836
|
+
}
|
|
2837
|
+
onChange={(
|
|
2838
|
+
e
|
|
2839
|
+
) =>
|
|
2840
|
+
handleJoinChange(
|
|
2841
|
+
index,
|
|
2842
|
+
'targetTable',
|
|
2843
|
+
e
|
|
2844
|
+
.target
|
|
2845
|
+
.value
|
|
2846
|
+
)
|
|
2847
|
+
}
|
|
2848
|
+
>
|
|
2849
|
+
<option value="">
|
|
2850
|
+
Select
|
|
2851
|
+
Table
|
|
2852
|
+
</option>
|
|
2853
|
+
{availableTables.map(
|
|
2854
|
+
(
|
|
2855
|
+
table
|
|
2856
|
+
) => (
|
|
2857
|
+
<option
|
|
2858
|
+
key={
|
|
2859
|
+
table.name
|
|
2860
|
+
}
|
|
2861
|
+
value={
|
|
2862
|
+
table.name
|
|
2863
|
+
}
|
|
2864
|
+
>
|
|
2865
|
+
{formatName(
|
|
2866
|
+
table.name
|
|
2867
|
+
)}
|
|
2868
|
+
</option>
|
|
2869
|
+
)
|
|
2870
|
+
)}
|
|
2871
|
+
</select>
|
|
2872
|
+
</div>
|
|
2873
|
+
|
|
2874
|
+
{join.targetTable &&
|
|
2875
|
+
join.availableColumns && (
|
|
2876
|
+
<div
|
|
2877
|
+
className={
|
|
2878
|
+
styles.joinField
|
|
2611
2879
|
}
|
|
2612
2880
|
>
|
|
2613
|
-
<
|
|
2614
|
-
|
|
2615
|
-
Column
|
|
2616
|
-
</
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2881
|
+
<label>
|
|
2882
|
+
Target
|
|
2883
|
+
Column:
|
|
2884
|
+
</label>
|
|
2885
|
+
<select
|
|
2886
|
+
className={
|
|
2887
|
+
styles.selectControl
|
|
2888
|
+
}
|
|
2889
|
+
value={
|
|
2890
|
+
join.targetColumn
|
|
2891
|
+
}
|
|
2892
|
+
onChange={(
|
|
2893
|
+
e
|
|
2894
|
+
) =>
|
|
2895
|
+
handleJoinChange(
|
|
2896
|
+
index,
|
|
2897
|
+
'targetColumn',
|
|
2898
|
+
e
|
|
2899
|
+
.target
|
|
2900
|
+
.value
|
|
2901
|
+
)
|
|
2902
|
+
}
|
|
2903
|
+
>
|
|
2904
|
+
<option value="">
|
|
2905
|
+
Select
|
|
2906
|
+
Column
|
|
2907
|
+
</option>
|
|
2908
|
+
{join.availableColumns.map(
|
|
2909
|
+
(
|
|
2910
|
+
column
|
|
2911
|
+
) => (
|
|
2912
|
+
<option
|
|
2913
|
+
key={
|
|
2914
|
+
column.name
|
|
2915
|
+
}
|
|
2916
|
+
value={
|
|
2917
|
+
column.name
|
|
2918
|
+
}
|
|
2919
|
+
>
|
|
2920
|
+
{formatName(
|
|
2921
|
+
column.name
|
|
2922
|
+
)}
|
|
2923
|
+
</option>
|
|
2924
|
+
)
|
|
2925
|
+
)}
|
|
2926
|
+
</select>
|
|
2927
|
+
</div>
|
|
2928
|
+
)}
|
|
2929
|
+
</div>
|
|
2638
2930
|
</div>
|
|
2639
2931
|
</div>
|
|
2640
|
-
|
|
2641
|
-
|
|
2932
|
+
))}
|
|
2933
|
+
</div>
|
|
2642
2934
|
</div>
|
|
2643
2935
|
)}
|
|
2644
2936
|
</>
|
|
@@ -2992,249 +3284,298 @@ const GenericReport = ({ setting = {} }) => {
|
|
|
2992
3284
|
<div className={styles.reportSection}>
|
|
2993
3285
|
<div
|
|
2994
3286
|
className={styles.sectionHeader}
|
|
2995
|
-
onClick={() =>
|
|
2996
|
-
setShowSortingSection(!showSortingSection)
|
|
2997
|
-
}
|
|
2998
|
-
style={{ cursor: 'pointer' }}
|
|
2999
3287
|
title={
|
|
3000
3288
|
showSortingSection
|
|
3001
3289
|
? 'Hide sorting options'
|
|
3002
3290
|
: 'Show sorting options'
|
|
3003
3291
|
}
|
|
3004
3292
|
>
|
|
3005
|
-
<h3
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
}
|
|
3293
|
+
<h3
|
|
3294
|
+
onClick={() =>
|
|
3295
|
+
setShowSortingSection(
|
|
3296
|
+
!showSortingSection
|
|
3297
|
+
)
|
|
3298
|
+
}
|
|
3299
|
+
style={{ cursor: 'pointer' }}
|
|
3012
3300
|
>
|
|
3013
|
-
|
|
3014
|
-
</
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3301
|
+
Sorting
|
|
3302
|
+
</h3>
|
|
3303
|
+
<div className={styles.sectionHeaderActions}>
|
|
3304
|
+
<button
|
|
3305
|
+
className={styles.btn}
|
|
3306
|
+
onClick={handleAddSortCriterion}
|
|
3307
|
+
disabled={selectedColumns.length === 0}
|
|
3308
|
+
>
|
|
3309
|
+
Add Sort Criterion
|
|
3310
|
+
</button>
|
|
3019
3311
|
<div
|
|
3020
|
-
className={
|
|
3021
|
-
|
|
3312
|
+
className={`${styles.toggleBtn} ${
|
|
3313
|
+
showSortingSection
|
|
3314
|
+
? styles.toggleBtnActive
|
|
3315
|
+
: ''
|
|
3316
|
+
}`}
|
|
3317
|
+
onClick={() =>
|
|
3318
|
+
setShowSortingSection(
|
|
3319
|
+
!showSortingSection
|
|
3320
|
+
)
|
|
3022
3321
|
}
|
|
3322
|
+
style={{ cursor: 'pointer' }}
|
|
3023
3323
|
>
|
|
3024
|
-
|
|
3025
|
-
className={styles.btn}
|
|
3026
|
-
onClick={handleAddSortCriterion}
|
|
3027
|
-
disabled={
|
|
3028
|
-
selectedColumns.length === 0
|
|
3029
|
-
}
|
|
3030
|
-
>
|
|
3031
|
-
Add Sort Criterion
|
|
3032
|
-
</button>
|
|
3324
|
+
{showSortingSection ? '▲' : '▼'}
|
|
3033
3325
|
</div>
|
|
3326
|
+
</div>
|
|
3327
|
+
</div>
|
|
3034
3328
|
|
|
3329
|
+
{showSortingSection && (
|
|
3330
|
+
<>
|
|
3035
3331
|
{sortCriteria.length > 0 && (
|
|
3036
|
-
<div
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
(
|
|
3043
|
-
|
|
3044
|
-
key={index}
|
|
3045
|
-
className={
|
|
3046
|
-
styles.joinSection
|
|
3047
|
-
}
|
|
3048
|
-
>
|
|
3332
|
+
<div className={styles.filterGroup}>
|
|
3333
|
+
<div
|
|
3334
|
+
className={
|
|
3335
|
+
styles.joinTablesContainer
|
|
3336
|
+
}
|
|
3337
|
+
>
|
|
3338
|
+
{sortCriteria.map(
|
|
3339
|
+
(criterion, index) => (
|
|
3049
3340
|
<div
|
|
3341
|
+
key={index}
|
|
3050
3342
|
className={
|
|
3051
|
-
styles.
|
|
3343
|
+
styles.joinSection
|
|
3344
|
+
}
|
|
3345
|
+
data-sort-index={
|
|
3346
|
+
index + 1
|
|
3052
3347
|
}
|
|
3053
3348
|
>
|
|
3054
|
-
<
|
|
3055
|
-
Sort by{' '}
|
|
3056
|
-
{criterion.table &&
|
|
3057
|
-
criterion.column
|
|
3058
|
-
? `${formatName(
|
|
3059
|
-
criterion.table
|
|
3060
|
-
)}.${formatName(
|
|
3061
|
-
criterion.column
|
|
3062
|
-
)}`
|
|
3063
|
-
: `Criterion #${
|
|
3064
|
-
index +
|
|
3065
|
-
1
|
|
3066
|
-
}`}
|
|
3067
|
-
</h4>
|
|
3068
|
-
<button
|
|
3349
|
+
<div
|
|
3069
3350
|
className={
|
|
3070
|
-
styles.
|
|
3071
|
-
}
|
|
3072
|
-
onClick={() =>
|
|
3073
|
-
handleRemoveSortCriterion(
|
|
3074
|
-
index
|
|
3075
|
-
)
|
|
3351
|
+
styles.joinHeader
|
|
3076
3352
|
}
|
|
3077
|
-
title="Remove Sort Criterion"
|
|
3078
3353
|
>
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3354
|
+
<h4
|
|
3355
|
+
data-sort-index={
|
|
3356
|
+
index +
|
|
3357
|
+
1
|
|
3358
|
+
}
|
|
3359
|
+
>
|
|
3360
|
+
by{' '}
|
|
3361
|
+
{criterion.table &&
|
|
3362
|
+
criterion.column
|
|
3363
|
+
? `${formatName(
|
|
3364
|
+
criterion.table
|
|
3365
|
+
)}.${formatName(
|
|
3366
|
+
criterion.column
|
|
3367
|
+
)}`
|
|
3368
|
+
: `Criterion #${
|
|
3369
|
+
index +
|
|
3370
|
+
1
|
|
3371
|
+
}`}
|
|
3372
|
+
</h4>
|
|
3373
|
+
<button
|
|
3374
|
+
className={
|
|
3375
|
+
styles.removeJoinBtn
|
|
3376
|
+
}
|
|
3377
|
+
onClick={() =>
|
|
3378
|
+
handleRemoveSortCriterion(
|
|
3379
|
+
index
|
|
3380
|
+
)
|
|
3381
|
+
}
|
|
3382
|
+
title="Remove Sort Criterion"
|
|
3383
|
+
>
|
|
3384
|
+
×
|
|
3385
|
+
</button>
|
|
3386
|
+
</div>
|
|
3082
3387
|
|
|
3083
|
-
<div
|
|
3084
|
-
className={
|
|
3085
|
-
styles.joinGrid
|
|
3086
|
-
}
|
|
3087
|
-
>
|
|
3088
3388
|
<div
|
|
3089
3389
|
className={
|
|
3090
|
-
styles.
|
|
3390
|
+
styles.joinGrid
|
|
3091
3391
|
}
|
|
3092
3392
|
>
|
|
3093
3393
|
<div
|
|
3094
3394
|
className={
|
|
3095
|
-
styles.
|
|
3395
|
+
styles.joinGridColumn
|
|
3096
3396
|
}
|
|
3097
3397
|
>
|
|
3098
|
-
<
|
|
3099
|
-
Column:
|
|
3100
|
-
</label>
|
|
3101
|
-
<select
|
|
3398
|
+
<div
|
|
3102
3399
|
className={
|
|
3103
|
-
styles.
|
|
3400
|
+
styles.joinField
|
|
3104
3401
|
}
|
|
3105
|
-
value={`${criterion.table}.${criterion.column}`}
|
|
3106
|
-
onChange={(
|
|
3107
|
-
e
|
|
3108
|
-
) => {
|
|
3109
|
-
const [
|
|
3110
|
-
table,
|
|
3111
|
-
column,
|
|
3112
|
-
] =
|
|
3113
|
-
e.target.value.split(
|
|
3114
|
-
'.'
|
|
3115
|
-
);
|
|
3116
|
-
handleSortCriterionChange(
|
|
3117
|
-
index,
|
|
3118
|
-
'table',
|
|
3119
|
-
table
|
|
3120
|
-
);
|
|
3121
|
-
handleSortCriterionChange(
|
|
3122
|
-
index,
|
|
3123
|
-
'column',
|
|
3124
|
-
column
|
|
3125
|
-
);
|
|
3126
|
-
}}
|
|
3127
3402
|
>
|
|
3128
|
-
<
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3403
|
+
<label>
|
|
3404
|
+
Column:
|
|
3405
|
+
</label>
|
|
3406
|
+
<select
|
|
3407
|
+
className={
|
|
3408
|
+
styles.selectControl
|
|
3409
|
+
}
|
|
3410
|
+
value={
|
|
3411
|
+
criterion.table &&
|
|
3412
|
+
criterion.column
|
|
3413
|
+
? `${criterion.table}.${criterion.column}`
|
|
3414
|
+
: ''
|
|
3415
|
+
}
|
|
3416
|
+
onChange={(
|
|
3417
|
+
e
|
|
3418
|
+
) => {
|
|
3419
|
+
if (
|
|
3420
|
+
e
|
|
3421
|
+
.target
|
|
3422
|
+
.value
|
|
3423
|
+
) {
|
|
3424
|
+
// Split by the first occurrence of '.' to handle table names that might contain dots
|
|
3425
|
+
const dotIndex =
|
|
3426
|
+
e.target.value.indexOf(
|
|
3427
|
+
'.'
|
|
3428
|
+
);
|
|
3429
|
+
if (
|
|
3430
|
+
dotIndex !==
|
|
3431
|
+
-1
|
|
3432
|
+
) {
|
|
3433
|
+
const table =
|
|
3434
|
+
e.target.value.substring(
|
|
3435
|
+
0,
|
|
3436
|
+
dotIndex
|
|
3437
|
+
);
|
|
3438
|
+
const column =
|
|
3439
|
+
e.target.value.substring(
|
|
3440
|
+
dotIndex +
|
|
3441
|
+
1
|
|
3442
|
+
);
|
|
3443
|
+
|
|
3444
|
+
// First set the column to empty to avoid any issues with the value attribute
|
|
3445
|
+
handleSortCriterionChange(
|
|
3446
|
+
index,
|
|
3447
|
+
'column',
|
|
3448
|
+
''
|
|
3449
|
+
);
|
|
3450
|
+
|
|
3451
|
+
// Then set the table
|
|
3452
|
+
handleSortCriterionChange(
|
|
3453
|
+
index,
|
|
3454
|
+
'table',
|
|
3455
|
+
table
|
|
3456
|
+
);
|
|
3457
|
+
|
|
3458
|
+
// Finally set the column
|
|
3459
|
+
handleSortCriterionChange(
|
|
3460
|
+
index,
|
|
3461
|
+
'column',
|
|
3462
|
+
column
|
|
3463
|
+
);
|
|
3464
|
+
}
|
|
3465
|
+
}
|
|
3466
|
+
}}
|
|
3137
3467
|
>
|
|
3138
|
-
|
|
3468
|
+
<option value="">
|
|
3469
|
+
Select
|
|
3470
|
+
Column
|
|
3471
|
+
</option>
|
|
3472
|
+
{/* Main table columns */}
|
|
3473
|
+
<optgroup
|
|
3474
|
+
label={`${formatName(
|
|
3475
|
+
selectedTable
|
|
3476
|
+
)} Columns`}
|
|
3477
|
+
>
|
|
3478
|
+
{tableColumns.map(
|
|
3479
|
+
(
|
|
3480
|
+
column
|
|
3481
|
+
) => (
|
|
3482
|
+
<option
|
|
3483
|
+
key={`${selectedTable}.${column.name}`}
|
|
3484
|
+
value={`${selectedTable}.${column.name}`}
|
|
3485
|
+
>
|
|
3486
|
+
{formatName(
|
|
3487
|
+
column.name
|
|
3488
|
+
)}
|
|
3489
|
+
</option>
|
|
3490
|
+
)
|
|
3491
|
+
)}
|
|
3492
|
+
</optgroup>
|
|
3493
|
+
|
|
3494
|
+
{/* Joined tables columns */}
|
|
3495
|
+
{joins.map(
|
|
3139
3496
|
(
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3497
|
+
join,
|
|
3498
|
+
joinIndex
|
|
3499
|
+
) =>
|
|
3500
|
+
join.targetTable &&
|
|
3501
|
+
join.availableColumns &&
|
|
3502
|
+
join
|
|
3503
|
+
.availableColumns
|
|
3504
|
+
.length >
|
|
3505
|
+
0 ? (
|
|
3506
|
+
<optgroup
|
|
3507
|
+
key={`join-${joinIndex}`}
|
|
3508
|
+
label={`${formatName(
|
|
3509
|
+
join.targetTable
|
|
3510
|
+
)} Columns`}
|
|
3511
|
+
>
|
|
3512
|
+
{join.availableColumns.map(
|
|
3513
|
+
(
|
|
3514
|
+
column
|
|
3515
|
+
) => (
|
|
3516
|
+
<option
|
|
3517
|
+
key={`${join.targetTable}.${column.name}`}
|
|
3518
|
+
value={`${join.targetTable}.${column.name}`}
|
|
3519
|
+
>
|
|
3520
|
+
{formatName(
|
|
3521
|
+
column.name
|
|
3522
|
+
)}
|
|
3523
|
+
</option>
|
|
3524
|
+
)
|
|
3525
|
+
)}
|
|
3526
|
+
</optgroup>
|
|
3527
|
+
) : null
|
|
3151
3528
|
)}
|
|
3152
|
-
</
|
|
3153
|
-
|
|
3154
|
-
{/* Joined tables columns */}
|
|
3155
|
-
{joins.map(
|
|
3156
|
-
(
|
|
3157
|
-
join,
|
|
3158
|
-
joinIndex
|
|
3159
|
-
) =>
|
|
3160
|
-
join.targetTable &&
|
|
3161
|
-
join.availableColumns &&
|
|
3162
|
-
join
|
|
3163
|
-
.availableColumns
|
|
3164
|
-
.length >
|
|
3165
|
-
0 ? (
|
|
3166
|
-
<optgroup
|
|
3167
|
-
key={`join-${joinIndex}`}
|
|
3168
|
-
label={`${formatName(
|
|
3169
|
-
join.targetTable
|
|
3170
|
-
)} Columns`}
|
|
3171
|
-
>
|
|
3172
|
-
{join.availableColumns.map(
|
|
3173
|
-
(
|
|
3174
|
-
column
|
|
3175
|
-
) => (
|
|
3176
|
-
<option
|
|
3177
|
-
key={`${join.targetTable}.${column.name}`}
|
|
3178
|
-
value={`${join.targetTable}.${column.name}`}
|
|
3179
|
-
>
|
|
3180
|
-
{formatName(
|
|
3181
|
-
column.name
|
|
3182
|
-
)}
|
|
3183
|
-
</option>
|
|
3184
|
-
)
|
|
3185
|
-
)}
|
|
3186
|
-
</optgroup>
|
|
3187
|
-
) : null
|
|
3188
|
-
)}
|
|
3189
|
-
</select>
|
|
3529
|
+
</select>
|
|
3530
|
+
</div>
|
|
3190
3531
|
</div>
|
|
3191
|
-
</div>
|
|
3192
3532
|
|
|
3193
|
-
<div
|
|
3194
|
-
className={
|
|
3195
|
-
styles.joinGridColumn
|
|
3196
|
-
}
|
|
3197
|
-
>
|
|
3198
3533
|
<div
|
|
3199
3534
|
className={
|
|
3200
|
-
styles.
|
|
3535
|
+
styles.joinGridColumn
|
|
3201
3536
|
}
|
|
3202
3537
|
>
|
|
3203
|
-
<
|
|
3204
|
-
Direction:
|
|
3205
|
-
</label>
|
|
3206
|
-
<select
|
|
3538
|
+
<div
|
|
3207
3539
|
className={
|
|
3208
|
-
styles.
|
|
3209
|
-
}
|
|
3210
|
-
value={
|
|
3211
|
-
criterion.direction
|
|
3212
|
-
}
|
|
3213
|
-
onChange={(
|
|
3214
|
-
e
|
|
3215
|
-
) =>
|
|
3216
|
-
handleSortCriterionChange(
|
|
3217
|
-
index,
|
|
3218
|
-
'direction',
|
|
3219
|
-
e
|
|
3220
|
-
.target
|
|
3221
|
-
.value
|
|
3222
|
-
)
|
|
3540
|
+
styles.joinField
|
|
3223
3541
|
}
|
|
3224
3542
|
>
|
|
3225
|
-
<
|
|
3226
|
-
|
|
3227
|
-
</
|
|
3228
|
-
<
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3543
|
+
<label>
|
|
3544
|
+
Direction:
|
|
3545
|
+
</label>
|
|
3546
|
+
<select
|
|
3547
|
+
className={
|
|
3548
|
+
styles.selectControl
|
|
3549
|
+
}
|
|
3550
|
+
value={
|
|
3551
|
+
criterion.direction
|
|
3552
|
+
}
|
|
3553
|
+
onChange={(
|
|
3554
|
+
e
|
|
3555
|
+
) =>
|
|
3556
|
+
handleSortCriterionChange(
|
|
3557
|
+
index,
|
|
3558
|
+
'direction',
|
|
3559
|
+
e
|
|
3560
|
+
.target
|
|
3561
|
+
.value
|
|
3562
|
+
)
|
|
3563
|
+
}
|
|
3564
|
+
>
|
|
3565
|
+
<option value="ASC">
|
|
3566
|
+
Ascending
|
|
3567
|
+
</option>
|
|
3568
|
+
<option value="DESC">
|
|
3569
|
+
Descending
|
|
3570
|
+
</option>
|
|
3571
|
+
</select>
|
|
3572
|
+
</div>
|
|
3232
3573
|
</div>
|
|
3233
3574
|
</div>
|
|
3234
3575
|
</div>
|
|
3235
|
-
|
|
3236
|
-
)
|
|
3237
|
-
|
|
3576
|
+
)
|
|
3577
|
+
)}
|
|
3578
|
+
</div>
|
|
3238
3579
|
</div>
|
|
3239
3580
|
)}
|
|
3240
3581
|
</>
|
|
@@ -3512,14 +3853,22 @@ const GenericReport = ({ setting = {} }) => {
|
|
|
3512
3853
|
className={
|
|
3513
3854
|
styles.joinSection
|
|
3514
3855
|
}
|
|
3856
|
+
data-filter-index={
|
|
3857
|
+
filterIndex +
|
|
3858
|
+
1
|
|
3859
|
+
}
|
|
3515
3860
|
>
|
|
3516
3861
|
<div
|
|
3517
3862
|
className={
|
|
3518
3863
|
styles.joinHeader
|
|
3519
3864
|
}
|
|
3520
3865
|
>
|
|
3521
|
-
<h4
|
|
3522
|
-
|
|
3866
|
+
<h4
|
|
3867
|
+
data-filter-index={
|
|
3868
|
+
filterIndex +
|
|
3869
|
+
1
|
|
3870
|
+
}
|
|
3871
|
+
>
|
|
3523
3872
|
on{' '}
|
|
3524
3873
|
{criterion.table &&
|
|
3525
3874
|
criterion.column
|
|
@@ -3571,29 +3920,81 @@ const GenericReport = ({ setting = {} }) => {
|
|
|
3571
3920
|
className={
|
|
3572
3921
|
styles.selectControl
|
|
3573
3922
|
}
|
|
3574
|
-
value={
|
|
3923
|
+
value={
|
|
3924
|
+
criterion.table &&
|
|
3925
|
+
criterion.column
|
|
3926
|
+
? `${criterion.table}.${criterion.column}`
|
|
3927
|
+
: ''
|
|
3928
|
+
}
|
|
3575
3929
|
onChange={(
|
|
3576
3930
|
e
|
|
3577
3931
|
) => {
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3932
|
+
if (
|
|
3933
|
+
e
|
|
3934
|
+
.target
|
|
3935
|
+
.value
|
|
3936
|
+
) {
|
|
3937
|
+
// Split by the first occurrence of '.' to handle table names that might contain dots
|
|
3938
|
+
const dotIndex =
|
|
3939
|
+
e.target.value.indexOf(
|
|
3940
|
+
'.'
|
|
3941
|
+
);
|
|
3942
|
+
if (
|
|
3943
|
+
dotIndex !==
|
|
3944
|
+
-1
|
|
3945
|
+
) {
|
|
3946
|
+
const table =
|
|
3947
|
+
e.target.value.substring(
|
|
3948
|
+
0,
|
|
3949
|
+
dotIndex
|
|
3950
|
+
);
|
|
3951
|
+
const column =
|
|
3952
|
+
e.target.value.substring(
|
|
3953
|
+
dotIndex +
|
|
3954
|
+
1
|
|
3955
|
+
);
|
|
3956
|
+
|
|
3957
|
+
console.log(
|
|
3958
|
+
'Filter dropdown selection:',
|
|
3959
|
+
{
|
|
3960
|
+
value: e
|
|
3961
|
+
.target
|
|
3962
|
+
.value,
|
|
3963
|
+
table,
|
|
3964
|
+
column,
|
|
3965
|
+
groupIndex,
|
|
3966
|
+
filterIndex,
|
|
3967
|
+
}
|
|
3968
|
+
);
|
|
3969
|
+
|
|
3970
|
+
// Create a temporary copy of the filter criteria
|
|
3971
|
+
const updatedFilterCriteria =
|
|
3972
|
+
JSON.parse(
|
|
3973
|
+
JSON.stringify(
|
|
3974
|
+
filterCriteria
|
|
3975
|
+
)
|
|
3976
|
+
);
|
|
3977
|
+
|
|
3978
|
+
// Update both properties at once
|
|
3979
|
+
updatedFilterCriteria.groups[
|
|
3980
|
+
groupIndex
|
|
3981
|
+
].filters[
|
|
3982
|
+
filterIndex
|
|
3983
|
+
].table =
|
|
3984
|
+
table;
|
|
3985
|
+
updatedFilterCriteria.groups[
|
|
3986
|
+
groupIndex
|
|
3987
|
+
].filters[
|
|
3988
|
+
filterIndex
|
|
3989
|
+
].column =
|
|
3990
|
+
column;
|
|
3991
|
+
|
|
3992
|
+
// Set the state once with both updates
|
|
3993
|
+
setFilterCriteria(
|
|
3994
|
+
updatedFilterCriteria
|
|
3995
|
+
);
|
|
3996
|
+
}
|
|
3997
|
+
}
|
|
3597
3998
|
}}
|
|
3598
3999
|
>
|
|
3599
4000
|
<option value="">
|
|
@@ -3890,6 +4291,7 @@ const GenericReport = ({ setting = {} }) => {
|
|
|
3890
4291
|
{
|
|
3891
4292
|
keyInfo.percentage
|
|
3892
4293
|
}
|
|
4294
|
+
|
|
3893
4295
|
%
|
|
3894
4296
|
</span>
|
|
3895
4297
|
</div>
|
|
@@ -4033,6 +4435,17 @@ const GenericReport = ({ setting = {} }) => {
|
|
|
4033
4435
|
>
|
|
4034
4436
|
Export as Excel
|
|
4035
4437
|
</button>
|
|
4438
|
+
<button
|
|
4439
|
+
className={`${styles.btn} ${styles.btnSecondary}`}
|
|
4440
|
+
onClick={() => handleExportReport('pdf')}
|
|
4441
|
+
disabled={
|
|
4442
|
+
isLoading ||
|
|
4443
|
+
selectedColumns.length === 0 ||
|
|
4444
|
+
!reportName
|
|
4445
|
+
}
|
|
4446
|
+
>
|
|
4447
|
+
Export as PDF
|
|
4448
|
+
</button>
|
|
4036
4449
|
<button
|
|
4037
4450
|
className={`${styles.btn} ${styles.btnPrimary}`}
|
|
4038
4451
|
onClick={handleSaveReport}
|