robobyte-front-builder 1.0.0
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/jsconfig.json +28 -0
- package/next.config.js +75 -0
- package/package.json +163 -0
- package/public/fonts/NotoSansArabic-VariableFont_wdth,wght.ttf +0 -0
- package/public/fonts/font.js +2 -0
- package/public/fonts/logo.js +2 -0
- package/public/images/appicon.png +0 -0
- package/public/images/appicon1.png +0 -0
- package/public/images/asiacell.png +0 -0
- package/public/images/avatars/1.png +0 -0
- package/public/images/avatars/3.png +0 -0
- package/public/images/avatars/4.png +0 -0
- package/public/images/avatars/5.png +0 -0
- package/public/images/cards/trophy.png +0 -0
- package/public/images/favicon.png +0 -0
- package/public/images/favicon1.png +0 -0
- package/public/images/icons/bag.png +0 -0
- package/public/images/icons/briefcase.png +0 -0
- package/public/images/icons/calendar.png +0 -0
- package/public/images/icons/dashboard.png +0 -0
- package/public/images/icons/dollar.png +0 -0
- package/public/images/icons/person.png +0 -0
- package/public/images/icons/profit.png +0 -0
- package/public/images/icons/setting.png +0 -0
- package/public/images/misc/chart.png +0 -0
- package/public/images/misc/paypal.png +0 -0
- package/public/images/pages/401.png +0 -0
- package/public/images/pages/404.png +0 -0
- package/public/images/pages/500.png +0 -0
- package/public/images/pages/auth-v2-forgot-password-illustration-bordered-dark.png +0 -0
- package/public/images/pages/auth-v2-forgot-password-illustration-bordered-light.png +0 -0
- package/public/images/pages/auth-v2-forgot-password-illustration-dark.png +0 -0
- package/public/images/pages/auth-v2-forgot-password-illustration-light.png +0 -0
- package/public/images/pages/auth-v2-forgot-password-mask-dark.png +0 -0
- package/public/images/pages/auth-v2-forgot-password-mask-light.png +0 -0
- package/public/images/pages/auth-v2-login-illustration-bordered-dark.png +0 -0
- package/public/images/pages/auth-v2-login-illustration-bordered-light.png +0 -0
- package/public/images/pages/auth-v2-login-illustration-dark.png +0 -0
- package/public/images/pages/auth-v2-login-illustration-light.png +0 -0
- package/public/images/pages/auth-v2-login-mask-dark.png +0 -0
- package/public/images/pages/auth-v2-login-mask-light.png +0 -0
- package/public/images/pages/auth-v2-register-illustration-bordered-dark.png +0 -0
- package/public/images/pages/auth-v2-register-illustration-bordered-light.png +0 -0
- package/public/images/pages/auth-v2-register-illustration-dark.png +0 -0
- package/public/images/pages/auth-v2-register-illustration-light.png +0 -0
- package/public/images/pages/auth-v2-register-mask-dark.png +0 -0
- package/public/images/pages/auth-v2-register-mask-light.png +0 -0
- package/public/images/pages/misc-401-object.png +0 -0
- package/public/images/pages/misc-404-object.png +0 -0
- package/public/images/pages/misc-500-object.png +0 -0
- package/public/images/pages/misc-coming-soon-object.png +0 -0
- package/public/images/pages/misc-mask-dark.png +0 -0
- package/public/images/pages/misc-mask-light.png +0 -0
- package/public/images/white.jpg +0 -0
- package/public/images/zain.png +0 -0
- package/public/locales/ar.json +35 -0
- package/public/navigationTest/Navigation.json +13 -0
- package/public/vercel.svg +4 -0
- package/src/@core/components/auth/AclGuard.js +55 -0
- package/src/@core/components/auth/AuthGuard.js +40 -0
- package/src/@core/components/auth/GuestGuard.js +30 -0
- package/src/@core/components/custom-inputs/Horizontal.jsx +143 -0
- package/src/@core/components/custom-inputs/Image.jsx +78 -0
- package/src/@core/components/custom-inputs/Vertical.jsx +113 -0
- package/src/@core/components/customizer/index.jsx +470 -0
- package/src/@core/components/customizer/styles.module.css +169 -0
- package/src/@core/components/mui/Avatar.jsx +41 -0
- package/src/@core/components/mui/Badge.jsx +20 -0
- package/src/@core/components/mui/IconButton.jsx +74 -0
- package/src/@core/components/mui/TabList.jsx +60 -0
- package/src/@core/components/option-menu/index.jsx +137 -0
- package/src/@core/components/scroll-to-top/index.jsx +43 -0
- package/src/@core/components/spinner/index.js +26 -0
- package/src/@core/components/window-wrapper/index.js +27 -0
- package/src/@core/contexts/settingsContext.jsx +98 -0
- package/src/@core/hooks/useBgColor.js +63 -0
- package/src/@core/hooks/useImageVariant.js +27 -0
- package/src/@core/hooks/useLayoutInit.js +37 -0
- package/src/@core/hooks/useObjectCookie.js +18 -0
- package/src/@core/hooks/useSettings.jsx +15 -0
- package/src/@core/layouts/BlankLayout.js +37 -0
- package/src/@core/layouts/BlankLayoutWithAppBar.js +51 -0
- package/src/@core/layouts/HorizontalLayout.jsx +151 -0
- package/src/@core/layouts/Layout.js +39 -0
- package/src/@core/layouts/VerticalLayout.jsx +124 -0
- package/src/@core/layouts/components/blank-layout-with-appBar/index.js +115 -0
- package/src/@core/layouts/components/horizontal/app-bar-content/index.js +67 -0
- package/src/@core/layouts/components/horizontal/navigation/HorizontalNavGroup.js +352 -0
- package/src/@core/layouts/components/horizontal/navigation/HorizontalNavItems.js +21 -0
- package/src/@core/layouts/components/horizontal/navigation/HorizontalNavLink.js +195 -0
- package/src/@core/layouts/components/horizontal/navigation/index.js +31 -0
- package/src/@core/layouts/components/shared-components/LanguageDropdown.js +96 -0
- package/src/@core/layouts/components/shared-components/ModeToggler.js +32 -0
- package/src/@core/layouts/components/shared-components/NotificationDropdown.js +226 -0
- package/src/@core/layouts/components/shared-components/UserDropdown.js +177 -0
- package/src/@core/layouts/components/shared-components/footer/FooterContent.js +46 -0
- package/src/@core/layouts/components/shared-components/footer/index.js +61 -0
- package/src/@core/layouts/components/vertical/appBar/index.js +74 -0
- package/src/@core/layouts/components/vertical/navigation/Drawer.js +122 -0
- package/src/@core/layouts/components/vertical/navigation/VerticalNavGroup.js +435 -0
- package/src/@core/layouts/components/vertical/navigation/VerticalNavHeader.js +180 -0
- package/src/@core/layouts/components/vertical/navigation/VerticalNavItems.js +26 -0
- package/src/@core/layouts/components/vertical/navigation/VerticalNavLink.js +258 -0
- package/src/@core/layouts/components/vertical/navigation/VerticalNavSectionTitle.js +102 -0
- package/src/@core/layouts/components/vertical/navigation/index.js +169 -0
- package/src/@core/layouts/utils.js +69 -0
- package/src/@core/styles/Table.module.css +93 -0
- package/src/@core/styles/horizontal/menuItemStyles.js +100 -0
- package/src/@core/styles/horizontal/menuRootStyles.js +19 -0
- package/src/@core/styles/libs/fullcalendar/index.js +461 -0
- package/src/@core/styles/libs/keen-slider/index.js +111 -0
- package/src/@core/styles/libs/react-apexcharts/index.js +107 -0
- package/src/@core/styles/libs/react-cleave/index.js +33 -0
- package/src/@core/styles/libs/react-credit-cards/index.js +11 -0
- package/src/@core/styles/libs/react-datepicker/index.js +388 -0
- package/src/@core/styles/libs/react-draft-wysiwyg/index.js +144 -0
- package/src/@core/styles/libs/react-dropzone/index.js +76 -0
- package/src/@core/styles/libs/react-hot-toast/index.js +37 -0
- package/src/@core/styles/libs/recharts/index.js +47 -0
- package/src/@core/styles/stepper.js +103 -0
- package/src/@core/styles/vertical/menuItemStyles.js +138 -0
- package/src/@core/styles/vertical/menuSectionStyles.js +54 -0
- package/src/@core/styles/vertical/navigationCustomStyles.js +62 -0
- package/src/@core/svg/ContentCompact.jsx +17 -0
- package/src/@core/svg/ContentWide.jsx +17 -0
- package/src/@core/svg/DirectionLtr.jsx +93 -0
- package/src/@core/svg/DirectionRtl.jsx +93 -0
- package/src/@core/svg/LayoutCollapsed.jsx +59 -0
- package/src/@core/svg/LayoutHorizontal.jsx +42 -0
- package/src/@core/svg/LayoutVertical.jsx +59 -0
- package/src/@core/svg/Logo.jsx +76 -0
- package/src/@core/svg/SkinBordered.jsx +54 -0
- package/src/@core/svg/SkinDefault.jsx +59 -0
- package/src/@core/tailwind/plugin.js +78 -0
- package/src/@core/theme/ThemeComponent.js +63 -0
- package/src/@core/theme/ThemeOptions.js +71 -0
- package/src/@core/theme/breakpoints/index.js +11 -0
- package/src/@core/theme/colorSchemes.js +326 -0
- package/src/@core/theme/customShadows.js +11 -0
- package/src/@core/theme/globalStyles.js +81 -0
- package/src/@core/theme/index.js +42 -0
- package/src/@core/theme/overrides/accordion.js +51 -0
- package/src/@core/theme/overrides/accordion.jsx +85 -0
- package/src/@core/theme/overrides/alerts.js +110 -0
- package/src/@core/theme/overrides/alerts.jsx +180 -0
- package/src/@core/theme/overrides/autocomplete.js +14 -0
- package/src/@core/theme/overrides/autocomplete.jsx +68 -0
- package/src/@core/theme/overrides/avatar.js +38 -0
- package/src/@core/theme/overrides/avatars.js +27 -0
- package/src/@core/theme/overrides/backdrop.js +22 -0
- package/src/@core/theme/overrides/badges.js +16 -0
- package/src/@core/theme/overrides/breadcrumbs.js +11 -0
- package/src/@core/theme/overrides/button-group.js +84 -0
- package/src/@core/theme/overrides/button.js +93 -0
- package/src/@core/theme/overrides/buttonGroup.js +9 -0
- package/src/@core/theme/overrides/card.js +83 -0
- package/src/@core/theme/overrides/checkbox.jsx +95 -0
- package/src/@core/theme/overrides/chip.js +72 -0
- package/src/@core/theme/overrides/dataGrid.js +114 -0
- package/src/@core/theme/overrides/dateTimePicker.js +65 -0
- package/src/@core/theme/overrides/dialog.js +120 -0
- package/src/@core/theme/overrides/divider.js +13 -0
- package/src/@core/theme/overrides/drawer.js +20 -0
- package/src/@core/theme/overrides/fab.js +13 -0
- package/src/@core/theme/overrides/form-control-label.js +19 -0
- package/src/@core/theme/overrides/icon-button.js +145 -0
- package/src/@core/theme/overrides/index.js +103 -0
- package/src/@core/theme/overrides/input.js +72 -0
- package/src/@core/theme/overrides/link.js +9 -0
- package/src/@core/theme/overrides/list.js +44 -0
- package/src/@core/theme/overrides/menu.js +25 -0
- package/src/@core/theme/overrides/pagination.js +41 -0
- package/src/@core/theme/overrides/paper.js +9 -0
- package/src/@core/theme/overrides/popover.js +16 -0
- package/src/@core/theme/overrides/progress.js +38 -0
- package/src/@core/theme/overrides/radio.jsx +80 -0
- package/src/@core/theme/overrides/rating.js +16 -0
- package/src/@core/theme/overrides/rating.jsx +32 -0
- package/src/@core/theme/overrides/select.js +19 -0
- package/src/@core/theme/overrides/select.jsx +52 -0
- package/src/@core/theme/overrides/slider.js +97 -0
- package/src/@core/theme/overrides/snackbar.js +19 -0
- package/src/@core/theme/overrides/switch.js +73 -0
- package/src/@core/theme/overrides/switches.js +25 -0
- package/src/@core/theme/overrides/table-pagination.js +39 -0
- package/src/@core/theme/overrides/table.js +81 -0
- package/src/@core/theme/overrides/tabs.js +30 -0
- package/src/@core/theme/overrides/timeline.js +80 -0
- package/src/@core/theme/overrides/toggle-button.js +33 -0
- package/src/@core/theme/overrides/toggleButton.js +16 -0
- package/src/@core/theme/overrides/tooltip.js +21 -0
- package/src/@core/theme/overrides/typography.js +13 -0
- package/src/@core/theme/palette/index.js +107 -0
- package/src/@core/theme/shadows/index.js +61 -0
- package/src/@core/theme/shadows.js +12 -0
- package/src/@core/theme/spacing/index.js +3 -0
- package/src/@core/theme/spacing.js +5 -0
- package/src/@core/theme/typography/index.js +65 -0
- package/src/@core/theme/typography.js +84 -0
- package/src/@core/utils/create-emotion-cache.js +5 -0
- package/src/@core/utils/hex-to-rgba.js +11 -0
- package/src/@core/utils/serverHelpers.js +45 -0
- package/src/@menu/components/RouterLink.jsx +18 -0
- package/src/@menu/components/horizontal-menu/HorizontalNav.jsx +88 -0
- package/src/@menu/components/horizontal-menu/Menu.jsx +83 -0
- package/src/@menu/components/horizontal-menu/MenuButton.jsx +100 -0
- package/src/@menu/components/horizontal-menu/MenuItem.jsx +183 -0
- package/src/@menu/components/horizontal-menu/SubMenu.jsx +418 -0
- package/src/@menu/components/horizontal-menu/SubMenuContent.jsx +41 -0
- package/src/@menu/components/horizontal-menu/VerticalNavInHorizontal.jsx +20 -0
- package/src/@menu/components/vertical-menu/Menu.jsx +161 -0
- package/src/@menu/components/vertical-menu/MenuButton.jsx +95 -0
- package/src/@menu/components/vertical-menu/MenuItem.jsx +180 -0
- package/src/@menu/components/vertical-menu/MenuSection.jsx +124 -0
- package/src/@menu/components/vertical-menu/NavCollapseIcons.jsx +70 -0
- package/src/@menu/components/vertical-menu/NavHeader.jsx +39 -0
- package/src/@menu/components/vertical-menu/SubMenu.jsx +420 -0
- package/src/@menu/components/vertical-menu/SubMenuContent.jsx +101 -0
- package/src/@menu/components/vertical-menu/VerticalNav.jsx +216 -0
- package/src/@menu/contexts/horizontalNavContext.jsx +29 -0
- package/src/@menu/contexts/verticalNavContext.jsx +65 -0
- package/src/@menu/defaultConfigs.js +12 -0
- package/src/@menu/hooks/useHorizontalMenu.jsx +19 -0
- package/src/@menu/hooks/useHorizontalNav.jsx +19 -0
- package/src/@menu/hooks/useMediaQuery.jsx +29 -0
- package/src/@menu/hooks/useVerticalMenu.jsx +19 -0
- package/src/@menu/hooks/useVerticalNav.jsx +19 -0
- package/src/@menu/horizontal-menu/index.jsx +8 -0
- package/src/@menu/styles/StyledBackdrop.jsx +15 -0
- package/src/@menu/styles/StyledMenuIcon.jsx +12 -0
- package/src/@menu/styles/StyledMenuLabel.jsx +16 -0
- package/src/@menu/styles/StyledMenuPrefix.jsx +10 -0
- package/src/@menu/styles/StyledMenuSectionLabel.jsx +21 -0
- package/src/@menu/styles/StyledMenuSuffix.jsx +10 -0
- package/src/@menu/styles/StyledSubMenuContent.jsx +43 -0
- package/src/@menu/styles/horizontal/StyledHorizontalMenu.jsx +13 -0
- package/src/@menu/styles/horizontal/StyledHorizontalMenuItem.jsx +26 -0
- package/src/@menu/styles/horizontal/StyledHorizontalNav.jsx +11 -0
- package/src/@menu/styles/horizontal/StyledHorizontalNavExpandIcon.jsx +33 -0
- package/src/@menu/styles/horizontal/StyledHorizontalSubMenuContent.jsx +18 -0
- package/src/@menu/styles/horizontal/StyledHorizontalSubMenuContentWrapper.jsx +10 -0
- package/src/@menu/styles/horizontal/horizontalUl.module.css +15 -0
- package/src/@menu/styles/styles.module.css +5 -0
- package/src/@menu/styles/vertical/StyledVerticalMenu.jsx +16 -0
- package/src/@menu/styles/vertical/StyledVerticalMenuItem.jsx +28 -0
- package/src/@menu/styles/vertical/StyledVerticalMenuSection.jsx +23 -0
- package/src/@menu/styles/vertical/StyledVerticalNav.jsx +67 -0
- package/src/@menu/styles/vertical/StyledVerticalNavBgColorContainer.jsx +15 -0
- package/src/@menu/styles/vertical/StyledVerticalNavContainer.jsx +23 -0
- package/src/@menu/styles/vertical/StyledVerticalNavExpandIcon.jsx +25 -0
- package/src/@menu/styles/vertical/verticalNavBgImage.module.css +10 -0
- package/src/@menu/svg/ChevronRight.jsx +9 -0
- package/src/@menu/svg/Close.jsx +12 -0
- package/src/@menu/svg/RadioCircle.jsx +12 -0
- package/src/@menu/svg/RadioCircleMarked.jsx +13 -0
- package/src/@menu/utils/menuClasses.js +44 -0
- package/src/@menu/utils/menuUtils.jsx +145 -0
- package/src/@menu/vertical-menu/index.jsx +11 -0
- package/src/configs/Permissions/PermissionsActions.json +6 -0
- package/src/configs/Permissions/PermissionsSubjects.json +107 -0
- package/src/configs/acl.js +115 -0
- package/src/configs/auth.js +5 -0
- package/src/configs/aws-exports.js +30 -0
- package/src/configs/firebase.js +25 -0
- package/src/configs/i18n.js +34 -0
- package/src/configs/izColors.json +11 -0
- package/src/configs/primaryColorConfig.js +35 -0
- package/src/configs/themeConfig.js +44 -0
- package/src/context/AuthContext.js +179 -0
- package/src/context/BuilderContext.jsx +209 -0
- package/src/context/SystemContext.js +99 -0
- package/src/hooks/useAuth.js +4 -0
- package/src/layouts/UserLayout.js +94 -0
- package/src/layouts/UserThemeOptions.js +191 -0
- package/src/layouts/components/Direction.js +30 -0
- package/src/layouts/components/HtmlTooltip.js +15 -0
- package/src/layouts/components/Translations.js +11 -0
- package/src/layouts/components/UserDropdown.js +217 -0
- package/src/layouts/components/UserIcon.js +40 -0
- package/src/layouts/components/acl/Can.js +6 -0
- package/src/layouts/components/acl/CanViewNavGroup.js +36 -0
- package/src/layouts/components/acl/CanViewNavLink.js +17 -0
- package/src/layouts/components/acl/CanViewNavSectionTitle.js +17 -0
- package/src/layouts/components/horizontal/AppBarContent.js +39 -0
- package/src/layouts/components/horizontal/ServerSideNavItems.js +44 -0
- package/src/layouts/components/mui/StepperComps.js +55 -0
- package/src/layouts/components/vertical/AppBarContent.js +35 -0
- package/src/layouts/components/vertical/ServerSideNavItems.js +44 -0
- package/src/lib/index.js +75 -0
- package/src/lib/navigation/NavigationExtensionContext.jsx +81 -0
- package/src/lib/navigation/mergeNavExtensions.js +66 -0
- package/src/lib/navigation/useNavExtension.js +54 -0
- package/src/lib/providers/RoboByteFrontBuilderProvider.jsx +57 -0
- package/src/libs/ApexCharts.jsx +5 -0
- package/src/libs/ReactPlayer.jsx +5 -0
- package/src/libs/Recharts.jsx +4 -0
- package/src/libs/auth.js +124 -0
- package/src/libs/styles/AppFullCalendar.js +505 -0
- package/src/libs/styles/AppKeenSlider.js +116 -0
- package/src/libs/styles/AppReactApexCharts.jsx +110 -0
- package/src/libs/styles/AppReactDatepicker.jsx +470 -0
- package/src/libs/styles/AppReactDropzone.js +76 -0
- package/src/libs/styles/AppReactToastify.jsx +108 -0
- package/src/libs/styles/AppRecharts.js +55 -0
- package/src/libs/styles/inputOtp.module.css +39 -0
- package/src/libs/styles/tiptapEditor.css +72 -0
- package/src/navigation/horizontal/index.js +246 -0
- package/src/navigation/vertical/index.js +253 -0
- package/src/pages/401.js +70 -0
- package/src/pages/404.js +67 -0
- package/src/pages/500.js +68 -0
- package/src/pages/[slug].js +115 -0
- package/src/pages/_app.js +148 -0
- package/src/pages/_document.js +72 -0
- package/src/pages/api/navigation/regenerate-registry.js +116 -0
- package/src/pages/api/navigation/save.js +218 -0
- package/src/pages/authModule/acl/index.js +48 -0
- package/src/pages/authModule/forgot-password/index.js +228 -0
- package/src/pages/authModule/permissions/rolePermissions/[id]/rolePermissionsUser/index.js +392 -0
- package/src/pages/authModule/permissions/rolePermissions/index.js +343 -0
- package/src/pages/authModule/permissions/systemPermissions/index.js +354 -0
- package/src/pages/authModule/privacy/index.js +721 -0
- package/src/pages/authModule/users/index.js +210 -0
- package/src/pages/index.js +44 -0
- package/src/pages/login/index.js +328 -0
- package/src/pages/mainHome/index.js +181 -0
- package/src/pages/navigatorBuilder/index.jsx +2070 -0
- package/src/pages/reportModule/reportBuilder/index.js +1361 -0
- package/src/pages/reportModule/reportBuilder/reportViewer/index.js +187 -0
- package/src/pages/reportModule/reportBuilder/reports/index.js +198 -0
- package/src/pages/viewBuilder/index.jsx +94 -0
- package/src/pages/viewBuilder/viewPage/index.jsx +46 -0
- package/src/pages/viewBuilder/views/index.js +146 -0
- package/src/pages/viewer/[id]/index.js +88 -0
- package/src/services/ContentTypes.js +10 -0
- package/src/services/DeleteService.js +77 -0
- package/src/services/Endpoints/BunnyEndpoints.js +26 -0
- package/src/services/Endpoints/CaseEndpoints.js +29 -0
- package/src/services/Endpoints/CaseTypeEndpoints.js +29 -0
- package/src/services/Endpoints/ContactsEndpoints.js +81 -0
- package/src/services/Endpoints/CourtEndpoints.js +29 -0
- package/src/services/Endpoints/FilterEndpoints.js +31 -0
- package/src/services/Endpoints/NavigatorEndpoints.js +21 -0
- package/src/services/Endpoints/ReportBuilderEndpoints.js +45 -0
- package/src/services/Endpoints/UiBuilderEndpoints.js +37 -0
- package/src/services/Endpoints/UserTableTemplateEndpoints.js +26 -0
- package/src/services/Endpoints/UsersEndpoints.js +142 -0
- package/src/services/Endpoints/ViewEndpoints.js +28 -0
- package/src/services/Endpoints/ViewPermissionEndpoints.js +37 -0
- package/src/services/Endpoints/ViewPermissionRoleEndpoints.js +39 -0
- package/src/services/Endpoints/ViewPermissionRoleItemsEndpoints.js +32 -0
- package/src/services/Endpoints/ViewPermissionRoleUsersEndpoints.js +28 -0
- package/src/services/Endpoints/WidgetEndpoints.js +28 -0
- package/src/services/Endpoints.js +49 -0
- package/src/services/External/BunnyCdn/BunnyUploadFile.js +168 -0
- package/src/services/GetService.js +67 -0
- package/src/services/MetaDataTemplate/index.js +5 -0
- package/src/services/PatchService.js +83 -0
- package/src/services/PostService.js +81 -0
- package/src/services/StreamService.js +82 -0
- package/src/services/UpdateService.js +82 -0
- package/src/services/auth/AuthService.js +47 -0
- package/src/services/auth/GetUsersService.js +38 -0
- package/src/services/auth/PostRegisterUser.js +29 -0
- package/src/services/auth/PostResetPasswordService.js +28 -0
- package/src/services/auth/PutAccountService.js +29 -0
- package/src/services/auth/PutRefreshToken.js +69 -0
- package/src/services/auth/RefreshToken.js +0 -0
- package/src/services/builderHelper/actionExecutor.js +73 -0
- package/src/services/builderHelper/builderHelper.js +99 -0
- package/src/services/builderHelper/index.js +2 -0
- package/src/services/builderHelper/jsExecutor.js +115 -0
- package/src/services/builderHelper/layoutHelpers.js +231 -0
- package/src/services/builderHelper/nodeFactory.js +44 -0
- package/src/services/builderHelper/resolveProps.js +34 -0
- package/src/services/builderHelper/tree.js +131 -0
- package/src/services/components/UniversalNestedAutocomplete.js +331 -0
- package/src/services/components/agGridAutoComplete.js +172 -0
- package/src/services/components/universalAutoComplete.js +207 -0
- package/src/services/enums/ReportBuilderTypeEnum.js +18 -0
- package/src/services/helper/FilterFormat.js +70 -0
- package/src/services/helper/FormatCurrencyIQD.js +11 -0
- package/src/services/helper/datagridEditComponents.js +38 -0
- package/src/services/helper/dateFormat.js +30 -0
- package/src/services/helper/formData.js +21 -0
- package/src/services/helper/getFieldByType.js +0 -0
- package/src/services/helper/getPropByString.js +18 -0
- package/src/services/helper/handleChange.js +26 -0
- package/src/services/helper/helper.js +105 -0
- package/src/services/helper/multiSelectEditor.js +226 -0
- package/src/services/helper/translateOrderReturnStatus.js +12 -0
- package/src/services/helper/translateRole.js +24 -0
- package/src/services/helper/translateStatus.js +12 -0
- package/src/services/helper/translateTransferReceiptType.js +67 -0
- package/src/services/helper/translsateStoreProductTransfer.js +40 -0
- package/src/services/helper/translsateStoreType.js +25 -0
- package/src/services/helper/useInterval.js +21 -0
- package/src/services/helper/yupCutomization.js +15 -0
- package/src/services/reportData/fetchReportData.js +210 -0
- package/src/views/ConfirmDialog.js +178 -0
- package/src/views/builder/JSEditor.js +226 -0
- package/src/views/builder/inspector/Inspector.jsx +63 -0
- package/src/views/builder/inspector/Tabs/ComponentActionsTab.jsx +117 -0
- package/src/views/builder/inspector/Tabs/MainTab.jsx +95 -0
- package/src/views/builder/inspector/Tabs/RulesTab.jsx +79 -0
- package/src/views/builder/inspector/Tabs/StyleTab.jsx +79 -0
- package/src/views/builder/inspector/definitions/autocomplete/main.js +25 -0
- package/src/views/builder/inspector/definitions/breadcrumb/main.js +9 -0
- package/src/views/builder/inspector/definitions/button/actions.js +12 -0
- package/src/views/builder/inspector/definitions/button/main.js +14 -0
- package/src/views/builder/inspector/definitions/button/rules.js +5 -0
- package/src/views/builder/inspector/definitions/button/style.js +32 -0
- package/src/views/builder/inspector/definitions/button.actions.js +12 -0
- package/src/views/builder/inspector/definitions/card/main.js +11 -0
- package/src/views/builder/inspector/definitions/cell/main.js +4 -0
- package/src/views/builder/inspector/definitions/checkbox/actions.js +1 -0
- package/src/views/builder/inspector/definitions/checkbox/main.js +13 -0
- package/src/views/builder/inspector/definitions/checkbox/rules.js +8 -0
- package/src/views/builder/inspector/definitions/checkbox/style.js +38 -0
- package/src/views/builder/inspector/definitions/checkboxFields.js +0 -0
- package/src/views/builder/inspector/definitions/column/main.js +9 -0
- package/src/views/builder/inspector/definitions/column-group/main.js +18 -0
- package/src/views/builder/inspector/definitions/common/actions.js +1 -0
- package/src/views/builder/inspector/definitions/common/main.js +14 -0
- package/src/views/builder/inspector/definitions/common/rules.js +8 -0
- package/src/views/builder/inspector/definitions/common/style.js +39 -0
- package/src/views/builder/inspector/definitions/common.advanced.js +8 -0
- package/src/views/builder/inspector/definitions/common.main.js +14 -0
- package/src/views/builder/inspector/definitions/common.style.js +33 -0
- package/src/views/builder/inspector/definitions/commonMainFields.js +18 -0
- package/src/views/builder/inspector/definitions/container/actions.js +1 -0
- package/src/views/builder/inspector/definitions/container/main.js +4 -0
- package/src/views/builder/inspector/definitions/container/rules.js +4 -0
- package/src/views/builder/inspector/definitions/container/style.js +32 -0
- package/src/views/builder/inspector/definitions/datepicker/actions.js +1 -0
- package/src/views/builder/inspector/definitions/datepicker/main.js +28 -0
- package/src/views/builder/inspector/definitions/datepicker/rules.js +8 -0
- package/src/views/builder/inspector/definitions/datepicker/style.js +38 -0
- package/src/views/builder/inspector/definitions/datepicker.main.js +28 -0
- package/src/views/builder/inspector/definitions/divider/actions.js +1 -0
- package/src/views/builder/inspector/definitions/divider/main.js +23 -0
- package/src/views/builder/inspector/definitions/divider/rules.js +4 -0
- package/src/views/builder/inspector/definitions/divider/style.js +9 -0
- package/src/views/builder/inspector/definitions/dropdown/actions.js +10 -0
- package/src/views/builder/inspector/definitions/dropdown/main.js +19 -0
- package/src/views/builder/inspector/definitions/dropdown/rules.js +8 -0
- package/src/views/builder/inspector/definitions/dropdown/style.js +38 -0
- package/src/views/builder/inspector/definitions/header/actions.js +1 -0
- package/src/views/builder/inspector/definitions/header/main.js +29 -0
- package/src/views/builder/inspector/definitions/header/rules.js +4 -0
- package/src/views/builder/inspector/definitions/header/style.js +12 -0
- package/src/views/builder/inspector/definitions/header-cell/main.js +5 -0
- package/src/views/builder/inspector/definitions/image/actions.js +1 -0
- package/src/views/builder/inspector/definitions/image/main.js +13 -0
- package/src/views/builder/inspector/definitions/image/rules.js +4 -0
- package/src/views/builder/inspector/definitions/image/style.js +12 -0
- package/src/views/builder/inspector/definitions/index.js +407 -0
- package/src/views/builder/inspector/definitions/input/actions.js +1 -0
- package/src/views/builder/inspector/definitions/input/main.js +14 -0
- package/src/views/builder/inspector/definitions/input/rules.js +8 -0
- package/src/views/builder/inspector/definitions/input/style.js +32 -0
- package/src/views/builder/inspector/definitions/label/actions.js +1 -0
- package/src/views/builder/inspector/definitions/label/main.js +24 -0
- package/src/views/builder/inspector/definitions/label/rules.js +4 -0
- package/src/views/builder/inspector/definitions/label/style.js +12 -0
- package/src/views/builder/inspector/definitions/layout/actions.js +1 -0
- package/src/views/builder/inspector/definitions/layout/main.js +6 -0
- package/src/views/builder/inspector/definitions/layout/rules.js +3 -0
- package/src/views/builder/inspector/definitions/layout/style.js +7 -0
- package/src/views/builder/inspector/definitions/layout-cell/actions.js +1 -0
- package/src/views/builder/inspector/definitions/layout-cell/main.js +7 -0
- package/src/views/builder/inspector/definitions/layout-cell/rules.js +3 -0
- package/src/views/builder/inspector/definitions/layout-cell/style.js +44 -0
- package/src/views/builder/inspector/definitions/link/actions.js +1 -0
- package/src/views/builder/inspector/definitions/link/main.js +29 -0
- package/src/views/builder/inspector/definitions/link/rules.js +4 -0
- package/src/views/builder/inspector/definitions/link/style.js +11 -0
- package/src/views/builder/inspector/definitions/menu/actions.js +3 -0
- package/src/views/builder/inspector/definitions/menu/main.js +16 -0
- package/src/views/builder/inspector/definitions/menu/rules.js +4 -0
- package/src/views/builder/inspector/definitions/menu/style.js +33 -0
- package/src/views/builder/inspector/definitions/number/actions.js +10 -0
- package/src/views/builder/inspector/definitions/number/main.js +29 -0
- package/src/views/builder/inspector/definitions/number/rules.js +8 -0
- package/src/views/builder/inspector/definitions/number/style.js +32 -0
- package/src/views/builder/inspector/definitions/progress-circle/actions.js +1 -0
- package/src/views/builder/inspector/definitions/progress-circle/main.js +18 -0
- package/src/views/builder/inspector/definitions/progress-circle/rules.js +4 -0
- package/src/views/builder/inspector/definitions/progress-circle/style.js +5 -0
- package/src/views/builder/inspector/definitions/progress-line/actions.js +1 -0
- package/src/views/builder/inspector/definitions/progress-line/main.js +16 -0
- package/src/views/builder/inspector/definitions/progress-line/rules.js +4 -0
- package/src/views/builder/inspector/definitions/progress-line/style.js +6 -0
- package/src/views/builder/inspector/definitions/radio/actions.js +10 -0
- package/src/views/builder/inspector/definitions/radio/main.js +16 -0
- package/src/views/builder/inspector/definitions/radio/rules.js +8 -0
- package/src/views/builder/inspector/definitions/radio/style.js +32 -0
- package/src/views/builder/inspector/definitions/reportViewer/main.js +12 -0
- package/src/views/builder/inspector/definitions/richtext/actions.js +10 -0
- package/src/views/builder/inspector/definitions/richtext/main.js +21 -0
- package/src/views/builder/inspector/definitions/richtext/rules.js +8 -0
- package/src/views/builder/inspector/definitions/richtext/style.js +32 -0
- package/src/views/builder/inspector/definitions/signature/actions.js +1 -0
- package/src/views/builder/inspector/definitions/signature/main.js +13 -0
- package/src/views/builder/inspector/definitions/signature/rules.js +8 -0
- package/src/views/builder/inspector/definitions/signature/style.js +26 -0
- package/src/views/builder/inspector/definitions/table/main.js +9 -0
- package/src/views/builder/inspector/definitions/tag/actions.js +10 -0
- package/src/views/builder/inspector/definitions/tag/main.js +17 -0
- package/src/views/builder/inspector/definitions/tag/rules.js +8 -0
- package/src/views/builder/inspector/definitions/tag/style.js +32 -0
- package/src/views/builder/inspector/definitions/textarea/actions.js +1 -0
- package/src/views/builder/inspector/definitions/textarea/main.js +16 -0
- package/src/views/builder/inspector/definitions/textarea/rules.js +8 -0
- package/src/views/builder/inspector/definitions/textarea/style.js +32 -0
- package/src/views/builder/inspector/definitions/time/actions.js +10 -0
- package/src/views/builder/inspector/definitions/time/main.js +18 -0
- package/src/views/builder/inspector/definitions/time/rules.js +8 -0
- package/src/views/builder/inspector/definitions/time/style.js +32 -0
- package/src/views/builder/inspector/definitions/toggle/actions.js +10 -0
- package/src/views/builder/inspector/definitions/toggle/main.js +26 -0
- package/src/views/builder/inspector/definitions/toggle/rules.js +8 -0
- package/src/views/builder/inspector/definitions/toggle/style.js +32 -0
- package/src/views/builder/inspector/fields/BooleanEditor.jsx +30 -0
- package/src/views/builder/inspector/fields/ExpressionEditor.jsx +35 -0
- package/src/views/builder/inspector/fields/FieldWrapper.jsx +15 -0
- package/src/views/builder/inspector/fields/ItemsEditor.jsx +118 -0
- package/src/views/builder/inspector/fields/OptionsEditor.jsx +118 -0
- package/src/views/builder/inspector/fields/SelectEditor.jsx +32 -0
- package/src/views/builder/inspector/fields/TabsEditor.jsx +128 -0
- package/src/views/builder/inspector/fields/TextEditor.jsx +28 -0
- package/src/views/builder/inspector/fields/TextFieldEditor.jsx +0 -0
- package/src/views/builder/sidebar/Sidebar.jsx +20 -0
- package/src/views/builder/sidebar/SidebarTabs.jsx +50 -0
- package/src/views/builder/sidebar/tabs/ActionsTab.jsx +94 -0
- package/src/views/builder/sidebar/tabs/Components/ComponentItem.jsx +69 -0
- package/src/views/builder/sidebar/tabs/Components/ComponentsTab.jsx +89 -0
- package/src/views/builder/sidebar/tabs/Components/GroupLevelAutocomplete.jsx +269 -0
- package/src/views/builder/sidebar/tabs/Components/componentCatalog.js +69 -0
- package/src/views/builder/sidebar/tabs/TreeTab.jsx +205 -0
- package/src/views/builder/sidebar/tabs/ViewTab.jsx +121 -0
- package/src/views/builder/viewer/Canvas.jsx +7 -0
- package/src/views/builder/viewer/ComponentRenderer.jsx +166 -0
- package/src/views/builder/viewer/DropZone.jsx +60 -0
- package/src/views/builder/viewer/ProductionViewer.jsx +155 -0
- package/src/views/builder/viewer/SaveViewDialog.jsx +60 -0
- package/src/views/builder/viewer/SaveWidgetDialog.jsx +142 -0
- package/src/views/builder/viewer/Viewer.jsx +83 -0
- package/src/views/builder/viewer/ViewerComponentWrapper.jsx +238 -0
- package/src/views/builder/viewer/ViewerToolbar.jsx +89 -0
- package/src/views/builder/viewer/renderers/AutoCompleteRenderer.jsx +57 -0
- package/src/views/builder/viewer/renderers/BreadcrumbRenderer.jsx +32 -0
- package/src/views/builder/viewer/renderers/ButtonRenderer.jsx +55 -0
- package/src/views/builder/viewer/renderers/CardRenderer.jsx +76 -0
- package/src/views/builder/viewer/renderers/CellRenderer.jsx +71 -0
- package/src/views/builder/viewer/renderers/CheckboxRenderer.jsx +27 -0
- package/src/views/builder/viewer/renderers/ColumnGroupRenderer.jsx +96 -0
- package/src/views/builder/viewer/renderers/ColumnRenderer.jsx +71 -0
- package/src/views/builder/viewer/renderers/ContainerRenderer.jsx +111 -0
- package/src/views/builder/viewer/renderers/DatePickerRenderer.jsx +49 -0
- package/src/views/builder/viewer/renderers/DividerRenderer.jsx +22 -0
- package/src/views/builder/viewer/renderers/DropdownRenderer.jsx +63 -0
- package/src/views/builder/viewer/renderers/HeaderCellRenderer.jsx +78 -0
- package/src/views/builder/viewer/renderers/HeaderRenderer.jsx +23 -0
- package/src/views/builder/viewer/renderers/ImageRenderer.jsx +26 -0
- package/src/views/builder/viewer/renderers/InputRenderer.jsx +34 -0
- package/src/views/builder/viewer/renderers/LabelRenderer.jsx +23 -0
- package/src/views/builder/viewer/renderers/LayoutCellRenderer.jsx +162 -0
- package/src/views/builder/viewer/renderers/LayoutContextMenu.jsx +173 -0
- package/src/views/builder/viewer/renderers/LayoutRenderer.jsx +51 -0
- package/src/views/builder/viewer/renderers/LinkRenderer.jsx +24 -0
- package/src/views/builder/viewer/renderers/MenuRenderer.jsx +291 -0
- package/src/views/builder/viewer/renderers/NumberFormatRenderer.jsx +80 -0
- package/src/views/builder/viewer/renderers/ProgressCircleRenderer.jsx +47 -0
- package/src/views/builder/viewer/renderers/ProgressLineRenderer.jsx +36 -0
- package/src/views/builder/viewer/renderers/RadioGroupRenderer.jsx +57 -0
- package/src/views/builder/viewer/renderers/RepeaterRenderer.jsx +94 -0
- package/src/views/builder/viewer/renderers/ReportViewerRenderer.jsx +15 -0
- package/src/views/builder/viewer/renderers/RichTextRenderer.jsx +76 -0
- package/src/views/builder/viewer/renderers/SignatureRenderer.jsx +89 -0
- package/src/views/builder/viewer/renderers/TabRenderer.jsx +82 -0
- package/src/views/builder/viewer/renderers/TableRenderer.jsx +92 -0
- package/src/views/builder/viewer/renderers/TagPickerRenderer.jsx +67 -0
- package/src/views/builder/viewer/renderers/TextAreaRenderer.jsx +37 -0
- package/src/views/builder/viewer/renderers/TextRenderer.jsx +9 -0
- package/src/views/builder/viewer/renderers/TimePickerRenderer.jsx +49 -0
- package/src/views/builder/viewer/renderers/ToggleRenderer.jsx +46 -0
- package/src/views/builder/viewer/renderers/WizardRenderer.jsx +88 -0
- package/src/views/builder/viewer/renderers/WizardStepRenderer.jsx +72 -0
- package/src/views/customFilter/CustomFilterDialog.js +1142 -0
- package/src/views/genericTable/BuilderExpressionParams.js +193 -0
- package/src/views/genericTable/FixedFilterDialog.js +447 -0
- package/src/views/genericTable/GenericForm.js +301 -0
- package/src/views/genericTable/QueryEditor.js +99 -0
- package/src/views/genericTable/RegexTextEditor.js +182 -0
- package/src/views/genericTable/ReportBuilderSaveDialog.js +153 -0
- package/src/views/genericTable/RoutingSettingDialog.js +189 -0
- package/src/views/genericTable/SGrid.js +2168 -0
- package/src/views/genericTable/SearchFilterDialog.js +247 -0
- package/src/views/genericTable/TAGGrid.js +1046 -0
- package/src/views/genericTable/cellEditors/autocompleteEditor.js +229 -0
- package/src/views/genericTable/cellRenderers/imageRenderer.js +14 -0
- package/src/views/genericTable/statusBar/rowCountStatusBar.js +37 -0
- package/src/views/genericTable/template/addTemplate.js +187 -0
- package/src/views/genericTable/toolPanels/CustomColumnsToolPanel.js +43 -0
- package/src/views/pages/auth/FooterIllustrationsV2.js +40 -0
- package/src/views/pages/misc/FooterIllustrations.js +47 -0
- package/src/views/pages/misc/muiTable/CustomPagination.js +34 -0
- package/src/views/pages/users/UserManageDialog.js +283 -0
- package/src/views/pages/users/UserViewPage.js +199 -0
- package/src/views/users/AddUserNameDialog.js +162 -0
- package/src/views/users/ContactManage.js +449 -0
- package/src/views/users/ResetPasswordDialog.js +242 -0
- package/styles/globals.css +71 -0
|
@@ -0,0 +1,2168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SGrid: Server-side data grid wrapper around AG Grid for Mazajak
|
|
3
|
+
*
|
|
4
|
+
* What this component does
|
|
5
|
+
* - Renders an AG Grid in server-side row model mode with optional grouping, pivoting, and aggregation.
|
|
6
|
+
* - Fetches data from ReportBuilderEndpoints.Post.GenericGet for grouped, streamed, and paged requests.
|
|
7
|
+
* - Applies a unified filtering system (Tfilter) coming from multiple sources: external props, builder model, and local UI state.
|
|
8
|
+
* - Supports a global quick search term that behaves smartly for numeric vs. text fields.
|
|
9
|
+
* - Manages templates (save/load) for column layout, filters, and settings.
|
|
10
|
+
* - Exports data to PDF/Excel with current columns, order, and applied filters.
|
|
11
|
+
* - Integrates with dashboard/report builder contexts and honors time zone and formatting.
|
|
12
|
+
*
|
|
13
|
+
* Key props of interest
|
|
14
|
+
* - builderData: Provides selected fields, initial filters, and meta used to construct column definitions and filters.
|
|
15
|
+
* - filter: External filter object merged with local filters (Filter.LocalTfilter) and builder filters.
|
|
16
|
+
* - groupBy: Initial grouping configuration for server-side grouping.
|
|
17
|
+
* - actions: Optional cell renderer for Actions column.
|
|
18
|
+
* - refresh / externalTimer: Triggers to refresh the grid’s data.
|
|
19
|
+
* - fixedTIncludes: Extra includes to send with requests (controls data shape/joins on server).
|
|
20
|
+
* - reportTitle, pageName, uniqueIdPath, columnsConfig: Presentation/behavior options.
|
|
21
|
+
*
|
|
22
|
+
* Data flow overview
|
|
23
|
+
* 1) Column definitions are derived from builderData.selectedFields (+ extraCols) and user templates.
|
|
24
|
+
* 2) AG Grid is initialized with server-side datasource; getRowsFromApi constructs the request payload:
|
|
25
|
+
* - Merges filters in this order: LocalTfilter (component state) + builder filters + fixed filters from props.
|
|
26
|
+
* - Adds search term filters based on searchTermRef and searchFieldsRef metadata.
|
|
27
|
+
* - Translates group/pivot/value columns, sort model, and pagination into the expected backend format.
|
|
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 viewer state.
|
|
30
|
+
*
|
|
31
|
+
* Quick search behavior (important)
|
|
32
|
+
* - searchTermRef holds the current string. If it parses to a finite number, we search numeric (Int) fields with a numeric value.
|
|
33
|
+
* - Otherwise, we search only non-Int fields using the raw string. This prevents type errors on the backend and improves matches.
|
|
34
|
+
* - searchFieldsRef is metadata describing which fields are searchable and their propertyType.
|
|
35
|
+
*
|
|
36
|
+
* Filters (Tfilter)
|
|
37
|
+
* - Filter object has LocalTfilter for user-added filters. Builder filters and fixed filters are merged with it.
|
|
38
|
+
* - Each filter item typically has: { path, friendlyName, value, method, dtoClassName, modelClassName, afterSelect }.
|
|
39
|
+
* - Grouping adds implicit Equals filters for the currently expanded group keys when requesting child levels.
|
|
40
|
+
*
|
|
41
|
+
* Exports
|
|
42
|
+
* - PDF export uses current visible columns (in order) and transformed cell values, includes a summary of active filters.
|
|
43
|
+
* - Excel export is supported (see FileExcelOutline usage) to dump the current dataset.
|
|
44
|
+
*
|
|
45
|
+
* Implementation notes
|
|
46
|
+
* - Uses themeQuartz from ag-grid-community with a custom accent color.
|
|
47
|
+
* - Maintains gridApi refs to read column state, sorting, and to trigger refreshServerSide.
|
|
48
|
+
* - Be cautious when modifying getRowsFromApi: it is responsible for composing the exact backend payload.
|
|
49
|
+
* - When adjusting quick search logic, keep numeric vs. text handling aligned with backend expectations.
|
|
50
|
+
*/
|
|
51
|
+
// ** React Imports
|
|
52
|
+
// ** Next Import
|
|
53
|
+
|
|
54
|
+
// ** MUI Imports
|
|
55
|
+
import Box from '@mui/material/Box'
|
|
56
|
+
import Grid from '@mui/material/Grid'
|
|
57
|
+
|
|
58
|
+
// ** Icons Imports
|
|
59
|
+
// ** Store Imports
|
|
60
|
+
// ** Custom Components Imports
|
|
61
|
+
import {useCallback, useContext, useEffect, useMemo, useRef, useState} from 'react'
|
|
62
|
+
import {Endpoints, Services} from 'src/services/Endpoints'
|
|
63
|
+
import {
|
|
64
|
+
Autocomplete, Checkbox,
|
|
65
|
+
CircularProgress,
|
|
66
|
+
Dialog,
|
|
67
|
+
FormControl, FormControlLabel,
|
|
68
|
+
IconButton,
|
|
69
|
+
MenuItem,
|
|
70
|
+
Select,
|
|
71
|
+
TextField,
|
|
72
|
+
Tooltip,
|
|
73
|
+
Chip,
|
|
74
|
+
Stack,
|
|
75
|
+
Popper,
|
|
76
|
+
Paper,
|
|
77
|
+
List,
|
|
78
|
+
ListItemButton,
|
|
79
|
+
ClickAwayListener
|
|
80
|
+
} from '@mui/material'
|
|
81
|
+
import {AgGridReact} from "ag-grid-react";
|
|
82
|
+
import {Edit, FilterAlt, PrintOutlined, RefreshOutlined, Save, SaveAs, Close} from "@mui/icons-material";
|
|
83
|
+
import {getRandomInt, Helper} from "services/helper/helper";
|
|
84
|
+
import PostService from 'services/PostService'
|
|
85
|
+
import handleChange from 'services/helper/handleChange'
|
|
86
|
+
import {DotsVerticalCircleOutline, FileExcelOutline} from 'mdi-material-ui'
|
|
87
|
+
import AddTemplateDialog from './template/addTemplate'
|
|
88
|
+
import UpdateService from 'services/UpdateService'
|
|
89
|
+
import {useRouter} from 'next/router'
|
|
90
|
+
import {SystemContext} from 'context/SystemContext'
|
|
91
|
+
import {AuthContext} from 'context/AuthContext'
|
|
92
|
+
import moment from "moment-timezone"
|
|
93
|
+
import numeral from 'numeral'
|
|
94
|
+
import CustomFilterDialog from "views/customFilter/CustomFilterDialog";
|
|
95
|
+
import CustomStatusBar from "views/genericTable/statusBar/rowCountStatusBar";
|
|
96
|
+
import StreamService from "services/StreamService";
|
|
97
|
+
import {themeQuartz} from 'ag-grid-community';
|
|
98
|
+
import {ReportBuilderEndpoints} from "services/Endpoints/ReportBuilderEndpoints";
|
|
99
|
+
import {debounce} from "lodash";
|
|
100
|
+
import jsPDF from "jspdf";
|
|
101
|
+
import "jspdf-autotable";
|
|
102
|
+
import arabicFontBase64 from "../../../public/fonts/font";
|
|
103
|
+
import {FilterFormat} from "services/helper/FilterFormat";
|
|
104
|
+
|
|
105
|
+
// ** Utils Import
|
|
106
|
+
|
|
107
|
+
// ** Actions Imports
|
|
108
|
+
|
|
109
|
+
// ** Custom Components Imports
|
|
110
|
+
const defaultFinalRequest = {
|
|
111
|
+
groupBy: null,
|
|
112
|
+
endpoint: null,
|
|
113
|
+
filter: {},
|
|
114
|
+
params: {}
|
|
115
|
+
}
|
|
116
|
+
const SGrid = props => {
|
|
117
|
+
// ** State
|
|
118
|
+
const appContext = useContext(SystemContext);
|
|
119
|
+
const imageBaseUrl = appContext?.settings?.imagesStorageServer;
|
|
120
|
+
const agTheme = themeQuartz
|
|
121
|
+
.withParams({
|
|
122
|
+
accentColor: "#FF1185"
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
const {
|
|
126
|
+
externalTimer,
|
|
127
|
+
isSingle,
|
|
128
|
+
minimized,
|
|
129
|
+
setData,
|
|
130
|
+
builderModel,
|
|
131
|
+
expireReport,
|
|
132
|
+
filter: externalFilter,
|
|
133
|
+
actions,
|
|
134
|
+
refresh,
|
|
135
|
+
height,
|
|
136
|
+
extraCols,
|
|
137
|
+
setOutGridApi,
|
|
138
|
+
setEventRowSelected,
|
|
139
|
+
pageName,
|
|
140
|
+
paramsPage,
|
|
141
|
+
fixedTIncludes,
|
|
142
|
+
groupBy,
|
|
143
|
+
noPurge,
|
|
144
|
+
reportTitle,
|
|
145
|
+
uniqueIdPath,
|
|
146
|
+
columnsConfig,
|
|
147
|
+
dataAsObject = false
|
|
148
|
+
} = props
|
|
149
|
+
const groupEndPoint = ReportBuilderEndpoints.Post.GenericGet;
|
|
150
|
+
const streamEndPoint = ReportBuilderEndpoints.Post.GenericGet;
|
|
151
|
+
const pagedEndPoint = ReportBuilderEndpoints.Post.GenericGet;
|
|
152
|
+
const [responseType, setResponseType] = useState()
|
|
153
|
+
const [pagedAgg, setPagedAgg] = useState()
|
|
154
|
+
const [colDefs, setColDefs] = useState([])
|
|
155
|
+
const [gridApi, setGridApi] = useState(null)
|
|
156
|
+
const [includes, setIncludes] = useState([])
|
|
157
|
+
const [isPagination, setIsPagination] = useState(true)
|
|
158
|
+
const [templates, setTemplates] = useState([])
|
|
159
|
+
const [timerValue, setTimerValue] = useState(0)
|
|
160
|
+
const [localRefresh, setLocalRefresh] = useState(false)
|
|
161
|
+
const [selectedTemplate, setSelectedTemplate] = useState(null)
|
|
162
|
+
const [localClasName, setLocalClasName] = useState(null)
|
|
163
|
+
const userTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
164
|
+
const router = useRouter()
|
|
165
|
+
const authValues = useContext(AuthContext)
|
|
166
|
+
const [isTemplateEditing, setIsTemplateEditing] = useState(false)
|
|
167
|
+
const [isDownloading, setIsDownloading] = useState(false)
|
|
168
|
+
const [finalRequestObject, setFinalRequestObject] = useState(defaultFinalRequest)
|
|
169
|
+
const [selectedFields, setSelectedFields] = useState([])
|
|
170
|
+
const [selectParams, setSelectParams] = useState([])
|
|
171
|
+
const [selectTFilter, setSelectTFilter] = useState([])
|
|
172
|
+
const [builderTFilter, setBuilderTFilter] = useState([])
|
|
173
|
+
const [searchTerm, setSearchTerm] = useState('');
|
|
174
|
+
const [selectedSearchObjects, setSelectedSearchObjects] = useState([]);
|
|
175
|
+
const [tRouting, setTRouting] = useState([]);
|
|
176
|
+
const [builderData, setBuilderData] = useState(null);
|
|
177
|
+
|
|
178
|
+
// Search grouping name for OR groups
|
|
179
|
+
const SEARCH_GROUP_NAME = 'searchGroup';
|
|
180
|
+
|
|
181
|
+
// UI refs/states for search popover
|
|
182
|
+
const searchInputRef = useRef(null);
|
|
183
|
+
const [searchPopoverOpen, setSearchPopoverOpen] = useState(false);
|
|
184
|
+
const [searchPopoverAnchor, setSearchPopoverAnchor] = useState(null);
|
|
185
|
+
|
|
186
|
+
const searchTermRef = useRef('');
|
|
187
|
+
const searchFieldsRef = useRef([]); // metadata only, no value
|
|
188
|
+
const lastRowRef = useRef({});
|
|
189
|
+
|
|
190
|
+
const [Filter, setFilter] = useState({
|
|
191
|
+
Tfilter: [],
|
|
192
|
+
LocalTfilter: [],
|
|
193
|
+
})
|
|
194
|
+
const [openDialogs, setOpenDialogs] = useState({
|
|
195
|
+
addTemplate: false,
|
|
196
|
+
CustomFilter: false,
|
|
197
|
+
})
|
|
198
|
+
const getDefaultColDefs = () => {
|
|
199
|
+
return [
|
|
200
|
+
{
|
|
201
|
+
field: 'Actions',
|
|
202
|
+
sortable: false,
|
|
203
|
+
width: 60,
|
|
204
|
+
pinned: 'left',
|
|
205
|
+
enableRowGroup: false,
|
|
206
|
+
cellRenderer: (params) => {
|
|
207
|
+
if (params.node.group) {
|
|
208
|
+
return <Box sx={{display: 'flex', alignItems: 'center'}}>
|
|
209
|
+
<IconButton
|
|
210
|
+
sx={{color: 'primary.light'}}
|
|
211
|
+
onClick={() => {
|
|
212
|
+
const groupKeys = getParentKeys(params.node.parent)
|
|
213
|
+
groupKeys.push(params.node.key)
|
|
214
|
+
params.api.refreshServerSide({purge: !noPurge, route: groupKeys});
|
|
215
|
+
}}
|
|
216
|
+
>
|
|
217
|
+
<RefreshOutlined/>
|
|
218
|
+
</IconButton>
|
|
219
|
+
</Box>
|
|
220
|
+
}
|
|
221
|
+
if (actions != null) return actions(params)
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
]
|
|
225
|
+
}
|
|
226
|
+
const autoGroupColumnDef = {
|
|
227
|
+
headerName: 'My Group',
|
|
228
|
+
sortable: false,
|
|
229
|
+
minWidth: 220,
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const applyValueFormatter = (formatterString) => {
|
|
233
|
+
return function (params) {
|
|
234
|
+
return new Function("params", "moment", "userTimeZone", "enumTrans", "numeral", formatterString)(
|
|
235
|
+
params,
|
|
236
|
+
moment,
|
|
237
|
+
userTimeZone,
|
|
238
|
+
Helper.enumTrans,
|
|
239
|
+
numeral,
|
|
240
|
+
);
|
|
241
|
+
};
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
const handlePDFExport = async () => {
|
|
245
|
+
if (!gridApi) return;
|
|
246
|
+
|
|
247
|
+
// Build filter summary from current filters
|
|
248
|
+
const activeTFilters = Filter?.LocalTfilter ?? [];
|
|
249
|
+
const activeFixedTFilter = builderData?.filter?.LocalTfilter ?? []
|
|
250
|
+
const activeFilters = [...activeFixedTFilter, ...activeTFilters]
|
|
251
|
+
const filterSummary = activeFilters.map(f => {
|
|
252
|
+
const field = f.friendlyName.replace('>', '.') || f.path;
|
|
253
|
+
const method = f.method || "=";
|
|
254
|
+
let value = f.value;
|
|
255
|
+
|
|
256
|
+
// Handle special types
|
|
257
|
+
if (Array.isArray(value)) {
|
|
258
|
+
value = value.map(v => (v?.name ?? v)).join(", ");
|
|
259
|
+
} else if (typeof value === "object" && value?.name) {
|
|
260
|
+
value = value.name;
|
|
261
|
+
} else if (value == null || value === "") {
|
|
262
|
+
value = "—";
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return `${field} ${method} ${value}`;
|
|
266
|
+
}).join(" | ");
|
|
267
|
+
|
|
268
|
+
// 1. Get visible columns in current AG Grid order
|
|
269
|
+
const colState = gridApi.getColumnState();
|
|
270
|
+
let orderedVisibleCols = colState
|
|
271
|
+
.filter(c => !c.hide)
|
|
272
|
+
.map(c => {
|
|
273
|
+
if (c.colId === "ag-Grid-AutoColumn") {
|
|
274
|
+
return {...autoGroupColumnDef, field: "__autoGroup"};
|
|
275
|
+
}
|
|
276
|
+
// ✅ handle groupCount separately
|
|
277
|
+
if (c.colId === "IZ_groupCount") {
|
|
278
|
+
return {field: "IZ_groupCount", headerName: "Group Count"};
|
|
279
|
+
}
|
|
280
|
+
return colDefs.find(cd => cd.field === c.colId);
|
|
281
|
+
})
|
|
282
|
+
.filter(Boolean);
|
|
283
|
+
|
|
284
|
+
// ✅ 2. Handle pivot mode
|
|
285
|
+
if (gridApi.isPivotMode()) {
|
|
286
|
+
const pivotResultCols = gridApi.getPivotResultColumns();
|
|
287
|
+
if (pivotResultCols && pivotResultCols.length > 0) {
|
|
288
|
+
pivotResultCols.forEach(pivotCol => {
|
|
289
|
+
orderedVisibleCols.push({
|
|
290
|
+
field: pivotCol.getColId(),
|
|
291
|
+
headerName: pivotCol.getColDef().headerName,
|
|
292
|
+
isPivot: true,
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// reverse for RTL
|
|
299
|
+
orderedVisibleCols = orderedVisibleCols.reverse();
|
|
300
|
+
|
|
301
|
+
// 2. Get rows
|
|
302
|
+
const rows = gridApi.getDisplayedRowCount()
|
|
303
|
+
? Array.from({length: gridApi.getDisplayedRowCount()})
|
|
304
|
+
.map((_, i) => gridApi.getDisplayedRowAtIndex(i)?.data)
|
|
305
|
+
: [];
|
|
306
|
+
|
|
307
|
+
// 3. Setup jsPDF
|
|
308
|
+
const doc = new jsPDF("landscape");
|
|
309
|
+
doc.addFileToVFS("NotoSansArabic-Regular.ttf", arabicFontBase64);
|
|
310
|
+
doc.addFont("NotoSansArabic-Regular.ttf", "NotoSansArabic", "normal");
|
|
311
|
+
doc.setFont("NotoSansArabic");
|
|
312
|
+
|
|
313
|
+
doc.setFontSize(14);
|
|
314
|
+
if (reportTitle) {
|
|
315
|
+
doc.text(String(reportTitle), doc.internal.pageSize.getWidth() - 14, 15, {
|
|
316
|
+
align: "right",
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
// ✅ Add filters summary if exists
|
|
320
|
+
if (filterSummary) {
|
|
321
|
+
doc.setFontSize(9);
|
|
322
|
+
doc.setTextColor(100); // gray
|
|
323
|
+
const lines = doc.splitTextToSize(filterSummary, doc.internal.pageSize.getWidth() - 30);
|
|
324
|
+
doc.text(lines, doc.internal.pageSize.getWidth() - 14, 25, {align: "right"});
|
|
325
|
+
}
|
|
326
|
+
// 4. Build header
|
|
327
|
+
const head = [
|
|
328
|
+
orderedVisibleCols.map(c =>
|
|
329
|
+
/image|logo|url/i.test(c.field) ? "" : (c.headerName)
|
|
330
|
+
)
|
|
331
|
+
];
|
|
332
|
+
|
|
333
|
+
// 5. Build body
|
|
334
|
+
const body = await Promise.all(
|
|
335
|
+
rows.map(async row =>
|
|
336
|
+
Promise.all(
|
|
337
|
+
orderedVisibleCols.map(async c => {
|
|
338
|
+
if (c.field === "__autoGroup") {
|
|
339
|
+
return row?.[gridApi.getRowGroupColumns()[0]?.getColId()] ?? "";
|
|
340
|
+
}
|
|
341
|
+
if (c.field === "IZ_groupCount") {
|
|
342
|
+
const val = row?.groupCount ?? row?.IZ_groupCount ?? "";
|
|
343
|
+
return val ? numeral(Number(val)).format("0,0") : "";
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// ✅ Pivot values
|
|
347
|
+
if (c.isPivot) {
|
|
348
|
+
const val = row?.[c.field];
|
|
349
|
+
return val == null ? "" : numeral(Number(val).toFixed(2)).format("0,0.00");
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// normal values
|
|
353
|
+
const val = row?.[c.field] ?? "";
|
|
354
|
+
const isImageField = /image|logo|url/i.test(c.field);
|
|
355
|
+
if (isImageField && val) {
|
|
356
|
+
const img = await loadImage(val);
|
|
357
|
+
if (img) return {isImage: true, image: img};
|
|
358
|
+
return "";
|
|
359
|
+
}
|
|
360
|
+
return String(val);
|
|
361
|
+
})
|
|
362
|
+
)
|
|
363
|
+
)
|
|
364
|
+
);
|
|
365
|
+
|
|
366
|
+
// 6. Render table
|
|
367
|
+
doc.autoTable({
|
|
368
|
+
head,
|
|
369
|
+
body,
|
|
370
|
+
startY: filterSummary ? 35 : 25, // push table down if filters exist
|
|
371
|
+
styles: {
|
|
372
|
+
font: "NotoSansArabic",
|
|
373
|
+
fontSize: 10,
|
|
374
|
+
halign: "right",
|
|
375
|
+
valign: "middle"
|
|
376
|
+
},
|
|
377
|
+
headStyles: {
|
|
378
|
+
fillColor: [63, 81, 181],
|
|
379
|
+
textColor: [255, 255, 255],
|
|
380
|
+
halign: "right",
|
|
381
|
+
valign: "middle"
|
|
382
|
+
},
|
|
383
|
+
bodyStyles: {
|
|
384
|
+
halign: "right",
|
|
385
|
+
valign: "middle"
|
|
386
|
+
},
|
|
387
|
+
alternateRowStyles: {fillColor: [245, 245, 245]},
|
|
388
|
+
|
|
389
|
+
didParseCell: (data) => {
|
|
390
|
+
// ✅ Handle images
|
|
391
|
+
if (data.cell.raw?.isImage) {
|
|
392
|
+
data.cell.styles.minCellHeight = 18;
|
|
393
|
+
data.cell.text = [];
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
const val = data.cell.raw ?? data.cell.text?.[0];
|
|
398
|
+
|
|
399
|
+
// ⛔ Ignore falsy / empty
|
|
400
|
+
if (val == null || val === "") return;
|
|
401
|
+
|
|
402
|
+
// ✅ PURE number check (no letters or spaces)
|
|
403
|
+
const isPureNumber =
|
|
404
|
+
typeof val === "number" ||
|
|
405
|
+
(typeof val === "string" && /^[+-]?\d+(\.\d+)?$/.test(val.trim()));
|
|
406
|
+
|
|
407
|
+
if (isPureNumber) {
|
|
408
|
+
const num = parseFloat(val);
|
|
409
|
+
if (!isNaN(num)) {
|
|
410
|
+
data.cell.text = [numeral(num.toFixed(2)).format("0,0.00")];
|
|
411
|
+
}
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// ✅ STRICT date check (ISO, yyyy-mm-dd, or recognizable formats)
|
|
416
|
+
const isIsoDate =
|
|
417
|
+
typeof val === "string" &&
|
|
418
|
+
/^\d{4}-\d{2}-\d{2}(T.*)?$/.test(val.trim());
|
|
419
|
+
|
|
420
|
+
const isLikelyDate =
|
|
421
|
+
isIsoDate ||
|
|
422
|
+
moment(val, [
|
|
423
|
+
"YYYY-MM-DD",
|
|
424
|
+
"DD/MM/YYYY",
|
|
425
|
+
"MM/DD/YYYY",
|
|
426
|
+
"YYYY/MM/DD",
|
|
427
|
+
"DD-MM-YYYY",
|
|
428
|
+
"MM-DD-YYYY",
|
|
429
|
+
], true).isValid();
|
|
430
|
+
|
|
431
|
+
if (isLikelyDate) {
|
|
432
|
+
const m = moment.utc(val).tz(userTimeZone);
|
|
433
|
+
data.cell.text = [m.format("DD/MM/YYYY - A hh:mm")];
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// ✅ Otherwise: leave text as is
|
|
438
|
+
},
|
|
439
|
+
|
|
440
|
+
didDrawCell: (data) => {
|
|
441
|
+
// ✅ Draw images
|
|
442
|
+
if (data.cell.raw?.isImage) {
|
|
443
|
+
const {base64, mimeType} = data.cell.raw.image;
|
|
444
|
+
if (base64) {
|
|
445
|
+
const format = mimeType.includes("jpeg") ? "JPEG" : "PNG";
|
|
446
|
+
const size = 12;
|
|
447
|
+
const x = data.cell.x + (data.cell.width - size) / 2;
|
|
448
|
+
const y = data.cell.y + (data.cell.height - size) / 2;
|
|
449
|
+
doc.addImage(base64, format, x, y, size, size);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
},
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
// 7. Print Aggregations if available
|
|
457
|
+
if (pagedAgg && pagedAgg.length > 0) {
|
|
458
|
+
const aggRow = pagedAgg[0];
|
|
459
|
+
|
|
460
|
+
const aggHead = [
|
|
461
|
+
orderedVisibleCols.map(c => /image|logo|url/i.test(c.field) ? "" : (c.headerName || ""))
|
|
462
|
+
];
|
|
463
|
+
const aggBody = [
|
|
464
|
+
orderedVisibleCols.map(c => {
|
|
465
|
+
if (c.field === "__autoGroup") return "";
|
|
466
|
+
if (c.field === "IZ_groupCount") {
|
|
467
|
+
const val = aggRow["groupCount"] ?? aggRow["IZ_groupCount"];
|
|
468
|
+
return val ? numeral(Number(val)).format("0,0") : "";
|
|
469
|
+
}
|
|
470
|
+
const val = aggRow[c.field];
|
|
471
|
+
if (val == null) return "";
|
|
472
|
+
if (typeof val === "number" && !isNaN(val)) {
|
|
473
|
+
return numeral(val.toFixed(2)).format("0,0.00");
|
|
474
|
+
}
|
|
475
|
+
return String(val);
|
|
476
|
+
})
|
|
477
|
+
];
|
|
478
|
+
|
|
479
|
+
doc.autoTable({
|
|
480
|
+
head: aggHead,
|
|
481
|
+
body: aggBody,
|
|
482
|
+
startY: doc.lastAutoTable.finalY + 10,
|
|
483
|
+
styles: {
|
|
484
|
+
font: "NotoSansArabic",
|
|
485
|
+
fontSize: 10,
|
|
486
|
+
halign: "right",
|
|
487
|
+
valign: "middle",
|
|
488
|
+
},
|
|
489
|
+
headStyles: {
|
|
490
|
+
fillColor: [33, 150, 243],
|
|
491
|
+
textColor: [255, 255, 255],
|
|
492
|
+
halign: "right",
|
|
493
|
+
},
|
|
494
|
+
bodyStyles: {
|
|
495
|
+
halign: "right",
|
|
496
|
+
},
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
// 7. Footer
|
|
502
|
+
const date = new Date().toLocaleString("ar-IQ");
|
|
503
|
+
doc.setFontSize(8);
|
|
504
|
+
doc.text(
|
|
505
|
+
`تاريخ الإنشاء: ${date}`,
|
|
506
|
+
doc.internal.pageSize.getWidth() - 14,
|
|
507
|
+
doc.internal.pageSize.height - 10,
|
|
508
|
+
{align: "right"}
|
|
509
|
+
);
|
|
510
|
+
|
|
511
|
+
doc.save("report.pdf");
|
|
512
|
+
};
|
|
513
|
+
|
|
514
|
+
// Utility to fetch + encode image
|
|
515
|
+
async function loadImage(val) {
|
|
516
|
+
try {
|
|
517
|
+
const imageUrl = `${imageBaseUrl}/${val}`;
|
|
518
|
+
const resp = await fetch(imageUrl);
|
|
519
|
+
const blob = await resp.blob();
|
|
520
|
+
const mimeType = blob.type || "image/png";
|
|
521
|
+
|
|
522
|
+
return await new Promise(resolve => {
|
|
523
|
+
const reader = new FileReader();
|
|
524
|
+
reader.onload = () => resolve({base64: reader.result, mimeType});
|
|
525
|
+
reader.readAsDataURL(blob);
|
|
526
|
+
});
|
|
527
|
+
} catch (e) {
|
|
528
|
+
console.warn("Image load failed:", val, e);
|
|
529
|
+
return null;
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
|
|
534
|
+
const processColumns = (columns) => {
|
|
535
|
+
return columns.map((col) => {
|
|
536
|
+
let processedColumn = {
|
|
537
|
+
...col,
|
|
538
|
+
valueFormatter: col.valueFormatter
|
|
539
|
+
? applyValueFormatter(col.valueFormatter)
|
|
540
|
+
: undefined,
|
|
541
|
+
};
|
|
542
|
+
|
|
543
|
+
// If the column has children, process them recursively
|
|
544
|
+
if (col.children && Array.isArray(col.children)) {
|
|
545
|
+
processedColumn.children = processColumns(col.children);
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
return processedColumn;
|
|
549
|
+
});
|
|
550
|
+
};
|
|
551
|
+
|
|
552
|
+
async function handleResetColsToStudio() {
|
|
553
|
+
try {
|
|
554
|
+
setBuilderTFilter(builderData?.filter?.Tfilter ?? [])
|
|
555
|
+
console.log(builderModel)
|
|
556
|
+
const allowedAggFuncs = ["sum", "avg", "min", "max"];
|
|
557
|
+
const userTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
558
|
+
let defaultCols = getDefaultColDefs()
|
|
559
|
+
const routingSettings = builderData?.routingSettings || [];
|
|
560
|
+
|
|
561
|
+
setTRouting(routingSettings)
|
|
562
|
+
// Build visible colDefs: exclude collection containers and any leaf field marked as hidden
|
|
563
|
+
let localColDefs = builderData.selectedFields
|
|
564
|
+
.filter(x => x.propertyType != 'Collection' && x.hidden !== true)
|
|
565
|
+
.map(col => {
|
|
566
|
+
|
|
567
|
+
const propertyType = col.propertyType ?? col.field?.propertyType;
|
|
568
|
+
const propPath = col.headerName ?? col.path;
|
|
569
|
+
const fieldName = col.headerName ?? col.path.replace(/\./g, '_');
|
|
570
|
+
const externalColConfig = (columnsConfig ?? []).find(x => x.field === fieldName)?.config ?? {}
|
|
571
|
+
const headerName = col.title ?? col.headerName ?? col.path;
|
|
572
|
+
const hasRouting = routingSettings.some(r => r.fieldName === fieldName);
|
|
573
|
+
let valueFormatter = null;
|
|
574
|
+
// Handle valueFormatter as string
|
|
575
|
+
if (propertyType === 'DateTime') {
|
|
576
|
+
if (propPath.toLowerCase().endsWith('time')) {
|
|
577
|
+
valueFormatter =
|
|
578
|
+
`return params?.value != null ? moment.utc(params.value).tz('${userTimeZone}').format('LT') : ''`;
|
|
579
|
+
} else {
|
|
580
|
+
valueFormatter =
|
|
581
|
+
`return params?.value != null ? moment.utc(params.value).tz('${userTimeZone}').format('DD/MM/yyyy hh:mm A') : ''`;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
if (propertyType === 'Double') {
|
|
586
|
+
valueFormatter =
|
|
587
|
+
`return params?.value != null ? numeral(params.value.toFixed(2)).format('0,0') : ''`;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
if (propertyType === 'Enum') {
|
|
591
|
+
const enumName = col.field?.enumName || col.field?.propertyName || 'Enum';
|
|
592
|
+
valueFormatter =
|
|
593
|
+
`return params?.value != null ? enumTrans('${enumName}', params.value) : ''`;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
const isNumericAgg = (propertyType === 'Int' || propertyType === 'Double') &&
|
|
597
|
+
!col.field?.path?.toLowerCase().endsWith('id');
|
|
598
|
+
|
|
599
|
+
const isImage = col.image === true;
|
|
600
|
+
return {
|
|
601
|
+
field: fieldName,
|
|
602
|
+
headerName: headerName,
|
|
603
|
+
enableRowGroup: true,
|
|
604
|
+
sortable: true,
|
|
605
|
+
enablePivot: true,
|
|
606
|
+
enableValue: isNumericAgg,
|
|
607
|
+
cellRenderer: isImage ? 'imageCell' : (hasRouting ? 'routingCell' : (propertyType === 'Bool'
|
|
608
|
+
? "agCheckboxCellRenderer"
|
|
609
|
+
: null)),
|
|
610
|
+
width: isImage ? 90 : undefined,
|
|
611
|
+
cellStyle: isImage ? {display: 'flex', alignItems: 'center', justifyContent: 'center'} : undefined,
|
|
612
|
+
allowedAggFuncs: isNumericAgg ? allowedAggFuncs : [],
|
|
613
|
+
valueFormatter: valueFormatter
|
|
614
|
+
? applyValueFormatter(valueFormatter)
|
|
615
|
+
: undefined,
|
|
616
|
+
...externalColConfig
|
|
617
|
+
};
|
|
618
|
+
});
|
|
619
|
+
|
|
620
|
+
|
|
621
|
+
const localSelectedFields = trimSelectedFields(builderData.selectedFields);
|
|
622
|
+
|
|
623
|
+
|
|
624
|
+
setSelectedFields(localSelectedFields);
|
|
625
|
+
|
|
626
|
+
const localSelectTFilter = builderData.selectedFields.filter(x => x.type === 'computed').map(x => ({
|
|
627
|
+
friendlyName: x.title,
|
|
628
|
+
path: x.path,
|
|
629
|
+
afterSelect: true,
|
|
630
|
+
propertyType: x.propertyType,
|
|
631
|
+
enumName: x.enumName
|
|
632
|
+
|
|
633
|
+
}))
|
|
634
|
+
setSelectTFilter(localSelectTFilter)
|
|
635
|
+
const searchGroupName = 'searchGroup';
|
|
636
|
+
const localSearchFilterFields = builderData?.searchFilter ?? [];
|
|
637
|
+
|
|
638
|
+
const localSearchFilter = localSearchFilterFields.map(f => ({
|
|
639
|
+
path: f.path,
|
|
640
|
+
value: '',
|
|
641
|
+
isWithinCollection: f.isWithinCollection ?? false,
|
|
642
|
+
collectionMethod: f.isWithinCollection ? 'Any' : null,
|
|
643
|
+
method: f.propertyType === 'String' ? 'Contains' : 'Equals',
|
|
644
|
+
collectionPath: getCollectionPath(f.fullPath, f.path, f.isWithinCollection),
|
|
645
|
+
// isWithinOrGroup: true,
|
|
646
|
+
// orGroupName: searchGroupName,
|
|
647
|
+
propertyType: f.propertyType,
|
|
648
|
+
friendlyName: builderData.selectedFields.find(x => x.path === f.path)?.title ?? f.path,
|
|
649
|
+
}))
|
|
650
|
+
searchFieldsRef.current = localSearchFilter;
|
|
651
|
+
const localSelectParams = builderData.selectionParams.map((x, index) => ({
|
|
652
|
+
id: index,
|
|
653
|
+
PropertyType: x.propertyType,
|
|
654
|
+
value: x.value
|
|
655
|
+
}))
|
|
656
|
+
setSelectParams(localSelectParams);
|
|
657
|
+
if (extraCols != null) {
|
|
658
|
+
localColDefs = [...extraCols, ...localColDefs];
|
|
659
|
+
}
|
|
660
|
+
localColDefs = [...localColDefs, ...defaultCols];
|
|
661
|
+
setColDefs([
|
|
662
|
+
{
|
|
663
|
+
field: 'IZ_groupCount',
|
|
664
|
+
headerName: 'Group Count',
|
|
665
|
+
sortable: true,
|
|
666
|
+
hide: true,
|
|
667
|
+
valueGetter: (params) => params.data?.groupCount
|
|
668
|
+
},
|
|
669
|
+
...localColDefs
|
|
670
|
+
]);
|
|
671
|
+
} catch (error) {
|
|
672
|
+
console.error('Error in handleResetColsToStudio:', error);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
function getCollectionPath(fullPath, path, isWithinCollection) {
|
|
677
|
+
if (!isWithinCollection) return null;
|
|
678
|
+
if (typeof fullPath !== 'string' || typeof path !== 'string') return null;
|
|
679
|
+
|
|
680
|
+
// 1) remove the first segment (e.g., "Orders." from "Orders.Items.Product.Name")
|
|
681
|
+
let mid = fullPath.replace(/^[^.]+\.?/, "");
|
|
682
|
+
|
|
683
|
+
// 2) remove trailing `path` (with optional preceding dot)
|
|
684
|
+
const esc = s => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
685
|
+
const tail = new RegExp(`(?:\\.)?${esc(path)}$`);
|
|
686
|
+
mid = mid.replace(tail, "");
|
|
687
|
+
|
|
688
|
+
// clean up stray leading/trailing dots
|
|
689
|
+
mid = mid.replace(/^\.|\.$/g, "");
|
|
690
|
+
|
|
691
|
+
return mid || null;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
async function handleGetRawColumns(rawSql) {
|
|
695
|
+
try {
|
|
696
|
+
let response = null
|
|
697
|
+
|
|
698
|
+
response = await Services.PostService(Endpoints.ReportBuilder.Post.GetRawColumns, false, {
|
|
699
|
+
rawSql: rawSql
|
|
700
|
+
}, {})
|
|
701
|
+
|
|
702
|
+
if (response) {
|
|
703
|
+
let defaultCols = getDefaultColDefs()
|
|
704
|
+
let tableCols = [...response.data]
|
|
705
|
+
tableCols = processColumns(tableCols)
|
|
706
|
+
let localColDefs = [...tableCols, ...defaultCols]
|
|
707
|
+
if (extraCols != null) {
|
|
708
|
+
localColDefs = [...extraCols, ...localColDefs]
|
|
709
|
+
}
|
|
710
|
+
const localSelectTFilter = response.data.map(x => ({
|
|
711
|
+
friendlyName: x.fieldName,
|
|
712
|
+
path: x.path,
|
|
713
|
+
afterSelect: true,
|
|
714
|
+
propertyType: x.type,
|
|
715
|
+
}))
|
|
716
|
+
setSelectTFilter(localSelectTFilter)
|
|
717
|
+
setColDefs(localColDefs)
|
|
718
|
+
} else {
|
|
719
|
+
setColDefs([])
|
|
720
|
+
}
|
|
721
|
+
} catch (error) {
|
|
722
|
+
|
|
723
|
+
} finally {
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
const ImageCell = (props) => {
|
|
728
|
+
const {value} = props;
|
|
729
|
+
if (!value) return <span/>;
|
|
730
|
+
let src = String(value);
|
|
731
|
+
try {
|
|
732
|
+
if (imageBaseUrl && !/^https?:\/\//i.test(src)) {
|
|
733
|
+
src = `${imageBaseUrl}/${src}`;
|
|
734
|
+
}
|
|
735
|
+
} catch {
|
|
736
|
+
}
|
|
737
|
+
const size = 50;
|
|
738
|
+
return (
|
|
739
|
+
<img
|
|
740
|
+
src={src}
|
|
741
|
+
alt=""
|
|
742
|
+
style={{width: size, height: size, objectFit: 'contain', borderRadius: 4}}
|
|
743
|
+
onDoubleClick={() => window.open(src, "_blank", "noopener,noreferrer")}
|
|
744
|
+
onError={(e) => {
|
|
745
|
+
e.currentTarget.style.visibility = 'hidden';
|
|
746
|
+
}}
|
|
747
|
+
/>
|
|
748
|
+
);
|
|
749
|
+
};
|
|
750
|
+
|
|
751
|
+
const RoutingCell = (props) => {
|
|
752
|
+
const {value, colDef, context, data} = props;
|
|
753
|
+
const {tRouting} = context;
|
|
754
|
+
const fieldName = colDef.field;
|
|
755
|
+
|
|
756
|
+
const routing = tRouting?.find(r => r.fieldName === fieldName || r.headerName === fieldName);
|
|
757
|
+
if (!routing) return <span>{value}</span>;
|
|
758
|
+
|
|
759
|
+
// Determine behavior based on routing.type
|
|
760
|
+
const type = routing.type || 'Route';
|
|
761
|
+
|
|
762
|
+
// Build finalRoute for Route type
|
|
763
|
+
let finalRoute = null;
|
|
764
|
+
if (type === 'Route') {
|
|
765
|
+
if (routing.script) {
|
|
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
|
+
}
|
|
780
|
+
|
|
781
|
+
const handleClick = () => {
|
|
782
|
+
if (type === 'Filter') {
|
|
783
|
+
try {
|
|
784
|
+
// 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
|
+
let externalFilter = null;
|
|
791
|
+
try {
|
|
792
|
+
externalFilter = replaced ? JSON.parse(replaced) : null;
|
|
793
|
+
} catch (e) {
|
|
794
|
+
console.error('Invalid externalFilterJson after replacement', e);
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
const builderId = context?.builderId;
|
|
798
|
+
const payload = {
|
|
799
|
+
pageId: routing.pageId ?? null,
|
|
800
|
+
externalFilter,
|
|
801
|
+
id: builderId ?? null
|
|
802
|
+
};
|
|
803
|
+
|
|
804
|
+
const base = '/reportBuilder/reportViewer';
|
|
805
|
+
const url = builderId ? `${base}?id=${encodeURIComponent(builderId)}&useWindowName=1` : `${base}?useWindowName=1`;
|
|
806
|
+
// Open the new tab and set its window.name with a prefixed base64 JSON payload
|
|
807
|
+
const child = window.open(url, "_blank"); // do not use noopener because we need to set name
|
|
808
|
+
if (child) {
|
|
809
|
+
try {
|
|
810
|
+
const json = JSON.stringify(payload);
|
|
811
|
+
const b64 = typeof btoa !== 'undefined' ? btoa(unescape(encodeURIComponent(json))) : json;
|
|
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 {}
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
} catch (e) {
|
|
822
|
+
console.error('Filter routing error', e);
|
|
823
|
+
}
|
|
824
|
+
} else {
|
|
825
|
+
if (finalRoute && finalRoute !== '#') {
|
|
826
|
+
window.open(finalRoute, "_blank", "noopener,noreferrer");
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
};
|
|
830
|
+
|
|
831
|
+
return (
|
|
832
|
+
<span
|
|
833
|
+
style={{
|
|
834
|
+
color: '#1976d2',
|
|
835
|
+
fontWeight: 600,
|
|
836
|
+
cursor: 'pointer',
|
|
837
|
+
}}
|
|
838
|
+
onClick={handleClick}
|
|
839
|
+
>
|
|
840
|
+
{value}
|
|
841
|
+
</span>
|
|
842
|
+
);
|
|
843
|
+
};
|
|
844
|
+
|
|
845
|
+
|
|
846
|
+
function trimSelectedFields(fields, level = 1) {
|
|
847
|
+
return fields.map(col => {
|
|
848
|
+
const trimmed = {
|
|
849
|
+
...col,
|
|
850
|
+
path: col.path,
|
|
851
|
+
headerName: col.headerName ?? col.path.replace(/\./g, '_')
|
|
852
|
+
};
|
|
853
|
+
|
|
854
|
+
if (col.children && col.children.length > 0) {
|
|
855
|
+
trimmed.children = trimSelectedFields(col.children, level + 1);
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
return trimmed;
|
|
859
|
+
});
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
function getParentKeys(parentNode) {
|
|
863
|
+
const keys = [];
|
|
864
|
+
let currentNode = parentNode;
|
|
865
|
+
while (currentNode?.data) {
|
|
866
|
+
keys.unshift(currentNode.key); // Prepend to keep the order of ancestors
|
|
867
|
+
currentNode = currentNode.parent;
|
|
868
|
+
}
|
|
869
|
+
return keys;
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
// function getValueAtPath(obj, path) {
|
|
873
|
+
// // Split the path into parts based on the dot notation
|
|
874
|
+
// const parts = path.split('.');
|
|
875
|
+
// // Traverse the object according to the path
|
|
876
|
+
// let current = obj;
|
|
877
|
+
//
|
|
878
|
+
// for (let part of parts) {
|
|
879
|
+
// if (current === null || current === undefined) {
|
|
880
|
+
// return 'null'; // If any part is null/undefined, return 'null'
|
|
881
|
+
// }
|
|
882
|
+
// current = current[part];
|
|
883
|
+
// }
|
|
884
|
+
//
|
|
885
|
+
// // If the final value is null, return 'null', otherwise return the value
|
|
886
|
+
// return current === null ? 'null' : current;
|
|
887
|
+
// }
|
|
888
|
+
|
|
889
|
+
const getRowId = (params) => {
|
|
890
|
+
try {
|
|
891
|
+
let itemRowId = getValueByPath(params.data, uniqueIdPath);
|
|
892
|
+
let rowId = itemRowId + getRandomInt(1, 999999999999).toString()
|
|
893
|
+
return noPurge ? itemRowId : rowId
|
|
894
|
+
} catch (error) {
|
|
895
|
+
console.error(error)
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
};
|
|
899
|
+
const handleGetSortObject = (colId, sort, isGrouping, isPivot) => {
|
|
900
|
+
const computedField = builderData.selectedFields.find(x => x.headerName === colId)
|
|
901
|
+
const isComputedField = builderData.selectedFields.some(x => x.headerName === colId && x.type === 'computed')
|
|
902
|
+
if (colId == "IZ_groupCount") {
|
|
903
|
+
return {
|
|
904
|
+
columnName: 'groupCount',
|
|
905
|
+
sortDirection: sort === 'asc' ? 'Ascending' : 'Descending',
|
|
906
|
+
afterGroupBy: isGrouping === true && !isComputedField,
|
|
907
|
+
afterSelect: isComputedField
|
|
908
|
+
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
if (isPivot || colId.endsWith("groupCount")) {
|
|
912
|
+
return {
|
|
913
|
+
columnName: colId,
|
|
914
|
+
sortDirection: sort === 'asc' ? 'Ascending' : 'Descending',
|
|
915
|
+
afterGroupBy: isGrouping === true && !isComputedField,
|
|
916
|
+
afterSelect: isComputedField
|
|
917
|
+
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
const field = {path: colId, afterSelect: true}
|
|
921
|
+
return {
|
|
922
|
+
columnName: computedField ? computedField.path : colId,
|
|
923
|
+
sortDirection: sort === 'asc' ? 'Ascending' : 'Descending',
|
|
924
|
+
afterGroupBy: isGrouping === true,
|
|
925
|
+
afterSelect: isComputedField
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
const sideBarConfig = useMemo(() => ({
|
|
930
|
+
toolPanels: [
|
|
931
|
+
{
|
|
932
|
+
id: 'columns',
|
|
933
|
+
labelDefault: 'Columns',
|
|
934
|
+
labelKey: 'columns',
|
|
935
|
+
iconKey: 'columns',
|
|
936
|
+
toolPanel: 'agColumnsToolPanel',
|
|
937
|
+
toolPanelParams: {
|
|
938
|
+
suppressRowGroups: groupBy != null,
|
|
939
|
+
suppressValues: groupBy != null,
|
|
940
|
+
},
|
|
941
|
+
minWidth: 225,
|
|
942
|
+
},
|
|
943
|
+
|
|
944
|
+
],
|
|
945
|
+
position: 'left',
|
|
946
|
+
// ← optionally open this panel by default on init
|
|
947
|
+
defaultToolPanel: 'columns',
|
|
948
|
+
}), [groupBy]); // only re-create if groupBy changes
|
|
949
|
+
const handleGetAggregationObject = (agg) => {
|
|
950
|
+
|
|
951
|
+
const matchedCol = builderData.selectedFields.find(col => {
|
|
952
|
+
const cleanedColPath = col.headerName || col.path.replace(/\./g, '_');
|
|
953
|
+
return cleanedColPath?.toLowerCase() === agg.field?.toLowerCase();
|
|
954
|
+
});
|
|
955
|
+
|
|
956
|
+
if (matchedCol) {
|
|
957
|
+
|
|
958
|
+
} else {
|
|
959
|
+
console.warn(`No match found for aggregation field "${agg.field}"`);
|
|
960
|
+
}
|
|
961
|
+
return {
|
|
962
|
+
path: matchedCol.headerName || matchedCol?.path,
|
|
963
|
+
method: agg.aggFunc,
|
|
964
|
+
afterSelect: matchedCol.type === 'computed'
|
|
965
|
+
// afterSelect: matchedCol?.afterSelect // Uncomment if needed
|
|
966
|
+
};
|
|
967
|
+
};
|
|
968
|
+
const handleGetPath = (colId) => {
|
|
969
|
+
return colId.replace(/_/g, '.')
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
function getMatchedColByPath(path) {
|
|
973
|
+
if (!path) return undefined;
|
|
974
|
+
|
|
975
|
+
const matchedCol = builderData.selectedFields.find(col => {
|
|
976
|
+
const cleanedColPath = col.headerName || col.path.replace(/\./g, '_');
|
|
977
|
+
return cleanedColPath?.toLowerCase() === path.replace(/\./g, '_').toLowerCase();
|
|
978
|
+
});
|
|
979
|
+
|
|
980
|
+
if (matchedCol) {
|
|
981
|
+
const cleanedColPath = matchedCol.path.replace(/\./g, '_');
|
|
982
|
+
return cleanedColPath;
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
console.warn(`No match found for: ${path}`);
|
|
986
|
+
return path.replace(/\./g, '_'); // fallback to flattened path
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
function convertToNestedObject(flatObject) {
|
|
990
|
+
const resultObject = {};
|
|
991
|
+
|
|
992
|
+
Object.keys(flatObject).forEach(path => {
|
|
993
|
+
const value = flatObject[path];
|
|
994
|
+
|
|
995
|
+
// Case-insensitive match with transformed col.path
|
|
996
|
+
const matchedCol = builderData.selectedFields.find(col => {
|
|
997
|
+
const cleanedColPath = col.headerName ?? col.path.replace(/\./g, '_');
|
|
998
|
+
return cleanedColPath.toLowerCase() === path.toLowerCase();
|
|
999
|
+
});
|
|
1000
|
+
|
|
1001
|
+
if (path.startsWith("pivot_")) {
|
|
1002
|
+
const cleanedPath = path.substring(6); // Remove "pivot_"
|
|
1003
|
+
resultObject[cleanedPath] = value;
|
|
1004
|
+
} else {
|
|
1005
|
+
const newPath = matchedCol?.headerName ?? matchedCol?.path?.replace(/\./g, '_') ?? path;
|
|
1006
|
+
resultObject[newPath] = value;
|
|
1007
|
+
}
|
|
1008
|
+
});
|
|
1009
|
+
|
|
1010
|
+
return resultObject;
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
|
|
1014
|
+
function returnAdditionalPivotCols(flatCols) {
|
|
1015
|
+
const resultFields = new Set();
|
|
1016
|
+
flatCols.forEach(row => {
|
|
1017
|
+
Object.keys(row).forEach(key => {
|
|
1018
|
+
if (!key.startsWith("pivot_") && key !== "groupCount" && !builderData.selectedFields.some(
|
|
1019
|
+
col => col.headerName === key
|
|
1020
|
+
)) {
|
|
1021
|
+
resultFields.add(key);
|
|
1022
|
+
}
|
|
1023
|
+
});
|
|
1024
|
+
});
|
|
1025
|
+
|
|
1026
|
+
const distinctFields = Array.from(resultFields);
|
|
1027
|
+
return distinctFields;
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
const createServerSideDatasource = (getRowsFromApi) => {
|
|
1031
|
+
return {
|
|
1032
|
+
getRows: (params) => {
|
|
1033
|
+
const isPivotMode = params.api.isPivotMode()
|
|
1034
|
+
// Fetch data from API based on request
|
|
1035
|
+
getRowsFromApi(params)
|
|
1036
|
+
.then((response) => {
|
|
1037
|
+
if (response.success) {
|
|
1038
|
+
// Supply rows for requested block to grid
|
|
1039
|
+
params.success({
|
|
1040
|
+
rowData: response.rows,
|
|
1041
|
+
rowCount: response.total,
|
|
1042
|
+
pivotResultFields: isPivotMode ? response.pivotColResult : null
|
|
1043
|
+
});
|
|
1044
|
+
} else {
|
|
1045
|
+
params.fail();
|
|
1046
|
+
}
|
|
1047
|
+
})
|
|
1048
|
+
.catch((e) => {
|
|
1049
|
+
|
|
1050
|
+
console.log(e)
|
|
1051
|
+
params.fail()
|
|
1052
|
+
});
|
|
1053
|
+
},
|
|
1054
|
+
};
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
const getRowsFromApi = useCallback(
|
|
1058
|
+
async params => {
|
|
1059
|
+
setFinalRequestObject(defaultFinalRequest)
|
|
1060
|
+
const fixedTFilter = externalFilter?.fixedTFilter ?? externalFilter?.fixedTfilter ?? []
|
|
1061
|
+
const localFixedTFilter = Filter?.fixedTFilter ?? []
|
|
1062
|
+
let localFilter = externalFilter ? {...externalFilter} : {}
|
|
1063
|
+
localFilter = {...localFilter, ...Filter}
|
|
1064
|
+
|
|
1065
|
+
let localTFilter = localFilter?.Tfilter ? [...localFilter?.Tfilter] : []
|
|
1066
|
+
localTFilter = localFilter?.TFilter ? [...localTFilter, ...localFilter?.TFilter] : [...localTFilter]
|
|
1067
|
+
localTFilter = [...localTFilter, ...fixedTFilter, ...localFixedTFilter, ...builderTFilter]
|
|
1068
|
+
|
|
1069
|
+
// Apply explicit user-selected search filters (selectedSearchObjects), grouped by path
|
|
1070
|
+
if ((selectedSearchObjects?.length ?? 0) > 0) {
|
|
1071
|
+
const byPath = selectedSearchObjects.reduce((acc, item) => {
|
|
1072
|
+
const key = item.path;
|
|
1073
|
+
if (!acc[key]) acc[key] = [];
|
|
1074
|
+
acc[key].push(item);
|
|
1075
|
+
return acc;
|
|
1076
|
+
}, {});
|
|
1077
|
+
|
|
1078
|
+
const grouped = [];
|
|
1079
|
+
Object.keys(byPath).forEach(path => {
|
|
1080
|
+
const items = byPath[path];
|
|
1081
|
+
if (items.length <= 1) {
|
|
1082
|
+
// Single value: push without OR grouping flags
|
|
1083
|
+
const single = {...items[0]};
|
|
1084
|
+
delete single.isWithinOrGroup;
|
|
1085
|
+
delete single.orGroupName;
|
|
1086
|
+
grouped.push(single);
|
|
1087
|
+
} else {
|
|
1088
|
+
// Multiple values for same path: mark each as OR group member
|
|
1089
|
+
items.forEach(it => {
|
|
1090
|
+
grouped.push({
|
|
1091
|
+
...it,
|
|
1092
|
+
isWithinOrGroup: true,
|
|
1093
|
+
orGroupName: path
|
|
1094
|
+
});
|
|
1095
|
+
});
|
|
1096
|
+
}
|
|
1097
|
+
});
|
|
1098
|
+
|
|
1099
|
+
localTFilter = [...localTFilter, ...grouped];
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
localTFilter = localTFilter.filter(x => x.value !== null && x.value !== undefined && x.value !== '')
|
|
1103
|
+
|
|
1104
|
+
delete localFilter.Tfilter
|
|
1105
|
+
delete localFilter.fixedTfilter
|
|
1106
|
+
delete localFilter.fixedTFilter
|
|
1107
|
+
delete localFilter.LocalTfilter
|
|
1108
|
+
delete localFilter.localTfilter
|
|
1109
|
+
localFilter = localFilter ?? {}
|
|
1110
|
+
const request = params.request
|
|
1111
|
+
const pageNumber = request.endRow / (request.endRow - request.startRow) // Calculate the page number
|
|
1112
|
+
const pageSize = request.endRow - request.startRow // Calculate the page size
|
|
1113
|
+
let aggregators = request.valueCols.filter(x => x.id != 'groupCount').map(agg => handleGetAggregationObject(agg))
|
|
1114
|
+
let updateAggregation = true
|
|
1115
|
+
if (colDefs && gridApi) {
|
|
1116
|
+
let resultColDef = [...colDefs]
|
|
1117
|
+
if (request.rowGroupCols.length > 0) {
|
|
1118
|
+
}
|
|
1119
|
+
// gridApi.setGridOption('columnDefs', resultColDef)
|
|
1120
|
+
// gridApi.applyColumnState({state: colState});
|
|
1121
|
+
}
|
|
1122
|
+
// Build tFilter safely: remove fixed from preformatted lists and merge a single fixed source
|
|
1123
|
+
// 1) Strip fixed items from local Tfilter/TFilter (they may already be formatted by CustomFilterDialog)
|
|
1124
|
+
let nonFixedLocal = Array.isArray(localTFilter) ? localTFilter.filter(it => !(it && it.fixed === true && it.value === null)) : []
|
|
1125
|
+
|
|
1126
|
+
// 2) Choose ONE fixed source by priority: component state -> external -> builder
|
|
1127
|
+
const extFixed = Array.isArray(externalFilter?.fixedTFilter)
|
|
1128
|
+
? externalFilter.fixedTFilter
|
|
1129
|
+
: (Array.isArray(externalFilter?.fixedTfilter) ? externalFilter.fixedTfilter : [])
|
|
1130
|
+
const fixedSource = (Array.isArray(Filter?.fixedTFilter) && Filter.fixedTFilter.length > 0)
|
|
1131
|
+
? Filter.fixedTFilter
|
|
1132
|
+
: (extFixed.length > 0 ? extFixed : (Array.isArray(builderTFilter) ? builderTFilter : []))
|
|
1133
|
+
|
|
1134
|
+
// 3) Merge and format once
|
|
1135
|
+
const mergedForFormat = [...nonFixedLocal]
|
|
1136
|
+
console.log("Merged for format:", mergedForFormat)
|
|
1137
|
+
let formattedT = FilterFormat(mergedForFormat)
|
|
1138
|
+
|
|
1139
|
+
let data = {
|
|
1140
|
+
...localFilter,
|
|
1141
|
+
tFilter: formattedT,
|
|
1142
|
+
aggregators: aggregators,
|
|
1143
|
+
pivotCols: request.pivotCols.map(x => handleGetPath(x.field))
|
|
1144
|
+
}
|
|
1145
|
+
// Exclude any tFilter entries with null value before sending the request (per requirement)
|
|
1146
|
+
if (Array.isArray(data.tFilter)) {
|
|
1147
|
+
data.tFilter = data.tFilter.filter(f => f == null ? false : f.value !== null);
|
|
1148
|
+
}
|
|
1149
|
+
try {
|
|
1150
|
+
if (request.rowGroupCols.length !== request.groupKeys.length) {
|
|
1151
|
+
if (request.rowGroupCols.length > 1 && request.groupKeys.length > 0) {
|
|
1152
|
+
updateAggregation = false
|
|
1153
|
+
}
|
|
1154
|
+
let tFilters = request.groupKeys.map((x, index) => ({
|
|
1155
|
+
path: request.rowGroupCols[index].id.replace(/_/g, '.'),
|
|
1156
|
+
value: request.groupKeys[index] === 'null' ? null : request.groupKeys[index],
|
|
1157
|
+
method: 'Equals',
|
|
1158
|
+
dtoClassName: '',
|
|
1159
|
+
modelClassName: '',
|
|
1160
|
+
afterSelect: builderData.selectedFields.some(col => col.headerName === request.rowGroupCols[index].id && col.type === 'computed')
|
|
1161
|
+
}))
|
|
1162
|
+
const groupByColId = handleGetPath(params.request.rowGroupCols[params.parentNode.level + 1]?.id)
|
|
1163
|
+
const rowGroupColsIds = request.rowGroupCols.map(value => value.id)
|
|
1164
|
+
const valueColsIds = request.valueCols.map(value => value.id)
|
|
1165
|
+
const groupOrderCols = [...rowGroupColsIds, ...valueColsIds]
|
|
1166
|
+
let isGroupCountOrder = true;
|
|
1167
|
+
// if (rowGroupColsIds.length > 1 && params.request.sortModel.length > 1) {
|
|
1168
|
+
// isGroupCountOrder = false;
|
|
1169
|
+
// }
|
|
1170
|
+
request.sortModel = (request.sortModel ?? []).map(x => ({
|
|
1171
|
+
...x,
|
|
1172
|
+
colId: x?.colId?.endsWith("_groupCount")
|
|
1173
|
+
? x.colId.replace("_groupCount", "_groupCount")
|
|
1174
|
+
: x.colId
|
|
1175
|
+
}));
|
|
1176
|
+
const aggIds = request.valueCols.map(vc => vc.id);
|
|
1177
|
+
|
|
1178
|
+
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
|
+
let orderBy = groupOrderColdIds.map(sort => handleGetSortObject(sort.colId, sort.sort, true, aggIds.some(id => sort.colId.toLowerCase().endsWith(id.toLowerCase()))))
|
|
1180
|
+
data = {
|
|
1181
|
+
...data,
|
|
1182
|
+
tFilter: [...tFilters, ...data.tFilter],
|
|
1183
|
+
orderBy: orderBy
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
// if (updateAggregation !== true) {
|
|
1187
|
+
// data.aggregators = []
|
|
1188
|
+
// }
|
|
1189
|
+
data.selectFields = selectedFields
|
|
1190
|
+
data.selectParams = selectParams
|
|
1191
|
+
data.rawSql = builderData.rawSql
|
|
1192
|
+
|
|
1193
|
+
const response = await Services.PostService(groupEndPoint, false, data, {
|
|
1194
|
+
groupBy: groupByColId,
|
|
1195
|
+
page: isSingle ? 1 : pageNumber,
|
|
1196
|
+
pageSize: isSingle ? 1 : pageSize,
|
|
1197
|
+
getType: isPagination ? 'GroupingPagination' : 'GroupingNoPagination',
|
|
1198
|
+
sourceModel: builderData.reportSource.fullName,
|
|
1199
|
+
|
|
1200
|
+
})
|
|
1201
|
+
|
|
1202
|
+
if (setData != null) {
|
|
1203
|
+
if (isSingle) {
|
|
1204
|
+
const rowObj = response.data[0]
|
|
1205
|
+
setData(dataAsObject ? toNestedByUnderscore(rowObj) : rowObj)
|
|
1206
|
+
} else {
|
|
1207
|
+
const resp = dataAsObject
|
|
1208
|
+
? {...response, data: (response.data || []).map(toNestedByUnderscore)}
|
|
1209
|
+
: response
|
|
1210
|
+
setData(resp)
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
setFinalRequestObject({
|
|
1214
|
+
groupBy: groupByColId,
|
|
1215
|
+
endpoint: groupEndPoint,
|
|
1216
|
+
filter: data,
|
|
1217
|
+
params: {}
|
|
1218
|
+
})
|
|
1219
|
+
const pivotColResult = []
|
|
1220
|
+
if (request.pivotCols.length > 0) {
|
|
1221
|
+
if (response?.pivotCols.length > 0) {
|
|
1222
|
+
pivotColResult.push('groupCount')
|
|
1223
|
+
const responsePivotCol = response.pivotCols.map(x => x.field) ?? []
|
|
1224
|
+
pivotColResult.push(...responsePivotCol)
|
|
1225
|
+
const additionalPivotCols = returnAdditionalPivotCols(response.data)
|
|
1226
|
+
pivotColResult.push(...additionalPivotCols)
|
|
1227
|
+
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
response.data = response.data.map(r => {
|
|
1232
|
+
return convertToNestedObject(r)
|
|
1233
|
+
})
|
|
1234
|
+
if (response.aggregation != null && updateAggregation === true) {
|
|
1235
|
+
const flatAggs = flattenObject(response.aggregation)
|
|
1236
|
+
setPagedAgg([flatAggs])
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
return {
|
|
1240
|
+
success: true,
|
|
1241
|
+
rows: Array.isArray(response.data) ? response.data : [], // Always return an array to AG Grid
|
|
1242
|
+
total: response.totalCount, // Total number of rows available from the server
|
|
1243
|
+
pivotColResult: pivotColResult.length > 0 ? pivotColResult : null
|
|
1244
|
+
}
|
|
1245
|
+
} else {
|
|
1246
|
+
if (request.groupKeys.length > 0) {
|
|
1247
|
+
let tFilters = request.groupKeys.map((x, index) => ({
|
|
1248
|
+
path: handleGetPath(request.rowGroupCols[index].id),
|
|
1249
|
+
value: request.groupKeys[index] === 'null' ? null : request.groupKeys[index],
|
|
1250
|
+
method: 'Equals',
|
|
1251
|
+
dtoClassName: '',
|
|
1252
|
+
modelClassName: '',
|
|
1253
|
+
afterSelect: builderData.selectedFields.some(col => col.headerName === request.rowGroupCols[index].id && col.type === 'computed')
|
|
1254
|
+
|
|
1255
|
+
}))
|
|
1256
|
+
updateAggregation = false
|
|
1257
|
+
|
|
1258
|
+
data = {
|
|
1259
|
+
...data,
|
|
1260
|
+
tFilter: [...tFilters, ...data.tFilter]
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
let orderBy = request.sortModel.filter(x => !x.colId.endsWith("IZ_groupCount")).map(sort => handleGetSortObject(sort.colId, sort.sort, false))
|
|
1264
|
+
if (data.tIncludes != null)
|
|
1265
|
+
data = {
|
|
1266
|
+
...data,
|
|
1267
|
+
tIncludes: [...data.tIncludes, ...includes],
|
|
1268
|
+
orderBy: orderBy
|
|
1269
|
+
}
|
|
1270
|
+
else {
|
|
1271
|
+
data = {
|
|
1272
|
+
...data,
|
|
1273
|
+
tIncludes: [...includes],
|
|
1274
|
+
orderBy: orderBy
|
|
1275
|
+
}
|
|
1276
|
+
if (fixedTIncludes != null) {
|
|
1277
|
+
data.tIncludes = [...data.tIncludes, ...fixedTIncludes]
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
if (updateAggregation !== true) {
|
|
1281
|
+
data.aggregators = []
|
|
1282
|
+
}
|
|
1283
|
+
data.selectFields = selectedFields
|
|
1284
|
+
data.selectParams = selectParams
|
|
1285
|
+
data.lastRowParams = lastRowRef.current[pageNumber];
|
|
1286
|
+
|
|
1287
|
+
data.isPaginationByFilter = builderData?.isRaw === false
|
|
1288
|
+
if (data.lastRowParams == null && pageNumber > 1 && data.isPaginationByFilter)
|
|
1289
|
+
return {
|
|
1290
|
+
success: true,
|
|
1291
|
+
rows: [],
|
|
1292
|
+
rowCount: undefined // <== This keeps the grid in "loading" state
|
|
1293
|
+
}
|
|
1294
|
+
data.rawSql = builderData?.rawSql
|
|
1295
|
+
console.log(builderData)
|
|
1296
|
+
const response = await Services.PostService(pagedEndPoint, false, data, {
|
|
1297
|
+
...paramsPage,
|
|
1298
|
+
page: isSingle ? 1 : pageNumber,
|
|
1299
|
+
pageSize: isSingle ? 1 : pageSize,
|
|
1300
|
+
getType: isPagination ? (builderData?.isRaw ? 'SqlPagination' : 'Pagination') : (builderData?.isRaw ? 'SqlNoPagination' : 'NoPagination'),
|
|
1301
|
+
sourceModel: builderData?.reportSource?.fullName,
|
|
1302
|
+
|
|
1303
|
+
})
|
|
1304
|
+
|
|
1305
|
+
if (setData != null) {
|
|
1306
|
+
if (isSingle) {
|
|
1307
|
+
const rowObj = response.data[0]
|
|
1308
|
+
setData(dataAsObject ? toNestedByUnderscore(rowObj) : rowObj)
|
|
1309
|
+
} else {
|
|
1310
|
+
const resp = dataAsObject
|
|
1311
|
+
? {...response, data: (response.data || []).map(toNestedByUnderscore)}
|
|
1312
|
+
: response
|
|
1313
|
+
setData(resp)
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
lastRowRef.current = {...lastRowRef.current, [pageNumber + 1]: response.lastRowParams};
|
|
1317
|
+
setFinalRequestObject({
|
|
1318
|
+
groupBy: null,
|
|
1319
|
+
endpoint: pagedEndPoint,
|
|
1320
|
+
getType: 'Pagination',
|
|
1321
|
+
filter: data,
|
|
1322
|
+
sourceModel: builderData?.reportSource?.fullName,
|
|
1323
|
+
params: paramsPage ?? {}
|
|
1324
|
+
})
|
|
1325
|
+
if (responseType == null) setResponseType(response.className)
|
|
1326
|
+
if (responseType == null) setLocalClasName(response.className)
|
|
1327
|
+
if (response.aggregation != null && updateAggregation === true) {
|
|
1328
|
+
const flatAggs = flattenObject(response.aggregation)
|
|
1329
|
+
setPagedAgg([flatAggs])
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
return {
|
|
1333
|
+
success: true,
|
|
1334
|
+
rows: Array.isArray(response.data) ? response.data : [], // Always return an array to AG Grid
|
|
1335
|
+
total: response.totalCount,
|
|
1336
|
+
rowCount: response.totalCount,
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
} catch (error) {
|
|
1340
|
+
console.log(error)
|
|
1341
|
+
return {success: false}
|
|
1342
|
+
}
|
|
1343
|
+
},
|
|
1344
|
+
[externalFilter, includes, paramsPage, Filter, selectedFields, isPagination, selectedSearchObjects, builderData]
|
|
1345
|
+
)
|
|
1346
|
+
const datasource = useMemo(() => createServerSideDatasource(getRowsFromApi), [getRowsFromApi]);
|
|
1347
|
+
|
|
1348
|
+
|
|
1349
|
+
const onGridReady = useCallback((params) => {
|
|
1350
|
+
setGridApi(params.api)
|
|
1351
|
+
if (setOutGridApi != null)
|
|
1352
|
+
setOutGridApi(params.api)
|
|
1353
|
+
// Create datasource with a reference to the API function
|
|
1354
|
+
// const datasource = createServerSideDatasource(getRowsFromApi);
|
|
1355
|
+
|
|
1356
|
+
// // Register the datasource with the grid
|
|
1357
|
+
// params.api.setGridOption("serverSideDatasource", datasource);
|
|
1358
|
+
}, []);
|
|
1359
|
+
|
|
1360
|
+
const onRowSelected = (event) => {
|
|
1361
|
+
if (setEventRowSelected != null) {
|
|
1362
|
+
setEventRowSelected(event)
|
|
1363
|
+
}
|
|
1364
|
+
};
|
|
1365
|
+
|
|
1366
|
+
function flattenObject(obj, prefix = '', result = {}) {
|
|
1367
|
+
for (const key in obj) {
|
|
1368
|
+
if (!Object.hasOwn(obj, key)) continue;
|
|
1369
|
+
|
|
1370
|
+
const value = obj[key];
|
|
1371
|
+
const fullKey = prefix ? `${prefix}.${key}` : key;
|
|
1372
|
+
|
|
1373
|
+
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
1374
|
+
flattenObject(value, fullKey, result);
|
|
1375
|
+
} else {
|
|
1376
|
+
const matchedPath = getMatchedColByPath(fullKey);
|
|
1377
|
+
const finalKey = matchedPath ?? fullKey; // fallback to original if no match
|
|
1378
|
+
|
|
1379
|
+
|
|
1380
|
+
result[finalKey] = value;
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
return result;
|
|
1384
|
+
}
|
|
1385
|
+
|
|
1386
|
+
function flattenArray(arr) {
|
|
1387
|
+
let result = [];
|
|
1388
|
+
|
|
1389
|
+
function traverse(item) {
|
|
1390
|
+
if (!item.children) {
|
|
1391
|
+
// If the item does not have children or the children array is empty, add it to the result
|
|
1392
|
+
result.push(item);
|
|
1393
|
+
} else {
|
|
1394
|
+
// If the item has children, recursively traverse each child
|
|
1395
|
+
item.children.forEach(child => traverse(child));
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
arr.forEach(item => traverse(item));
|
|
1400
|
+
return result;
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
function getValueByPath(object, path) {
|
|
1404
|
+
try {
|
|
1405
|
+
if (path == undefined)
|
|
1406
|
+
return getRandomInt(1, 999999999999).toString()
|
|
1407
|
+
let id = path.split('.').reduce((acc, key) => acc && acc[key], object);
|
|
1408
|
+
if (id === undefined)
|
|
1409
|
+
return getRandomInt(1, 999999999999).toString()
|
|
1410
|
+
else
|
|
1411
|
+
return id
|
|
1412
|
+
|
|
1413
|
+
} catch (error) {
|
|
1414
|
+
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
function handleFilterChange(field, value) {
|
|
1419
|
+
handleChange(setFilter, field, value)
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
async function handleGetTemplates() {
|
|
1423
|
+
try {
|
|
1424
|
+
let response = null
|
|
1425
|
+
let data = {
|
|
1426
|
+
tFilter: [
|
|
1427
|
+
{
|
|
1428
|
+
method: 'Equals',
|
|
1429
|
+
path: 'pageName',
|
|
1430
|
+
value: 'Builder' + builderData?.id
|
|
1431
|
+
},
|
|
1432
|
+
{
|
|
1433
|
+
method: 'Equals',
|
|
1434
|
+
path: 'UserId',
|
|
1435
|
+
value: authValues?.user?.id,
|
|
1436
|
+
},
|
|
1437
|
+
]
|
|
1438
|
+
}
|
|
1439
|
+
response = await PostService(Endpoints.UserTableTemplates.Post.GetAllPagedByFilter, false, data)
|
|
1440
|
+
|
|
1441
|
+
if (response) {
|
|
1442
|
+
setTemplates(response.data)
|
|
1443
|
+
|
|
1444
|
+
} else {
|
|
1445
|
+
setTemplates([])
|
|
1446
|
+
}
|
|
1447
|
+
} catch (error) {
|
|
1448
|
+
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
const handleToggleDialogs = dialog => {
|
|
1453
|
+
handleChange(setOpenDialogs, dialog, !openDialogs[dialog])
|
|
1454
|
+
}
|
|
1455
|
+
|
|
1456
|
+
|
|
1457
|
+
async function handleSaveTemplate() {
|
|
1458
|
+
try {
|
|
1459
|
+
let response = null;
|
|
1460
|
+
{
|
|
1461
|
+
let data = {
|
|
1462
|
+
...selectedTemplate,
|
|
1463
|
+
value: gridApi.getColumnState(),
|
|
1464
|
+
userId: authValues?.user?.id,
|
|
1465
|
+
filterValue: Filter,
|
|
1466
|
+
pageName: 'Builder' + builderData?.id
|
|
1467
|
+
}
|
|
1468
|
+
response = await UpdateService(Endpoints.UserTableTemplates.Put.UpdateTemplate, true, data, {
|
|
1469
|
+
id: selectedTemplate?.id
|
|
1470
|
+
})
|
|
1471
|
+
|
|
1472
|
+
if (response)
|
|
1473
|
+
handleGetTemplates();
|
|
1474
|
+
}
|
|
1475
|
+
} catch (error) {
|
|
1476
|
+
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
async function handleCSVExport() {
|
|
1481
|
+
try {
|
|
1482
|
+
let response = null;
|
|
1483
|
+
{
|
|
1484
|
+
setIsDownloading(true)
|
|
1485
|
+
const cols = gridApi
|
|
1486
|
+
.getColumnDefs()
|
|
1487
|
+
const flatCols = flattenArray(cols)
|
|
1488
|
+
const visibleCols = flatCols // all column definitions
|
|
1489
|
+
.filter(colDef =>
|
|
1490
|
+
gridApi.getColumnState().some(
|
|
1491
|
+
col => col.colId === colDef.field && col.hide !== true
|
|
1492
|
+
)
|
|
1493
|
+
)
|
|
1494
|
+
const visibleFields = visibleCols
|
|
1495
|
+
.filter(x => x?.path)
|
|
1496
|
+
.map(x => x.path);
|
|
1497
|
+
|
|
1498
|
+
let data = {
|
|
1499
|
+
...finalRequestObject.filter,
|
|
1500
|
+
isExcelExport: true,
|
|
1501
|
+
visibleFields: visibleFields,
|
|
1502
|
+
}
|
|
1503
|
+
const isPivotOff = !gridApi.isPivotMode()
|
|
1504
|
+
if (isPivotOff) {
|
|
1505
|
+
data.pivotCols = []
|
|
1506
|
+
}
|
|
1507
|
+
response = await StreamService(streamEndPoint, true, data, {
|
|
1508
|
+
...finalRequestObject.params,
|
|
1509
|
+
groupBy: finalRequestObject.groupBy,
|
|
1510
|
+
getType: 'Stream',
|
|
1511
|
+
sourceModel: builderData.reportSource.fullName
|
|
1512
|
+
|
|
1513
|
+
}, null,
|
|
1514
|
+
progress => {
|
|
1515
|
+
console.log(`Downloaded: ${progress}%`)
|
|
1516
|
+
})
|
|
1517
|
+
|
|
1518
|
+
}
|
|
1519
|
+
} catch (error) {
|
|
1520
|
+
console.log(error)
|
|
1521
|
+
} finally {
|
|
1522
|
+
setIsDownloading(false)
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
const restoreState = () => {
|
|
1527
|
+
if (gridApi !== null && colDefs !== null && selectedTemplate != null) {
|
|
1528
|
+
gridApi.applyColumnState({
|
|
1529
|
+
state: selectedTemplate.value,
|
|
1530
|
+
applyOrder: true,
|
|
1531
|
+
});
|
|
1532
|
+
}
|
|
1533
|
+
if (selectedTemplate.filterValue != null && (Filter.Tfilter == null || Filter.Tfilter.length == 0)) {
|
|
1534
|
+
setFilter(selectedTemplate.filterValue);
|
|
1535
|
+
}
|
|
1536
|
+
};
|
|
1537
|
+
|
|
1538
|
+
const debouncedRefresh = useMemo(
|
|
1539
|
+
() => debounce(() => {
|
|
1540
|
+
if (gridApi) gridApi.refreshServerSide({purge: true});
|
|
1541
|
+
}, 400),
|
|
1542
|
+
[gridApi]
|
|
1543
|
+
);
|
|
1544
|
+
|
|
1545
|
+
// cleanup debounce on unmount
|
|
1546
|
+
useEffect(() => () => debouncedRefresh.cancel(), [debouncedRefresh]);
|
|
1547
|
+
|
|
1548
|
+
const handlePickSearchField = (selectedField) => {
|
|
1549
|
+
if (!selectedField) return;
|
|
1550
|
+
const term = (searchTerm || '').trim();
|
|
1551
|
+
if (!term) return;
|
|
1552
|
+
|
|
1553
|
+
const propType = (selectedField.propertyType || '').toLowerCase();
|
|
1554
|
+
let valueToUse = term;
|
|
1555
|
+
if (propType === 'int') {
|
|
1556
|
+
const n = Number(term);
|
|
1557
|
+
if (!Number.isFinite(n)) {
|
|
1558
|
+
return; // ignore invalid numeric term for Int fields
|
|
1559
|
+
}
|
|
1560
|
+
valueToUse = Math.trunc(n);
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
const newObj = {
|
|
1564
|
+
...selectedField,
|
|
1565
|
+
value: valueToUse
|
|
1566
|
+
};
|
|
1567
|
+
|
|
1568
|
+
setSelectedSearchObjects(prev => [...prev, newObj]);
|
|
1569
|
+
console.log(newObj)
|
|
1570
|
+
setSearchTerm('');
|
|
1571
|
+
setSearchPopoverOpen(false);
|
|
1572
|
+
debouncedRefresh();
|
|
1573
|
+
};
|
|
1574
|
+
|
|
1575
|
+
|
|
1576
|
+
useEffect(() => {
|
|
1577
|
+
if (builderData) {
|
|
1578
|
+
|
|
1579
|
+
if (builderData.isRaw) {
|
|
1580
|
+
handleGetRawColumns(builderData.rawSql)
|
|
1581
|
+
} else {
|
|
1582
|
+
handleResetColsToStudio()
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
}, [builderData]);
|
|
1586
|
+
|
|
1587
|
+
useEffect(() => {
|
|
1588
|
+
if (builderModel != null) {
|
|
1589
|
+
console.log(builderModel)
|
|
1590
|
+
let rawSql = builderModel.rawSql;
|
|
1591
|
+
if (builderModel.isRaw === true) {
|
|
1592
|
+
const localSelectParams = builderModel.selectionParams.map((x, index) => ({
|
|
1593
|
+
id: index,
|
|
1594
|
+
PropertyType: x.propertyType,
|
|
1595
|
+
value: x.value
|
|
1596
|
+
}));
|
|
1597
|
+
|
|
1598
|
+
rawSql = rawSql.replace(/@(\d+)/g, (_, index) => {
|
|
1599
|
+
const param = localSelectParams[parseInt(index)];
|
|
1600
|
+
if (!param) return _;
|
|
1601
|
+
|
|
1602
|
+
// Add quotes for strings and dates
|
|
1603
|
+
if (typeof param.value === 'string') {
|
|
1604
|
+
return `'${param.value}'`;
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
return param.value;
|
|
1608
|
+
});
|
|
1609
|
+
}
|
|
1610
|
+
setBuilderData({...builderModel, rawSql: rawSql})
|
|
1611
|
+
setFilter(preValue => ({
|
|
1612
|
+
...preValue,
|
|
1613
|
+
LocalTfilter: [...(builderModel?.filter?.fixedTFilter || [])]
|
|
1614
|
+
}))
|
|
1615
|
+
}
|
|
1616
|
+
}, [builderModel]);
|
|
1617
|
+
|
|
1618
|
+
useEffect(() => {
|
|
1619
|
+
// In non-raw mode, changing selection params should not alter builderData to avoid unnecessary rerenders/fetches
|
|
1620
|
+
if (builderModel?.isRaw !== true) return;
|
|
1621
|
+
|
|
1622
|
+
if (selectParams.length > 0) {
|
|
1623
|
+
let rawSql = builderModel.rawSql;
|
|
1624
|
+
const localSelectParams = {...selectParams};
|
|
1625
|
+
rawSql = rawSql.replace(/@(\d+)/g, (_, index) => {
|
|
1626
|
+
const param = localSelectParams[parseInt(index)];
|
|
1627
|
+
if (!param) return _;
|
|
1628
|
+
// Add quotes for strings and dates
|
|
1629
|
+
if (typeof param.value === 'string') {
|
|
1630
|
+
return `'${param.value}'`;
|
|
1631
|
+
}
|
|
1632
|
+
return param.value;
|
|
1633
|
+
});
|
|
1634
|
+
// Only update if rawSql actually changed to prevent redundant state updates
|
|
1635
|
+
setBuilderData(prev => {
|
|
1636
|
+
if (prev?.rawSql === rawSql) return prev;
|
|
1637
|
+
return {...builderModel, rawSql};
|
|
1638
|
+
});
|
|
1639
|
+
}
|
|
1640
|
+
}, [selectParams, builderModel?.isRaw]);
|
|
1641
|
+
|
|
1642
|
+
useEffect(() => {
|
|
1643
|
+
|
|
1644
|
+
if (gridApi !== null) {
|
|
1645
|
+
gridApi.refreshServerSide({purge: !noPurge})
|
|
1646
|
+
lastRowRef.current = {}
|
|
1647
|
+
}
|
|
1648
|
+
}, [refresh, externalFilter, localRefresh, Filter]);
|
|
1649
|
+
|
|
1650
|
+
useEffect(() => {
|
|
1651
|
+
if (gridApi != null && colDefs != null)
|
|
1652
|
+
handleGetTemplates()
|
|
1653
|
+
}, [gridApi, colDefs])
|
|
1654
|
+
|
|
1655
|
+
useEffect(() => {
|
|
1656
|
+
if (colDefs.length > 0 && selectedTemplate != null) {
|
|
1657
|
+
restoreState()
|
|
1658
|
+
}
|
|
1659
|
+
}, [selectedTemplate])
|
|
1660
|
+
useEffect(() => {
|
|
1661
|
+
if (selectedTemplate == null && templates.length > 0 && colDefs.length > 0) {
|
|
1662
|
+
const userDefined = templates.find(x => x.isDefault === true)
|
|
1663
|
+
if (userDefined != null)
|
|
1664
|
+
setSelectedTemplate(userDefined)
|
|
1665
|
+
else {
|
|
1666
|
+
const systemDefined = templates.find(x => x.type === "UserPredefined")
|
|
1667
|
+
if (systemDefined != null)
|
|
1668
|
+
setSelectedTemplate(systemDefined)
|
|
1669
|
+
else {
|
|
1670
|
+
const anyTemplate = templates[0]
|
|
1671
|
+
setSelectedTemplate(anyTemplate)
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
}
|
|
1675
|
+
}, [templates, colDefs])
|
|
1676
|
+
|
|
1677
|
+
useEffect(() => {
|
|
1678
|
+
if (!timerValue || isNaN(timerValue) || timerValue == 0) {
|
|
1679
|
+
|
|
1680
|
+
return;
|
|
1681
|
+
}
|
|
1682
|
+
// Convert minutes to milliseconds
|
|
1683
|
+
const interval = (timerValue) * 60 * 1000;
|
|
1684
|
+
|
|
1685
|
+
const timeout = setInterval(() => {
|
|
1686
|
+
setLocalRefresh(prev => !prev); // Toggle value
|
|
1687
|
+
}, interval);
|
|
1688
|
+
|
|
1689
|
+
return () => clearTimeout(timeout); // Cleanup
|
|
1690
|
+
}, [timerValue]); // re-ru
|
|
1691
|
+
|
|
1692
|
+
useEffect(() => {
|
|
1693
|
+
if (!externalTimer || isNaN(externalTimer) || externalTimer == 0) {
|
|
1694
|
+
|
|
1695
|
+
return;
|
|
1696
|
+
}
|
|
1697
|
+
// Convert minutes to milliseconds
|
|
1698
|
+
const interval = (externalTimer) * 60 * 1000;
|
|
1699
|
+
|
|
1700
|
+
const timeout = setInterval(() => {
|
|
1701
|
+
setLocalRefresh(prev => !prev); // Toggle value
|
|
1702
|
+
}, interval);
|
|
1703
|
+
|
|
1704
|
+
return () => clearTimeout(timeout); // Cleanup
|
|
1705
|
+
}, [externalTimer]); // re// n after each refresh or change in value
|
|
1706
|
+
|
|
1707
|
+
return (
|
|
1708
|
+
<Grid item container size={12}>
|
|
1709
|
+
<Grid container item
|
|
1710
|
+
sx={{backgroundColor: '#fafafb', justifyContent: 'space-between'}} padding={2}
|
|
1711
|
+
size={12}
|
|
1712
|
+
>
|
|
1713
|
+
<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
|
+
<Box sx={{ml: '5px'}}>
|
|
1743
|
+
<Tooltip title='مؤقت' placement={'top'}>
|
|
1744
|
+
<Select variant={'outlined'} value={timerValue} onChange={(e) => setTimerValue(e.target.value)}
|
|
1745
|
+
defaultValue={0} size={'small'}
|
|
1746
|
+
color='primary' sx={{width: '60px'}}>
|
|
1747
|
+
<MenuItem key={1} value={0}>No</MenuItem>
|
|
1748
|
+
<MenuItem key={2} value={0.1667}>10s</MenuItem>
|
|
1749
|
+
<MenuItem key={2} value={0.5}>30s</MenuItem>
|
|
1750
|
+
<MenuItem key={2} value={1}>1m</MenuItem>
|
|
1751
|
+
<MenuItem key={2} value={2}>2m</MenuItem>
|
|
1752
|
+
<MenuItem key={2} value={5}>5m</MenuItem>
|
|
1753
|
+
<MenuItem key={3} value={15}>15m</MenuItem>
|
|
1754
|
+
<MenuItem key={4} value={30}>30m</MenuItem>
|
|
1755
|
+
</Select>
|
|
1756
|
+
</Tooltip>
|
|
1757
|
+
</Box>
|
|
1758
|
+
</Box>
|
|
1759
|
+
{((searchFieldsRef?.current?.length ?? []) > 0) &&
|
|
1760
|
+
<Box sx={{flex: 1, px: 1, minWidth: minimized ? 140 : 300, display: 'flex', alignItems: 'center'}}>
|
|
1761
|
+
{/*<Tooltip title={'اكتب كلمة البحث ثم اختر الحقل'}>*/}
|
|
1762
|
+
<Box sx={{position: 'relative', width: '100%'}}>
|
|
1763
|
+
<TextField
|
|
1764
|
+
label={'بحث'}
|
|
1765
|
+
fullWidth
|
|
1766
|
+
size={'small'}
|
|
1767
|
+
value={searchTerm}
|
|
1768
|
+
inputRef={searchInputRef}
|
|
1769
|
+
onFocus={(e) => {
|
|
1770
|
+
if ((e.target.value || '').length > 0) {
|
|
1771
|
+
setSearchPopoverAnchor(e.currentTarget);
|
|
1772
|
+
setSearchPopoverOpen(true);
|
|
1773
|
+
}
|
|
1774
|
+
}}
|
|
1775
|
+
onChange={(e) => {
|
|
1776
|
+
const v = e.target.value;
|
|
1777
|
+
setSearchTerm(v);
|
|
1778
|
+
setSearchPopoverAnchor(e.currentTarget);
|
|
1779
|
+
setSearchPopoverOpen((v || '').length > 0);
|
|
1780
|
+
}}
|
|
1781
|
+
onKeyDown={(e) => {
|
|
1782
|
+
if (e.key === 'Enter') {
|
|
1783
|
+
e.preventDefault();
|
|
1784
|
+
const term = (searchTerm || '').trim();
|
|
1785
|
+
if (!term) return;
|
|
1786
|
+
const fields = searchFieldsRef?.current ?? [];
|
|
1787
|
+
if (fields.length === 0) return;
|
|
1788
|
+
handlePickSearchField(fields[0]);
|
|
1789
|
+
} else if (e.key === 'Escape') {
|
|
1790
|
+
setSearchPopoverOpen(false);
|
|
1791
|
+
}
|
|
1792
|
+
}}
|
|
1793
|
+
InputProps={{
|
|
1794
|
+
startAdornment: (
|
|
1795
|
+
<Box sx={{display: 'flex', gap: 0.5, flexWrap: 'wrap'}}>
|
|
1796
|
+
{(() => {
|
|
1797
|
+
const byPath = selectedSearchObjects.reduce((acc, it) => {
|
|
1798
|
+
const key = it.path;
|
|
1799
|
+
if (!acc[key]) acc[key] = {meta: it, values: []};
|
|
1800
|
+
acc[key].values.push(String(it.value));
|
|
1801
|
+
return acc;
|
|
1802
|
+
}, {});
|
|
1803
|
+
return Object.keys(byPath).map(path => {
|
|
1804
|
+
const g = byPath[path];
|
|
1805
|
+
const labelBase = g.meta.friendlyName || g.meta.path;
|
|
1806
|
+
const valueLabel = g.values.reduce((acc, val, idx) => {
|
|
1807
|
+
if (idx > 0) acc.push(<strong key={`sep-${idx}`}> أو </strong>);
|
|
1808
|
+
acc.push(val);
|
|
1809
|
+
return acc;
|
|
1810
|
+
}, []);
|
|
1811
|
+
return (
|
|
1812
|
+
<Chip
|
|
1813
|
+
key={`group-${path}`}
|
|
1814
|
+
size="small"
|
|
1815
|
+
label={
|
|
1816
|
+
<span>
|
|
1817
|
+
<strong>{labelBase}</strong>: {valueLabel}
|
|
1818
|
+
</span>
|
|
1819
|
+
} onDelete={() => {
|
|
1820
|
+
setSelectedSearchObjects(prev => prev.filter(it => it.path !== path));
|
|
1821
|
+
debouncedRefresh();
|
|
1822
|
+
}}
|
|
1823
|
+
deleteIcon={
|
|
1824
|
+
<Box sx={{
|
|
1825
|
+
display: 'flex',
|
|
1826
|
+
alignItems: 'center',
|
|
1827
|
+
px: 0.5,
|
|
1828
|
+
bgcolor: 'error.main',
|
|
1829
|
+
color: (theme) => theme.palette.error.contrastText,
|
|
1830
|
+
height: '100%',
|
|
1831
|
+
alignSelf: 'stretch',
|
|
1832
|
+
borderTopRightRadius: '4px',
|
|
1833
|
+
borderBottomRightRadius: '4px'
|
|
1834
|
+
}}>
|
|
1835
|
+
<Close fontSize="small"/>
|
|
1836
|
+
</Box>
|
|
1837
|
+
}
|
|
1838
|
+
sx={{
|
|
1839
|
+
mr: 0.5,
|
|
1840
|
+
borderRadius: '8px',
|
|
1841
|
+
'& .MuiChip-deleteIcon': {
|
|
1842
|
+
margin: 0
|
|
1843
|
+
}
|
|
1844
|
+
}}
|
|
1845
|
+
/>
|
|
1846
|
+
);
|
|
1847
|
+
});
|
|
1848
|
+
})()}
|
|
1849
|
+
</Box>
|
|
1850
|
+
)
|
|
1851
|
+
}}
|
|
1852
|
+
/>
|
|
1853
|
+
|
|
1854
|
+
<ClickAwayListener onClickAway={() => setSearchPopoverOpen(false)}>
|
|
1855
|
+
<Popper
|
|
1856
|
+
open={searchPopoverOpen}
|
|
1857
|
+
anchorEl={searchPopoverAnchor}
|
|
1858
|
+
placement="bottom-start"
|
|
1859
|
+
style={{zIndex: 1300, width: searchInputRef?.current?.offsetWidth || undefined}}
|
|
1860
|
+
>
|
|
1861
|
+
<Paper elevation={3} sx={{mt: 0.5, maxHeight: 240, overflowY: 'auto'}}>
|
|
1862
|
+
<List dense>
|
|
1863
|
+
{(searchFieldsRef?.current ?? []).map((option, i) => (
|
|
1864
|
+
<ListItemButton key={`${option.path}-${i}`} onClick={() => handlePickSearchField(option)}>
|
|
1865
|
+
<Box sx={{display: 'flex', flexDirection: 'column'}}>
|
|
1866
|
+
<Box sx={{fontSize: 14, fontWeight: 500}}>{option.friendlyName || option.path}</Box>
|
|
1867
|
+
{/*<Box sx={{fontSize: 12, color: 'text.secondary'}}>{option.path}</Box>*/}
|
|
1868
|
+
</Box>
|
|
1869
|
+
</ListItemButton>
|
|
1870
|
+
))}
|
|
1871
|
+
{((searchFieldsRef?.current ?? []).length === 0) && (
|
|
1872
|
+
<ListItemButton disabled>
|
|
1873
|
+
<Box sx={{px: 1, py: 0.5, color: 'text.secondary'}}>لا توجد حقول للبحث</Box>
|
|
1874
|
+
</ListItemButton>
|
|
1875
|
+
)}
|
|
1876
|
+
</List>
|
|
1877
|
+
</Paper>
|
|
1878
|
+
</Popper>
|
|
1879
|
+
</ClickAwayListener>
|
|
1880
|
+
</Box>
|
|
1881
|
+
{/*</Tooltip>*/}
|
|
1882
|
+
</Box>}
|
|
1883
|
+
<Box sx={{display: 'flex', justifyContent: 'center'}}>
|
|
1884
|
+
{<Box>
|
|
1885
|
+
<Tooltip title={'جميع البيانات'}>
|
|
1886
|
+
<Checkbox
|
|
1887
|
+
checked={!isPagination}
|
|
1888
|
+
onChange={e => setIsPagination(!e.target.checked)}
|
|
1889
|
+
color="primary"
|
|
1890
|
+
/>
|
|
1891
|
+
</Tooltip>
|
|
1892
|
+
</Box>}
|
|
1893
|
+
{streamEndPoint && !builderData?.isRaw === true && minimized !== true &&
|
|
1894
|
+
<Box>
|
|
1895
|
+
<Tooltip title='تصدير'>
|
|
1896
|
+
<IconButton
|
|
1897
|
+
disabled={isDownloading}
|
|
1898
|
+
onClick={handleCSVExport}
|
|
1899
|
+
color='primary'
|
|
1900
|
+
>
|
|
1901
|
+
{isDownloading ? <CircularProgress size={24}/> : <FileExcelOutline/>}
|
|
1902
|
+
</IconButton>
|
|
1903
|
+
</Tooltip>
|
|
1904
|
+
</Box>
|
|
1905
|
+
}
|
|
1906
|
+
{minimized !== true && !isPagination &&
|
|
1907
|
+
<Box>
|
|
1908
|
+
<Tooltip title="تصدير PDF">
|
|
1909
|
+
<IconButton onClick={handlePDFExport} color="primary">
|
|
1910
|
+
<PrintOutlined/>
|
|
1911
|
+
</IconButton>
|
|
1912
|
+
</Tooltip>
|
|
1913
|
+
</Box>
|
|
1914
|
+
}
|
|
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
|
+
{<Box>
|
|
1953
|
+
|
|
1954
|
+
<IconButton color={'primary'} onClick={() => handleToggleDialogs('CustomFilter')}>
|
|
1955
|
+
<FilterAlt/>
|
|
1956
|
+
</IconButton>
|
|
1957
|
+
</Box>
|
|
1958
|
+
}
|
|
1959
|
+
<Box>
|
|
1960
|
+
<Tooltip title='اعادة تحميل'>
|
|
1961
|
+
<IconButton onClick={() => setLocalRefresh(!localRefresh)}>
|
|
1962
|
+
<RefreshOutlined/>
|
|
1963
|
+
</IconButton>
|
|
1964
|
+
</Tooltip>
|
|
1965
|
+
</Box>
|
|
1966
|
+
|
|
1967
|
+
</Box>
|
|
1968
|
+
</Grid>
|
|
1969
|
+
<div style={{width: "100%", height: minimized === true ? "0px" : height ?? "70vh", direction: 'ltr'}}>
|
|
1970
|
+
<AgGridReact
|
|
1971
|
+
|
|
1972
|
+
debug={false}
|
|
1973
|
+
columnHoverHighlight={true}
|
|
1974
|
+
theme={agTheme}
|
|
1975
|
+
enableRtl={true}
|
|
1976
|
+
columnDefs={colDefs}
|
|
1977
|
+
rowModelType={"serverSide"}
|
|
1978
|
+
onGridReady={onGridReady}
|
|
1979
|
+
maxConcurrentDatasourceRequests={0}
|
|
1980
|
+
cacheBlockSize={100}
|
|
1981
|
+
onRowSelected={onRowSelected}
|
|
1982
|
+
// getChildCount={getChildCount}
|
|
1983
|
+
sideBar={sideBarConfig}
|
|
1984
|
+
context={{tRouting, builderId: builderData?.id}} // pass routing and builder id
|
|
1985
|
+
gridOptions={{
|
|
1986
|
+
enableRangeSelection: true,
|
|
1987
|
+
enableCharts: true,
|
|
1988
|
+
}}
|
|
1989
|
+
rowSelection="multiple"
|
|
1990
|
+
statusBar={{
|
|
1991
|
+
statusPanels: [
|
|
1992
|
+
// { statusPanel: 'agTotalRowCountComponent' },
|
|
1993
|
+
{
|
|
1994
|
+
statusPanel: CustomStatusBar,
|
|
1995
|
+
align: 'left',
|
|
1996
|
+
},
|
|
1997
|
+
|
|
1998
|
+
// { statusPanel: 'agFilteredRowCountComponent' },
|
|
1999
|
+
// { statusPanel: 'agSelectedRowCountComponent' },
|
|
2000
|
+
],
|
|
2001
|
+
}}
|
|
2002
|
+
groupHeaderHeight={25}
|
|
2003
|
+
// onChartCreated={x => console.log(x)}
|
|
2004
|
+
headerHeight={25}
|
|
2005
|
+
autoGroupColumnDef={autoGroupColumnDef}
|
|
2006
|
+
getRowId={getRowId}
|
|
2007
|
+
serverSideDatasource={datasource}
|
|
2008
|
+
blockLoadDebounceMillis={200}
|
|
2009
|
+
pinnedBottomRowData={pagedAgg}
|
|
2010
|
+
suppressRowClickSelection={true}
|
|
2011
|
+
serverSidePivotResultFieldSeparator={"_"}
|
|
2012
|
+
pivotKeySeparator={"_"}
|
|
2013
|
+
getRowStyle={(row) => {
|
|
2014
|
+
if (row.node.group) {
|
|
2015
|
+
return {fontWeight: 'bold'};
|
|
2016
|
+
}
|
|
2017
|
+
if (expireReport) {
|
|
2018
|
+
if (row.node?.data?.expireDate && new Date(row.node.data.expireDate) <= new Date()) {
|
|
2019
|
+
return {background: '#FF625F'};
|
|
2020
|
+
}
|
|
2021
|
+
if (row.node?.data?.expireDate) {
|
|
2022
|
+
const expireDate = new Date(row.node.data.expireDate);
|
|
2023
|
+
const currentDate = new Date();
|
|
2024
|
+
const diffInDays = (expireDate - currentDate) / (1000 * 60 * 60 * 24); // Convert milliseconds to days
|
|
2025
|
+
|
|
2026
|
+
if (diffInDays > 10) {
|
|
2027
|
+
return {background: '#8AFF8A'};
|
|
2028
|
+
} else if (diffInDays > 0) {
|
|
2029
|
+
return {background: '#fcfd74'};
|
|
2030
|
+
}
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
2033
|
+
}}
|
|
2034
|
+
|
|
2035
|
+
components={{
|
|
2036
|
+
routingCell: RoutingCell,
|
|
2037
|
+
imageCell: ImageCell,
|
|
2038
|
+
customStatusBar: CustomStatusBar,
|
|
2039
|
+
// agColumnsToolPanel: CustomColumnsToolPanel
|
|
2040
|
+
|
|
2041
|
+
}}
|
|
2042
|
+
|
|
2043
|
+
|
|
2044
|
+
onSortChanged={params => {
|
|
2045
|
+
const sm = params.columns;
|
|
2046
|
+
if (sm.length == 1 && sm.some(s => s.colId === 'IZ_groupCount')) {
|
|
2047
|
+
params.api.refreshServerSide({purge: true})
|
|
2048
|
+
}
|
|
2049
|
+
}}
|
|
2050
|
+
/>
|
|
2051
|
+
</div>
|
|
2052
|
+
<Dialog
|
|
2053
|
+
fullWidth
|
|
2054
|
+
open={openDialogs?.addTemplate && builderData?.id != null}
|
|
2055
|
+
maxWidth='md'
|
|
2056
|
+
scroll='body'
|
|
2057
|
+
onClose={() => {
|
|
2058
|
+
handleToggleDialogs('addTemplate')
|
|
2059
|
+
}}
|
|
2060
|
+
>
|
|
2061
|
+
<AddTemplateDialog
|
|
2062
|
+
filterValue={Filter}
|
|
2063
|
+
handleToggleDialogs={handleToggleDialogs}
|
|
2064
|
+
pageName={'Builder' + builderData?.id}
|
|
2065
|
+
item={isTemplateEditing === true ? selectedTemplate : null}
|
|
2066
|
+
template={gridApi?.getColumnState()}
|
|
2067
|
+
userId={authValues?.user?.id}/>
|
|
2068
|
+
</Dialog>
|
|
2069
|
+
<Dialog
|
|
2070
|
+
fullWidth
|
|
2071
|
+
open={openDialogs.CustomFilter}
|
|
2072
|
+
maxWidth='xl'
|
|
2073
|
+
scroll='body'
|
|
2074
|
+
// onClose={() => handleToggleDialogs('CustomFilter')}
|
|
2075
|
+
>
|
|
2076
|
+
<CustomFilterDialog
|
|
2077
|
+
handleToggleDialogs={handleToggleDialogs}
|
|
2078
|
+
Filter={[...(Filter?.LocalTfilter || [])]}
|
|
2079
|
+
handleFilterChange={handleFilterChange}
|
|
2080
|
+
className={builderData?.reportSource?.fullName}
|
|
2081
|
+
LocalFilter={false}
|
|
2082
|
+
selectTFilter={selectTFilter}
|
|
2083
|
+
selectParamsMeta={builderData?.selectionParams || []}
|
|
2084
|
+
selectParamsValues={selectParams}
|
|
2085
|
+
onSelectParamsSave={(list) => {
|
|
2086
|
+
// list is array of { index, value, type }
|
|
2087
|
+
setSelectParams(prev => {
|
|
2088
|
+
const arr = [...(prev || [])];
|
|
2089
|
+
(list || []).forEach(item => {
|
|
2090
|
+
const i = item.index;
|
|
2091
|
+
const type = item.type;
|
|
2092
|
+
const current = arr[i] || {id: i, PropertyType: type, value: null};
|
|
2093
|
+
arr[i] = {...current, PropertyType: current.PropertyType || type, value: item.value};
|
|
2094
|
+
});
|
|
2095
|
+
return arr;
|
|
2096
|
+
});
|
|
2097
|
+
}}
|
|
2098
|
+
/>
|
|
2099
|
+
</Dialog>
|
|
2100
|
+
|
|
2101
|
+
|
|
2102
|
+
</Grid>
|
|
2103
|
+
|
|
2104
|
+
)
|
|
2105
|
+
}
|
|
2106
|
+
|
|
2107
|
+
|
|
2108
|
+
export default SGrid
|
|
2109
|
+
|
|
2110
|
+
|
|
2111
|
+
// Helper: convert a flat object with underscore-delimited keys into a nested object
|
|
2112
|
+
function toNestedByUnderscore(input) {
|
|
2113
|
+
if (input == null) return input;
|
|
2114
|
+
|
|
2115
|
+
if (Array.isArray(input)) {
|
|
2116
|
+
return input.map(v => (v && typeof v === 'object') ? toNestedByUnderscore(v) : v);
|
|
2117
|
+
}
|
|
2118
|
+
|
|
2119
|
+
if (typeof input !== 'object') return input;
|
|
2120
|
+
|
|
2121
|
+
const result = {};
|
|
2122
|
+
|
|
2123
|
+
const setNested = (target, parts, value) => {
|
|
2124
|
+
let ref = target;
|
|
2125
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
2126
|
+
const key = Helper.toCamelCaseDotNet(parts[i]);
|
|
2127
|
+
if (!ref[key] || typeof ref[key] !== 'object' || Array.isArray(ref[key])) {
|
|
2128
|
+
ref[key] = {};
|
|
2129
|
+
}
|
|
2130
|
+
ref = ref[key];
|
|
2131
|
+
}
|
|
2132
|
+
|
|
2133
|
+
const last = Helper.toCamelCaseDotNet(parts[parts.length - 1]);
|
|
2134
|
+
const existing = ref[last];
|
|
2135
|
+
if (
|
|
2136
|
+
existing && typeof existing === 'object' && !Array.isArray(existing) &&
|
|
2137
|
+
value && typeof value === 'object' && !Array.isArray(value)
|
|
2138
|
+
) {
|
|
2139
|
+
ref[last] = {...existing, ...value};
|
|
2140
|
+
} else {
|
|
2141
|
+
ref[last] = value;
|
|
2142
|
+
}
|
|
2143
|
+
};
|
|
2144
|
+
|
|
2145
|
+
for (const [key, val] of Object.entries(input)) {
|
|
2146
|
+
const nestedVal = (val && typeof val === 'object') ? toNestedByUnderscore(val) : val;
|
|
2147
|
+
const parts = String(key).split('_').filter(Boolean);
|
|
2148
|
+
if (parts.length === 0) continue;
|
|
2149
|
+
|
|
2150
|
+
if (parts.length === 1) {
|
|
2151
|
+
const k = Helper.toCamelCaseDotNet(parts[0]);
|
|
2152
|
+
const existing = result[k];
|
|
2153
|
+
if (
|
|
2154
|
+
existing && typeof existing === 'object' &&
|
|
2155
|
+
nestedVal && typeof nestedVal === 'object'
|
|
2156
|
+
) {
|
|
2157
|
+
result[k] = {...existing, ...nestedVal};
|
|
2158
|
+
} else {
|
|
2159
|
+
result[k] = nestedVal;
|
|
2160
|
+
}
|
|
2161
|
+
} else {
|
|
2162
|
+
setNested(result, parts, nestedVal);
|
|
2163
|
+
}
|
|
2164
|
+
}
|
|
2165
|
+
|
|
2166
|
+
return result;
|
|
2167
|
+
}
|
|
2168
|
+
|