robobyte-front-builder 1.0.16 → 1.0.19
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/package.json +1 -1
- package/src/lib/providers/RoboByteFrontBuilderProvider.jsx +26 -9
- package/src/pages/_app.js +0 -8
- package/src/pages/reportModule/reportBuilder/index.js +719 -561
- package/src/pages/reportModule/reportBuilder/reportViewer/index.js +135 -80
- package/src/pages/reportModule/reportBuilder/reports/index.js +51 -11
- package/src/pages/reportModule/reportBuilder/reportsPermissions/index.js +127 -0
- package/src/services/helper/multiSelectEditorByBuilder.js +245 -0
- package/src/services/helper/reportSessionHelper.js +83 -0
- package/src/views/genericTable/ColumnConfiguratorDialog.js +762 -0
- package/src/views/genericTable/FormattingSettingsDialog.js +546 -0
- package/src/views/genericTable/ReportSettingsDialog.js +151 -0
- package/src/views/genericTable/SGrid.js +872 -159
- package/src/views/genericTable/TAGGrid.js +83 -69
- package/src/views/genericTable/convertStringFunctions.js +200 -0
- package/src/views/genericTable/updateRefHelpers.js +421 -0
- package/src/views/rolePermissions/UpdateReportPermissionDialog.js +315 -0
|
@@ -8,8 +8,8 @@ import Grid from '@mui/material/Grid'
|
|
|
8
8
|
// ** Icons Imports
|
|
9
9
|
// ** Store Imports
|
|
10
10
|
// ** Custom Components Imports
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
11
|
+
import {useCallback, useContext, useEffect, useMemo, useState} from 'react'
|
|
12
|
+
import {Endpoints, Services} from 'src/services/Endpoints'
|
|
13
13
|
import {
|
|
14
14
|
Autocomplete,
|
|
15
15
|
CircularProgress,
|
|
@@ -21,23 +21,23 @@ import {
|
|
|
21
21
|
TextField,
|
|
22
22
|
Tooltip
|
|
23
23
|
} from '@mui/material'
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
24
|
+
import {AgGridReact} from "ag-grid-react";
|
|
25
|
+
import {Edit, FilterAlt, RefreshOutlined, Save, SaveAs} from "@mui/icons-material";
|
|
26
|
+
import {getRandomInt, Helper} from "services/helper/helper";
|
|
27
27
|
import PostService from 'services/PostService'
|
|
28
28
|
import handleChange from 'services/helper/handleChange'
|
|
29
|
-
import {
|
|
29
|
+
import {DotsVerticalCircleOutline, FileExcelOutline} from 'mdi-material-ui'
|
|
30
30
|
import AddTemplateDialog from './template/addTemplate'
|
|
31
31
|
import UpdateService from 'services/UpdateService'
|
|
32
|
-
import {
|
|
33
|
-
import {
|
|
34
|
-
import {
|
|
32
|
+
import {useRouter} from 'next/router'
|
|
33
|
+
import {SystemContext} from 'context/SystemContext'
|
|
34
|
+
import {AuthContext} from 'context/AuthContext'
|
|
35
35
|
import moment from "moment-timezone"
|
|
36
36
|
import numeral from 'numeral'
|
|
37
37
|
import CustomFilterDialog from "views/customFilter/CustomFilterDialog";
|
|
38
38
|
import CustomStatusBar from "views/genericTable/statusBar/rowCountStatusBar";
|
|
39
39
|
import StreamService from "services/StreamService";
|
|
40
|
-
import {
|
|
40
|
+
import {themeQuartz} from 'ag-grid-community';
|
|
41
41
|
|
|
42
42
|
// ** Utils Import
|
|
43
43
|
|
|
@@ -54,7 +54,7 @@ const TAGGrid = props => {
|
|
|
54
54
|
// ** State
|
|
55
55
|
const agTheme = themeQuartz
|
|
56
56
|
.withParams({
|
|
57
|
-
accentColor: "#
|
|
57
|
+
accentColor: "#FF1185"
|
|
58
58
|
});
|
|
59
59
|
const {
|
|
60
60
|
groupEndPoint,
|
|
@@ -114,16 +114,16 @@ const TAGGrid = props => {
|
|
|
114
114
|
enableRowGroup: false,
|
|
115
115
|
cellRenderer: (params) => {
|
|
116
116
|
if (params.node.group) {
|
|
117
|
-
return <Box sx={{
|
|
117
|
+
return <Box sx={{display: 'flex', alignItems: 'center'}}>
|
|
118
118
|
<IconButton
|
|
119
|
-
sx={{
|
|
119
|
+
sx={{color: 'primary.light'}}
|
|
120
120
|
onClick={() => {
|
|
121
121
|
const groupKeys = getParentKeys(params.node.parent)
|
|
122
122
|
groupKeys.push(params.node.key)
|
|
123
|
-
params.api.refreshServerSide({
|
|
123
|
+
params.api.refreshServerSide({purge: !noPurge, route: groupKeys});
|
|
124
124
|
}}
|
|
125
125
|
>
|
|
126
|
-
<RefreshOutlined
|
|
126
|
+
<RefreshOutlined/>
|
|
127
127
|
</IconButton>
|
|
128
128
|
</Box>
|
|
129
129
|
}
|
|
@@ -257,7 +257,7 @@ const TAGGrid = props => {
|
|
|
257
257
|
afterSelect: true
|
|
258
258
|
}
|
|
259
259
|
}
|
|
260
|
-
const field = isGrouping ? {
|
|
260
|
+
const field = isGrouping ? {path: colId, afterSelect: true} : flatCols.find(f => f.field === colId);
|
|
261
261
|
return {
|
|
262
262
|
columnName: isGrouping ? field.path.replace(".", "_") : field.path,
|
|
263
263
|
sortDirection: sort === 'asc' ? 'Ascending' : 'Descending',
|
|
@@ -318,6 +318,8 @@ const TAGGrid = props => {
|
|
|
318
318
|
const cleanedPath = path.substring(6); // Remove "pivot_"
|
|
319
319
|
resultObject[cleanedPath] = value;
|
|
320
320
|
} else {
|
|
321
|
+
resultObject[path] = value;
|
|
322
|
+
|
|
321
323
|
// Otherwise, split the path and nest it
|
|
322
324
|
const keys = path.split('_');
|
|
323
325
|
let current = resultObject;
|
|
@@ -338,6 +340,22 @@ const TAGGrid = props => {
|
|
|
338
340
|
return resultObject;
|
|
339
341
|
}
|
|
340
342
|
|
|
343
|
+
function returnAdditionalPivotCols(flatCols) {
|
|
344
|
+
const resultFields = new Set();
|
|
345
|
+
|
|
346
|
+
flatCols.forEach(row => {
|
|
347
|
+
Object.keys(row).forEach(key => {
|
|
348
|
+
if (!key.startsWith("pivot_") && key !== "groupCount" && key !== "totalPrice") {
|
|
349
|
+
console.log(key)
|
|
350
|
+
resultFields.add(key);
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
const distinctFields = Array.from(resultFields);
|
|
356
|
+
return distinctFields;
|
|
357
|
+
}
|
|
358
|
+
|
|
341
359
|
const createServerSideDatasource = (getRowsFromApi) => {
|
|
342
360
|
return {
|
|
343
361
|
getRows: (params) => {
|
|
@@ -357,6 +375,7 @@ const TAGGrid = props => {
|
|
|
357
375
|
}
|
|
358
376
|
})
|
|
359
377
|
.catch((e) => {
|
|
378
|
+
|
|
360
379
|
console.log(e)
|
|
361
380
|
params.fail()
|
|
362
381
|
});
|
|
@@ -368,13 +387,11 @@ const TAGGrid = props => {
|
|
|
368
387
|
async params => {
|
|
369
388
|
setFinalRequestObject(defaultFinalRequest)
|
|
370
389
|
const fixedTFilter = externalFilter?.fixedTFilter ?? externalFilter?.fixedTfilter ?? []
|
|
371
|
-
let localFilter = externalFilter ? {
|
|
372
|
-
localFilter = {
|
|
373
|
-
console.log(localFilter)
|
|
390
|
+
let localFilter = externalFilter ? {...externalFilter} : {}
|
|
391
|
+
localFilter = {...localFilter, ...Filter}
|
|
374
392
|
let localTFilter = localFilter?.Tfilter ? [...localFilter?.Tfilter] : []
|
|
375
393
|
localTFilter = localFilter?.TFilter ? [...localTFilter, ...localFilter?.TFilter] : [...localTFilter]
|
|
376
394
|
localTFilter = [...localTFilter, ...fixedTFilter]
|
|
377
|
-
console.log(localTFilter)
|
|
378
395
|
delete localFilter.Tfilter
|
|
379
396
|
delete localFilter.fixedTfilter
|
|
380
397
|
delete localFilter.fixedTFilter
|
|
@@ -419,21 +436,17 @@ const TAGGrid = props => {
|
|
|
419
436
|
// if (rowGroupColsIds.length > 1 && params.request.sortModel.length > 1) {
|
|
420
437
|
// isGroupCountOrder = false;
|
|
421
438
|
// }
|
|
422
|
-
console.log(request.sortModel)
|
|
423
439
|
request.sortModel = (request.sortModel ?? []).map(x => ({
|
|
424
440
|
...x,
|
|
425
441
|
colId: x?.colId?.endsWith("_groupCount")
|
|
426
442
|
? x.colId.replace("_groupCount", "_groupCount")
|
|
427
443
|
: x.colId
|
|
428
444
|
}));
|
|
429
|
-
|
|
430
|
-
console.log(request.sortModel)
|
|
445
|
+
|
|
431
446
|
const aggIds = request.valueCols.map(vc => vc.id);
|
|
432
447
|
|
|
433
448
|
const groupOrderColdIds = request.sortModel.filter(x => groupOrderCols.includes(x.colId) || ((x.colId == "IZ_groupCount" || x.colId.endsWith("groupCount") || aggIds.some(id => x.colId.endsWith(id))) && isGroupCountOrder))
|
|
434
449
|
let orderBy = groupOrderColdIds.map(sort => handleGetSortObject(sort.colId, sort.sort, true, aggIds.some(id => sort.colId.endsWith(id))))
|
|
435
|
-
console.log(groupOrderColdIds)
|
|
436
|
-
console.log(orderBy)
|
|
437
450
|
data = {
|
|
438
451
|
...data,
|
|
439
452
|
tFilter: [...tFilters, ...data.tFilter],
|
|
@@ -461,6 +474,9 @@ const TAGGrid = props => {
|
|
|
461
474
|
pivotColResult.push('groupCount')
|
|
462
475
|
const responsePivotCol = response.pivotCols.map(x => x.field) ?? []
|
|
463
476
|
pivotColResult.push(...responsePivotCol)
|
|
477
|
+
const additionalPivotCols = returnAdditionalPivotCols(response.data)
|
|
478
|
+
// pivotColResult.push(...additionalPivotCols)
|
|
479
|
+
|
|
464
480
|
}
|
|
465
481
|
}
|
|
466
482
|
// groupKeys.push(request.rowGroupCols[request.groupKeys.length].id)
|
|
@@ -534,7 +550,6 @@ const TAGGrid = props => {
|
|
|
534
550
|
if (response.aggregation != null && updateAggregation === true) {
|
|
535
551
|
setPagedAgg([response.aggregation])
|
|
536
552
|
}
|
|
537
|
-
|
|
538
553
|
return {
|
|
539
554
|
success: true,
|
|
540
555
|
rows: colDefs && response.data, // Adjust based on your API's response structure
|
|
@@ -544,7 +559,7 @@ const TAGGrid = props => {
|
|
|
544
559
|
}
|
|
545
560
|
} catch (error) {
|
|
546
561
|
console.log(error)
|
|
547
|
-
return {
|
|
562
|
+
return {success: false}
|
|
548
563
|
}
|
|
549
564
|
},
|
|
550
565
|
[externalFilter, includes, paramsPage, Filter]
|
|
@@ -706,7 +721,6 @@ const TAGGrid = props => {
|
|
|
706
721
|
const cols = gridApi
|
|
707
722
|
.getColumnDefs()
|
|
708
723
|
const flatCols = flattenArray(cols)
|
|
709
|
-
console.log(flatCols)
|
|
710
724
|
const visibleCols = flatCols // all column definitions
|
|
711
725
|
.filter(colDef =>
|
|
712
726
|
gridApi.getColumnState().some(
|
|
@@ -727,10 +741,10 @@ const TAGGrid = props => {
|
|
|
727
741
|
data.pivotCols = []
|
|
728
742
|
}
|
|
729
743
|
response = await StreamService(streamEndPoint, true, data, {
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
744
|
+
...finalRequestObject.params,
|
|
745
|
+
groupBy: finalRequestObject.groupBy,
|
|
746
|
+
getType: 'Stream'
|
|
747
|
+
}, null,
|
|
734
748
|
progress => {
|
|
735
749
|
console.log(`Downloaded: ${progress}%`)
|
|
736
750
|
})
|
|
@@ -750,7 +764,7 @@ const TAGGrid = props => {
|
|
|
750
764
|
applyOrder: true,
|
|
751
765
|
});
|
|
752
766
|
}
|
|
753
|
-
if (selectedTemplate.filterValue != null
|
|
767
|
+
if (selectedTemplate.filterValue != null) {
|
|
754
768
|
setFilter(selectedTemplate.filterValue);
|
|
755
769
|
}
|
|
756
770
|
};
|
|
@@ -765,7 +779,7 @@ const TAGGrid = props => {
|
|
|
765
779
|
useEffect(() => {
|
|
766
780
|
|
|
767
781
|
if (gridApi !== null) {
|
|
768
|
-
gridApi.refreshServerSide({
|
|
782
|
+
gridApi.refreshServerSide({purge: !noPurge})
|
|
769
783
|
}
|
|
770
784
|
}, [refresh, externalFilter, localRefresh, Filter]);
|
|
771
785
|
|
|
@@ -812,12 +826,11 @@ const TAGGrid = props => {
|
|
|
812
826
|
}, [timerValue]); // re-run after each refresh or change in value
|
|
813
827
|
|
|
814
828
|
return (
|
|
815
|
-
<Grid
|
|
816
|
-
<Grid container
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
<Box sx={{ minWidth: '250px' }}>
|
|
829
|
+
<Grid container size={{ xs: 12 }}>
|
|
830
|
+
<Grid container
|
|
831
|
+
sx={{borderTop: '1px solid #ccc', backgroundColor: '#fafafb', justifyContent: 'space-between'}} padding={2} size={{ xs: 12 }}>
|
|
832
|
+
<Box sx={{display: 'flex', minWidth: '250px'}}>
|
|
833
|
+
<Box sx={{minWidth: '250px'}}>
|
|
821
834
|
|
|
822
835
|
<FormControl fullWidth>
|
|
823
836
|
<Autocomplete
|
|
@@ -828,7 +841,6 @@ const TAGGrid = props => {
|
|
|
828
841
|
options={templates}
|
|
829
842
|
onChange={(e, value) => {
|
|
830
843
|
setSelectedTemplate(value)
|
|
831
|
-
|
|
832
844
|
}
|
|
833
845
|
}
|
|
834
846
|
getOptionLabel={option => option.name}
|
|
@@ -846,20 +858,23 @@ const TAGGrid = props => {
|
|
|
846
858
|
</FormControl>
|
|
847
859
|
|
|
848
860
|
</Box>
|
|
849
|
-
<Box sx={{
|
|
861
|
+
<Box sx={{ml: '5px'}}>
|
|
850
862
|
<Tooltip title='مؤقت' placement={'top'}>
|
|
851
863
|
<Select variant={'outlined'} value={timerValue} onChange={(e) => setTimerValue(e.target.value)}
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
<MenuItem key={1} value={0}>
|
|
855
|
-
<MenuItem key={2} value={5}>
|
|
856
|
-
<MenuItem key={
|
|
857
|
-
<MenuItem key={
|
|
864
|
+
defaultValue={0} size={'small'}
|
|
865
|
+
color='primary' sx={{width: '60px'}}>
|
|
866
|
+
<MenuItem key={1} value={0}>No</MenuItem>
|
|
867
|
+
<MenuItem key={2} value={0.5}>30s</MenuItem>
|
|
868
|
+
<MenuItem key={2} value={1}>1m</MenuItem>
|
|
869
|
+
<MenuItem key={2} value={2}>2m</MenuItem>
|
|
870
|
+
<MenuItem key={2} value={5}>5m</MenuItem>
|
|
871
|
+
<MenuItem key={3} value={15}>15m</MenuItem>
|
|
872
|
+
<MenuItem key={4} value={30}>30m</MenuItem>
|
|
858
873
|
</Select>
|
|
859
874
|
</Tooltip>
|
|
860
875
|
</Box>
|
|
861
876
|
</Box>
|
|
862
|
-
<Box sx={{
|
|
877
|
+
<Box sx={{display: 'flex', justifyContent: 'center'}}>
|
|
863
878
|
{streamEndPoint &&
|
|
864
879
|
<Box>
|
|
865
880
|
<Tooltip title='تصدير'>
|
|
@@ -868,7 +883,7 @@ const TAGGrid = props => {
|
|
|
868
883
|
onClick={handleCSVExport}
|
|
869
884
|
color='primary'
|
|
870
885
|
>
|
|
871
|
-
{isDownloading ? <CircularProgress size={24}
|
|
886
|
+
{isDownloading ? <CircularProgress size={24}/> : <FileExcelOutline/>}
|
|
872
887
|
</IconButton>
|
|
873
888
|
</Tooltip>
|
|
874
889
|
</Box>
|
|
@@ -878,7 +893,7 @@ const TAGGrid = props => {
|
|
|
878
893
|
<IconButton disabled={selectedTemplate == null} onClick={() => {
|
|
879
894
|
handleSaveTemplate()
|
|
880
895
|
}} color='primary'>
|
|
881
|
-
<Save
|
|
896
|
+
<Save/>
|
|
882
897
|
</IconButton>
|
|
883
898
|
</Tooltip>
|
|
884
899
|
</Box>
|
|
@@ -888,7 +903,7 @@ const TAGGrid = props => {
|
|
|
888
903
|
setIsTemplateEditing(false)
|
|
889
904
|
handleToggleDialogs('addTemplate')
|
|
890
905
|
}} color='primary'>
|
|
891
|
-
<SaveAs
|
|
906
|
+
<SaveAs/>
|
|
892
907
|
</IconButton>
|
|
893
908
|
</Tooltip>
|
|
894
909
|
</Box>
|
|
@@ -896,39 +911,38 @@ const TAGGrid = props => {
|
|
|
896
911
|
<Box>
|
|
897
912
|
<Tooltip title='تعديل'>
|
|
898
913
|
<IconButton disabled={selectedTemplate == null}
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
914
|
+
onClick={() => {
|
|
915
|
+
setIsTemplateEditing(true)
|
|
916
|
+
handleToggleDialogs('addTemplate')
|
|
917
|
+
}}
|
|
918
|
+
color='primary'
|
|
904
919
|
>
|
|
905
|
-
<Edit
|
|
920
|
+
<Edit/>
|
|
906
921
|
</IconButton>
|
|
907
922
|
</Tooltip>
|
|
908
923
|
</Box>
|
|
909
924
|
<Box>
|
|
910
925
|
<IconButton color={'primary'} onClick={() => handleToggleDialogs('CustomFilter')}>
|
|
911
|
-
<FilterAlt
|
|
926
|
+
<FilterAlt/>
|
|
912
927
|
</IconButton>
|
|
913
928
|
</Box>
|
|
914
929
|
<Box>
|
|
915
930
|
<Tooltip title='اعادة تحميل'>
|
|
916
931
|
<IconButton onClick={() => setLocalRefresh(!localRefresh)}>
|
|
917
|
-
<RefreshOutlined
|
|
932
|
+
<RefreshOutlined/>
|
|
918
933
|
</IconButton>
|
|
919
934
|
</Tooltip>
|
|
920
935
|
</Box>
|
|
921
936
|
|
|
922
937
|
</Box>
|
|
923
938
|
</Grid>
|
|
924
|
-
<div style={{
|
|
939
|
+
<div style={{width: "100%", height: height ?? "70vh", direction: 'ltr'}}>
|
|
925
940
|
<AgGridReact
|
|
926
941
|
debug={false}
|
|
927
942
|
columnHoverHighlight={true}
|
|
928
943
|
theme={agTheme}
|
|
929
944
|
enableRtl={true}
|
|
930
945
|
columnDefs={colDefs}
|
|
931
|
-
stopEditingWhenCellsLoseFocus={true}
|
|
932
946
|
rowModelType={"serverSide"}
|
|
933
947
|
onGridReady={onGridReady}
|
|
934
948
|
// defaultColDef={{
|
|
@@ -969,11 +983,11 @@ const TAGGrid = props => {
|
|
|
969
983
|
pivotKeySeparator={"_"}
|
|
970
984
|
getRowStyle={(row) => {
|
|
971
985
|
if (row.node.group) {
|
|
972
|
-
return {
|
|
986
|
+
return {fontWeight: 'bold'};
|
|
973
987
|
}
|
|
974
988
|
if (expireReport) {
|
|
975
989
|
if (row.node?.data?.expireDate && new Date(row.node.data.expireDate) <= new Date()) {
|
|
976
|
-
return {
|
|
990
|
+
return {background: '#FF625F'};
|
|
977
991
|
}
|
|
978
992
|
if (row.node?.data?.expireDate) {
|
|
979
993
|
const expireDate = new Date(row.node.data.expireDate);
|
|
@@ -981,9 +995,9 @@ const TAGGrid = props => {
|
|
|
981
995
|
const diffInDays = (expireDate - currentDate) / (1000 * 60 * 60 * 24); // Convert milliseconds to days
|
|
982
996
|
|
|
983
997
|
if (diffInDays > 10) {
|
|
984
|
-
return {
|
|
998
|
+
return {background: '#8AFF8A'};
|
|
985
999
|
} else if (diffInDays > 0) {
|
|
986
|
-
return {
|
|
1000
|
+
return {background: '#fcfd74'};
|
|
987
1001
|
}
|
|
988
1002
|
}
|
|
989
1003
|
}
|
|
@@ -999,7 +1013,7 @@ const TAGGrid = props => {
|
|
|
999
1013
|
onSortChanged={params => {
|
|
1000
1014
|
const sm = params.columns;
|
|
1001
1015
|
if (sm.length == 1 && sm.some(s => s.colId === 'IZ_groupCount')) {
|
|
1002
|
-
params.api.refreshServerSide({
|
|
1016
|
+
params.api.refreshServerSide({purge: true})
|
|
1003
1017
|
}
|
|
1004
1018
|
}}
|
|
1005
1019
|
/>
|
|
@@ -1019,7 +1033,7 @@ const TAGGrid = props => {
|
|
|
1019
1033
|
pageName={router.pathname}
|
|
1020
1034
|
item={isTemplateEditing === true ? selectedTemplate : null}
|
|
1021
1035
|
template={gridApi?.getColumnState()}
|
|
1022
|
-
userId={authValues?.user?.id}
|
|
1036
|
+
userId={authValues?.user?.id}/>
|
|
1023
1037
|
</Dialog>
|
|
1024
1038
|
|
|
1025
1039
|
<Dialog
|
|
@@ -1027,7 +1041,7 @@ const TAGGrid = props => {
|
|
|
1027
1041
|
open={openDialogs.CustomFilter && localClasName}
|
|
1028
1042
|
maxWidth='xl'
|
|
1029
1043
|
scroll='body'
|
|
1030
|
-
|
|
1044
|
+
// onClose={() => handleToggleDialogs('CustomFilter')}
|
|
1031
1045
|
>
|
|
1032
1046
|
<CustomFilterDialog
|
|
1033
1047
|
handleToggleDialogs={handleToggleDialogs}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert string-based functions to executable functions
|
|
3
|
+
* Used for extraCols and columnsConfig that come from JSON configuration
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Import helper functions that need to be available in the converted functions
|
|
7
|
+
import {
|
|
8
|
+
setUpdateRefValue,
|
|
9
|
+
setUpdateRefRow,
|
|
10
|
+
getUpdateRefValue,
|
|
11
|
+
hasUpdateRefValue,
|
|
12
|
+
removeUpdateRefByRowId,
|
|
13
|
+
clearUpdateRefRow,
|
|
14
|
+
clearAllUpdateRef,
|
|
15
|
+
cloneUpdateRefToOriginal,
|
|
16
|
+
restoreUpdateRefFromOriginal
|
|
17
|
+
} from './updateRefHelpers'
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Convert a string function to an executable function
|
|
21
|
+
* Injects helper functions into the scope so they're available when the function executes
|
|
22
|
+
* @param {string} funcString - The function as a string
|
|
23
|
+
* @returns {Function|string} The converted function or original string if conversion fails
|
|
24
|
+
*/
|
|
25
|
+
export const convertStringToFunction = (funcString) => {
|
|
26
|
+
if (typeof funcString !== 'string' || !funcString.trim()) {
|
|
27
|
+
return funcString
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
// Check if it looks like a function
|
|
32
|
+
const trimmed = funcString.trim()
|
|
33
|
+
|
|
34
|
+
// Arrow function: (params) => { ... } or (params) => ...
|
|
35
|
+
if (trimmed.startsWith('(') && trimmed.includes('=>')) {
|
|
36
|
+
// Create a wrapper that provides helper functions in scope
|
|
37
|
+
// We wrap the user's function and inject the helpers as local variables
|
|
38
|
+
// eslint-disable-next-line no-new-func
|
|
39
|
+
const wrapper = new Function(
|
|
40
|
+
'setUpdateRefValue',
|
|
41
|
+
'setUpdateRefRow',
|
|
42
|
+
'getUpdateRefValue',
|
|
43
|
+
'hasUpdateRefValue',
|
|
44
|
+
'removeUpdateRefByRowId',
|
|
45
|
+
'clearUpdateRefRow',
|
|
46
|
+
'clearAllUpdateRef',
|
|
47
|
+
'cloneUpdateRefToOriginal',
|
|
48
|
+
'restoreUpdateRefFromOriginal',
|
|
49
|
+
`"use strict";
|
|
50
|
+
const userFunc = ${trimmed};
|
|
51
|
+
return userFunc;`
|
|
52
|
+
)
|
|
53
|
+
return wrapper(setUpdateRefValue, setUpdateRefRow, getUpdateRefValue, hasUpdateRefValue, removeUpdateRefByRowId, clearUpdateRefRow, clearAllUpdateRef, cloneUpdateRefToOriginal, restoreUpdateRefFromOriginal)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Regular function: function(params) { ... }
|
|
57
|
+
if (trimmed.startsWith('function')) {
|
|
58
|
+
// Create a wrapper that provides helper functions in scope
|
|
59
|
+
// eslint-disable-next-line no-new-func
|
|
60
|
+
const wrapper = new Function(
|
|
61
|
+
'setUpdateRefValue',
|
|
62
|
+
'setUpdateRefRow',
|
|
63
|
+
'getUpdateRefValue',
|
|
64
|
+
'hasUpdateRefValue',
|
|
65
|
+
'removeUpdateRefByRowId',
|
|
66
|
+
'clearUpdateRefRow',
|
|
67
|
+
'clearAllUpdateRef',
|
|
68
|
+
'cloneUpdateRefToOriginal',
|
|
69
|
+
'restoreUpdateRefFromOriginal',
|
|
70
|
+
`"use strict";
|
|
71
|
+
const userFunc = ${trimmed};
|
|
72
|
+
return userFunc;`
|
|
73
|
+
)
|
|
74
|
+
return wrapper(setUpdateRefValue, setUpdateRefRow, getUpdateRefValue, hasUpdateRefValue, removeUpdateRefByRowId, clearUpdateRefRow, clearAllUpdateRef, cloneUpdateRefToOriginal, restoreUpdateRefFromOriginal)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Expression function (old AG Grid style): return params.value
|
|
78
|
+
if (trimmed.startsWith('return ')) {
|
|
79
|
+
// For expression functions, wrap in a function with helpers available
|
|
80
|
+
// eslint-disable-next-line no-new-func
|
|
81
|
+
const wrapper = new Function(
|
|
82
|
+
'setUpdateRefValue',
|
|
83
|
+
'setUpdateRefRow',
|
|
84
|
+
'getUpdateRefValue',
|
|
85
|
+
'hasUpdateRefValue',
|
|
86
|
+
'removeUpdateRefByRowId',
|
|
87
|
+
'clearUpdateRefRow',
|
|
88
|
+
'clearAllUpdateRef',
|
|
89
|
+
'cloneUpdateRefToOriginal',
|
|
90
|
+
'restoreUpdateRefFromOriginal',
|
|
91
|
+
`"use strict";
|
|
92
|
+
return function(params) {
|
|
93
|
+
${trimmed}
|
|
94
|
+
};`
|
|
95
|
+
)
|
|
96
|
+
return wrapper(setUpdateRefValue, setUpdateRefRow, getUpdateRefValue, hasUpdateRefValue, removeUpdateRefByRowId, clearUpdateRefRow, clearAllUpdateRef, cloneUpdateRefToOriginal, restoreUpdateRefFromOriginal)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// If not a function format, return as is
|
|
100
|
+
return funcString
|
|
101
|
+
} catch (e) {
|
|
102
|
+
console.error('Failed to convert string to function:', e)
|
|
103
|
+
console.error('Function string:', funcString)
|
|
104
|
+
console.error('Stack:', e.stack)
|
|
105
|
+
return funcString
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Process a column definition and convert all string functions to executable functions
|
|
111
|
+
* @param {object} colDef - The column definition object
|
|
112
|
+
* @returns {object} The processed column definition with converted functions
|
|
113
|
+
*/
|
|
114
|
+
export const processColumnDefinition = (colDef) => {
|
|
115
|
+
if (!colDef || typeof colDef !== 'object') {
|
|
116
|
+
return colDef
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const processed = {...colDef}
|
|
120
|
+
|
|
121
|
+
// List of AG Grid properties that should be functions
|
|
122
|
+
const functionProperties = [
|
|
123
|
+
'valueSetter',
|
|
124
|
+
'valueGetter',
|
|
125
|
+
'valueFormatter',
|
|
126
|
+
'valueParser',
|
|
127
|
+
'cellRenderer',
|
|
128
|
+
'cellEditor',
|
|
129
|
+
'cellClass',
|
|
130
|
+
'cellStyle',
|
|
131
|
+
'editable',
|
|
132
|
+
'comparator',
|
|
133
|
+
'equals',
|
|
134
|
+
'keyCreator',
|
|
135
|
+
'filterValueGetter',
|
|
136
|
+
'filterParams',
|
|
137
|
+
'cellEditorParams',
|
|
138
|
+
'cellRendererParams',
|
|
139
|
+
'headerValueGetter',
|
|
140
|
+
'tooltipValueGetter',
|
|
141
|
+
'aggFunc',
|
|
142
|
+
'getQuickFilterText',
|
|
143
|
+
'suppressKeyboardEvent',
|
|
144
|
+
'suppressPaste',
|
|
145
|
+
'cellClassRules'
|
|
146
|
+
]
|
|
147
|
+
|
|
148
|
+
functionProperties.forEach(prop => {
|
|
149
|
+
if (prop in processed && typeof processed[prop] === 'string') {
|
|
150
|
+
const converted = convertStringToFunction(processed[prop])
|
|
151
|
+
if (converted !== processed[prop]) {
|
|
152
|
+
processed[prop] = converted
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
// Special handling for cellEditorParams - can be a function or object
|
|
158
|
+
if ('cellEditorParams' in processed) {
|
|
159
|
+
if (typeof processed.cellEditorParams === 'string') {
|
|
160
|
+
processed.cellEditorParams = convertStringToFunction(processed.cellEditorParams)
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return processed
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Process an array of column definitions
|
|
169
|
+
* @param {array} colDefs - Array of column definitions
|
|
170
|
+
* @returns {array} Processed column definitions
|
|
171
|
+
*/
|
|
172
|
+
export const processColumnDefinitions = (colDefs) => {
|
|
173
|
+
if (!Array.isArray(colDefs)) {
|
|
174
|
+
return colDefs
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return colDefs.map(colDef => processColumnDefinition(colDef))
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Process columnsConfig array (field + config format)
|
|
182
|
+
* @param {array} columnsConfig - Array of column configs [{field, config}]
|
|
183
|
+
* @returns {array} Processed column configs
|
|
184
|
+
*/
|
|
185
|
+
export const processColumnsConfig = (columnsConfig) => {
|
|
186
|
+
if (!Array.isArray(columnsConfig)) {
|
|
187
|
+
return columnsConfig
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return columnsConfig.map(item => {
|
|
191
|
+
if (!item || !item.config) {
|
|
192
|
+
return item
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return {
|
|
196
|
+
...item,
|
|
197
|
+
config: processColumnDefinition(item.config)
|
|
198
|
+
}
|
|
199
|
+
})
|
|
200
|
+
}
|