robobyte-front-builder 1.0.17 → 1.0.21
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 +211 -0
- package/next.config.js +19 -48
- package/package.json +39 -85
- package/src/context/BuilderContext.jsx +134 -6
- package/src/context/SystemContext.js +2 -2
- package/src/hooks/useGlobalStore.js +36 -0
- package/src/hooks/useTimerEngine.js +54 -0
- package/src/lib/index.js +11 -3
- package/src/lib/layouts/BlankLayout.jsx +13 -0
- package/src/lib/providers/RoboByteFrontBuilderProvider.jsx +59 -1
- package/src/lib/themes/builderTheme.js +41 -0
- package/src/pages/_app.js +32 -134
- package/src/pages/api/ai.js +87 -0
- package/src/pages/builders/report/index.js +1 -0
- package/src/pages/builders/report/list/index.js +1 -0
- package/src/pages/builders/report/viewer/index.js +1 -0
- package/src/pages/index.js +88 -37
- package/src/pages/printBuilder/index.jsx +263 -0
- package/src/pages/printBuilder/layouts/index.jsx +298 -0
- package/src/pages/reportModule/reportBuilder/index.js +723 -563
- package/src/pages/reportModule/reportBuilder/reportViewer/index.js +137 -71
- package/src/pages/reportModule/reportBuilder/reports/index.js +51 -13
- package/src/pages/reportModule/reportBuilder/reportsPermissions/index.js +126 -0
- package/src/pages/viewBuilder/index.jsx +117 -32
- package/src/pages/viewBuilder/views/index.js +3 -3
- package/src/pages/viewer/[id]/index.js +2 -1
- package/src/services/DeleteService.js +31 -60
- package/src/services/Endpoints/PrintLayoutEndpoints.js +42 -0
- package/src/services/Endpoints.js +2 -0
- package/src/services/GetService.js +33 -54
- package/src/services/PatchService.js +38 -65
- package/src/services/PostService.js +37 -63
- package/src/services/UpdateService.js +39 -65
- package/src/services/builderHelper/actionExecutor.js +141 -25
- package/src/services/builderHelper/builderHelper.js +92 -0
- package/src/services/builderHelper/colorSchema.js +95 -0
- package/src/services/builderHelper/iconResolver.js +50 -0
- package/src/services/builderHelper/jsExecutor.js +212 -46
- package/src/services/builderHelper/nodeFactory.js +32 -15
- package/src/services/builderHelper/numberFormat.js +123 -0
- package/src/services/builderHelper/resolveProps.js +73 -4
- package/src/services/builderHelper/thresholdEngine.js +77 -0
- package/src/services/builderHelper/tree.js +31 -0
- package/src/services/components/agGridAutoComplete.js +5 -9
- package/src/services/config.js +9 -1
- package/src/services/globalStore.js +80 -0
- package/src/services/helper/multiSelectEditor.js +5 -9
- package/src/services/helper/multiSelectEditorByBuilder.js +241 -0
- package/src/services/helper/reportSessionHelper.js +83 -0
- package/src/services/reportData/fetchReportData.js +69 -28
- package/src/services/routerRef.js +35 -0
- package/src/views/ConfirmDialog.js +2 -2
- package/src/views/builder/JSEditor.js +105 -107
- package/src/views/builder/inspector/Inspector.jsx +6 -9
- package/src/views/builder/inspector/Tabs/ComponentActionsTab.jsx +7 -13
- package/src/views/builder/inspector/Tabs/MainTab.jsx +143 -25
- package/src/views/builder/inspector/Tabs/RulesTab.jsx +9 -24
- package/src/views/builder/inspector/Tabs/StyleTab.jsx +9 -24
- package/src/views/builder/inspector/definitions/autocomplete/main.js +4 -6
- package/src/views/builder/inspector/definitions/banner/actions.js +7 -0
- package/src/views/builder/inspector/definitions/banner/main.js +22 -0
- package/src/views/builder/inspector/definitions/banner/rules.js +1 -0
- package/src/views/builder/inspector/definitions/banner/style.js +1 -0
- package/src/views/builder/inspector/definitions/breadcrumb/main.js +43 -6
- package/src/views/builder/inspector/definitions/button/main.js +11 -12
- package/src/views/builder/inspector/definitions/button/style.js +18 -30
- package/src/views/builder/inspector/definitions/checkbox/actions.js +3 -1
- package/src/views/builder/inspector/definitions/checkbox/main.js +4 -6
- package/src/views/builder/inspector/definitions/common/main.js +13 -2
- package/src/views/builder/inspector/definitions/dataGrid/main.js +23 -0
- package/src/views/builder/inspector/definitions/dataTableViewer/main.js +46 -0
- package/src/views/builder/inspector/definitions/datepicker/actions.js +3 -1
- package/src/views/builder/inspector/definitions/datepicker/main.js +6 -14
- package/src/views/builder/inspector/definitions/dialog/main.js +36 -0
- package/src/views/builder/inspector/definitions/dropdown/main.js +5 -8
- package/src/views/builder/inspector/definitions/excelUpload/actions.js +23 -0
- package/src/views/builder/inspector/definitions/excelUpload/main.js +17 -0
- package/src/views/builder/inspector/definitions/excelUpload/rules.js +1 -0
- package/src/views/builder/inspector/definitions/excelUpload/style.js +45 -0
- package/src/views/builder/inspector/definitions/header/main.js +10 -1
- package/src/views/builder/inspector/definitions/index.js +106 -19
- package/src/views/builder/inspector/definitions/input/actions.js +4 -1
- package/src/views/builder/inspector/definitions/input/main.js +20 -11
- package/src/views/builder/inspector/definitions/kpi/avatarGroup.js +22 -0
- package/src/views/builder/inspector/definitions/kpi/badge.js +17 -0
- package/src/views/builder/inspector/definitions/kpi/bulletChart.js +47 -0
- package/src/views/builder/inspector/definitions/kpi/chart.js +55 -0
- package/src/views/builder/inspector/definitions/kpi/colorScale.js +60 -0
- package/src/views/builder/inspector/definitions/kpi/comparisonBars.js +41 -0
- package/src/views/builder/inspector/definitions/kpi/countdown.js +46 -0
- package/src/views/builder/inspector/definitions/kpi/donut.js +51 -0
- package/src/views/builder/inspector/definitions/kpi/funnel.js +25 -0
- package/src/views/builder/inspector/definitions/kpi/gauge.js +39 -0
- package/src/views/builder/inspector/definitions/kpi/heatmapGrid.js +96 -0
- package/src/views/builder/inspector/definitions/kpi/iconBox.js +20 -0
- package/src/views/builder/inspector/definitions/kpi/metric.js +45 -0
- package/src/views/builder/inspector/definitions/kpi/rating.js +27 -0
- package/src/views/builder/inspector/definitions/kpi/statusDot.js +18 -0
- package/src/views/builder/inspector/definitions/kpi/stepStage.js +65 -0
- package/src/views/builder/inspector/definitions/kpi/tagList.js +32 -0
- package/src/views/builder/inspector/definitions/kpi/timeline.js +80 -0
- package/src/views/builder/inspector/definitions/kpi/trend.js +20 -0
- package/src/views/builder/inspector/definitions/label/main.js +10 -1
- package/src/views/builder/inspector/definitions/layout/main.js +27 -3
- package/src/views/builder/inspector/definitions/number/main.js +6 -14
- package/src/views/builder/inspector/definitions/pageNumber/main.js +21 -0
- package/src/views/builder/inspector/definitions/popover/main.js +71 -0
- package/src/views/builder/inspector/definitions/radio/main.js +5 -8
- package/src/views/builder/inspector/definitions/repeater/main.js +31 -0
- package/src/views/builder/inspector/definitions/reportViewer/main.js +15 -1
- package/src/views/builder/inspector/definitions/richtext/main.js +5 -8
- package/src/views/builder/inspector/definitions/signature/main.js +4 -1
- package/src/views/builder/inspector/definitions/tag/main.js +5 -8
- package/src/views/builder/inspector/definitions/textarea/actions.js +4 -1
- package/src/views/builder/inspector/definitions/textarea/main.js +5 -7
- package/src/views/builder/inspector/definitions/time/main.js +5 -8
- package/src/views/builder/inspector/definitions/toggle/main.js +5 -19
- package/src/views/builder/inspector/definitions/treeView/main.js +61 -0
- package/src/views/builder/inspector/definitions/viewRenderer/main.js +53 -0
- package/src/views/builder/inspector/definitions/wizard/main.js +68 -0
- package/src/views/builder/inspector/definitions/wizard-step/main.js +25 -0
- package/src/views/builder/inspector/fields/ActionsConfigEditor.jsx +426 -0
- package/src/views/builder/inspector/fields/ColorSchemaField.jsx +140 -0
- package/src/views/builder/inspector/fields/ColumnFunctionEditor.jsx +238 -0
- package/src/views/builder/inspector/fields/ColumnMappingEditor.jsx +105 -0
- package/src/views/builder/inspector/fields/ColumnsConfigEditor.jsx +506 -0
- package/src/views/builder/inspector/fields/DonutRingsEditorField.jsx +337 -0
- package/src/views/builder/inspector/fields/ExtraColsEditor.jsx +618 -0
- package/src/views/builder/inspector/fields/FunctionHelpPopover.jsx +295 -0
- package/src/views/builder/inspector/fields/IconEditor.jsx +64 -0
- package/src/views/builder/inspector/fields/KpiActionField.jsx +223 -0
- package/src/views/builder/inspector/fields/MarkersEditorField.jsx +173 -0
- package/src/views/builder/inspector/fields/SelectEditor.jsx +9 -5
- package/src/views/builder/inspector/fields/SeriesEditorField.jsx +363 -0
- package/src/views/builder/inspector/fields/TableColumnsEditor.jsx +104 -0
- package/src/views/builder/inspector/fields/ThresholdsEditor.jsx +247 -0
- package/src/views/builder/inspector/fields/ValueFunctionsRefPanel.jsx +217 -0
- package/src/views/builder/inspector/fields/columnEditorShared.jsx +217 -0
- package/src/views/builder/sidebar/Sidebar.jsx +4 -2
- package/src/views/builder/sidebar/SidebarTabs.jsx +28 -17
- package/src/views/builder/sidebar/tabs/ActionsTab.jsx +7 -3
- package/src/views/builder/sidebar/tabs/AiTab/AiPreviewDialog.jsx +193 -0
- package/src/views/builder/sidebar/tabs/AiTab/aiProvider.js +49 -0
- package/src/views/builder/sidebar/tabs/AiTab/index.jsx +409 -0
- package/src/views/builder/sidebar/tabs/AiTab/schemaTransformer.js +102 -0
- package/src/views/builder/sidebar/tabs/AiTab/schemaValidator.js +64 -0
- package/src/views/builder/sidebar/tabs/AiTab/systemPrompt.js +1151 -0
- package/src/views/builder/sidebar/tabs/Components/ComponentsTab.jsx +31 -31
- package/src/views/builder/sidebar/tabs/Components/componentCatalog.js +43 -21
- package/src/views/builder/sidebar/tabs/Components/printComponentCatalog.js +81 -0
- package/src/views/builder/sidebar/tabs/TimersTab.jsx +338 -0
- package/src/views/builder/sidebar/tabs/TreeTab.jsx +13 -4
- package/src/views/builder/sidebar/tabs/ViewTab.jsx +1 -1
- package/src/views/builder/viewer/AdornedLabel.jsx +82 -0
- package/src/views/builder/viewer/ComponentRenderer.jsx +98 -24
- package/src/views/builder/viewer/DialogsZone.jsx +259 -0
- package/src/views/builder/viewer/FieldLabel.jsx +106 -0
- package/src/views/builder/viewer/PrintDialog.jsx +481 -0
- package/src/views/builder/viewer/ProductionViewer.jsx +80 -5
- package/src/views/builder/viewer/Viewer.jsx +106 -8
- package/src/views/builder/viewer/ViewerComponentWrapper.jsx +61 -4
- package/src/views/builder/viewer/ViewerToolbar.jsx +273 -59
- package/src/views/builder/viewer/renderers/AutoCompleteRenderer.jsx +26 -22
- package/src/views/builder/viewer/renderers/AvatarGroupRenderer.jsx +112 -0
- package/src/views/builder/viewer/renderers/BadgeRenderer.jsx +79 -0
- package/src/views/builder/viewer/renderers/BannerRenderer.jsx +62 -0
- package/src/views/builder/viewer/renderers/BreadcrumbRenderer.jsx +203 -15
- package/src/views/builder/viewer/renderers/BulletChartRenderer.jsx +147 -0
- package/src/views/builder/viewer/renderers/ButtonRenderer.jsx +98 -39
- package/src/views/builder/viewer/renderers/CardRenderer.jsx +1 -1
- package/src/views/builder/viewer/renderers/ChartRenderer.jsx +388 -0
- package/src/views/builder/viewer/renderers/CheckboxRenderer.jsx +17 -9
- package/src/views/builder/viewer/renderers/ColorScaleRenderer.jsx +300 -0
- package/src/views/builder/viewer/renderers/ComparisonBarsRenderer.jsx +133 -0
- package/src/views/builder/viewer/renderers/ContainerRenderer.jsx +3 -1
- package/src/views/builder/viewer/renderers/CountdownRenderer.jsx +249 -0
- package/src/views/builder/viewer/renderers/DataGridRenderer.jsx +380 -0
- package/src/views/builder/viewer/renderers/DataTableViewerRenderer.jsx +240 -0
- package/src/views/builder/viewer/renderers/DatePickerRenderer.jsx +25 -24
- package/src/views/builder/viewer/renderers/DialogRenderer.jsx +327 -0
- package/src/views/builder/viewer/renderers/DividerRenderer.jsx +1 -1
- package/src/views/builder/viewer/renderers/DonutRenderer.jsx +294 -0
- package/src/views/builder/viewer/renderers/DropdownRenderer.jsx +36 -44
- package/src/views/builder/viewer/renderers/ExcelUploadRenderer.jsx +639 -0
- package/src/views/builder/viewer/renderers/FunnelRenderer.jsx +93 -0
- package/src/views/builder/viewer/renderers/GaugeRenderer.jsx +159 -0
- package/src/views/builder/viewer/renderers/HeaderRenderer.jsx +31 -9
- package/src/views/builder/viewer/renderers/HeatmapGridRenderer.jsx +432 -0
- package/src/views/builder/viewer/renderers/IconBoxRenderer.jsx +59 -0
- package/src/views/builder/viewer/renderers/ImageRenderer.jsx +1 -1
- package/src/views/builder/viewer/renderers/InputRenderer.jsx +75 -18
- package/src/views/builder/viewer/renderers/LabelRenderer.jsx +35 -9
- package/src/views/builder/viewer/renderers/LayoutCellRenderer.jsx +102 -40
- package/src/views/builder/viewer/renderers/LayoutContextMenu.jsx +8 -8
- package/src/views/builder/viewer/renderers/LayoutRenderer.jsx +48 -6
- package/src/views/builder/viewer/renderers/LinkRenderer.jsx +1 -1
- package/src/views/builder/viewer/renderers/MenuRenderer.jsx +2 -2
- package/src/views/builder/viewer/renderers/MetricRenderer.jsx +80 -0
- package/src/views/builder/viewer/renderers/NumberFormatRenderer.jsx +21 -30
- package/src/views/builder/viewer/renderers/PageNumberRenderer.jsx +76 -0
- package/src/views/builder/viewer/renderers/PopoverRenderer.jsx +350 -0
- package/src/views/builder/viewer/renderers/ProgressCircleRenderer.jsx +1 -1
- package/src/views/builder/viewer/renderers/ProgressLineRenderer.jsx +1 -1
- package/src/views/builder/viewer/renderers/RadioGroupRenderer.jsx +28 -39
- package/src/views/builder/viewer/renderers/RatingRenderer.jsx +80 -0
- package/src/views/builder/viewer/renderers/RepeaterRenderer.jsx +297 -38
- package/src/views/builder/viewer/renderers/ReportViewerRenderer.jsx +219 -5
- package/src/views/builder/viewer/renderers/RichTextRenderer.jsx +60 -66
- package/src/views/builder/viewer/renderers/RowActionsCell.jsx +308 -0
- package/src/views/builder/viewer/renderers/SignatureRenderer.jsx +33 -62
- package/src/views/builder/viewer/renderers/StatusDotRenderer.jsx +75 -0
- package/src/views/builder/viewer/renderers/StepStageRenderer.jsx +348 -0
- package/src/views/builder/viewer/renderers/TagListRenderer.jsx +115 -0
- package/src/views/builder/viewer/renderers/TagPickerRenderer.jsx +31 -45
- package/src/views/builder/viewer/renderers/TextAreaRenderer.jsx +25 -18
- package/src/views/builder/viewer/renderers/TextRenderer.jsx +7 -1
- package/src/views/builder/viewer/renderers/TimePickerRenderer.jsx +25 -24
- package/src/views/builder/viewer/renderers/TimelineRenderer.jsx +525 -0
- package/src/views/builder/viewer/renderers/ToggleRenderer.jsx +21 -27
- package/src/views/builder/viewer/renderers/TreeViewRenderer.jsx +832 -0
- package/src/views/builder/viewer/renderers/TrendRenderer.jsx +66 -0
- package/src/views/builder/viewer/renderers/ViewRendererRenderer.jsx +315 -0
- package/src/views/builder/viewer/renderers/WizardRenderer.jsx +380 -64
- package/src/views/builder/viewer/renderers/WizardStepRenderer.jsx +21 -12
- package/src/views/builder/viewer/renderers/dataGridComponents.jsx +824 -0
- package/src/views/customFilter/CustomFilterDialog.js +1023 -660
- package/src/views/customFilter/FixedFilterDialog.js +649 -0
- package/src/views/customFilter/SearchFilterDialog.js +248 -0
- package/src/views/genericTable/BuilderExpressionParams.js +3 -3
- package/src/views/genericTable/ColumnConfiguratorDialog.js +771 -0
- package/src/views/genericTable/FixedFilterDialog.js +3 -2
- package/src/views/genericTable/FormattingSettingsDialog.js +551 -0
- package/src/views/genericTable/ReportSettingsDialog.js +151 -0
- package/src/views/genericTable/SGrid.js +1061 -247
- package/src/views/genericTable/SearchFilterDialog.js +3 -2
- package/src/views/genericTable/TAGGrid.js +83 -69
- package/src/views/genericTable/cellEditors/autocompleteEditor.js +5 -9
- package/src/views/genericTable/convertStringFunctions.js +336 -0
- package/src/views/genericTable/statusBar/rowCountStatusBar.js +3 -1
- package/src/views/genericTable/updateRefHelpers.js +424 -0
- package/src/views/printBuilder/PrintBuilderViewer.jsx +607 -0
- package/src/views/printBuilder/PrintPreviewCanvas.jsx +157 -0
- package/src/views/rolePermissions/UpdateReportPermissionDialog.js +316 -0
- package/src/@core/components/auth/AclGuard.js +0 -55
- package/src/@core/components/auth/AuthGuard.js +0 -40
- package/src/@core/components/auth/GuestGuard.js +0 -30
- package/src/@core/components/custom-inputs/Horizontal.jsx +0 -143
- package/src/@core/components/custom-inputs/Image.jsx +0 -78
- package/src/@core/components/custom-inputs/Vertical.jsx +0 -113
- package/src/@core/components/customizer/index.jsx +0 -470
- package/src/@core/components/customizer/styles.module.css +0 -169
- package/src/@core/components/mui/Avatar.jsx +0 -41
- package/src/@core/components/mui/Badge.jsx +0 -20
- package/src/@core/components/mui/IconButton.jsx +0 -74
- package/src/@core/components/mui/TabList.jsx +0 -60
- package/src/@core/components/option-menu/index.jsx +0 -137
- package/src/@core/components/scroll-to-top/index.jsx +0 -43
- package/src/@core/components/spinner/index.js +0 -26
- package/src/@core/components/window-wrapper/index.js +0 -27
- package/src/@core/contexts/settingsContext.jsx +0 -98
- package/src/@core/hooks/useBgColor.js +0 -63
- package/src/@core/hooks/useImageVariant.js +0 -27
- package/src/@core/hooks/useLayoutInit.js +0 -37
- package/src/@core/hooks/useObjectCookie.js +0 -18
- package/src/@core/hooks/useSettings.jsx +0 -15
- package/src/@core/layouts/BlankLayout.js +0 -37
- package/src/@core/layouts/BlankLayoutWithAppBar.js +0 -51
- package/src/@core/layouts/HorizontalLayout.jsx +0 -151
- package/src/@core/layouts/Layout.js +0 -39
- package/src/@core/layouts/VerticalLayout.jsx +0 -124
- package/src/@core/layouts/components/blank-layout-with-appBar/index.js +0 -115
- package/src/@core/layouts/components/horizontal/app-bar-content/index.js +0 -67
- package/src/@core/layouts/components/horizontal/navigation/HorizontalNavGroup.js +0 -352
- package/src/@core/layouts/components/horizontal/navigation/HorizontalNavItems.js +0 -21
- package/src/@core/layouts/components/horizontal/navigation/HorizontalNavLink.js +0 -195
- package/src/@core/layouts/components/horizontal/navigation/index.js +0 -31
- package/src/@core/layouts/components/shared-components/LanguageDropdown.js +0 -96
- package/src/@core/layouts/components/shared-components/ModeToggler.js +0 -32
- package/src/@core/layouts/components/shared-components/NotificationDropdown.js +0 -226
- package/src/@core/layouts/components/shared-components/UserDropdown.js +0 -177
- package/src/@core/layouts/components/shared-components/footer/FooterContent.js +0 -46
- package/src/@core/layouts/components/shared-components/footer/index.js +0 -61
- package/src/@core/layouts/components/vertical/appBar/index.js +0 -74
- package/src/@core/layouts/components/vertical/navigation/Drawer.js +0 -122
- package/src/@core/layouts/components/vertical/navigation/VerticalNavGroup.js +0 -435
- package/src/@core/layouts/components/vertical/navigation/VerticalNavHeader.js +0 -180
- package/src/@core/layouts/components/vertical/navigation/VerticalNavItems.js +0 -26
- package/src/@core/layouts/components/vertical/navigation/VerticalNavLink.js +0 -258
- package/src/@core/layouts/components/vertical/navigation/VerticalNavSectionTitle.js +0 -102
- package/src/@core/layouts/components/vertical/navigation/index.js +0 -169
- package/src/@core/layouts/utils.js +0 -69
- package/src/@core/styles/Table.module.css +0 -93
- package/src/@core/styles/horizontal/menuItemStyles.js +0 -100
- package/src/@core/styles/horizontal/menuRootStyles.js +0 -19
- package/src/@core/styles/libs/fullcalendar/index.js +0 -461
- package/src/@core/styles/libs/keen-slider/index.js +0 -111
- package/src/@core/styles/libs/react-apexcharts/index.js +0 -107
- package/src/@core/styles/libs/react-cleave/index.js +0 -33
- package/src/@core/styles/libs/react-credit-cards/index.js +0 -11
- package/src/@core/styles/libs/react-datepicker/index.js +0 -388
- package/src/@core/styles/libs/react-draft-wysiwyg/index.js +0 -144
- package/src/@core/styles/libs/react-dropzone/index.js +0 -76
- package/src/@core/styles/libs/react-hot-toast/index.js +0 -37
- package/src/@core/styles/libs/recharts/index.js +0 -47
- package/src/@core/styles/stepper.js +0 -103
- package/src/@core/styles/vertical/menuItemStyles.js +0 -138
- package/src/@core/styles/vertical/menuSectionStyles.js +0 -54
- package/src/@core/styles/vertical/navigationCustomStyles.js +0 -62
- package/src/@core/svg/ContentCompact.jsx +0 -17
- package/src/@core/svg/ContentWide.jsx +0 -17
- package/src/@core/svg/DirectionLtr.jsx +0 -93
- package/src/@core/svg/DirectionRtl.jsx +0 -93
- package/src/@core/svg/LayoutCollapsed.jsx +0 -59
- package/src/@core/svg/LayoutHorizontal.jsx +0 -42
- package/src/@core/svg/LayoutVertical.jsx +0 -59
- package/src/@core/svg/Logo.jsx +0 -76
- package/src/@core/svg/SkinBordered.jsx +0 -54
- package/src/@core/svg/SkinDefault.jsx +0 -59
- package/src/@core/tailwind/plugin.js +0 -78
- package/src/@core/theme/ThemeComponent.js +0 -63
- package/src/@core/theme/ThemeOptions.js +0 -71
- package/src/@core/theme/breakpoints/index.js +0 -11
- package/src/@core/theme/colorSchemes.js +0 -326
- package/src/@core/theme/customShadows.js +0 -11
- package/src/@core/theme/globalStyles.js +0 -81
- package/src/@core/theme/index.js +0 -42
- package/src/@core/theme/overrides/accordion.js +0 -51
- package/src/@core/theme/overrides/accordion.jsx +0 -85
- package/src/@core/theme/overrides/alerts.js +0 -110
- package/src/@core/theme/overrides/alerts.jsx +0 -180
- package/src/@core/theme/overrides/autocomplete.js +0 -14
- package/src/@core/theme/overrides/autocomplete.jsx +0 -68
- package/src/@core/theme/overrides/avatar.js +0 -38
- package/src/@core/theme/overrides/avatars.js +0 -27
- package/src/@core/theme/overrides/backdrop.js +0 -22
- package/src/@core/theme/overrides/badges.js +0 -16
- package/src/@core/theme/overrides/breadcrumbs.js +0 -11
- package/src/@core/theme/overrides/button-group.js +0 -84
- package/src/@core/theme/overrides/button.js +0 -93
- package/src/@core/theme/overrides/buttonGroup.js +0 -9
- package/src/@core/theme/overrides/card.js +0 -83
- package/src/@core/theme/overrides/checkbox.jsx +0 -95
- package/src/@core/theme/overrides/chip.js +0 -72
- package/src/@core/theme/overrides/dataGrid.js +0 -114
- package/src/@core/theme/overrides/dateTimePicker.js +0 -65
- package/src/@core/theme/overrides/dialog.js +0 -120
- package/src/@core/theme/overrides/divider.js +0 -13
- package/src/@core/theme/overrides/drawer.js +0 -20
- package/src/@core/theme/overrides/fab.js +0 -13
- package/src/@core/theme/overrides/form-control-label.js +0 -19
- package/src/@core/theme/overrides/icon-button.js +0 -145
- package/src/@core/theme/overrides/index.js +0 -103
- package/src/@core/theme/overrides/input.js +0 -72
- package/src/@core/theme/overrides/link.js +0 -9
- package/src/@core/theme/overrides/list.js +0 -44
- package/src/@core/theme/overrides/menu.js +0 -25
- package/src/@core/theme/overrides/pagination.js +0 -41
- package/src/@core/theme/overrides/paper.js +0 -9
- package/src/@core/theme/overrides/popover.js +0 -16
- package/src/@core/theme/overrides/progress.js +0 -38
- package/src/@core/theme/overrides/radio.jsx +0 -80
- package/src/@core/theme/overrides/rating.js +0 -16
- package/src/@core/theme/overrides/rating.jsx +0 -32
- package/src/@core/theme/overrides/select.js +0 -19
- package/src/@core/theme/overrides/select.jsx +0 -52
- package/src/@core/theme/overrides/slider.js +0 -97
- package/src/@core/theme/overrides/snackbar.js +0 -19
- package/src/@core/theme/overrides/switch.js +0 -73
- package/src/@core/theme/overrides/switches.js +0 -25
- package/src/@core/theme/overrides/table-pagination.js +0 -39
- package/src/@core/theme/overrides/table.js +0 -81
- package/src/@core/theme/overrides/tabs.js +0 -30
- package/src/@core/theme/overrides/timeline.js +0 -80
- package/src/@core/theme/overrides/toggle-button.js +0 -33
- package/src/@core/theme/overrides/toggleButton.js +0 -16
- package/src/@core/theme/overrides/tooltip.js +0 -21
- package/src/@core/theme/overrides/typography.js +0 -13
- package/src/@core/theme/palette/index.js +0 -107
- package/src/@core/theme/shadows/index.js +0 -61
- package/src/@core/theme/shadows.js +0 -12
- package/src/@core/theme/spacing/index.js +0 -3
- package/src/@core/theme/spacing.js +0 -5
- package/src/@core/theme/typography/index.js +0 -65
- package/src/@core/theme/typography.js +0 -84
- package/src/@core/utils/create-emotion-cache.js +0 -5
- package/src/@core/utils/hex-to-rgba.js +0 -11
- package/src/@core/utils/serverHelpers.js +0 -45
- package/src/@menu/components/RouterLink.jsx +0 -18
- package/src/@menu/components/horizontal-menu/HorizontalNav.jsx +0 -88
- package/src/@menu/components/horizontal-menu/Menu.jsx +0 -83
- package/src/@menu/components/horizontal-menu/MenuButton.jsx +0 -100
- package/src/@menu/components/horizontal-menu/MenuItem.jsx +0 -183
- package/src/@menu/components/horizontal-menu/SubMenu.jsx +0 -418
- package/src/@menu/components/horizontal-menu/SubMenuContent.jsx +0 -41
- package/src/@menu/components/horizontal-menu/VerticalNavInHorizontal.jsx +0 -20
- package/src/@menu/components/vertical-menu/Menu.jsx +0 -161
- package/src/@menu/components/vertical-menu/MenuButton.jsx +0 -95
- package/src/@menu/components/vertical-menu/MenuItem.jsx +0 -180
- package/src/@menu/components/vertical-menu/MenuSection.jsx +0 -124
- package/src/@menu/components/vertical-menu/NavCollapseIcons.jsx +0 -70
- package/src/@menu/components/vertical-menu/NavHeader.jsx +0 -39
- package/src/@menu/components/vertical-menu/SubMenu.jsx +0 -420
- package/src/@menu/components/vertical-menu/SubMenuContent.jsx +0 -101
- package/src/@menu/components/vertical-menu/VerticalNav.jsx +0 -216
- package/src/@menu/contexts/horizontalNavContext.jsx +0 -29
- package/src/@menu/contexts/verticalNavContext.jsx +0 -65
- package/src/@menu/defaultConfigs.js +0 -12
- package/src/@menu/hooks/useHorizontalMenu.jsx +0 -19
- package/src/@menu/hooks/useHorizontalNav.jsx +0 -19
- package/src/@menu/hooks/useMediaQuery.jsx +0 -29
- package/src/@menu/hooks/useVerticalMenu.jsx +0 -19
- package/src/@menu/hooks/useVerticalNav.jsx +0 -19
- package/src/@menu/horizontal-menu/index.jsx +0 -8
- package/src/@menu/styles/StyledBackdrop.jsx +0 -15
- package/src/@menu/styles/StyledMenuIcon.jsx +0 -12
- package/src/@menu/styles/StyledMenuLabel.jsx +0 -16
- package/src/@menu/styles/StyledMenuPrefix.jsx +0 -10
- package/src/@menu/styles/StyledMenuSectionLabel.jsx +0 -21
- package/src/@menu/styles/StyledMenuSuffix.jsx +0 -10
- package/src/@menu/styles/StyledSubMenuContent.jsx +0 -43
- package/src/@menu/styles/horizontal/StyledHorizontalMenu.jsx +0 -13
- package/src/@menu/styles/horizontal/StyledHorizontalMenuItem.jsx +0 -26
- package/src/@menu/styles/horizontal/StyledHorizontalNav.jsx +0 -11
- package/src/@menu/styles/horizontal/StyledHorizontalNavExpandIcon.jsx +0 -33
- package/src/@menu/styles/horizontal/StyledHorizontalSubMenuContent.jsx +0 -18
- package/src/@menu/styles/horizontal/StyledHorizontalSubMenuContentWrapper.jsx +0 -10
- package/src/@menu/styles/horizontal/horizontalUl.module.css +0 -15
- package/src/@menu/styles/styles.module.css +0 -5
- package/src/@menu/styles/vertical/StyledVerticalMenu.jsx +0 -16
- package/src/@menu/styles/vertical/StyledVerticalMenuItem.jsx +0 -28
- package/src/@menu/styles/vertical/StyledVerticalMenuSection.jsx +0 -23
- package/src/@menu/styles/vertical/StyledVerticalNav.jsx +0 -67
- package/src/@menu/styles/vertical/StyledVerticalNavBgColorContainer.jsx +0 -15
- package/src/@menu/styles/vertical/StyledVerticalNavContainer.jsx +0 -23
- package/src/@menu/styles/vertical/StyledVerticalNavExpandIcon.jsx +0 -25
- package/src/@menu/styles/vertical/verticalNavBgImage.module.css +0 -10
- package/src/@menu/svg/ChevronRight.jsx +0 -9
- package/src/@menu/svg/Close.jsx +0 -12
- package/src/@menu/svg/RadioCircle.jsx +0 -12
- package/src/@menu/svg/RadioCircleMarked.jsx +0 -13
- package/src/@menu/utils/menuClasses.js +0 -44
- package/src/@menu/utils/menuUtils.jsx +0 -145
- package/src/@menu/vertical-menu/index.jsx +0 -11
- package/src/configs/acl.js +0 -115
- package/src/configs/auth.js +0 -5
- package/src/configs/aws-exports.js +0 -30
- package/src/configs/firebase.js +0 -25
- package/src/configs/i18n.js +0 -34
- package/src/configs/primaryColorConfig.js +0 -35
- package/src/configs/themeConfig.js +0 -44
- package/src/layouts/UserLayout.js +0 -94
- package/src/layouts/UserThemeOptions.js +0 -191
- package/src/layouts/components/Direction.js +0 -30
- package/src/layouts/components/HtmlTooltip.js +0 -15
- package/src/layouts/components/Translations.js +0 -11
- package/src/layouts/components/UserDropdown.js +0 -217
- package/src/layouts/components/UserIcon.js +0 -40
- package/src/layouts/components/acl/Can.js +0 -6
- package/src/layouts/components/acl/CanViewNavGroup.js +0 -36
- package/src/layouts/components/acl/CanViewNavLink.js +0 -17
- package/src/layouts/components/acl/CanViewNavSectionTitle.js +0 -17
- package/src/layouts/components/horizontal/AppBarContent.js +0 -39
- package/src/layouts/components/horizontal/ServerSideNavItems.js +0 -44
- package/src/layouts/components/mui/StepperComps.js +0 -55
- package/src/layouts/components/vertical/AppBarContent.js +0 -35
- package/src/layouts/components/vertical/ServerSideNavItems.js +0 -44
- package/src/libs/ApexCharts.jsx +0 -5
- package/src/libs/ReactPlayer.jsx +0 -5
- package/src/libs/Recharts.jsx +0 -4
- package/src/libs/auth.js +0 -124
- package/src/libs/styles/AppFullCalendar.js +0 -505
- package/src/libs/styles/AppKeenSlider.js +0 -116
- package/src/libs/styles/AppReactApexCharts.jsx +0 -110
- package/src/libs/styles/AppReactDatepicker.jsx +0 -470
- package/src/libs/styles/AppReactDropzone.js +0 -76
- package/src/libs/styles/AppReactToastify.jsx +0 -108
- package/src/libs/styles/AppRecharts.js +0 -55
- package/src/libs/styles/inputOtp.module.css +0 -39
- package/src/libs/styles/tiptapEditor.css +0 -72
- package/src/navigation/horizontal/index.js +0 -246
- package/src/navigation/vertical/index.js +0 -253
- package/src/pages/401.js +0 -70
- package/src/pages/404.js +0 -67
- package/src/pages/500.js +0 -68
- package/src/pages/[slug].js +0 -115
- package/src/pages/_document.js +0 -72
- package/src/pages/api/navigation/regenerate-registry.js +0 -116
- package/src/pages/api/navigation/save.js +0 -218
- package/src/pages/authModule/acl/index.js +0 -48
- package/src/pages/authModule/forgot-password/index.js +0 -228
- package/src/pages/authModule/permissions/rolePermissions/[id]/rolePermissionsUser/index.js +0 -392
- package/src/pages/authModule/permissions/rolePermissions/index.js +0 -343
- package/src/pages/authModule/permissions/systemPermissions/index.js +0 -354
- package/src/pages/authModule/privacy/index.js +0 -721
- package/src/pages/authModule/users/index.js +0 -210
- package/src/pages/login/index.js +0 -328
- package/src/pages/mainHome/index.js +0 -181
- package/src/views/builder/inspector/definitions/cell/main.js +0 -4
- package/src/views/builder/inspector/definitions/column/main.js +0 -9
- package/src/views/builder/inspector/definitions/column-group/main.js +0 -18
- package/src/views/builder/inspector/definitions/header-cell/main.js +0 -5
- package/src/views/builder/inspector/definitions/table/main.js +0 -9
- package/src/views/builder/viewer/renderers/CellRenderer.jsx +0 -71
- package/src/views/builder/viewer/renderers/ColumnGroupRenderer.jsx +0 -96
- package/src/views/builder/viewer/renderers/ColumnRenderer.jsx +0 -71
- package/src/views/builder/viewer/renderers/HeaderCellRenderer.jsx +0 -78
- package/src/views/builder/viewer/renderers/TabRenderer.jsx +0 -82
- package/src/views/builder/viewer/renderers/TableRenderer.jsx +0 -92
- package/src/views/pages/auth/FooterIllustrationsV2.js +0 -40
- package/src/views/pages/misc/FooterIllustrations.js +0 -47
- package/src/views/pages/misc/muiTable/CustomPagination.js +0 -34
- package/src/views/pages/users/UserManageDialog.js +0 -283
- package/src/views/pages/users/UserViewPage.js +0 -199
- package/src/views/users/AddUserNameDialog.js +0 -162
- package/src/views/users/ContactManage.js +0 -449
- package/src/views/users/ResetPasswordDialog.js +0 -242
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
* - Adds search term filters based on searchTermRef and searchFieldsRef metadata.
|
|
27
27
|
* - Translates group/pivot/value columns, sort model, and pagination into the expected backend format.
|
|
28
28
|
* 3) Data is requested via ReportBuilderEndpoints.Post.GenericGet. Responses may contain rows and aggregations.
|
|
29
|
-
* 4) Grid updates, status bar shows counts/aggregations, and export functions can read current
|
|
29
|
+
* 4) Grid updates, status bar shows counts/aggregations, and export functions can read current view state.
|
|
30
30
|
*
|
|
31
31
|
* Quick search behavior (important)
|
|
32
32
|
* - searchTermRef holds the current string. If it parses to a finite number, we search numeric (Int) fields with a numeric value.
|
|
@@ -58,25 +58,44 @@ import Grid from '@mui/material/Grid'
|
|
|
58
58
|
// ** Icons Imports
|
|
59
59
|
// ** Store Imports
|
|
60
60
|
// ** Custom Components Imports
|
|
61
|
-
import {useCallback, useContext, useEffect, useMemo, useRef, useState} from 'react'
|
|
61
|
+
import {createContext, useCallback, useContext, useEffect, useMemo, useRef, useState} from 'react'
|
|
62
|
+
|
|
63
|
+
// Global styles for flashing effect
|
|
64
|
+
if (typeof document !== 'undefined') {
|
|
65
|
+
const styleId = 'ag-grid-flashing-effect';
|
|
66
|
+
if (!document.getElementById(styleId)) {
|
|
67
|
+
const style = document.createElement('style');
|
|
68
|
+
style.id = styleId;
|
|
69
|
+
style.innerHTML = `
|
|
70
|
+
@keyframes flashing-bg {
|
|
71
|
+
0% { opacity: 1; }
|
|
72
|
+
50% { opacity: 0.5; }
|
|
73
|
+
100% { opacity: 1; }
|
|
74
|
+
}
|
|
75
|
+
`;
|
|
76
|
+
document.head.appendChild(style);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
62
80
|
import {Endpoints, Services} from 'src/services/Endpoints'
|
|
63
81
|
import {
|
|
64
|
-
Autocomplete, Checkbox,
|
|
82
|
+
Autocomplete, Button, Checkbox,
|
|
65
83
|
CircularProgress,
|
|
66
|
-
Dialog,
|
|
84
|
+
Dialog, Divider,
|
|
67
85
|
FormControl, FormControlLabel,
|
|
68
86
|
IconButton,
|
|
69
87
|
MenuItem,
|
|
70
88
|
Select,
|
|
71
89
|
TextField,
|
|
72
|
-
Tooltip,
|
|
90
|
+
Tooltip, Typography,
|
|
73
91
|
Chip,
|
|
74
92
|
Stack,
|
|
75
93
|
Popper,
|
|
76
94
|
Paper,
|
|
77
95
|
List,
|
|
78
96
|
ListItemButton,
|
|
79
|
-
ClickAwayListener
|
|
97
|
+
ClickAwayListener,
|
|
98
|
+
Menu
|
|
80
99
|
} from '@mui/material'
|
|
81
100
|
import {AgGridReact} from "ag-grid-react";
|
|
82
101
|
import {Edit, FilterAlt, PrintOutlined, RefreshOutlined, Save, SaveAs, Close} from "@mui/icons-material";
|
|
@@ -101,6 +120,23 @@ import jsPDF from "jspdf";
|
|
|
101
120
|
import "jspdf-autotable";
|
|
102
121
|
import arabicFontBase64 from "../../../public/fonts/font";
|
|
103
122
|
import {FilterFormat} from "services/helper/FilterFormat";
|
|
123
|
+
import {saveReportSession} from 'src/services/helper/reportSessionHelper'
|
|
124
|
+
import {
|
|
125
|
+
setUpdateRefValue,
|
|
126
|
+
setUpdateRefRow,
|
|
127
|
+
getUpdateRefValue,
|
|
128
|
+
hasUpdateRefValue,
|
|
129
|
+
clearUpdateRefRow,
|
|
130
|
+
clearAllUpdateRef,
|
|
131
|
+
getAllUpdates,
|
|
132
|
+
removeUpdateRefByRowId,
|
|
133
|
+
getRowId as getRowIdFromSettings,
|
|
134
|
+
normalizeUpdateRef,
|
|
135
|
+
cloneUpdateRefToOriginal,
|
|
136
|
+
restoreUpdateRefFromOriginal
|
|
137
|
+
} from './updateRefHelpers'
|
|
138
|
+
import {processColumnDefinitions, processColumnsConfig} from './convertStringFunctions'
|
|
139
|
+
import { AG_COMPONENTS } from 'views/builder/viewer/renderers/dataGridComponents'
|
|
104
140
|
|
|
105
141
|
// ** Utils Import
|
|
106
142
|
|
|
@@ -113,6 +149,122 @@ const defaultFinalRequest = {
|
|
|
113
149
|
filter: {},
|
|
114
150
|
params: {}
|
|
115
151
|
}
|
|
152
|
+
|
|
153
|
+
// ── Templates tool panel ──────────────────────────────────────────────────────
|
|
154
|
+
// Defined outside SGrid so the reference is stable (no remounts on parent renders).
|
|
155
|
+
// State flows in via React Context (AG Grid v33 renders custom components in the
|
|
156
|
+
// same React tree, so context is fully supported).
|
|
157
|
+
const TemplateStateContext = createContext(null)
|
|
158
|
+
|
|
159
|
+
function SettingsSection({ title, children }) {
|
|
160
|
+
return (
|
|
161
|
+
<Box style={{ display: 'block', width: '100%' }}>
|
|
162
|
+
<Box sx={{
|
|
163
|
+
px: 2, py: 0.75,
|
|
164
|
+
bgcolor: 'grey.100',
|
|
165
|
+
borderTop: '1px solid', borderBottom: '1px solid', borderColor: 'divider',
|
|
166
|
+
}}>
|
|
167
|
+
<Typography sx={{ fontSize: '0.6875rem', fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.8, color: 'text.secondary' }}>
|
|
168
|
+
{title}
|
|
169
|
+
</Typography>
|
|
170
|
+
</Box>
|
|
171
|
+
<Box sx={{ p: 2, boxSizing: 'border-box', width: '100%' }}>
|
|
172
|
+
{children}
|
|
173
|
+
</Box>
|
|
174
|
+
</Box>
|
|
175
|
+
)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function TemplatesToolPanel() {
|
|
179
|
+
const ctx = useContext(TemplateStateContext)
|
|
180
|
+
if (!ctx) return null
|
|
181
|
+
const {
|
|
182
|
+
templates, selectedTemplate, setSelectedTemplate,
|
|
183
|
+
handleGetTemplates, handleSaveTemplate,
|
|
184
|
+
handleToggleDialogs, setIsTemplateEditing,
|
|
185
|
+
builderData,
|
|
186
|
+
} = ctx
|
|
187
|
+
|
|
188
|
+
return (
|
|
189
|
+
<Box style={{ display: 'flex', flexDirection: 'column', height: '100%', width: 250 }}>
|
|
190
|
+
{/* Panel header */}
|
|
191
|
+
<Box sx={{
|
|
192
|
+
px: 2, py: 1.5,
|
|
193
|
+
borderBottom: '1px solid', borderColor: 'divider',
|
|
194
|
+
bgcolor: 'background.paper',
|
|
195
|
+
position: 'sticky', top: 0, zIndex: 1,
|
|
196
|
+
}}>
|
|
197
|
+
<Typography variant='subtitle2' sx={{ fontWeight: 700, color: 'text.primary' }}>
|
|
198
|
+
Settings
|
|
199
|
+
</Typography>
|
|
200
|
+
</Box>
|
|
201
|
+
|
|
202
|
+
{/* Template section */}
|
|
203
|
+
<SettingsSection title='Template'>
|
|
204
|
+
{builderData?.id == null ? (
|
|
205
|
+
<Typography variant='caption' sx={{ color: 'text.disabled' }}>No report loaded</Typography>
|
|
206
|
+
) : (
|
|
207
|
+
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2, width: '100%' }}>
|
|
208
|
+
<Autocomplete
|
|
209
|
+
size='small'
|
|
210
|
+
value={selectedTemplate}
|
|
211
|
+
options={templates}
|
|
212
|
+
onChange={(_, value) => setSelectedTemplate(value)}
|
|
213
|
+
getOptionLabel={option => option.name}
|
|
214
|
+
renderInput={params => (
|
|
215
|
+
<TextField
|
|
216
|
+
label='Active Template'
|
|
217
|
+
{...params}
|
|
218
|
+
onMouseDown={handleGetTemplates}
|
|
219
|
+
/>
|
|
220
|
+
)}
|
|
221
|
+
/>
|
|
222
|
+
|
|
223
|
+
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1, width: '100%' }}>
|
|
224
|
+
<Button
|
|
225
|
+
size='small'
|
|
226
|
+
variant='outlined'
|
|
227
|
+
startIcon={<Save fontSize='small' />}
|
|
228
|
+
disabled={selectedTemplate == null}
|
|
229
|
+
onClick={handleSaveTemplate}
|
|
230
|
+
fullWidth
|
|
231
|
+
sx={{ justifyContent: 'flex-start' }}
|
|
232
|
+
>
|
|
233
|
+
Save
|
|
234
|
+
</Button>
|
|
235
|
+
|
|
236
|
+
<Button
|
|
237
|
+
size='small'
|
|
238
|
+
variant='outlined'
|
|
239
|
+
startIcon={<SaveAs fontSize='small' />}
|
|
240
|
+
onClick={() => { setIsTemplateEditing(false); handleToggleDialogs('addTemplate') }}
|
|
241
|
+
fullWidth
|
|
242
|
+
sx={{ justifyContent: 'flex-start' }}
|
|
243
|
+
>
|
|
244
|
+
Save As New
|
|
245
|
+
</Button>
|
|
246
|
+
|
|
247
|
+
<Button
|
|
248
|
+
size='small'
|
|
249
|
+
variant='outlined'
|
|
250
|
+
startIcon={<Edit fontSize='small' />}
|
|
251
|
+
disabled={selectedTemplate == null}
|
|
252
|
+
onClick={() => { setIsTemplateEditing(true); handleToggleDialogs('addTemplate') }}
|
|
253
|
+
fullWidth
|
|
254
|
+
sx={{ justifyContent: 'flex-start' }}
|
|
255
|
+
>
|
|
256
|
+
Edit
|
|
257
|
+
</Button>
|
|
258
|
+
</Box>
|
|
259
|
+
</Box>
|
|
260
|
+
)}
|
|
261
|
+
</SettingsSection>
|
|
262
|
+
</Box>
|
|
263
|
+
)
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
267
|
+
|
|
116
268
|
const SGrid = props => {
|
|
117
269
|
// ** State
|
|
118
270
|
const appContext = useContext(SystemContext);
|
|
@@ -137,6 +289,7 @@ const SGrid = props => {
|
|
|
137
289
|
setOutGridApi,
|
|
138
290
|
setEventRowSelected,
|
|
139
291
|
pageName,
|
|
292
|
+
pageId,
|
|
140
293
|
paramsPage,
|
|
141
294
|
fixedTIncludes,
|
|
142
295
|
groupBy,
|
|
@@ -144,14 +297,26 @@ const SGrid = props => {
|
|
|
144
297
|
reportTitle,
|
|
145
298
|
uniqueIdPath,
|
|
146
299
|
columnsConfig,
|
|
147
|
-
dataAsObject = false
|
|
300
|
+
dataAsObject = false,
|
|
301
|
+
isRerender = false,
|
|
302
|
+
updateRef,
|
|
303
|
+
// nodeId — builder schema node ID for this ReportViewer (set by ReportViewerRenderer)
|
|
304
|
+
// reportRefs — shared registry { [nodeId]: updateRef } for all reports on the page
|
|
305
|
+
nodeId,
|
|
306
|
+
reportRefs,
|
|
307
|
+
// Viewer state — passed through to column string functions via convertStringFunctions ctx
|
|
308
|
+
data: viewerData,
|
|
309
|
+
dataRef: viewerDataRef,
|
|
310
|
+
openDialog,
|
|
311
|
+
closeDialog,
|
|
148
312
|
} = props
|
|
149
313
|
const groupEndPoint = ReportBuilderEndpoints.Post.GenericGet;
|
|
150
314
|
const streamEndPoint = ReportBuilderEndpoints.Post.GenericGet;
|
|
151
315
|
const pagedEndPoint = ReportBuilderEndpoints.Post.GenericGet;
|
|
152
316
|
const [responseType, setResponseType] = useState()
|
|
153
317
|
const [pagedAgg, setPagedAgg] = useState()
|
|
154
|
-
const
|
|
318
|
+
const colDefs = useRef([])
|
|
319
|
+
const originalRefData = useRef([])
|
|
155
320
|
const [gridApi, setGridApi] = useState(null)
|
|
156
321
|
const [includes, setIncludes] = useState([])
|
|
157
322
|
const [isPagination, setIsPagination] = useState(true)
|
|
@@ -163,6 +328,7 @@ const SGrid = props => {
|
|
|
163
328
|
const userTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
164
329
|
const router = useRouter()
|
|
165
330
|
const authValues = useContext(AuthContext)
|
|
331
|
+
const contextValues = useContext(SystemContext)
|
|
166
332
|
const [isTemplateEditing, setIsTemplateEditing] = useState(false)
|
|
167
333
|
const [isDownloading, setIsDownloading] = useState(false)
|
|
168
334
|
const [finalRequestObject, setFinalRequestObject] = useState(defaultFinalRequest)
|
|
@@ -191,6 +357,87 @@ const SGrid = props => {
|
|
|
191
357
|
Tfilter: [],
|
|
192
358
|
LocalTfilter: [],
|
|
193
359
|
})
|
|
360
|
+
|
|
361
|
+
// Persistence Key helper
|
|
362
|
+
const getSessionKey = useCallback(() => {
|
|
363
|
+
const reportId = builderData?.id || builderModel?.id;
|
|
364
|
+
const pId = pageId || router.query?.pageId;
|
|
365
|
+
if (pId) return `RB_SESSION_FILTERS_PAGE_${pId}`;
|
|
366
|
+
if (reportId) return `RB_SESSION_FILTERS_REP_${reportId}`;
|
|
367
|
+
return null;
|
|
368
|
+
}, [builderData?.id, builderModel?.id, pageId, router.query?.pageId]);
|
|
369
|
+
|
|
370
|
+
// Clone updateRef to originalRefData when it first gets data
|
|
371
|
+
useEffect(() => {
|
|
372
|
+
if (updateRef && updateRef.current && Array.isArray(updateRef.current) && updateRef.current.length > 0) {
|
|
373
|
+
// Only clone if originalRefData is empty (first time updateRef has data)
|
|
374
|
+
if (!originalRefData.current || originalRefData.current.length === 0) {
|
|
375
|
+
cloneUpdateRefToOriginal(updateRef, originalRefData);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}, [updateRef?.current?.length]); // Watch for when updateRef gets data
|
|
379
|
+
|
|
380
|
+
// Load filters from sessionStorage on mount
|
|
381
|
+
useEffect(() => {
|
|
382
|
+
const key = getSessionKey();
|
|
383
|
+
if (!key) return;
|
|
384
|
+
|
|
385
|
+
try {
|
|
386
|
+
// Check if it's a refresh
|
|
387
|
+
let isRefresh = false;
|
|
388
|
+
try {
|
|
389
|
+
const navEntries = performance.getEntriesByType('navigation');
|
|
390
|
+
isRefresh = navEntries.length > 0 && navEntries[0].type === 'reload';
|
|
391
|
+
} catch (e) {
|
|
392
|
+
console.warn('SGrid: performance.getEntriesByType not supported', e);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
if (isRefresh) {
|
|
396
|
+
sessionStorage.removeItem(key);
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
const stored = sessionStorage.getItem(key);
|
|
401
|
+
if (stored) {
|
|
402
|
+
// If externalFilter is provided via props (routing payload), it should probably take precedence
|
|
403
|
+
// but let's see if it's actually passed. In ReportViewer, it's passed as 'filter' prop.
|
|
404
|
+
if (externalFilter) {
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
const parsed = JSON.parse(stored);
|
|
409
|
+
|
|
410
|
+
if (parsed.Filter) setFilter(parsed.Filter);
|
|
411
|
+
if (parsed.selectedSearchObjects) setSelectedSearchObjects(parsed.selectedSearchObjects);
|
|
412
|
+
if (parsed.selectParams) setSelectParams(parsed.selectParams);
|
|
413
|
+
}
|
|
414
|
+
} catch (e) {
|
|
415
|
+
console.error('SGrid: Failed to restore session filters', e);
|
|
416
|
+
}
|
|
417
|
+
}, [getSessionKey, externalFilter]);
|
|
418
|
+
|
|
419
|
+
// Save filters to sessionStorage whenever they change
|
|
420
|
+
useEffect(() => {
|
|
421
|
+
const key = getSessionKey();
|
|
422
|
+
if (!key) return;
|
|
423
|
+
|
|
424
|
+
const timeout = setTimeout(() => {
|
|
425
|
+
try {
|
|
426
|
+
const toStore = {
|
|
427
|
+
Filter,
|
|
428
|
+
selectedSearchObjects,
|
|
429
|
+
selectParams
|
|
430
|
+
};
|
|
431
|
+
// Always store current state. If user cleared all filters, we want to remember it's empty in this session.
|
|
432
|
+
// We only avoid storing if the state is exactly the default/initial state and we haven't modified it yet.
|
|
433
|
+
sessionStorage.setItem(key, JSON.stringify(toStore));
|
|
434
|
+
} catch (e) {
|
|
435
|
+
console.error('SGrid: Failed to save session filters', e);
|
|
436
|
+
}
|
|
437
|
+
}, 1000); // debounce saving
|
|
438
|
+
|
|
439
|
+
return () => clearTimeout(timeout);
|
|
440
|
+
}, [Filter, selectedSearchObjects, selectParams, getSessionKey]);
|
|
194
441
|
const [openDialogs, setOpenDialogs] = useState({
|
|
195
442
|
addTemplate: false,
|
|
196
443
|
CustomFilter: false,
|
|
@@ -277,7 +524,7 @@ const SGrid = props => {
|
|
|
277
524
|
if (c.colId === "IZ_groupCount") {
|
|
278
525
|
return {field: "IZ_groupCount", headerName: "Group Count"};
|
|
279
526
|
}
|
|
280
|
-
return colDefs.find(cd => cd.field === c.colId);
|
|
527
|
+
return colDefs.current.find(cd => cd.field === c.colId);
|
|
281
528
|
})
|
|
282
529
|
.filter(Boolean);
|
|
283
530
|
|
|
@@ -552,7 +799,15 @@ const SGrid = props => {
|
|
|
552
799
|
async function handleResetColsToStudio() {
|
|
553
800
|
try {
|
|
554
801
|
setBuilderTFilter(builderData?.filter?.Tfilter ?? [])
|
|
555
|
-
|
|
802
|
+
setFilter(pre => ({
|
|
803
|
+
...pre,
|
|
804
|
+
LocalTfilter: [
|
|
805
|
+
...(builderData?.filter?.fixedTFilter || []).map(f => ({...f})),
|
|
806
|
+
...(builderData?.filter?.LocalTfilter || []).map(f => ({...f}))
|
|
807
|
+
],
|
|
808
|
+
Tfilter: builderData?.filter?.Tfilter || [],
|
|
809
|
+
customFilterCode: builderData?.filter?.customFilterCode || ''
|
|
810
|
+
}))
|
|
556
811
|
const allowedAggFuncs = ["sum", "avg", "min", "max"];
|
|
557
812
|
const userTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
558
813
|
let defaultCols = getDefaultColDefs()
|
|
@@ -567,7 +822,8 @@ const SGrid = props => {
|
|
|
567
822
|
const propertyType = col.propertyType ?? col.field?.propertyType;
|
|
568
823
|
const propPath = col.headerName ?? col.path;
|
|
569
824
|
const fieldName = col.headerName ?? col.path.replace(/\./g, '_');
|
|
570
|
-
const
|
|
825
|
+
const processedColumnsConfig = processColumnsConfig(columnsConfig ?? [], { reportRefs, nodeName: nodeId, data: viewerData, dataRef: viewerDataRef, setData, openDialog, closeDialog });
|
|
826
|
+
const externalColConfig = processedColumnsConfig.find(x => x.field === fieldName)?.config ?? {}
|
|
571
827
|
const headerName = col.title ?? col.headerName ?? col.path;
|
|
572
828
|
const hasRouting = routingSettings.some(r => r.fieldName === fieldName);
|
|
573
829
|
let valueFormatter = null;
|
|
@@ -583,8 +839,15 @@ const SGrid = props => {
|
|
|
583
839
|
}
|
|
584
840
|
|
|
585
841
|
if (propertyType === 'Double') {
|
|
842
|
+
const decimals = col.formatting?.decimals ?? 0;
|
|
843
|
+
valueFormatter =
|
|
844
|
+
`return params?.value != null ? numeral(params.value.toFixed(${decimals})).format('0,0.${'0'.repeat(decimals)}') : ''`;
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
if (propertyType === 'Int' && col.formatting?.decimals > 0) {
|
|
848
|
+
const decimals = col.formatting.decimals;
|
|
586
849
|
valueFormatter =
|
|
587
|
-
`return params?.value != null ? numeral(params.value.toFixed(
|
|
850
|
+
`return params?.value != null ? numeral(params.value.toFixed(${decimals})).format('0,0.${'0'.repeat(decimals)}') : ''`;
|
|
588
851
|
}
|
|
589
852
|
|
|
590
853
|
if (propertyType === 'Enum') {
|
|
@@ -593,7 +856,8 @@ const SGrid = props => {
|
|
|
593
856
|
`return params?.value != null ? enumTrans('${enumName}', params.value) : ''`;
|
|
594
857
|
}
|
|
595
858
|
|
|
596
|
-
const
|
|
859
|
+
const isNumeric = propertyType === 'Int' || propertyType === 'Double';
|
|
860
|
+
const isNumericAgg = isNumeric &&
|
|
597
861
|
!col.field?.path?.toLowerCase().endsWith('id');
|
|
598
862
|
|
|
599
863
|
const isImage = col.image === true;
|
|
@@ -608,7 +872,173 @@ const SGrid = props => {
|
|
|
608
872
|
? "agCheckboxCellRenderer"
|
|
609
873
|
: null)),
|
|
610
874
|
width: isImage ? 90 : undefined,
|
|
611
|
-
cellStyle:
|
|
875
|
+
cellStyle: (params) => {
|
|
876
|
+
let style = isImage ? {display: 'flex', alignItems: 'center', justifyContent: 'center'} : {};
|
|
877
|
+
const formatting = col.formatting;
|
|
878
|
+
if (formatting) {
|
|
879
|
+
if (formatting.fixedStyle) {
|
|
880
|
+
style = {...style, ...formatting.fixedStyle};
|
|
881
|
+
if (formatting.fixedStyle.flashing) {
|
|
882
|
+
style.animation = 'flashing-bg 1s infinite';
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
if (formatting.conditions && formatting.conditions.length > 0) {
|
|
886
|
+
const val = params.value;
|
|
887
|
+
for (const cond of formatting.conditions) {
|
|
888
|
+
let match = false;
|
|
889
|
+
const baseField = cond.baseField || 'self';
|
|
890
|
+
let currentVal;
|
|
891
|
+
if (baseField === 'self') {
|
|
892
|
+
currentVal = val;
|
|
893
|
+
} else {
|
|
894
|
+
// Resolve field path from data
|
|
895
|
+
// First try as is
|
|
896
|
+
currentVal = params.node.data[baseField];
|
|
897
|
+
|
|
898
|
+
// If not found and contains dots, try nested path
|
|
899
|
+
if ((currentVal === undefined || currentVal === null) && baseField.includes('.')) {
|
|
900
|
+
currentVal = baseField.split('.').reduce((obj, key) => (obj && obj[key] !== undefined) ? obj[key] : undefined, params.node.data);
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
const isNumericValue = typeof currentVal === 'number' || (!isNaN(parseFloat(currentVal)) && isFinite(currentVal));
|
|
905
|
+
let condVal;
|
|
906
|
+
if (cond.valueType === 'field' && cond.compareField) {
|
|
907
|
+
const compareField = cond.compareField;
|
|
908
|
+
// Resolve field path from data
|
|
909
|
+
// First try as is
|
|
910
|
+
condVal = params.node.data[compareField];
|
|
911
|
+
|
|
912
|
+
// If not found and contains dots, try nested path
|
|
913
|
+
if ((condVal === undefined || condVal === null) && compareField.includes('.')) {
|
|
914
|
+
condVal = compareField.split('.').reduce((obj, key) => (obj && obj[key] !== undefined) ? obj[key] : undefined, params.node.data);
|
|
915
|
+
}
|
|
916
|
+
} else if (cond.valueType === 'expression' && cond.expression) {
|
|
917
|
+
try {
|
|
918
|
+
// Math Expression evaluation
|
|
919
|
+
// Replace "FieldPath" with actual values from row data
|
|
920
|
+
let expr = cond.expression;
|
|
921
|
+
const fieldRegex = /"([^"]+)"/g;
|
|
922
|
+
let match;
|
|
923
|
+
let hasMissingValue = false;
|
|
924
|
+
const fieldValues = {};
|
|
925
|
+
|
|
926
|
+
// Find all fields in quotes
|
|
927
|
+
while ((match = fieldRegex.exec(cond.expression)) !== null) {
|
|
928
|
+
const fullMatch = match[0];
|
|
929
|
+
const path = match[1];
|
|
930
|
+
let val;
|
|
931
|
+
let fieldFound = false;
|
|
932
|
+
|
|
933
|
+
if (path === 'self') {
|
|
934
|
+
val = params.value;
|
|
935
|
+
fieldFound = true;
|
|
936
|
+
} else {
|
|
937
|
+
// Resolve field path from data
|
|
938
|
+
// First try as is (handles fieldName with underscores)
|
|
939
|
+
val = params.node.data[path];
|
|
940
|
+
|
|
941
|
+
if (val !== undefined) {
|
|
942
|
+
fieldFound = true;
|
|
943
|
+
} else if (path.includes('.')) {
|
|
944
|
+
// If not found and contains dots, try nested path
|
|
945
|
+
val = path.split('.').reduce((obj, key) => (obj && obj[key] !== undefined) ? obj[key] : undefined, params.node.data);
|
|
946
|
+
if (val !== undefined) {
|
|
947
|
+
fieldFound = true;
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
if (fieldFound) {
|
|
953
|
+
// If it's a string that is not a number, wrap it in single quotes to make it a string literal in the expression
|
|
954
|
+
// unless it's already a number
|
|
955
|
+
if (typeof val === 'string' && isNaN(parseFloat(val))) {
|
|
956
|
+
fieldValues[fullMatch] = `'${val.replace(/'/g, "\\'")}'`;
|
|
957
|
+
} else if (typeof val === 'number') {
|
|
958
|
+
fieldValues[fullMatch] = val;
|
|
959
|
+
} else if (!isNaN(parseFloat(val)) && isFinite(val)) {
|
|
960
|
+
fieldValues[fullMatch] = parseFloat(val);
|
|
961
|
+
} else if (val === null) {
|
|
962
|
+
fieldValues[fullMatch] = 'null';
|
|
963
|
+
} else if (typeof val === 'boolean') {
|
|
964
|
+
fieldValues[fullMatch] = val;
|
|
965
|
+
} else {
|
|
966
|
+
// Default to string if we can't be sure
|
|
967
|
+
fieldValues[fullMatch] = `'${String(val).replace(/'/g, "\\'")}'`;
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
// Replace fields with their values
|
|
973
|
+
// Sort keys by length descending to avoid partial replacements (e.g., "Field" before "FieldLonger")
|
|
974
|
+
const sortedKeys = Object.keys(fieldValues).sort((a, b) => b.length - a.length);
|
|
975
|
+
sortedKeys.forEach(key => {
|
|
976
|
+
// Escape special characters in key for RegExp
|
|
977
|
+
const escapedKey = key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
978
|
+
expr = expr.replace(new RegExp(escapedKey, 'g'), fieldValues[key]);
|
|
979
|
+
});
|
|
980
|
+
|
|
981
|
+
// Use Function constructor for evaluation
|
|
982
|
+
// Strip potentially dangerous characters while allowing math, comparison, ternary, and basic logical operators
|
|
983
|
+
// We allow: numbers, operators (+-*/), comparison (><=!|&), ternary (?:), parens, dots, spaces, commas, and some math words
|
|
984
|
+
// Updated to allow keywords for if and switch statements
|
|
985
|
+
// Also added ' for string literals
|
|
986
|
+
const safeExpr = expr.replace(/[^0-9+\-*/().\s><=!|&?:,;{}'a-zA-Z\\]/g, '');
|
|
987
|
+
// Check if it already contains 'return', otherwise wrap it if it looks like a simple expression
|
|
988
|
+
const finalCode = safeExpr.trim().startsWith('if') || safeExpr.trim().startsWith('switch') || safeExpr.includes('return')
|
|
989
|
+
? safeExpr
|
|
990
|
+
: `return ${safeExpr}`;
|
|
991
|
+
condVal = new Function(finalCode)();
|
|
992
|
+
} catch (e) {
|
|
993
|
+
console.error("Math expression evaluation failed:", e);
|
|
994
|
+
condVal = undefined;
|
|
995
|
+
}
|
|
996
|
+
} else {
|
|
997
|
+
condVal = cond.value;
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
const isCondNumeric = typeof condVal === 'number' || (!isNaN(parseFloat(condVal)) && isFinite(condVal));
|
|
1001
|
+
const finalCondVal = isCondNumeric ? parseFloat(condVal) : condVal;
|
|
1002
|
+
const compareVal = isNumericValue ? parseFloat(currentVal) : currentVal;
|
|
1003
|
+
|
|
1004
|
+
if (cond.valueType === 'expression') {
|
|
1005
|
+
match = !!condVal;
|
|
1006
|
+
} else {
|
|
1007
|
+
switch (cond.operator) {
|
|
1008
|
+
case '==':
|
|
1009
|
+
match = compareVal == finalCondVal;
|
|
1010
|
+
break;
|
|
1011
|
+
case '!=':
|
|
1012
|
+
match = compareVal != finalCondVal;
|
|
1013
|
+
break;
|
|
1014
|
+
case '>':
|
|
1015
|
+
match = compareVal > finalCondVal;
|
|
1016
|
+
break;
|
|
1017
|
+
case '<':
|
|
1018
|
+
match = compareVal < finalCondVal;
|
|
1019
|
+
break;
|
|
1020
|
+
case '>=':
|
|
1021
|
+
match = compareVal >= finalCondVal;
|
|
1022
|
+
break;
|
|
1023
|
+
case '<=':
|
|
1024
|
+
match = compareVal <= finalCondVal;
|
|
1025
|
+
break;
|
|
1026
|
+
case 'contains':
|
|
1027
|
+
match = String(compareVal).toLowerCase().includes(String(finalCondVal).toLowerCase());
|
|
1028
|
+
break;
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
if (match) {
|
|
1032
|
+
style = {...style, ...cond.style};
|
|
1033
|
+
if (cond.style.flashing) {
|
|
1034
|
+
style.animation = 'flashing-bg 1s infinite';
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
return style;
|
|
1041
|
+
},
|
|
612
1042
|
allowedAggFuncs: isNumericAgg ? allowedAggFuncs : [],
|
|
613
1043
|
valueFormatter: valueFormatter
|
|
614
1044
|
? applyValueFormatter(valueFormatter)
|
|
@@ -655,10 +1085,11 @@ const SGrid = props => {
|
|
|
655
1085
|
}))
|
|
656
1086
|
setSelectParams(localSelectParams);
|
|
657
1087
|
if (extraCols != null) {
|
|
658
|
-
|
|
1088
|
+
const processedExtraCols = processColumnDefinitions(extraCols, { reportRefs, nodeName: nodeId, data: viewerData, dataRef: viewerDataRef, setData, openDialog, closeDialog });
|
|
1089
|
+
localColDefs = [...processedExtraCols, ...localColDefs];
|
|
659
1090
|
}
|
|
660
1091
|
localColDefs = [...localColDefs, ...defaultCols];
|
|
661
|
-
|
|
1092
|
+
colDefs.current = ([
|
|
662
1093
|
{
|
|
663
1094
|
field: 'IZ_groupCount',
|
|
664
1095
|
headerName: 'Group Count',
|
|
@@ -705,7 +1136,8 @@ const SGrid = props => {
|
|
|
705
1136
|
tableCols = processColumns(tableCols)
|
|
706
1137
|
let localColDefs = [...tableCols, ...defaultCols]
|
|
707
1138
|
if (extraCols != null) {
|
|
708
|
-
|
|
1139
|
+
const processedExtraCols = processColumnDefinitions(extraCols, { reportRefs, nodeName: nodeId, data: viewerData, dataRef: viewerDataRef, setData, openDialog, closeDialog });
|
|
1140
|
+
localColDefs = [...processedExtraCols, ...localColDefs]
|
|
709
1141
|
}
|
|
710
1142
|
const localSelectTFilter = response.data.map(x => ({
|
|
711
1143
|
friendlyName: x.fieldName,
|
|
@@ -714,9 +1146,9 @@ const SGrid = props => {
|
|
|
714
1146
|
propertyType: x.type,
|
|
715
1147
|
}))
|
|
716
1148
|
setSelectTFilter(localSelectTFilter)
|
|
717
|
-
|
|
1149
|
+
colDefs.current = localColDefs
|
|
718
1150
|
} else {
|
|
719
|
-
|
|
1151
|
+
colDefs.current = []
|
|
720
1152
|
}
|
|
721
1153
|
} catch (error) {
|
|
722
1154
|
|
|
@@ -753,92 +1185,161 @@ const SGrid = props => {
|
|
|
753
1185
|
const {tRouting} = context;
|
|
754
1186
|
const fieldName = colDef.field;
|
|
755
1187
|
|
|
756
|
-
const
|
|
757
|
-
|
|
1188
|
+
const [anchorEl, setAnchorEl] = useState(null);
|
|
1189
|
+
const open = Boolean(anchorEl);
|
|
758
1190
|
|
|
759
|
-
|
|
760
|
-
|
|
1191
|
+
const routes = tRouting?.filter(r => r.fieldName === fieldName || r.headerName === fieldName) || [];
|
|
1192
|
+
if (routes.length === 0) return <span>{value}</span>;
|
|
761
1193
|
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
try {
|
|
767
|
-
const fn = new Function("row", routing.script);
|
|
768
|
-
finalRoute = fn(data);
|
|
769
|
-
} catch (err) {
|
|
770
|
-
console.error("Routing script error:", err);
|
|
771
|
-
finalRoute = "#";
|
|
772
|
-
}
|
|
773
|
-
} else if (routing.pattern) {
|
|
774
|
-
finalRoute = routing.pattern.replace(/\{\{(.*?)\}\}/g, (_, key) => {
|
|
775
|
-
const val = data?.[key];
|
|
776
|
-
return val != null ? val : `:${key}`;
|
|
777
|
-
});
|
|
778
|
-
}
|
|
779
|
-
}
|
|
1194
|
+
const handleRouteClick = (routing) => {
|
|
1195
|
+
setAnchorEl(null);
|
|
1196
|
+
// Determine behavior based on routing.type
|
|
1197
|
+
const type = routing.type || 'Route';
|
|
780
1198
|
|
|
781
|
-
const handleClick = () => {
|
|
782
1199
|
if (type === 'Filter') {
|
|
783
1200
|
try {
|
|
784
1201
|
// Prepare payload to pass via window.name (works across new tabs without session)
|
|
785
|
-
const raw = routing.externalFilterJson || '';
|
|
786
|
-
const replaced = raw.replace(/\{\{(.*?)\}\}/g, (_, key) => {
|
|
787
|
-
const v = data?.[key];
|
|
788
|
-
return v != null ? String(v) : '';
|
|
789
|
-
});
|
|
790
1202
|
let externalFilter = null;
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
1203
|
+
|
|
1204
|
+
if (routing.customFilterCode) {
|
|
1205
|
+
try {
|
|
1206
|
+
// Create function with access to authContext (if needed) and row data
|
|
1207
|
+
const executeCode = new Function('context', 'authContext', 'row', `
|
|
1208
|
+
let customFilter = [];
|
|
1209
|
+
try {
|
|
1210
|
+
${routing.customFilterCode}
|
|
1211
|
+
} catch (e) {
|
|
1212
|
+
console.error('Inner error in routing customFilterCode:', e);
|
|
1213
|
+
}
|
|
1214
|
+
return customFilter;
|
|
1215
|
+
`);
|
|
1216
|
+
const customFilterResult = executeCode(contextValues, authValues, data);
|
|
1217
|
+
|
|
1218
|
+
if (customFilterResult && Array.isArray(customFilterResult)) {
|
|
1219
|
+
externalFilter = {Tfilter: FilterFormat(customFilterResult)};
|
|
1220
|
+
} else if (customFilterResult && typeof customFilterResult === 'object') {
|
|
1221
|
+
// If it returned { Tfilter: [...] } directly
|
|
1222
|
+
externalFilter = customFilterResult;
|
|
1223
|
+
}
|
|
1224
|
+
} catch (error) {
|
|
1225
|
+
console.error('Error executing routing custom filter code:', error);
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
if (!externalFilter) {
|
|
1230
|
+
const raw = routing.externalFilterJson || '';
|
|
1231
|
+
const replaced = raw.replace(/\{\{(.*?)\}\}/g, (_, key) => {
|
|
1232
|
+
const v = data?.[key];
|
|
1233
|
+
return v != null ? String(v) : '';
|
|
1234
|
+
});
|
|
1235
|
+
try {
|
|
1236
|
+
externalFilter = replaced ? JSON.parse(replaced) : null;
|
|
1237
|
+
} catch (e) {
|
|
1238
|
+
console.error('Invalid externalFilterJson after replacement', e);
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
if (externalFilter && routing.customFilterCode) {
|
|
1243
|
+
externalFilter.customFilterCode = routing.customFilterCode;
|
|
795
1244
|
}
|
|
796
1245
|
|
|
797
1246
|
const builderId = context?.builderId;
|
|
1247
|
+
const targetPageId = routing.pageId;
|
|
798
1248
|
const payload = {
|
|
799
|
-
pageId:
|
|
1249
|
+
pageId: targetPageId ?? null,
|
|
800
1250
|
externalFilter,
|
|
801
|
-
id: builderId ?? null
|
|
1251
|
+
id: targetPageId ? null : (builderId ?? null)
|
|
802
1252
|
};
|
|
803
1253
|
|
|
804
|
-
const base = '/
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
if (
|
|
809
|
-
|
|
1254
|
+
const base = '/builders/report/viewer';
|
|
1255
|
+
let url = base;
|
|
1256
|
+
if (targetPageId) {
|
|
1257
|
+
url += `?pageId=${encodeURIComponent(targetPageId)}`;
|
|
1258
|
+
} else if (builderId) {
|
|
1259
|
+
url += `?id=${encodeURIComponent(builderId)}`;
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
try {
|
|
1263
|
+
const sessionId = saveReportSession(payload);
|
|
1264
|
+
if (sessionId) {
|
|
1265
|
+
url += (url.includes('?') ? '&' : '?') + `sessionId=${sessionId}`;
|
|
1266
|
+
} else {
|
|
1267
|
+
// fallback to session storage if localStorage fails
|
|
810
1268
|
const json = JSON.stringify(payload);
|
|
811
|
-
|
|
812
|
-
child.name = `RB:${b64}`;
|
|
813
|
-
} catch (e) {
|
|
814
|
-
// as a fallback, put minimal info in URL (may be long for large filters)
|
|
815
|
-
try {
|
|
816
|
-
const fallback = encodeURIComponent(JSON.stringify(payload));
|
|
817
|
-
child.location.href = builderId ? `${base}?id=${encodeURIComponent(builderId)}&payload=${fallback}` : `${base}?payload=${fallback}`;
|
|
818
|
-
} catch {}
|
|
1269
|
+
sessionStorage.setItem('RB_PAYLOAD', json);
|
|
819
1270
|
}
|
|
1271
|
+
} catch (e) {
|
|
1272
|
+
console.error('Failed to set session payload', e);
|
|
820
1273
|
}
|
|
1274
|
+
router.push(url).then(() => {
|
|
1275
|
+
});
|
|
821
1276
|
} catch (e) {
|
|
822
1277
|
console.error('Filter routing error', e);
|
|
823
1278
|
}
|
|
824
1279
|
} else {
|
|
1280
|
+
// Build finalRoute for Route type
|
|
1281
|
+
let finalRoute = null;
|
|
1282
|
+
if (routing.script) {
|
|
1283
|
+
try {
|
|
1284
|
+
const fn = new Function("row", routing.script);
|
|
1285
|
+
finalRoute = fn(data);
|
|
1286
|
+
} catch (err) {
|
|
1287
|
+
console.error("Routing script error:", err);
|
|
1288
|
+
finalRoute = "#";
|
|
1289
|
+
}
|
|
1290
|
+
} else if (routing.pattern) {
|
|
1291
|
+
finalRoute = routing.pattern.replace(/\{\{(.*?)\}\}/g, (_, key) => {
|
|
1292
|
+
const val = data?.[key];
|
|
1293
|
+
return val != null ? val : `:${key}`;
|
|
1294
|
+
});
|
|
1295
|
+
}
|
|
1296
|
+
|
|
825
1297
|
if (finalRoute && finalRoute !== '#') {
|
|
826
|
-
|
|
1298
|
+
const target = routing.target || '_self';
|
|
1299
|
+
|
|
1300
|
+
if (target === '_blank' || target === '_parent' || target === '_top') {
|
|
1301
|
+
// Open in new tab/window or specific frame
|
|
1302
|
+
window.open(finalRoute, target);
|
|
1303
|
+
} else {
|
|
1304
|
+
// Default: navigate in same tab using Next.js router
|
|
1305
|
+
router.push(finalRoute);
|
|
1306
|
+
}
|
|
827
1307
|
}
|
|
828
1308
|
}
|
|
829
1309
|
};
|
|
830
1310
|
|
|
1311
|
+
const handleClick = (event) => {
|
|
1312
|
+
if (routes.length > 1) {
|
|
1313
|
+
setAnchorEl(event.currentTarget);
|
|
1314
|
+
} else {
|
|
1315
|
+
handleRouteClick(routes[0]);
|
|
1316
|
+
}
|
|
1317
|
+
};
|
|
1318
|
+
|
|
831
1319
|
return (
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
1320
|
+
<>
|
|
1321
|
+
<span
|
|
1322
|
+
style={{
|
|
1323
|
+
color: '#1976d2',
|
|
1324
|
+
fontWeight: 600,
|
|
1325
|
+
cursor: 'pointer',
|
|
1326
|
+
}}
|
|
1327
|
+
onClick={handleClick}
|
|
1328
|
+
>
|
|
1329
|
+
{value}
|
|
1330
|
+
</span>
|
|
1331
|
+
<Menu
|
|
1332
|
+
anchorEl={anchorEl}
|
|
1333
|
+
open={open}
|
|
1334
|
+
onClose={() => setAnchorEl(null)}
|
|
1335
|
+
>
|
|
1336
|
+
{routes.map((r, idx) => (
|
|
1337
|
+
<MenuItem key={idx} onClick={() => handleRouteClick(r)}>
|
|
1338
|
+
{r.name || `Route ${idx + 1}`}
|
|
1339
|
+
</MenuItem>
|
|
1340
|
+
))}
|
|
1341
|
+
</Menu>
|
|
1342
|
+
</>
|
|
842
1343
|
);
|
|
843
1344
|
};
|
|
844
1345
|
|
|
@@ -926,26 +1427,35 @@ const SGrid = props => {
|
|
|
926
1427
|
}
|
|
927
1428
|
}
|
|
928
1429
|
|
|
929
|
-
const sideBarConfig = useMemo(
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
1430
|
+
const sideBarConfig = useMemo(
|
|
1431
|
+
() => ({
|
|
1432
|
+
toolPanels: [
|
|
1433
|
+
{
|
|
1434
|
+
id: 'columns',
|
|
1435
|
+
labelDefault: 'Columns',
|
|
1436
|
+
labelKey: 'columns',
|
|
1437
|
+
iconKey: 'columns',
|
|
1438
|
+
toolPanel: 'agColumnsToolPanel',
|
|
1439
|
+
toolPanelParams: {
|
|
1440
|
+
suppressRowGroups: groupBy != null,
|
|
1441
|
+
suppressValues: groupBy != null
|
|
1442
|
+
},
|
|
1443
|
+
minWidth: 225
|
|
940
1444
|
},
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
1445
|
+
{
|
|
1446
|
+
id: 'templates',
|
|
1447
|
+
labelDefault: 'Templates',
|
|
1448
|
+
labelKey: 'templates',
|
|
1449
|
+
iconKey: 'menu',
|
|
1450
|
+
toolPanel: 'templatesToolPanel',
|
|
1451
|
+
minWidth: 250,
|
|
1452
|
+
}
|
|
1453
|
+
],
|
|
1454
|
+
position: 'right',
|
|
1455
|
+
defaultToolPanel: '' // closed by default
|
|
1456
|
+
}),
|
|
1457
|
+
[groupBy]
|
|
1458
|
+
) // only re-create if groupBy changes
|
|
949
1459
|
const handleGetAggregationObject = (agg) => {
|
|
950
1460
|
|
|
951
1461
|
const matchedCol = builderData.selectedFields.find(col => {
|
|
@@ -1059,13 +1569,30 @@ const SGrid = props => {
|
|
|
1059
1569
|
setFinalRequestObject(defaultFinalRequest)
|
|
1060
1570
|
const fixedTFilter = externalFilter?.fixedTFilter ?? externalFilter?.fixedTfilter ?? []
|
|
1061
1571
|
const localFixedTFilter = Filter?.fixedTFilter ?? []
|
|
1062
|
-
let localFilter = externalFilter ? {...externalFilter} : {}
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1572
|
+
let localFilter = externalFilter && !Array.isArray(externalFilter) ? {...externalFilter} : {}
|
|
1573
|
+
// Merge with Filter but be careful not to overwrite Tfilter/TFilter with empty ones
|
|
1574
|
+
const {Tfilter: _tf, TFilter: _tF, customFilterCode: _cfc, ...otherInternalFilter} = Filter || {}
|
|
1575
|
+
localFilter = {...localFilter, ...otherInternalFilter}
|
|
1576
|
+
|
|
1577
|
+
let localTFilter = []
|
|
1578
|
+
if (externalFilter?.Tfilter) localTFilter.push(...externalFilter.Tfilter)
|
|
1579
|
+
if (externalFilter?.TFilter) localTFilter.push(...externalFilter.TFilter)
|
|
1580
|
+
if (Filter?.Tfilter) localTFilter.push(...Filter.Tfilter)
|
|
1581
|
+
if (Filter?.TFilter) localTFilter.push(...Filter.TFilter)
|
|
1582
|
+
|
|
1583
|
+
// Also support LocalTfilter (this is where CustomFilterDialog often stores its filters)
|
|
1584
|
+
if (Filter?.LocalTfilter) localTFilter.push(...Filter.LocalTfilter)
|
|
1585
|
+
if (externalFilter?.LocalTfilter) localTFilter.push(...externalFilter.LocalTfilter)
|
|
1586
|
+
|
|
1587
|
+
// Support for routing-passed externalFilter that might be directly inside externalFilter (not under Tfilter)
|
|
1588
|
+
if (Array.isArray(externalFilter) && localTFilter.length === 0) {
|
|
1589
|
+
localTFilter = [...externalFilter];
|
|
1590
|
+
}
|
|
1067
1591
|
localTFilter = [...localTFilter, ...fixedTFilter, ...localFixedTFilter, ...builderTFilter]
|
|
1068
1592
|
|
|
1593
|
+
// Extract customFilterCode from externalFilter if present (e.g. from routing)
|
|
1594
|
+
let currentCustomFilterCode = Filter?.customFilterCode || externalFilter?.customFilterCode || "";
|
|
1595
|
+
|
|
1069
1596
|
// Apply explicit user-selected search filters (selectedSearchObjects), grouped by path
|
|
1070
1597
|
if ((selectedSearchObjects?.length ?? 0) > 0) {
|
|
1071
1598
|
const byPath = selectedSearchObjects.reduce((acc, item) => {
|
|
@@ -1099,8 +1626,6 @@ const SGrid = props => {
|
|
|
1099
1626
|
localTFilter = [...localTFilter, ...grouped];
|
|
1100
1627
|
}
|
|
1101
1628
|
|
|
1102
|
-
localTFilter = localTFilter.filter(x => x.value !== null && x.value !== undefined && x.value !== '')
|
|
1103
|
-
|
|
1104
1629
|
delete localFilter.Tfilter
|
|
1105
1630
|
delete localFilter.fixedTfilter
|
|
1106
1631
|
delete localFilter.fixedTFilter
|
|
@@ -1112,8 +1637,8 @@ const SGrid = props => {
|
|
|
1112
1637
|
const pageSize = request.endRow - request.startRow // Calculate the page size
|
|
1113
1638
|
let aggregators = request.valueCols.filter(x => x.id != 'groupCount').map(agg => handleGetAggregationObject(agg))
|
|
1114
1639
|
let updateAggregation = true
|
|
1115
|
-
if (colDefs && gridApi) {
|
|
1116
|
-
let resultColDef = [...colDefs]
|
|
1640
|
+
if (colDefs.current && gridApi) {
|
|
1641
|
+
let resultColDef = [...colDefs.current]
|
|
1117
1642
|
if (request.rowGroupCols.length > 0) {
|
|
1118
1643
|
}
|
|
1119
1644
|
// gridApi.setGridOption('columnDefs', resultColDef)
|
|
@@ -1121,7 +1646,7 @@ const SGrid = props => {
|
|
|
1121
1646
|
}
|
|
1122
1647
|
// Build tFilter safely: remove fixed from preformatted lists and merge a single fixed source
|
|
1123
1648
|
// 1) Strip fixed items from local Tfilter/TFilter (they may already be formatted by CustomFilterDialog)
|
|
1124
|
-
let nonFixedLocal = Array.isArray(localTFilter) ? localTFilter.filter(it =>
|
|
1649
|
+
let nonFixedLocal = Array.isArray(localTFilter) ? localTFilter.filter(it => it != null && !(it.fixed === true && it.value === null)) : []
|
|
1125
1650
|
|
|
1126
1651
|
// 2) Choose ONE fixed source by priority: component state -> external -> builder
|
|
1127
1652
|
const extFixed = Array.isArray(externalFilter?.fixedTFilter)
|
|
@@ -1129,12 +1654,80 @@ const SGrid = props => {
|
|
|
1129
1654
|
: (Array.isArray(externalFilter?.fixedTfilter) ? externalFilter.fixedTfilter : [])
|
|
1130
1655
|
const fixedSource = (Array.isArray(Filter?.fixedTFilter) && Filter.fixedTFilter.length > 0)
|
|
1131
1656
|
? Filter.fixedTFilter
|
|
1132
|
-
: (extFixed.length > 0 ? extFixed : (Array.isArray(builderTFilter) ? builderTFilter : []))
|
|
1657
|
+
: (extFixed.length > 0 ? extFixed : (Array.isArray(builderTFilter) && builderTFilter.length > 0 ? builderTFilter : []))
|
|
1133
1658
|
|
|
1134
1659
|
// 3) Merge and format once
|
|
1135
|
-
const mergedForFormat = [...nonFixedLocal]
|
|
1136
|
-
|
|
1137
|
-
|
|
1660
|
+
const mergedForFormat = [...nonFixedLocal, ...fixedSource]
|
|
1661
|
+
let formattedT = FilterFormat(mergedForFormat).filter(x => !x?.isCustom)
|
|
1662
|
+
|
|
1663
|
+
// Dynamic placeholder replacement for authValues
|
|
1664
|
+
if (formattedT && Array.isArray(formattedT)) {
|
|
1665
|
+
formattedT = formattedT.map(f => {
|
|
1666
|
+
if (typeof f.value === 'string' && f.value.includes('{{auth.')) {
|
|
1667
|
+
const replaced = String(f.value).replace(/\{\{auth\.(.*?)\}\}/g, (_, path) => {
|
|
1668
|
+
return path.split('.').reduce((acc, key) => acc && acc[key], authValues) ?? '';
|
|
1669
|
+
});
|
|
1670
|
+
return {...f, value: replaced};
|
|
1671
|
+
}
|
|
1672
|
+
return f;
|
|
1673
|
+
});
|
|
1674
|
+
}
|
|
1675
|
+
|
|
1676
|
+
// Dynamic placeholder replacement for authValues
|
|
1677
|
+
if (formattedT && Array.isArray(formattedT)) {
|
|
1678
|
+
formattedT = formattedT.map(f => {
|
|
1679
|
+
if (typeof f.value === 'string' && f.value.includes('{{context.')) {
|
|
1680
|
+
const replaced = String(f.value).replace(/\{\{context\.(.*?)\}\}/g, (_, path) => {
|
|
1681
|
+
return path.split('.').reduce((acc, key) => acc && acc[key], contextValues) ?? '';
|
|
1682
|
+
});
|
|
1683
|
+
return {...f, value: replaced};
|
|
1684
|
+
}
|
|
1685
|
+
return f;
|
|
1686
|
+
});
|
|
1687
|
+
}
|
|
1688
|
+
|
|
1689
|
+
// 4) Execute custom filter code if present
|
|
1690
|
+
let customFilterResult = null
|
|
1691
|
+
if (currentCustomFilterCode && currentCustomFilterCode.trim()) {
|
|
1692
|
+
try {
|
|
1693
|
+
// Wrap code in a function that provides contextValues
|
|
1694
|
+
const executeCode = new Function('context', 'authContext', 'filters', 'localFilter', `
|
|
1695
|
+
let customFilter = [];
|
|
1696
|
+
try {
|
|
1697
|
+
${currentCustomFilterCode}
|
|
1698
|
+
} catch (e) {
|
|
1699
|
+
console.error('Inner error in customFilterCode:', e);
|
|
1700
|
+
}
|
|
1701
|
+
return customFilter;
|
|
1702
|
+
`);
|
|
1703
|
+
customFilterResult = executeCode(contextValues, authValues, formattedT, localFilter)
|
|
1704
|
+
|
|
1705
|
+
// Validate that result is an array
|
|
1706
|
+
if (customFilterResult && !Array.isArray(customFilterResult)) {
|
|
1707
|
+
console.error('Custom filter must return an array, got:', typeof customFilterResult)
|
|
1708
|
+
customFilterResult = null
|
|
1709
|
+
}
|
|
1710
|
+
} catch (error) {
|
|
1711
|
+
console.error('Error executing custom filter code in SGrid:', error)
|
|
1712
|
+
customFilterResult = null
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1716
|
+
// Merge custom filter array with formattedT if present
|
|
1717
|
+
if (customFilterResult && Array.isArray(customFilterResult)) {
|
|
1718
|
+
formattedT = [...formattedT, ...customFilterResult]
|
|
1719
|
+
}
|
|
1720
|
+
|
|
1721
|
+
// Final Deduplication after all merges and custom code execution
|
|
1722
|
+
if (Array.isArray(formattedT)) {
|
|
1723
|
+
formattedT = formattedT.filter((f, idx, self) =>
|
|
1724
|
+
idx === self.findIndex(t => (
|
|
1725
|
+
t.path === f.path &&
|
|
1726
|
+
t.method === f.method &&
|
|
1727
|
+
JSON.stringify(t.value) === JSON.stringify(f.value)
|
|
1728
|
+
))
|
|
1729
|
+
);
|
|
1730
|
+
}
|
|
1138
1731
|
|
|
1139
1732
|
let data = {
|
|
1140
1733
|
...localFilter,
|
|
@@ -1144,7 +1737,7 @@ const SGrid = props => {
|
|
|
1144
1737
|
}
|
|
1145
1738
|
// Exclude any tFilter entries with null value before sending the request (per requirement)
|
|
1146
1739
|
if (Array.isArray(data.tFilter)) {
|
|
1147
|
-
data.tFilter = data.tFilter.filter(f => f == null ? false : f.value !== null);
|
|
1740
|
+
data.tFilter = data.tFilter.filter(f => f == null ? false : (f.value !== null && !f.isCustom));
|
|
1148
1741
|
}
|
|
1149
1742
|
try {
|
|
1150
1743
|
if (request.rowGroupCols.length !== request.groupKeys.length) {
|
|
@@ -1175,6 +1768,33 @@ const SGrid = props => {
|
|
|
1175
1768
|
}));
|
|
1176
1769
|
const aggIds = request.valueCols.map(vc => vc.id);
|
|
1177
1770
|
|
|
1771
|
+
// Dynamic placeholder replacement for authValues in selectParams
|
|
1772
|
+
let dynamicSelectParams = selectParams;
|
|
1773
|
+
if (Array.isArray(dynamicSelectParams)) {
|
|
1774
|
+
dynamicSelectParams = dynamicSelectParams.map(p => {
|
|
1775
|
+
if (typeof p.value === 'string' && p.value.includes('{{auth.')) {
|
|
1776
|
+
const replaced = p.value.replace(/\{\{auth\.(.*?)\}\}/g, (_, path) => {
|
|
1777
|
+
return path.split('.').reduce((acc, key) => acc && acc[key], authValues) ?? '';
|
|
1778
|
+
});
|
|
1779
|
+
return {...p, value: replaced};
|
|
1780
|
+
}
|
|
1781
|
+
return p;
|
|
1782
|
+
});
|
|
1783
|
+
}
|
|
1784
|
+
|
|
1785
|
+
// Dynamic placeholder replacement for contextValues in selectParams
|
|
1786
|
+
if (Array.isArray(dynamicSelectParams)) {
|
|
1787
|
+
dynamicSelectParams = dynamicSelectParams.map(p => {
|
|
1788
|
+
if (typeof p.value === 'string' && p.value.includes('{{context.')) {
|
|
1789
|
+
const replaced = p.value.replace(/\{\{context\.(.*?)\}\}/g, (_, path) => {
|
|
1790
|
+
return path.split('.').reduce((acc, key) => acc && acc[key], contextValues) ?? '';
|
|
1791
|
+
});
|
|
1792
|
+
return {...p, value: replaced};
|
|
1793
|
+
}
|
|
1794
|
+
return p;
|
|
1795
|
+
});
|
|
1796
|
+
}
|
|
1797
|
+
|
|
1178
1798
|
const groupOrderColdIds = request.sortModel.filter(x => groupOrderCols.includes(x.colId) || ((x.colId == "IZ_groupCount" || x.colId.endsWith("groupCount") || aggIds.some(id => x.colId.toLowerCase().endsWith(id.toLowerCase()))) && isGroupCountOrder))
|
|
1179
1799
|
let orderBy = groupOrderColdIds.map(sort => handleGetSortObject(sort.colId, sort.sort, true, aggIds.some(id => sort.colId.toLowerCase().endsWith(id.toLowerCase()))))
|
|
1180
1800
|
data = {
|
|
@@ -1183,11 +1803,22 @@ const SGrid = props => {
|
|
|
1183
1803
|
orderBy: orderBy
|
|
1184
1804
|
}
|
|
1185
1805
|
|
|
1806
|
+
// Final deduplication for group keys vs base filters
|
|
1807
|
+
if (Array.isArray(data.tFilter)) {
|
|
1808
|
+
data.tFilter = data.tFilter.filter((f, idx, self) =>
|
|
1809
|
+
idx === self.findIndex(t => (
|
|
1810
|
+
t.path === f.path &&
|
|
1811
|
+
t.method === f.method &&
|
|
1812
|
+
JSON.stringify(t.value) === JSON.stringify(f.value)
|
|
1813
|
+
))
|
|
1814
|
+
);
|
|
1815
|
+
}
|
|
1816
|
+
|
|
1186
1817
|
// if (updateAggregation !== true) {
|
|
1187
1818
|
// data.aggregators = []
|
|
1188
1819
|
// }
|
|
1189
1820
|
data.selectFields = selectedFields
|
|
1190
|
-
data.selectParams =
|
|
1821
|
+
data.selectParams = dynamicSelectParams
|
|
1191
1822
|
data.rawSql = builderData.rawSql
|
|
1192
1823
|
|
|
1193
1824
|
const response = await Services.PostService(groupEndPoint, false, data, {
|
|
@@ -1259,8 +1890,46 @@ const SGrid = props => {
|
|
|
1259
1890
|
...data,
|
|
1260
1891
|
tFilter: [...tFilters, ...data.tFilter]
|
|
1261
1892
|
}
|
|
1893
|
+
|
|
1894
|
+
// Final deduplication for group keys vs base filters
|
|
1895
|
+
if (Array.isArray(data.tFilter)) {
|
|
1896
|
+
data.tFilter = data.tFilter.filter((f, idx, self) =>
|
|
1897
|
+
idx === self.findIndex(t => (
|
|
1898
|
+
t.path === f.path &&
|
|
1899
|
+
t.method === f.method &&
|
|
1900
|
+
JSON.stringify(t.value) === JSON.stringify(f.value)
|
|
1901
|
+
))
|
|
1902
|
+
);
|
|
1903
|
+
}
|
|
1262
1904
|
}
|
|
1263
1905
|
let orderBy = request.sortModel.filter(x => !x.colId.endsWith("IZ_groupCount")).map(sort => handleGetSortObject(sort.colId, sort.sort, false))
|
|
1906
|
+
|
|
1907
|
+
// Dynamic placeholder replacement for authValues in selectParams
|
|
1908
|
+
let dynamicSelectParams = selectParams;
|
|
1909
|
+
if (Array.isArray(dynamicSelectParams)) {
|
|
1910
|
+
dynamicSelectParams = dynamicSelectParams.map(p => {
|
|
1911
|
+
if (typeof p.value === 'string' && p.value.includes('{{auth.')) {
|
|
1912
|
+
const replaced = p.value.replace(/\{\{auth\.(.*?)\}\}/g, (_, path) => {
|
|
1913
|
+
return path.split('.').reduce((acc, key) => acc && acc[key], authValues) ?? '';
|
|
1914
|
+
});
|
|
1915
|
+
return {...p, value: replaced};
|
|
1916
|
+
}
|
|
1917
|
+
return p;
|
|
1918
|
+
});
|
|
1919
|
+
}
|
|
1920
|
+
|
|
1921
|
+
if (Array.isArray(dynamicSelectParams)) {
|
|
1922
|
+
dynamicSelectParams = dynamicSelectParams.map(p => {
|
|
1923
|
+
if (typeof p.value === 'string' && p.value.includes('{{context.')) {
|
|
1924
|
+
const replaced = p.value.replace(/\{\{context\.(.*?)\}\}/g, (_, path) => {
|
|
1925
|
+
return path.split('.').reduce((acc, key) => acc && acc[key], contextValues) ?? '';
|
|
1926
|
+
});
|
|
1927
|
+
return {...p, value: replaced};
|
|
1928
|
+
}
|
|
1929
|
+
return p;
|
|
1930
|
+
});
|
|
1931
|
+
}
|
|
1932
|
+
|
|
1264
1933
|
if (data.tIncludes != null)
|
|
1265
1934
|
data = {
|
|
1266
1935
|
...data,
|
|
@@ -1281,7 +1950,7 @@ const SGrid = props => {
|
|
|
1281
1950
|
data.aggregators = []
|
|
1282
1951
|
}
|
|
1283
1952
|
data.selectFields = selectedFields
|
|
1284
|
-
data.selectParams =
|
|
1953
|
+
data.selectParams = dynamicSelectParams
|
|
1285
1954
|
data.lastRowParams = lastRowRef.current[pageNumber];
|
|
1286
1955
|
|
|
1287
1956
|
data.isPaginationByFilter = builderData?.isRaw === false
|
|
@@ -1292,7 +1961,6 @@ const SGrid = props => {
|
|
|
1292
1961
|
rowCount: undefined // <== This keeps the grid in "loading" state
|
|
1293
1962
|
}
|
|
1294
1963
|
data.rawSql = builderData?.rawSql
|
|
1295
|
-
console.log(builderData)
|
|
1296
1964
|
const response = await Services.PostService(pagedEndPoint, false, data, {
|
|
1297
1965
|
...paramsPage,
|
|
1298
1966
|
page: isSingle ? 1 : pageNumber,
|
|
@@ -1341,7 +2009,7 @@ const SGrid = props => {
|
|
|
1341
2009
|
return {success: false}
|
|
1342
2010
|
}
|
|
1343
2011
|
},
|
|
1344
|
-
[externalFilter, includes, paramsPage, Filter, selectedFields, isPagination, selectedSearchObjects, builderData]
|
|
2012
|
+
[externalFilter, includes, paramsPage, Filter, selectedFields, isPagination, selectedSearchObjects, builderData, authValues, contextValues]
|
|
1345
2013
|
)
|
|
1346
2014
|
const datasource = useMemo(() => createServerSideDatasource(getRowsFromApi), [getRowsFromApi]);
|
|
1347
2015
|
|
|
@@ -1416,7 +2084,19 @@ const SGrid = props => {
|
|
|
1416
2084
|
}
|
|
1417
2085
|
|
|
1418
2086
|
function handleFilterChange(field, value) {
|
|
1419
|
-
|
|
2087
|
+
if (field === 'LocalTfilter') {
|
|
2088
|
+
// When updating LocalTfilter, preserve main filters from builderModel
|
|
2089
|
+
setFilter(preValue => {
|
|
2090
|
+
const mainFilters = (preValue.LocalTfilter || []).filter(f => f.isMainFilter === true)
|
|
2091
|
+
const newFilters = Array.isArray(value) ? value : []
|
|
2092
|
+
return {
|
|
2093
|
+
...preValue,
|
|
2094
|
+
LocalTfilter: [...mainFilters, ...newFilters]
|
|
2095
|
+
}
|
|
2096
|
+
})
|
|
2097
|
+
} else {
|
|
2098
|
+
handleChange(setFilter, field, value)
|
|
2099
|
+
}
|
|
1420
2100
|
}
|
|
1421
2101
|
|
|
1422
2102
|
async function handleGetTemplates() {
|
|
@@ -1524,14 +2204,53 @@ const SGrid = props => {
|
|
|
1524
2204
|
}
|
|
1525
2205
|
|
|
1526
2206
|
const restoreState = () => {
|
|
1527
|
-
|
|
2207
|
+
let builderMainFilter = builderModel?.filter?.LocalTfilter ?? []
|
|
2208
|
+
|
|
2209
|
+
if (gridApi !== null && colDefs.current !== null && selectedTemplate != null) {
|
|
2210
|
+
console.log(selectedTemplate)
|
|
1528
2211
|
gridApi.applyColumnState({
|
|
1529
2212
|
state: selectedTemplate.value,
|
|
1530
2213
|
applyOrder: true,
|
|
1531
2214
|
});
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
2215
|
+
if (selectedTemplate.filterValue != null) {
|
|
2216
|
+
let fixedLocalFilters = builderModel?.filter?.fixedTFilter ?? []
|
|
2217
|
+
fixedLocalFilters = fixedLocalFilters.filter(x => x.fixed === true)
|
|
2218
|
+
fixedLocalFilters = fixedLocalFilters.map(x => ({
|
|
2219
|
+
...x,
|
|
2220
|
+
isMainFilter: x.fixed === true ? false : x.isMainFilter
|
|
2221
|
+
}))
|
|
2222
|
+
let templateFilter = selectedTemplate?.filterValue?.LocalTfilter ?? []
|
|
2223
|
+
let nonExistsFilter = fixedLocalFilters.filter(x => !templateFilter.some(y => y.path === x.path && y.method === x.method && y.isOrList === x.isOrList))
|
|
2224
|
+
let finalLocalFilter = [...templateFilter, ...nonExistsFilter]
|
|
2225
|
+
|
|
2226
|
+
// Handle Tfilter from template
|
|
2227
|
+
const templateTfilter = selectedTemplate?.filterValue?.Tfilter ?? []
|
|
2228
|
+
const templateCustomFilterCode = selectedTemplate?.filterValue?.customFilterCode ?? ''
|
|
2229
|
+
|
|
2230
|
+
setFilter(preValue => ({
|
|
2231
|
+
...preValue,
|
|
2232
|
+
LocalTfilter: [...finalLocalFilter, ...builderMainFilter],
|
|
2233
|
+
Tfilter: templateTfilter,
|
|
2234
|
+
customFilterCode: templateCustomFilterCode
|
|
2235
|
+
}));
|
|
2236
|
+
}
|
|
2237
|
+
} else {
|
|
2238
|
+
let fixedLocalFilters = builderModel?.filter?.fixedTFilter ?? []
|
|
2239
|
+
fixedLocalFilters = fixedLocalFilters.filter(x => x.fixed === true)
|
|
2240
|
+
|
|
2241
|
+
let finalLocalFilter = [...fixedLocalFilters]
|
|
2242
|
+
|
|
2243
|
+
// When no template, use builderModel filters
|
|
2244
|
+
const builderTfilter = builderModel?.filter?.Tfilter ?? []
|
|
2245
|
+
const builderCustomFilterCode = builderModel?.filter?.customFilterCode ?? ''
|
|
2246
|
+
|
|
2247
|
+
setFilter(preValue => ({
|
|
2248
|
+
...preValue,
|
|
2249
|
+
LocalTfilter: [...finalLocalFilter, ...builderMainFilter],
|
|
2250
|
+
Tfilter: builderTfilter,
|
|
2251
|
+
customFilterCode: builderCustomFilterCode
|
|
2252
|
+
}));
|
|
2253
|
+
|
|
1535
2254
|
}
|
|
1536
2255
|
};
|
|
1537
2256
|
|
|
@@ -1566,7 +2285,6 @@ const SGrid = props => {
|
|
|
1566
2285
|
};
|
|
1567
2286
|
|
|
1568
2287
|
setSelectedSearchObjects(prev => [...prev, newObj]);
|
|
1569
|
-
console.log(newObj)
|
|
1570
2288
|
setSearchTerm('');
|
|
1571
2289
|
setSearchPopoverOpen(false);
|
|
1572
2290
|
debouncedRefresh();
|
|
@@ -1575,18 +2293,16 @@ const SGrid = props => {
|
|
|
1575
2293
|
|
|
1576
2294
|
useEffect(() => {
|
|
1577
2295
|
if (builderData) {
|
|
1578
|
-
|
|
1579
2296
|
if (builderData.isRaw) {
|
|
1580
2297
|
handleGetRawColumns(builderData.rawSql)
|
|
1581
2298
|
} else {
|
|
1582
2299
|
handleResetColsToStudio()
|
|
1583
2300
|
}
|
|
1584
2301
|
}
|
|
1585
|
-
}, [builderData]);
|
|
2302
|
+
}, [builderData, isRerender]);
|
|
1586
2303
|
|
|
1587
2304
|
useEffect(() => {
|
|
1588
2305
|
if (builderModel != null) {
|
|
1589
|
-
console.log(builderModel)
|
|
1590
2306
|
let rawSql = builderModel.rawSql;
|
|
1591
2307
|
if (builderModel.isRaw === true) {
|
|
1592
2308
|
const localSelectParams = builderModel.selectionParams.map((x, index) => ({
|
|
@@ -1607,11 +2323,44 @@ const SGrid = props => {
|
|
|
1607
2323
|
return param.value;
|
|
1608
2324
|
});
|
|
1609
2325
|
}
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
2326
|
+
|
|
2327
|
+
setBuilderData(prev => {
|
|
2328
|
+
// Only update if builderModel data changed or rawSql changed
|
|
2329
|
+
const isSameModel = prev && JSON.stringify(prev) === JSON.stringify({...builderModel, rawSql});
|
|
2330
|
+
if (isSameModel) return prev;
|
|
2331
|
+
return {...builderModel, rawSql: rawSql};
|
|
2332
|
+
});
|
|
2333
|
+
|
|
2334
|
+
// We explicitly skip updating setFilter if builderModel triggered it but we just restored from session.
|
|
2335
|
+
// We rely on the fact that if a session restore happened, Filter.LocalTfilter will likely be populated.
|
|
2336
|
+
|
|
2337
|
+
setFilter(preValue => {
|
|
2338
|
+
const fixedTFilter = builderModel?.filter?.fixedTFilter || [];
|
|
2339
|
+
const localTFilter = builderModel?.filter?.LocalTfilter || [];
|
|
2340
|
+
const tFilter = builderModel?.filter?.Tfilter || [];
|
|
2341
|
+
const customFilterCode = builderModel?.filter?.customFilterCode || '';
|
|
2342
|
+
|
|
2343
|
+
// If we already have filters (possibly restored from session), don't overwrite with just fixed filters
|
|
2344
|
+
// unless it's a completely fresh state or fixed filters changed.
|
|
2345
|
+
const isSameFilter = JSON.stringify(preValue.LocalTfilter) === JSON.stringify([...fixedTFilter, ...localTFilter]);
|
|
2346
|
+
const isSameCode = preValue.customFilterCode === customFilterCode;
|
|
2347
|
+
|
|
2348
|
+
if (preValue.LocalTfilter.length > (fixedTFilter.length + localTFilter.length) && isSameCode) {
|
|
2349
|
+
return preValue;
|
|
2350
|
+
}
|
|
2351
|
+
|
|
2352
|
+
if (isSameFilter && isSameCode) return preValue;
|
|
2353
|
+
|
|
2354
|
+
return {
|
|
2355
|
+
...preValue,
|
|
2356
|
+
Tfilter: tFilter,
|
|
2357
|
+
LocalTfilter: [
|
|
2358
|
+
...fixedTFilter.map(f => ({...f})),
|
|
2359
|
+
...localTFilter.map(f => ({...f}))
|
|
2360
|
+
],
|
|
2361
|
+
customFilterCode: customFilterCode
|
|
2362
|
+
};
|
|
2363
|
+
})
|
|
1615
2364
|
}
|
|
1616
2365
|
}, [builderModel]);
|
|
1617
2366
|
|
|
@@ -1640,39 +2389,38 @@ const SGrid = props => {
|
|
|
1640
2389
|
}, [selectParams, builderModel?.isRaw]);
|
|
1641
2390
|
|
|
1642
2391
|
useEffect(() => {
|
|
1643
|
-
|
|
1644
2392
|
if (gridApi !== null) {
|
|
1645
2393
|
gridApi.refreshServerSide({purge: !noPurge})
|
|
1646
2394
|
lastRowRef.current = {}
|
|
1647
2395
|
}
|
|
1648
|
-
}, [refresh, externalFilter, localRefresh, Filter]);
|
|
2396
|
+
}, [refresh, externalFilter, localRefresh, Filter.Tfilter, Filter.LocalTfilter, Filter.customFilterCode, externalFilter?.customFilterCode]);
|
|
1649
2397
|
|
|
1650
2398
|
useEffect(() => {
|
|
1651
|
-
if (gridApi != null && colDefs != null)
|
|
2399
|
+
if (gridApi != null && colDefs.current != null)
|
|
1652
2400
|
handleGetTemplates()
|
|
1653
|
-
}, [gridApi, colDefs])
|
|
2401
|
+
}, [gridApi, colDefs.current])
|
|
1654
2402
|
|
|
1655
2403
|
useEffect(() => {
|
|
1656
|
-
if (colDefs.length > 0
|
|
2404
|
+
if (colDefs.current.length > 0) {
|
|
1657
2405
|
restoreState()
|
|
1658
2406
|
}
|
|
1659
2407
|
}, [selectedTemplate])
|
|
1660
|
-
useEffect(() => {
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
}, [
|
|
2408
|
+
// useEffect(() => {
|
|
2409
|
+
// if (templates.length > 0 && colDefs.length > 0) {
|
|
2410
|
+
// const userDefined = templates.find(x => x.isDefault === true)
|
|
2411
|
+
// if (userDefined != null)
|
|
2412
|
+
// setSelectedTemplate(userDefined)
|
|
2413
|
+
// else {
|
|
2414
|
+
// const systemDefined = templates.find(x => x.type === "UserPredefined")
|
|
2415
|
+
// if (systemDefined != null)
|
|
2416
|
+
// setSelectedTemplate(systemDefined)
|
|
2417
|
+
// else {
|
|
2418
|
+
// const anyTemplate = templates[0]
|
|
2419
|
+
// setSelectedTemplate(anyTemplate)
|
|
2420
|
+
// }
|
|
2421
|
+
// }
|
|
2422
|
+
// }
|
|
2423
|
+
// }, [])
|
|
1676
2424
|
|
|
1677
2425
|
useEffect(() => {
|
|
1678
2426
|
if (!timerValue || isNaN(timerValue) || timerValue == 0) {
|
|
@@ -1705,47 +2453,18 @@ const SGrid = props => {
|
|
|
1705
2453
|
}, [externalTimer]); // re// n after each refresh or change in value
|
|
1706
2454
|
|
|
1707
2455
|
return (
|
|
1708
|
-
<Grid
|
|
1709
|
-
<Grid container
|
|
2456
|
+
<Grid container size={{ xs: 12 }}>
|
|
2457
|
+
<Grid container
|
|
1710
2458
|
sx={{backgroundColor: '#fafafb', justifyContent: 'space-between'}} padding={2}
|
|
1711
|
-
|
|
1712
|
-
>
|
|
2459
|
+
size={{ xs: 12 }}>
|
|
1713
2460
|
<Box sx={{display: 'flex'}}>
|
|
1714
|
-
{(builderData?.id != null && minimized !== true) &&
|
|
1715
|
-
<Box sx={{minWidth: '250px'}}>
|
|
1716
|
-
|
|
1717
|
-
<FormControl fullWidth>
|
|
1718
|
-
<Autocomplete
|
|
1719
|
-
size={'small'}
|
|
1720
|
-
value={selectedTemplate}
|
|
1721
|
-
fullWidth
|
|
1722
|
-
disableClearable
|
|
1723
|
-
options={templates}
|
|
1724
|
-
onChange={(e, value) => {
|
|
1725
|
-
setSelectedTemplate(value)
|
|
1726
|
-
}
|
|
1727
|
-
}
|
|
1728
|
-
getOptionLabel={option => option.name}
|
|
1729
|
-
renderInput={params => (
|
|
1730
|
-
<TextField
|
|
1731
|
-
label='شكل النموذج'
|
|
1732
|
-
{...params}
|
|
1733
|
-
onMouseDown={() => {
|
|
1734
|
-
handleGetTemplates()
|
|
1735
|
-
}}
|
|
1736
|
-
/>
|
|
1737
|
-
)}
|
|
1738
|
-
/>
|
|
1739
|
-
</FormControl>
|
|
1740
|
-
</Box>
|
|
1741
|
-
}
|
|
1742
2461
|
<Box sx={{ml: '5px'}}>
|
|
1743
2462
|
<Tooltip title='مؤقت' placement={'top'}>
|
|
1744
2463
|
<Select variant={'outlined'} value={timerValue} onChange={(e) => setTimerValue(e.target.value)}
|
|
1745
2464
|
defaultValue={0} size={'small'}
|
|
1746
2465
|
color='primary' sx={{width: '60px'}}>
|
|
1747
2466
|
<MenuItem key={1} value={0}>No</MenuItem>
|
|
1748
|
-
|
|
2467
|
+
{/*<MenuItem key={2} value={0.1667}>10s</MenuItem>*/}
|
|
1749
2468
|
<MenuItem key={2} value={0.5}>30s</MenuItem>
|
|
1750
2469
|
<MenuItem key={2} value={1}>1m</MenuItem>
|
|
1751
2470
|
<MenuItem key={2} value={2}>2m</MenuItem>
|
|
@@ -1912,43 +2631,6 @@ const SGrid = props => {
|
|
|
1912
2631
|
</Tooltip>
|
|
1913
2632
|
</Box>
|
|
1914
2633
|
}
|
|
1915
|
-
{
|
|
1916
|
-
builderData?.id != null && minimized !== true && <>
|
|
1917
|
-
<Box>
|
|
1918
|
-
<Tooltip title='حفظ النموذج'>
|
|
1919
|
-
<IconButton disabled={selectedTemplate == null} onClick={() => {
|
|
1920
|
-
handleSaveTemplate()
|
|
1921
|
-
}} color='primary'>
|
|
1922
|
-
<Save/>
|
|
1923
|
-
</IconButton>
|
|
1924
|
-
</Tooltip>
|
|
1925
|
-
</Box>
|
|
1926
|
-
<Box>
|
|
1927
|
-
<Tooltip title='حفظ بأسم'>
|
|
1928
|
-
<IconButton onClick={() => {
|
|
1929
|
-
setIsTemplateEditing(false)
|
|
1930
|
-
handleToggleDialogs('addTemplate')
|
|
1931
|
-
}} color='primary'>
|
|
1932
|
-
<SaveAs/>
|
|
1933
|
-
</IconButton>
|
|
1934
|
-
</Tooltip>
|
|
1935
|
-
</Box>
|
|
1936
|
-
|
|
1937
|
-
<Box>
|
|
1938
|
-
<Tooltip title='تعديل'>
|
|
1939
|
-
<IconButton disabled={selectedTemplate == null}
|
|
1940
|
-
onClick={() => {
|
|
1941
|
-
setIsTemplateEditing(true)
|
|
1942
|
-
handleToggleDialogs('addTemplate')
|
|
1943
|
-
}}
|
|
1944
|
-
color='primary'
|
|
1945
|
-
>
|
|
1946
|
-
<Edit/>
|
|
1947
|
-
</IconButton>
|
|
1948
|
-
</Tooltip>
|
|
1949
|
-
</Box>
|
|
1950
|
-
</>
|
|
1951
|
-
}
|
|
1952
2634
|
{<Box>
|
|
1953
2635
|
|
|
1954
2636
|
<IconButton color={'primary'} onClick={() => handleToggleDialogs('CustomFilter')}>
|
|
@@ -1966,6 +2648,16 @@ const SGrid = props => {
|
|
|
1966
2648
|
|
|
1967
2649
|
</Box>
|
|
1968
2650
|
</Grid>
|
|
2651
|
+
<TemplateStateContext.Provider value={{
|
|
2652
|
+
templates,
|
|
2653
|
+
selectedTemplate,
|
|
2654
|
+
setSelectedTemplate,
|
|
2655
|
+
handleGetTemplates,
|
|
2656
|
+
handleSaveTemplate,
|
|
2657
|
+
handleToggleDialogs,
|
|
2658
|
+
setIsTemplateEditing,
|
|
2659
|
+
builderData,
|
|
2660
|
+
}}>
|
|
1969
2661
|
<div style={{width: "100%", height: minimized === true ? "0px" : height ?? "70vh", direction: 'ltr'}}>
|
|
1970
2662
|
<AgGridReact
|
|
1971
2663
|
|
|
@@ -1973,7 +2665,7 @@ const SGrid = props => {
|
|
|
1973
2665
|
columnHoverHighlight={true}
|
|
1974
2666
|
theme={agTheme}
|
|
1975
2667
|
enableRtl={true}
|
|
1976
|
-
columnDefs={colDefs}
|
|
2668
|
+
columnDefs={colDefs.current}
|
|
1977
2669
|
rowModelType={"serverSide"}
|
|
1978
2670
|
onGridReady={onGridReady}
|
|
1979
2671
|
maxConcurrentDatasourceRequests={0}
|
|
@@ -1981,10 +2673,107 @@ const SGrid = props => {
|
|
|
1981
2673
|
onRowSelected={onRowSelected}
|
|
1982
2674
|
// getChildCount={getChildCount}
|
|
1983
2675
|
sideBar={sideBarConfig}
|
|
1984
|
-
context={{
|
|
2676
|
+
context={{
|
|
2677
|
+
tRouting,
|
|
2678
|
+
builderId: builderData?.id,
|
|
2679
|
+
updateRef: updateRef,
|
|
2680
|
+
settings: builderModel?.settings,
|
|
2681
|
+
// Node identity — available inside all column functions as params.context.nodeId / nodeName
|
|
2682
|
+
nodeId: nodeId ?? null,
|
|
2683
|
+
nodeName: nodeId ?? null, // alias for convenience
|
|
2684
|
+
// Shared registry — access any report's ref: params.context.reportRefs.current['nodeId']
|
|
2685
|
+
reportRefs: reportRefs ?? null,
|
|
2686
|
+
// Returns the latest viewer state snapshot — used by MultiSelectEditor to commit values
|
|
2687
|
+
getViewerContext: () => ({
|
|
2688
|
+
data: viewerData,
|
|
2689
|
+
setData: setData ?? (() => {}),
|
|
2690
|
+
dataRef: viewerDataRef,
|
|
2691
|
+
reportRefs: reportRefs ?? null,
|
|
2692
|
+
}),
|
|
2693
|
+
}} // pass routing, builder id, updateRef, node identity and reportRefs
|
|
1985
2694
|
gridOptions={{
|
|
1986
2695
|
enableRangeSelection: true,
|
|
1987
2696
|
enableCharts: true,
|
|
2697
|
+
getContextMenuItems: (params) => {
|
|
2698
|
+
const rowUniqueId = builderModel?.settings?.rowUniqueId
|
|
2699
|
+
const rowData = params.node?.data
|
|
2700
|
+
const defaultItems = params.defaultItems || []
|
|
2701
|
+
|
|
2702
|
+
if (!updateRef || !rowUniqueId || !rowData) {
|
|
2703
|
+
return defaultItems
|
|
2704
|
+
}
|
|
2705
|
+
|
|
2706
|
+
const rowIdValue = getRowIdFromSettings(rowData, rowUniqueId)
|
|
2707
|
+
const hasUpdate = updateRef.current && Array.isArray(updateRef.current) &&
|
|
2708
|
+
updateRef.current.some(item => item.rowId === rowIdValue)
|
|
2709
|
+
|
|
2710
|
+
const customItems = []
|
|
2711
|
+
|
|
2712
|
+
if (hasUpdate) {
|
|
2713
|
+
customItems.push({
|
|
2714
|
+
name: 'Remove Row from Update Ref',
|
|
2715
|
+
icon: '<span class="ag-icon ag-icon-cancel" unselectable="on" role="presentation"></span>',
|
|
2716
|
+
action: () => {
|
|
2717
|
+
removeUpdateRefByRowId(updateRef, rowData, rowUniqueId)
|
|
2718
|
+
params.api.refreshCells({force: true})
|
|
2719
|
+
}
|
|
2720
|
+
})
|
|
2721
|
+
}
|
|
2722
|
+
|
|
2723
|
+
customItems.push({
|
|
2724
|
+
name: 'Clone Update Ref (Backup)',
|
|
2725
|
+
icon: '<span class="ag-icon ag-icon-copy" unselectable="on" role="presentation"></span>',
|
|
2726
|
+
action: () => {
|
|
2727
|
+
cloneUpdateRefToOriginal(updateRef, originalRefData)
|
|
2728
|
+
params.api.refreshCells({force: true})
|
|
2729
|
+
},
|
|
2730
|
+
disabled: !updateRef.current || updateRef.current.length === 0
|
|
2731
|
+
})
|
|
2732
|
+
|
|
2733
|
+
customItems.push({
|
|
2734
|
+
name: 'Restore Update Ref (from Backup)',
|
|
2735
|
+
icon: '<span class="ag-icon ag-icon-undo" unselectable="on" role="presentation"></span>',
|
|
2736
|
+
action: () => {
|
|
2737
|
+
restoreUpdateRefFromOriginal(updateRef, originalRefData)
|
|
2738
|
+
params.api.refreshCells({force: true})
|
|
2739
|
+
},
|
|
2740
|
+
disabled: !originalRefData.current || originalRefData.current.length === 0
|
|
2741
|
+
})
|
|
2742
|
+
|
|
2743
|
+
customItems.push({
|
|
2744
|
+
name: 'Normalize Update Ref (Merge Duplicates)',
|
|
2745
|
+
icon: '<span class="ag-icon ag-icon-columns" unselectable="on" role="presentation"></span>',
|
|
2746
|
+
action: () => {
|
|
2747
|
+
normalizeUpdateRef(updateRef)
|
|
2748
|
+
params.api.refreshCells({force: true})
|
|
2749
|
+
},
|
|
2750
|
+
disabled: !updateRef.current || updateRef.current.length === 0
|
|
2751
|
+
})
|
|
2752
|
+
|
|
2753
|
+
customItems.push({
|
|
2754
|
+
name: 'Clear All Update Ref',
|
|
2755
|
+
icon: '<span class="ag-icon ag-icon-cancel" unselectable="on" role="presentation"></span>',
|
|
2756
|
+
action: () => {
|
|
2757
|
+
if (updateRef.current && Array.isArray(updateRef.current)) {
|
|
2758
|
+
const count = updateRef.current.length
|
|
2759
|
+
clearAllUpdateRef(updateRef)
|
|
2760
|
+
params.api.refreshCells({force: true})
|
|
2761
|
+
console.log(`Cleared ${count} rows from updateRef`)
|
|
2762
|
+
}
|
|
2763
|
+
},
|
|
2764
|
+
disabled: !updateRef.current || updateRef.current.length === 0
|
|
2765
|
+
})
|
|
2766
|
+
|
|
2767
|
+
if (customItems.length > 0) {
|
|
2768
|
+
return [
|
|
2769
|
+
...customItems,
|
|
2770
|
+
'separator',
|
|
2771
|
+
...defaultItems
|
|
2772
|
+
]
|
|
2773
|
+
}
|
|
2774
|
+
|
|
2775
|
+
return defaultItems
|
|
2776
|
+
}
|
|
1988
2777
|
}}
|
|
1989
2778
|
rowSelection="multiple"
|
|
1990
2779
|
statusBar={{
|
|
@@ -2033,14 +2822,21 @@ const SGrid = props => {
|
|
|
2033
2822
|
}}
|
|
2034
2823
|
|
|
2035
2824
|
components={{
|
|
2825
|
+
...AG_COMPONENTS,
|
|
2036
2826
|
routingCell: RoutingCell,
|
|
2037
2827
|
imageCell: ImageCell,
|
|
2038
2828
|
customStatusBar: CustomStatusBar,
|
|
2039
|
-
|
|
2040
|
-
|
|
2829
|
+
templatesToolPanel: TemplatesToolPanel,
|
|
2041
2830
|
}}
|
|
2042
2831
|
|
|
2043
2832
|
|
|
2833
|
+
onCellValueChanged={params => {
|
|
2834
|
+
// Guard: skip undefined phantom reverts produced by MultiSelectEditor's stopEditing(true) cancel path
|
|
2835
|
+
if (params.newValue === undefined && params.colDef?.cellEditor === 'MultiSelectEditor') {
|
|
2836
|
+
return
|
|
2837
|
+
}
|
|
2838
|
+
}}
|
|
2839
|
+
|
|
2044
2840
|
onSortChanged={params => {
|
|
2045
2841
|
const sm = params.columns;
|
|
2046
2842
|
if (sm.length == 1 && sm.some(s => s.colId === 'IZ_groupCount')) {
|
|
@@ -2049,6 +2845,7 @@ const SGrid = props => {
|
|
|
2049
2845
|
}}
|
|
2050
2846
|
/>
|
|
2051
2847
|
</div>
|
|
2848
|
+
</TemplateStateContext.Provider>
|
|
2052
2849
|
<Dialog
|
|
2053
2850
|
fullWidth
|
|
2054
2851
|
open={openDialogs?.addTemplate && builderData?.id != null}
|
|
@@ -2073,29 +2870,34 @@ const SGrid = props => {
|
|
|
2073
2870
|
scroll='body'
|
|
2074
2871
|
// onClose={() => handleToggleDialogs('CustomFilter')}
|
|
2075
2872
|
>
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
const
|
|
2093
|
-
|
|
2873
|
+
{openDialogs.CustomFilter && (
|
|
2874
|
+
<CustomFilterDialog
|
|
2875
|
+
handleToggleDialogs={handleToggleDialogs}
|
|
2876
|
+
Filter={(Filter?.LocalTfilter || []).filter(f => (f.isMainFilter !== true))}
|
|
2877
|
+
customFilterCode={Filter?.customFilterCode}
|
|
2878
|
+
handleFilterChange={handleFilterChange}
|
|
2879
|
+
className={builderData?.reportSource?.fullName}
|
|
2880
|
+
LocalFilter={false}
|
|
2881
|
+
|
|
2882
|
+
isViewer={router.pathname.includes('report/viewer')}
|
|
2883
|
+
selectTFilter={selectTFilter}
|
|
2884
|
+
selectParamsMeta={builderData?.selectionParams || []}
|
|
2885
|
+
selectParamsValues={selectParams}
|
|
2886
|
+
onSelectParamsSave={(list) => {
|
|
2887
|
+
// list is array of { index, value, type }
|
|
2888
|
+
setSelectParams(prev => {
|
|
2889
|
+
const arr = [...(prev || [])];
|
|
2890
|
+
(list || []).forEach(item => {
|
|
2891
|
+
const i = item.index;
|
|
2892
|
+
const type = item.type;
|
|
2893
|
+
const current = arr[i] || {id: i, PropertyType: type, value: null};
|
|
2894
|
+
arr[i] = {...current, PropertyType: current.PropertyType || type, value: item.value};
|
|
2895
|
+
});
|
|
2896
|
+
return arr;
|
|
2094
2897
|
});
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
/>
|
|
2898
|
+
}}
|
|
2899
|
+
/>
|
|
2900
|
+
)}
|
|
2099
2901
|
</Dialog>
|
|
2100
2902
|
|
|
2101
2903
|
|
|
@@ -2166,3 +2968,15 @@ function toNestedByUnderscore(input) {
|
|
|
2166
2968
|
return result;
|
|
2167
2969
|
}
|
|
2168
2970
|
|
|
2971
|
+
// Export helper functions for use in column configurations
|
|
2972
|
+
export {
|
|
2973
|
+
setUpdateRefValue,
|
|
2974
|
+
setUpdateRefRow,
|
|
2975
|
+
getUpdateRefValue,
|
|
2976
|
+
hasUpdateRefValue,
|
|
2977
|
+
clearUpdateRefRow,
|
|
2978
|
+
clearAllUpdateRef,
|
|
2979
|
+
getAllUpdates,
|
|
2980
|
+
removeUpdateRefByRowId
|
|
2981
|
+
}
|
|
2982
|
+
|