robobyte-front-builder 1.0.17 → 1.0.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (516) hide show
  1. package/README.md +211 -0
  2. package/next.config.js +19 -48
  3. package/package.json +39 -85
  4. package/src/context/BuilderContext.jsx +134 -6
  5. package/src/context/SystemContext.js +2 -2
  6. package/src/hooks/useGlobalStore.js +36 -0
  7. package/src/hooks/useTimerEngine.js +54 -0
  8. package/src/lib/index.js +11 -3
  9. package/src/lib/layouts/BlankLayout.jsx +13 -0
  10. package/src/lib/providers/RoboByteFrontBuilderProvider.jsx +59 -1
  11. package/src/lib/themes/builderTheme.js +41 -0
  12. package/src/pages/_app.js +32 -134
  13. package/src/pages/api/ai.js +87 -0
  14. package/src/pages/builders/report/index.js +1 -0
  15. package/src/pages/builders/report/list/index.js +1 -0
  16. package/src/pages/builders/report/viewer/index.js +1 -0
  17. package/src/pages/index.js +88 -37
  18. package/src/pages/printBuilder/index.jsx +263 -0
  19. package/src/pages/printBuilder/layouts/index.jsx +298 -0
  20. package/src/pages/reportModule/reportBuilder/index.js +723 -563
  21. package/src/pages/reportModule/reportBuilder/reportViewer/index.js +137 -71
  22. package/src/pages/reportModule/reportBuilder/reports/index.js +51 -13
  23. package/src/pages/reportModule/reportBuilder/reportsPermissions/index.js +126 -0
  24. package/src/pages/viewBuilder/index.jsx +117 -32
  25. package/src/pages/viewBuilder/views/index.js +3 -3
  26. package/src/pages/viewer/[id]/index.js +2 -1
  27. package/src/services/DeleteService.js +31 -60
  28. package/src/services/Endpoints/PrintLayoutEndpoints.js +42 -0
  29. package/src/services/Endpoints.js +2 -0
  30. package/src/services/GetService.js +33 -54
  31. package/src/services/PatchService.js +38 -65
  32. package/src/services/PostService.js +37 -63
  33. package/src/services/UpdateService.js +39 -65
  34. package/src/services/builderHelper/actionExecutor.js +141 -25
  35. package/src/services/builderHelper/builderHelper.js +92 -0
  36. package/src/services/builderHelper/colorSchema.js +95 -0
  37. package/src/services/builderHelper/iconResolver.js +50 -0
  38. package/src/services/builderHelper/jsExecutor.js +212 -46
  39. package/src/services/builderHelper/nodeFactory.js +32 -15
  40. package/src/services/builderHelper/numberFormat.js +123 -0
  41. package/src/services/builderHelper/resolveProps.js +73 -4
  42. package/src/services/builderHelper/thresholdEngine.js +77 -0
  43. package/src/services/builderHelper/tree.js +31 -0
  44. package/src/services/components/agGridAutoComplete.js +5 -9
  45. package/src/services/config.js +9 -1
  46. package/src/services/globalStore.js +80 -0
  47. package/src/services/helper/multiSelectEditor.js +5 -9
  48. package/src/services/helper/multiSelectEditorByBuilder.js +241 -0
  49. package/src/services/helper/reportSessionHelper.js +83 -0
  50. package/src/services/reportData/fetchReportData.js +69 -28
  51. package/src/services/routerRef.js +35 -0
  52. package/src/views/ConfirmDialog.js +2 -2
  53. package/src/views/builder/JSEditor.js +105 -107
  54. package/src/views/builder/inspector/Inspector.jsx +6 -9
  55. package/src/views/builder/inspector/Tabs/ComponentActionsTab.jsx +7 -13
  56. package/src/views/builder/inspector/Tabs/MainTab.jsx +143 -25
  57. package/src/views/builder/inspector/Tabs/RulesTab.jsx +9 -24
  58. package/src/views/builder/inspector/Tabs/StyleTab.jsx +9 -24
  59. package/src/views/builder/inspector/definitions/autocomplete/main.js +4 -6
  60. package/src/views/builder/inspector/definitions/banner/actions.js +7 -0
  61. package/src/views/builder/inspector/definitions/banner/main.js +22 -0
  62. package/src/views/builder/inspector/definitions/banner/rules.js +1 -0
  63. package/src/views/builder/inspector/definitions/banner/style.js +1 -0
  64. package/src/views/builder/inspector/definitions/breadcrumb/main.js +43 -6
  65. package/src/views/builder/inspector/definitions/button/main.js +11 -12
  66. package/src/views/builder/inspector/definitions/button/style.js +18 -30
  67. package/src/views/builder/inspector/definitions/checkbox/actions.js +3 -1
  68. package/src/views/builder/inspector/definitions/checkbox/main.js +4 -6
  69. package/src/views/builder/inspector/definitions/common/main.js +13 -2
  70. package/src/views/builder/inspector/definitions/dataGrid/main.js +23 -0
  71. package/src/views/builder/inspector/definitions/dataTableViewer/main.js +46 -0
  72. package/src/views/builder/inspector/definitions/datepicker/actions.js +3 -1
  73. package/src/views/builder/inspector/definitions/datepicker/main.js +6 -14
  74. package/src/views/builder/inspector/definitions/dialog/main.js +36 -0
  75. package/src/views/builder/inspector/definitions/dropdown/main.js +5 -8
  76. package/src/views/builder/inspector/definitions/excelUpload/actions.js +23 -0
  77. package/src/views/builder/inspector/definitions/excelUpload/main.js +17 -0
  78. package/src/views/builder/inspector/definitions/excelUpload/rules.js +1 -0
  79. package/src/views/builder/inspector/definitions/excelUpload/style.js +45 -0
  80. package/src/views/builder/inspector/definitions/header/main.js +10 -1
  81. package/src/views/builder/inspector/definitions/index.js +106 -19
  82. package/src/views/builder/inspector/definitions/input/actions.js +4 -1
  83. package/src/views/builder/inspector/definitions/input/main.js +20 -11
  84. package/src/views/builder/inspector/definitions/kpi/avatarGroup.js +22 -0
  85. package/src/views/builder/inspector/definitions/kpi/badge.js +17 -0
  86. package/src/views/builder/inspector/definitions/kpi/bulletChart.js +47 -0
  87. package/src/views/builder/inspector/definitions/kpi/chart.js +55 -0
  88. package/src/views/builder/inspector/definitions/kpi/colorScale.js +60 -0
  89. package/src/views/builder/inspector/definitions/kpi/comparisonBars.js +41 -0
  90. package/src/views/builder/inspector/definitions/kpi/countdown.js +46 -0
  91. package/src/views/builder/inspector/definitions/kpi/donut.js +51 -0
  92. package/src/views/builder/inspector/definitions/kpi/funnel.js +25 -0
  93. package/src/views/builder/inspector/definitions/kpi/gauge.js +39 -0
  94. package/src/views/builder/inspector/definitions/kpi/heatmapGrid.js +96 -0
  95. package/src/views/builder/inspector/definitions/kpi/iconBox.js +20 -0
  96. package/src/views/builder/inspector/definitions/kpi/metric.js +45 -0
  97. package/src/views/builder/inspector/definitions/kpi/rating.js +27 -0
  98. package/src/views/builder/inspector/definitions/kpi/statusDot.js +18 -0
  99. package/src/views/builder/inspector/definitions/kpi/stepStage.js +65 -0
  100. package/src/views/builder/inspector/definitions/kpi/tagList.js +32 -0
  101. package/src/views/builder/inspector/definitions/kpi/timeline.js +80 -0
  102. package/src/views/builder/inspector/definitions/kpi/trend.js +20 -0
  103. package/src/views/builder/inspector/definitions/label/main.js +10 -1
  104. package/src/views/builder/inspector/definitions/layout/main.js +27 -3
  105. package/src/views/builder/inspector/definitions/number/main.js +6 -14
  106. package/src/views/builder/inspector/definitions/pageNumber/main.js +21 -0
  107. package/src/views/builder/inspector/definitions/popover/main.js +71 -0
  108. package/src/views/builder/inspector/definitions/radio/main.js +5 -8
  109. package/src/views/builder/inspector/definitions/repeater/main.js +31 -0
  110. package/src/views/builder/inspector/definitions/reportViewer/main.js +15 -1
  111. package/src/views/builder/inspector/definitions/richtext/main.js +5 -8
  112. package/src/views/builder/inspector/definitions/signature/main.js +4 -1
  113. package/src/views/builder/inspector/definitions/tag/main.js +5 -8
  114. package/src/views/builder/inspector/definitions/textarea/actions.js +4 -1
  115. package/src/views/builder/inspector/definitions/textarea/main.js +5 -7
  116. package/src/views/builder/inspector/definitions/time/main.js +5 -8
  117. package/src/views/builder/inspector/definitions/toggle/main.js +5 -19
  118. package/src/views/builder/inspector/definitions/treeView/main.js +61 -0
  119. package/src/views/builder/inspector/definitions/viewRenderer/main.js +53 -0
  120. package/src/views/builder/inspector/definitions/wizard/main.js +68 -0
  121. package/src/views/builder/inspector/definitions/wizard-step/main.js +25 -0
  122. package/src/views/builder/inspector/fields/ActionsConfigEditor.jsx +426 -0
  123. package/src/views/builder/inspector/fields/ColorSchemaField.jsx +140 -0
  124. package/src/views/builder/inspector/fields/ColumnFunctionEditor.jsx +238 -0
  125. package/src/views/builder/inspector/fields/ColumnMappingEditor.jsx +105 -0
  126. package/src/views/builder/inspector/fields/ColumnsConfigEditor.jsx +506 -0
  127. package/src/views/builder/inspector/fields/DonutRingsEditorField.jsx +337 -0
  128. package/src/views/builder/inspector/fields/ExtraColsEditor.jsx +618 -0
  129. package/src/views/builder/inspector/fields/FunctionHelpPopover.jsx +295 -0
  130. package/src/views/builder/inspector/fields/IconEditor.jsx +64 -0
  131. package/src/views/builder/inspector/fields/KpiActionField.jsx +223 -0
  132. package/src/views/builder/inspector/fields/MarkersEditorField.jsx +173 -0
  133. package/src/views/builder/inspector/fields/SelectEditor.jsx +9 -5
  134. package/src/views/builder/inspector/fields/SeriesEditorField.jsx +363 -0
  135. package/src/views/builder/inspector/fields/TableColumnsEditor.jsx +104 -0
  136. package/src/views/builder/inspector/fields/ThresholdsEditor.jsx +247 -0
  137. package/src/views/builder/inspector/fields/ValueFunctionsRefPanel.jsx +217 -0
  138. package/src/views/builder/inspector/fields/columnEditorShared.jsx +217 -0
  139. package/src/views/builder/sidebar/Sidebar.jsx +4 -2
  140. package/src/views/builder/sidebar/SidebarTabs.jsx +28 -17
  141. package/src/views/builder/sidebar/tabs/ActionsTab.jsx +7 -3
  142. package/src/views/builder/sidebar/tabs/AiTab/AiPreviewDialog.jsx +193 -0
  143. package/src/views/builder/sidebar/tabs/AiTab/aiProvider.js +49 -0
  144. package/src/views/builder/sidebar/tabs/AiTab/index.jsx +409 -0
  145. package/src/views/builder/sidebar/tabs/AiTab/schemaTransformer.js +102 -0
  146. package/src/views/builder/sidebar/tabs/AiTab/schemaValidator.js +64 -0
  147. package/src/views/builder/sidebar/tabs/AiTab/systemPrompt.js +1151 -0
  148. package/src/views/builder/sidebar/tabs/Components/ComponentsTab.jsx +31 -31
  149. package/src/views/builder/sidebar/tabs/Components/componentCatalog.js +43 -21
  150. package/src/views/builder/sidebar/tabs/Components/printComponentCatalog.js +81 -0
  151. package/src/views/builder/sidebar/tabs/TimersTab.jsx +338 -0
  152. package/src/views/builder/sidebar/tabs/TreeTab.jsx +13 -4
  153. package/src/views/builder/sidebar/tabs/ViewTab.jsx +1 -1
  154. package/src/views/builder/viewer/AdornedLabel.jsx +82 -0
  155. package/src/views/builder/viewer/ComponentRenderer.jsx +98 -24
  156. package/src/views/builder/viewer/DialogsZone.jsx +259 -0
  157. package/src/views/builder/viewer/FieldLabel.jsx +106 -0
  158. package/src/views/builder/viewer/PrintDialog.jsx +481 -0
  159. package/src/views/builder/viewer/ProductionViewer.jsx +80 -5
  160. package/src/views/builder/viewer/Viewer.jsx +106 -8
  161. package/src/views/builder/viewer/ViewerComponentWrapper.jsx +61 -4
  162. package/src/views/builder/viewer/ViewerToolbar.jsx +273 -59
  163. package/src/views/builder/viewer/renderers/AutoCompleteRenderer.jsx +26 -22
  164. package/src/views/builder/viewer/renderers/AvatarGroupRenderer.jsx +112 -0
  165. package/src/views/builder/viewer/renderers/BadgeRenderer.jsx +79 -0
  166. package/src/views/builder/viewer/renderers/BannerRenderer.jsx +62 -0
  167. package/src/views/builder/viewer/renderers/BreadcrumbRenderer.jsx +203 -15
  168. package/src/views/builder/viewer/renderers/BulletChartRenderer.jsx +147 -0
  169. package/src/views/builder/viewer/renderers/ButtonRenderer.jsx +98 -39
  170. package/src/views/builder/viewer/renderers/CardRenderer.jsx +1 -1
  171. package/src/views/builder/viewer/renderers/ChartRenderer.jsx +388 -0
  172. package/src/views/builder/viewer/renderers/CheckboxRenderer.jsx +17 -9
  173. package/src/views/builder/viewer/renderers/ColorScaleRenderer.jsx +300 -0
  174. package/src/views/builder/viewer/renderers/ComparisonBarsRenderer.jsx +133 -0
  175. package/src/views/builder/viewer/renderers/ContainerRenderer.jsx +3 -1
  176. package/src/views/builder/viewer/renderers/CountdownRenderer.jsx +249 -0
  177. package/src/views/builder/viewer/renderers/DataGridRenderer.jsx +380 -0
  178. package/src/views/builder/viewer/renderers/DataTableViewerRenderer.jsx +240 -0
  179. package/src/views/builder/viewer/renderers/DatePickerRenderer.jsx +25 -24
  180. package/src/views/builder/viewer/renderers/DialogRenderer.jsx +327 -0
  181. package/src/views/builder/viewer/renderers/DividerRenderer.jsx +1 -1
  182. package/src/views/builder/viewer/renderers/DonutRenderer.jsx +294 -0
  183. package/src/views/builder/viewer/renderers/DropdownRenderer.jsx +36 -44
  184. package/src/views/builder/viewer/renderers/ExcelUploadRenderer.jsx +639 -0
  185. package/src/views/builder/viewer/renderers/FunnelRenderer.jsx +93 -0
  186. package/src/views/builder/viewer/renderers/GaugeRenderer.jsx +159 -0
  187. package/src/views/builder/viewer/renderers/HeaderRenderer.jsx +31 -9
  188. package/src/views/builder/viewer/renderers/HeatmapGridRenderer.jsx +432 -0
  189. package/src/views/builder/viewer/renderers/IconBoxRenderer.jsx +59 -0
  190. package/src/views/builder/viewer/renderers/ImageRenderer.jsx +1 -1
  191. package/src/views/builder/viewer/renderers/InputRenderer.jsx +75 -18
  192. package/src/views/builder/viewer/renderers/LabelRenderer.jsx +35 -9
  193. package/src/views/builder/viewer/renderers/LayoutCellRenderer.jsx +102 -40
  194. package/src/views/builder/viewer/renderers/LayoutContextMenu.jsx +8 -8
  195. package/src/views/builder/viewer/renderers/LayoutRenderer.jsx +48 -6
  196. package/src/views/builder/viewer/renderers/LinkRenderer.jsx +1 -1
  197. package/src/views/builder/viewer/renderers/MenuRenderer.jsx +2 -2
  198. package/src/views/builder/viewer/renderers/MetricRenderer.jsx +80 -0
  199. package/src/views/builder/viewer/renderers/NumberFormatRenderer.jsx +21 -30
  200. package/src/views/builder/viewer/renderers/PageNumberRenderer.jsx +76 -0
  201. package/src/views/builder/viewer/renderers/PopoverRenderer.jsx +350 -0
  202. package/src/views/builder/viewer/renderers/ProgressCircleRenderer.jsx +1 -1
  203. package/src/views/builder/viewer/renderers/ProgressLineRenderer.jsx +1 -1
  204. package/src/views/builder/viewer/renderers/RadioGroupRenderer.jsx +28 -39
  205. package/src/views/builder/viewer/renderers/RatingRenderer.jsx +80 -0
  206. package/src/views/builder/viewer/renderers/RepeaterRenderer.jsx +297 -38
  207. package/src/views/builder/viewer/renderers/ReportViewerRenderer.jsx +219 -5
  208. package/src/views/builder/viewer/renderers/RichTextRenderer.jsx +60 -66
  209. package/src/views/builder/viewer/renderers/RowActionsCell.jsx +308 -0
  210. package/src/views/builder/viewer/renderers/SignatureRenderer.jsx +33 -62
  211. package/src/views/builder/viewer/renderers/StatusDotRenderer.jsx +75 -0
  212. package/src/views/builder/viewer/renderers/StepStageRenderer.jsx +348 -0
  213. package/src/views/builder/viewer/renderers/TagListRenderer.jsx +115 -0
  214. package/src/views/builder/viewer/renderers/TagPickerRenderer.jsx +31 -45
  215. package/src/views/builder/viewer/renderers/TextAreaRenderer.jsx +25 -18
  216. package/src/views/builder/viewer/renderers/TextRenderer.jsx +7 -1
  217. package/src/views/builder/viewer/renderers/TimePickerRenderer.jsx +25 -24
  218. package/src/views/builder/viewer/renderers/TimelineRenderer.jsx +525 -0
  219. package/src/views/builder/viewer/renderers/ToggleRenderer.jsx +21 -27
  220. package/src/views/builder/viewer/renderers/TreeViewRenderer.jsx +832 -0
  221. package/src/views/builder/viewer/renderers/TrendRenderer.jsx +66 -0
  222. package/src/views/builder/viewer/renderers/ViewRendererRenderer.jsx +315 -0
  223. package/src/views/builder/viewer/renderers/WizardRenderer.jsx +380 -64
  224. package/src/views/builder/viewer/renderers/WizardStepRenderer.jsx +21 -12
  225. package/src/views/builder/viewer/renderers/dataGridComponents.jsx +824 -0
  226. package/src/views/customFilter/CustomFilterDialog.js +1023 -660
  227. package/src/views/customFilter/FixedFilterDialog.js +649 -0
  228. package/src/views/customFilter/SearchFilterDialog.js +248 -0
  229. package/src/views/genericTable/BuilderExpressionParams.js +3 -3
  230. package/src/views/genericTable/ColumnConfiguratorDialog.js +771 -0
  231. package/src/views/genericTable/FixedFilterDialog.js +3 -2
  232. package/src/views/genericTable/FormattingSettingsDialog.js +551 -0
  233. package/src/views/genericTable/ReportSettingsDialog.js +151 -0
  234. package/src/views/genericTable/SGrid.js +1061 -247
  235. package/src/views/genericTable/SearchFilterDialog.js +3 -2
  236. package/src/views/genericTable/TAGGrid.js +83 -69
  237. package/src/views/genericTable/cellEditors/autocompleteEditor.js +5 -9
  238. package/src/views/genericTable/convertStringFunctions.js +336 -0
  239. package/src/views/genericTable/statusBar/rowCountStatusBar.js +3 -1
  240. package/src/views/genericTable/updateRefHelpers.js +424 -0
  241. package/src/views/printBuilder/PrintBuilderViewer.jsx +607 -0
  242. package/src/views/printBuilder/PrintPreviewCanvas.jsx +157 -0
  243. package/src/views/rolePermissions/UpdateReportPermissionDialog.js +316 -0
  244. package/src/@core/components/auth/AclGuard.js +0 -55
  245. package/src/@core/components/auth/AuthGuard.js +0 -40
  246. package/src/@core/components/auth/GuestGuard.js +0 -30
  247. package/src/@core/components/custom-inputs/Horizontal.jsx +0 -143
  248. package/src/@core/components/custom-inputs/Image.jsx +0 -78
  249. package/src/@core/components/custom-inputs/Vertical.jsx +0 -113
  250. package/src/@core/components/customizer/index.jsx +0 -470
  251. package/src/@core/components/customizer/styles.module.css +0 -169
  252. package/src/@core/components/mui/Avatar.jsx +0 -41
  253. package/src/@core/components/mui/Badge.jsx +0 -20
  254. package/src/@core/components/mui/IconButton.jsx +0 -74
  255. package/src/@core/components/mui/TabList.jsx +0 -60
  256. package/src/@core/components/option-menu/index.jsx +0 -137
  257. package/src/@core/components/scroll-to-top/index.jsx +0 -43
  258. package/src/@core/components/spinner/index.js +0 -26
  259. package/src/@core/components/window-wrapper/index.js +0 -27
  260. package/src/@core/contexts/settingsContext.jsx +0 -98
  261. package/src/@core/hooks/useBgColor.js +0 -63
  262. package/src/@core/hooks/useImageVariant.js +0 -27
  263. package/src/@core/hooks/useLayoutInit.js +0 -37
  264. package/src/@core/hooks/useObjectCookie.js +0 -18
  265. package/src/@core/hooks/useSettings.jsx +0 -15
  266. package/src/@core/layouts/BlankLayout.js +0 -37
  267. package/src/@core/layouts/BlankLayoutWithAppBar.js +0 -51
  268. package/src/@core/layouts/HorizontalLayout.jsx +0 -151
  269. package/src/@core/layouts/Layout.js +0 -39
  270. package/src/@core/layouts/VerticalLayout.jsx +0 -124
  271. package/src/@core/layouts/components/blank-layout-with-appBar/index.js +0 -115
  272. package/src/@core/layouts/components/horizontal/app-bar-content/index.js +0 -67
  273. package/src/@core/layouts/components/horizontal/navigation/HorizontalNavGroup.js +0 -352
  274. package/src/@core/layouts/components/horizontal/navigation/HorizontalNavItems.js +0 -21
  275. package/src/@core/layouts/components/horizontal/navigation/HorizontalNavLink.js +0 -195
  276. package/src/@core/layouts/components/horizontal/navigation/index.js +0 -31
  277. package/src/@core/layouts/components/shared-components/LanguageDropdown.js +0 -96
  278. package/src/@core/layouts/components/shared-components/ModeToggler.js +0 -32
  279. package/src/@core/layouts/components/shared-components/NotificationDropdown.js +0 -226
  280. package/src/@core/layouts/components/shared-components/UserDropdown.js +0 -177
  281. package/src/@core/layouts/components/shared-components/footer/FooterContent.js +0 -46
  282. package/src/@core/layouts/components/shared-components/footer/index.js +0 -61
  283. package/src/@core/layouts/components/vertical/appBar/index.js +0 -74
  284. package/src/@core/layouts/components/vertical/navigation/Drawer.js +0 -122
  285. package/src/@core/layouts/components/vertical/navigation/VerticalNavGroup.js +0 -435
  286. package/src/@core/layouts/components/vertical/navigation/VerticalNavHeader.js +0 -180
  287. package/src/@core/layouts/components/vertical/navigation/VerticalNavItems.js +0 -26
  288. package/src/@core/layouts/components/vertical/navigation/VerticalNavLink.js +0 -258
  289. package/src/@core/layouts/components/vertical/navigation/VerticalNavSectionTitle.js +0 -102
  290. package/src/@core/layouts/components/vertical/navigation/index.js +0 -169
  291. package/src/@core/layouts/utils.js +0 -69
  292. package/src/@core/styles/Table.module.css +0 -93
  293. package/src/@core/styles/horizontal/menuItemStyles.js +0 -100
  294. package/src/@core/styles/horizontal/menuRootStyles.js +0 -19
  295. package/src/@core/styles/libs/fullcalendar/index.js +0 -461
  296. package/src/@core/styles/libs/keen-slider/index.js +0 -111
  297. package/src/@core/styles/libs/react-apexcharts/index.js +0 -107
  298. package/src/@core/styles/libs/react-cleave/index.js +0 -33
  299. package/src/@core/styles/libs/react-credit-cards/index.js +0 -11
  300. package/src/@core/styles/libs/react-datepicker/index.js +0 -388
  301. package/src/@core/styles/libs/react-draft-wysiwyg/index.js +0 -144
  302. package/src/@core/styles/libs/react-dropzone/index.js +0 -76
  303. package/src/@core/styles/libs/react-hot-toast/index.js +0 -37
  304. package/src/@core/styles/libs/recharts/index.js +0 -47
  305. package/src/@core/styles/stepper.js +0 -103
  306. package/src/@core/styles/vertical/menuItemStyles.js +0 -138
  307. package/src/@core/styles/vertical/menuSectionStyles.js +0 -54
  308. package/src/@core/styles/vertical/navigationCustomStyles.js +0 -62
  309. package/src/@core/svg/ContentCompact.jsx +0 -17
  310. package/src/@core/svg/ContentWide.jsx +0 -17
  311. package/src/@core/svg/DirectionLtr.jsx +0 -93
  312. package/src/@core/svg/DirectionRtl.jsx +0 -93
  313. package/src/@core/svg/LayoutCollapsed.jsx +0 -59
  314. package/src/@core/svg/LayoutHorizontal.jsx +0 -42
  315. package/src/@core/svg/LayoutVertical.jsx +0 -59
  316. package/src/@core/svg/Logo.jsx +0 -76
  317. package/src/@core/svg/SkinBordered.jsx +0 -54
  318. package/src/@core/svg/SkinDefault.jsx +0 -59
  319. package/src/@core/tailwind/plugin.js +0 -78
  320. package/src/@core/theme/ThemeComponent.js +0 -63
  321. package/src/@core/theme/ThemeOptions.js +0 -71
  322. package/src/@core/theme/breakpoints/index.js +0 -11
  323. package/src/@core/theme/colorSchemes.js +0 -326
  324. package/src/@core/theme/customShadows.js +0 -11
  325. package/src/@core/theme/globalStyles.js +0 -81
  326. package/src/@core/theme/index.js +0 -42
  327. package/src/@core/theme/overrides/accordion.js +0 -51
  328. package/src/@core/theme/overrides/accordion.jsx +0 -85
  329. package/src/@core/theme/overrides/alerts.js +0 -110
  330. package/src/@core/theme/overrides/alerts.jsx +0 -180
  331. package/src/@core/theme/overrides/autocomplete.js +0 -14
  332. package/src/@core/theme/overrides/autocomplete.jsx +0 -68
  333. package/src/@core/theme/overrides/avatar.js +0 -38
  334. package/src/@core/theme/overrides/avatars.js +0 -27
  335. package/src/@core/theme/overrides/backdrop.js +0 -22
  336. package/src/@core/theme/overrides/badges.js +0 -16
  337. package/src/@core/theme/overrides/breadcrumbs.js +0 -11
  338. package/src/@core/theme/overrides/button-group.js +0 -84
  339. package/src/@core/theme/overrides/button.js +0 -93
  340. package/src/@core/theme/overrides/buttonGroup.js +0 -9
  341. package/src/@core/theme/overrides/card.js +0 -83
  342. package/src/@core/theme/overrides/checkbox.jsx +0 -95
  343. package/src/@core/theme/overrides/chip.js +0 -72
  344. package/src/@core/theme/overrides/dataGrid.js +0 -114
  345. package/src/@core/theme/overrides/dateTimePicker.js +0 -65
  346. package/src/@core/theme/overrides/dialog.js +0 -120
  347. package/src/@core/theme/overrides/divider.js +0 -13
  348. package/src/@core/theme/overrides/drawer.js +0 -20
  349. package/src/@core/theme/overrides/fab.js +0 -13
  350. package/src/@core/theme/overrides/form-control-label.js +0 -19
  351. package/src/@core/theme/overrides/icon-button.js +0 -145
  352. package/src/@core/theme/overrides/index.js +0 -103
  353. package/src/@core/theme/overrides/input.js +0 -72
  354. package/src/@core/theme/overrides/link.js +0 -9
  355. package/src/@core/theme/overrides/list.js +0 -44
  356. package/src/@core/theme/overrides/menu.js +0 -25
  357. package/src/@core/theme/overrides/pagination.js +0 -41
  358. package/src/@core/theme/overrides/paper.js +0 -9
  359. package/src/@core/theme/overrides/popover.js +0 -16
  360. package/src/@core/theme/overrides/progress.js +0 -38
  361. package/src/@core/theme/overrides/radio.jsx +0 -80
  362. package/src/@core/theme/overrides/rating.js +0 -16
  363. package/src/@core/theme/overrides/rating.jsx +0 -32
  364. package/src/@core/theme/overrides/select.js +0 -19
  365. package/src/@core/theme/overrides/select.jsx +0 -52
  366. package/src/@core/theme/overrides/slider.js +0 -97
  367. package/src/@core/theme/overrides/snackbar.js +0 -19
  368. package/src/@core/theme/overrides/switch.js +0 -73
  369. package/src/@core/theme/overrides/switches.js +0 -25
  370. package/src/@core/theme/overrides/table-pagination.js +0 -39
  371. package/src/@core/theme/overrides/table.js +0 -81
  372. package/src/@core/theme/overrides/tabs.js +0 -30
  373. package/src/@core/theme/overrides/timeline.js +0 -80
  374. package/src/@core/theme/overrides/toggle-button.js +0 -33
  375. package/src/@core/theme/overrides/toggleButton.js +0 -16
  376. package/src/@core/theme/overrides/tooltip.js +0 -21
  377. package/src/@core/theme/overrides/typography.js +0 -13
  378. package/src/@core/theme/palette/index.js +0 -107
  379. package/src/@core/theme/shadows/index.js +0 -61
  380. package/src/@core/theme/shadows.js +0 -12
  381. package/src/@core/theme/spacing/index.js +0 -3
  382. package/src/@core/theme/spacing.js +0 -5
  383. package/src/@core/theme/typography/index.js +0 -65
  384. package/src/@core/theme/typography.js +0 -84
  385. package/src/@core/utils/create-emotion-cache.js +0 -5
  386. package/src/@core/utils/hex-to-rgba.js +0 -11
  387. package/src/@core/utils/serverHelpers.js +0 -45
  388. package/src/@menu/components/RouterLink.jsx +0 -18
  389. package/src/@menu/components/horizontal-menu/HorizontalNav.jsx +0 -88
  390. package/src/@menu/components/horizontal-menu/Menu.jsx +0 -83
  391. package/src/@menu/components/horizontal-menu/MenuButton.jsx +0 -100
  392. package/src/@menu/components/horizontal-menu/MenuItem.jsx +0 -183
  393. package/src/@menu/components/horizontal-menu/SubMenu.jsx +0 -418
  394. package/src/@menu/components/horizontal-menu/SubMenuContent.jsx +0 -41
  395. package/src/@menu/components/horizontal-menu/VerticalNavInHorizontal.jsx +0 -20
  396. package/src/@menu/components/vertical-menu/Menu.jsx +0 -161
  397. package/src/@menu/components/vertical-menu/MenuButton.jsx +0 -95
  398. package/src/@menu/components/vertical-menu/MenuItem.jsx +0 -180
  399. package/src/@menu/components/vertical-menu/MenuSection.jsx +0 -124
  400. package/src/@menu/components/vertical-menu/NavCollapseIcons.jsx +0 -70
  401. package/src/@menu/components/vertical-menu/NavHeader.jsx +0 -39
  402. package/src/@menu/components/vertical-menu/SubMenu.jsx +0 -420
  403. package/src/@menu/components/vertical-menu/SubMenuContent.jsx +0 -101
  404. package/src/@menu/components/vertical-menu/VerticalNav.jsx +0 -216
  405. package/src/@menu/contexts/horizontalNavContext.jsx +0 -29
  406. package/src/@menu/contexts/verticalNavContext.jsx +0 -65
  407. package/src/@menu/defaultConfigs.js +0 -12
  408. package/src/@menu/hooks/useHorizontalMenu.jsx +0 -19
  409. package/src/@menu/hooks/useHorizontalNav.jsx +0 -19
  410. package/src/@menu/hooks/useMediaQuery.jsx +0 -29
  411. package/src/@menu/hooks/useVerticalMenu.jsx +0 -19
  412. package/src/@menu/hooks/useVerticalNav.jsx +0 -19
  413. package/src/@menu/horizontal-menu/index.jsx +0 -8
  414. package/src/@menu/styles/StyledBackdrop.jsx +0 -15
  415. package/src/@menu/styles/StyledMenuIcon.jsx +0 -12
  416. package/src/@menu/styles/StyledMenuLabel.jsx +0 -16
  417. package/src/@menu/styles/StyledMenuPrefix.jsx +0 -10
  418. package/src/@menu/styles/StyledMenuSectionLabel.jsx +0 -21
  419. package/src/@menu/styles/StyledMenuSuffix.jsx +0 -10
  420. package/src/@menu/styles/StyledSubMenuContent.jsx +0 -43
  421. package/src/@menu/styles/horizontal/StyledHorizontalMenu.jsx +0 -13
  422. package/src/@menu/styles/horizontal/StyledHorizontalMenuItem.jsx +0 -26
  423. package/src/@menu/styles/horizontal/StyledHorizontalNav.jsx +0 -11
  424. package/src/@menu/styles/horizontal/StyledHorizontalNavExpandIcon.jsx +0 -33
  425. package/src/@menu/styles/horizontal/StyledHorizontalSubMenuContent.jsx +0 -18
  426. package/src/@menu/styles/horizontal/StyledHorizontalSubMenuContentWrapper.jsx +0 -10
  427. package/src/@menu/styles/horizontal/horizontalUl.module.css +0 -15
  428. package/src/@menu/styles/styles.module.css +0 -5
  429. package/src/@menu/styles/vertical/StyledVerticalMenu.jsx +0 -16
  430. package/src/@menu/styles/vertical/StyledVerticalMenuItem.jsx +0 -28
  431. package/src/@menu/styles/vertical/StyledVerticalMenuSection.jsx +0 -23
  432. package/src/@menu/styles/vertical/StyledVerticalNav.jsx +0 -67
  433. package/src/@menu/styles/vertical/StyledVerticalNavBgColorContainer.jsx +0 -15
  434. package/src/@menu/styles/vertical/StyledVerticalNavContainer.jsx +0 -23
  435. package/src/@menu/styles/vertical/StyledVerticalNavExpandIcon.jsx +0 -25
  436. package/src/@menu/styles/vertical/verticalNavBgImage.module.css +0 -10
  437. package/src/@menu/svg/ChevronRight.jsx +0 -9
  438. package/src/@menu/svg/Close.jsx +0 -12
  439. package/src/@menu/svg/RadioCircle.jsx +0 -12
  440. package/src/@menu/svg/RadioCircleMarked.jsx +0 -13
  441. package/src/@menu/utils/menuClasses.js +0 -44
  442. package/src/@menu/utils/menuUtils.jsx +0 -145
  443. package/src/@menu/vertical-menu/index.jsx +0 -11
  444. package/src/configs/acl.js +0 -115
  445. package/src/configs/auth.js +0 -5
  446. package/src/configs/aws-exports.js +0 -30
  447. package/src/configs/firebase.js +0 -25
  448. package/src/configs/i18n.js +0 -34
  449. package/src/configs/primaryColorConfig.js +0 -35
  450. package/src/configs/themeConfig.js +0 -44
  451. package/src/layouts/UserLayout.js +0 -94
  452. package/src/layouts/UserThemeOptions.js +0 -191
  453. package/src/layouts/components/Direction.js +0 -30
  454. package/src/layouts/components/HtmlTooltip.js +0 -15
  455. package/src/layouts/components/Translations.js +0 -11
  456. package/src/layouts/components/UserDropdown.js +0 -217
  457. package/src/layouts/components/UserIcon.js +0 -40
  458. package/src/layouts/components/acl/Can.js +0 -6
  459. package/src/layouts/components/acl/CanViewNavGroup.js +0 -36
  460. package/src/layouts/components/acl/CanViewNavLink.js +0 -17
  461. package/src/layouts/components/acl/CanViewNavSectionTitle.js +0 -17
  462. package/src/layouts/components/horizontal/AppBarContent.js +0 -39
  463. package/src/layouts/components/horizontal/ServerSideNavItems.js +0 -44
  464. package/src/layouts/components/mui/StepperComps.js +0 -55
  465. package/src/layouts/components/vertical/AppBarContent.js +0 -35
  466. package/src/layouts/components/vertical/ServerSideNavItems.js +0 -44
  467. package/src/libs/ApexCharts.jsx +0 -5
  468. package/src/libs/ReactPlayer.jsx +0 -5
  469. package/src/libs/Recharts.jsx +0 -4
  470. package/src/libs/auth.js +0 -124
  471. package/src/libs/styles/AppFullCalendar.js +0 -505
  472. package/src/libs/styles/AppKeenSlider.js +0 -116
  473. package/src/libs/styles/AppReactApexCharts.jsx +0 -110
  474. package/src/libs/styles/AppReactDatepicker.jsx +0 -470
  475. package/src/libs/styles/AppReactDropzone.js +0 -76
  476. package/src/libs/styles/AppReactToastify.jsx +0 -108
  477. package/src/libs/styles/AppRecharts.js +0 -55
  478. package/src/libs/styles/inputOtp.module.css +0 -39
  479. package/src/libs/styles/tiptapEditor.css +0 -72
  480. package/src/navigation/horizontal/index.js +0 -246
  481. package/src/navigation/vertical/index.js +0 -253
  482. package/src/pages/401.js +0 -70
  483. package/src/pages/404.js +0 -67
  484. package/src/pages/500.js +0 -68
  485. package/src/pages/[slug].js +0 -115
  486. package/src/pages/_document.js +0 -72
  487. package/src/pages/api/navigation/regenerate-registry.js +0 -116
  488. package/src/pages/api/navigation/save.js +0 -218
  489. package/src/pages/authModule/acl/index.js +0 -48
  490. package/src/pages/authModule/forgot-password/index.js +0 -228
  491. package/src/pages/authModule/permissions/rolePermissions/[id]/rolePermissionsUser/index.js +0 -392
  492. package/src/pages/authModule/permissions/rolePermissions/index.js +0 -343
  493. package/src/pages/authModule/permissions/systemPermissions/index.js +0 -354
  494. package/src/pages/authModule/privacy/index.js +0 -721
  495. package/src/pages/authModule/users/index.js +0 -210
  496. package/src/pages/login/index.js +0 -328
  497. package/src/pages/mainHome/index.js +0 -181
  498. package/src/views/builder/inspector/definitions/cell/main.js +0 -4
  499. package/src/views/builder/inspector/definitions/column/main.js +0 -9
  500. package/src/views/builder/inspector/definitions/column-group/main.js +0 -18
  501. package/src/views/builder/inspector/definitions/header-cell/main.js +0 -5
  502. package/src/views/builder/inspector/definitions/table/main.js +0 -9
  503. package/src/views/builder/viewer/renderers/CellRenderer.jsx +0 -71
  504. package/src/views/builder/viewer/renderers/ColumnGroupRenderer.jsx +0 -96
  505. package/src/views/builder/viewer/renderers/ColumnRenderer.jsx +0 -71
  506. package/src/views/builder/viewer/renderers/HeaderCellRenderer.jsx +0 -78
  507. package/src/views/builder/viewer/renderers/TabRenderer.jsx +0 -82
  508. package/src/views/builder/viewer/renderers/TableRenderer.jsx +0 -92
  509. package/src/views/pages/auth/FooterIllustrationsV2.js +0 -40
  510. package/src/views/pages/misc/FooterIllustrations.js +0 -47
  511. package/src/views/pages/misc/muiTable/CustomPagination.js +0 -34
  512. package/src/views/pages/users/UserManageDialog.js +0 -283
  513. package/src/views/pages/users/UserViewPage.js +0 -199
  514. package/src/views/users/AddUserNameDialog.js +0 -162
  515. package/src/views/users/ContactManage.js +0 -449
  516. package/src/views/users/ResetPasswordDialog.js +0 -242
@@ -1,4 +1,4 @@
1
- import BlankLayout from 'src/@core/layouts/BlankLayout'
1
+ import BlankLayout from "../../../lib/layouts/BlankLayout";
2
2
  import {
3
3
  Autocomplete,
4
4
  Box,
@@ -16,68 +16,73 @@ import {
16
16
  Link,
17
17
  Chip,
18
18
  Button,
19
+ DialogActions,
20
+ MenuItem,
21
+ Select,
22
+ InputLabel,
23
+ FormControl,
24
+ DialogContent,
25
+ DialogTitle,
19
26
  Dialog,
20
27
  Tooltip,
21
- Accordion,
22
- AccordionSummary,
23
- AccordionDetails,
24
- FormControlLabel
25
- } from '@mui/material'
26
- import { useEffect, useRef, useState } from 'react'
27
- import { Endpoints, Services } from 'services/Endpoints'
28
+ Checkbox, Accordion, AccordionSummary, AccordionDetails, FormControlLabel,
29
+ } from '@mui/material';
30
+ import {useEffect, useRef, useState} from "react";
31
+ import {Endpoints, Services} from "services/Endpoints";
28
32
  import {
29
33
  AddBox,
34
+ ArrowBackOutlined,
30
35
  ArrowForwardSharp,
31
36
  AssessmentOutlined,
32
- Expand,
33
- FilterAlt,
37
+ BackupOutlined,
38
+ Expand, FilterAlt, FilterBAndW, FilterVintageOutlined,
39
+ KeyboardReturnOutlined,
34
40
  PreviewOutlined,
35
41
  SaveAsOutlined,
36
- SaveOutlined,
37
- Search,
38
- Visibility,
39
- VisibilityOff,
40
- Image as ImageIcon,
42
+ SaveOutlined, Search, Visibility, VisibilityOff, Image as ImageIcon,
41
43
  CloudDownloadOutlined,
42
- CloudUploadOutlined
43
- } from '@mui/icons-material'
44
- import dayjs from 'dayjs'
45
- import { BackspaceOutline, CheckCircleOutline, DeleteOutline, Filter, PencilOutline } from 'mdi-material-ui'
46
- import SGrid from 'views/genericTable/SGrid'
47
- import { Controller, useForm } from 'react-hook-form'
48
- import ComputedTextEditor from 'views/genericTable/RegexTextEditor'
49
- import ExpressionEditor from 'views/genericTable/RegexTextEditor'
50
- import BuilderExpressionParams from 'views/genericTable/BuilderExpressionParams'
51
- import handleChange from 'services/helper/handleChange'
52
- import DynamicValueList from 'views/genericTable/BuilderExpressionParams'
53
- import SqlEditor from 'views/genericTable/QueryEditor'
54
- import Switch from '@mui/material/Switch'
55
- import { EditorState } from 'draft-js'
56
- import PermissionsSubjects from 'src/configs/Permissions/PermissionsSubjects.json'
57
- import ReportBuilderSaveForm from 'views/genericTable/ReportBuilderSaveDialog'
58
- import { useRouter } from 'next/router'
59
- import CustomFilterDialog from 'views/customFilter/CustomFilterDialog'
60
-
61
- import RoutingSettingDialog from 'views/genericTable/RoutingSettingDialog'
62
- import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd'
63
- import FixedFilterDialog from 'views/genericTable/FixedFilterDialog'
64
- import fetchReportData from 'services/reportData/fetchReportData'
44
+ CloudUploadOutlined,
45
+ CheckCircleOutlined,
46
+ DeleteOutlined
47
+ } from "@mui/icons-material";
48
+ import dayjs from 'dayjs';
49
+ import {BackspaceOutline, Filter, PencilOutline} from "mdi-material-ui";
50
+ import SGrid from "views/genericTable/SGrid";
51
+ import {Controller, useForm} from "react-hook-form";
52
+ import ComputedTextEditor from "views/genericTable/RegexTextEditor";
53
+ import ExpressionEditor from "views/genericTable/RegexTextEditor";
54
+ import BuilderExpressionParams from "views/genericTable/BuilderExpressionParams";
55
+ import handleChange from "services/helper/handleChange";
56
+ import DynamicValueList from "views/genericTable/BuilderExpressionParams";
57
+ import SqlEditor from "views/genericTable/QueryEditor";
58
+ import Switch from "@mui/material/Switch";
59
+ import {EditorState} from "draft-js";
60
+ import PermissionsSubjects from "src/configs/Permissions/PermissionsSubjects.json";
61
+ import ReportBuilderSaveForm from "views/genericTable/ReportBuilderSaveDialog";
62
+ import {useRouter} from "next/router";
63
+ import CustomFilterDialog from "views/customFilter/CustomFilterDialog";
64
+ import FixedFilterDialog from "views/customFilter/FixedFilterDialog";
65
+ import RoutingSettingDialog from "views/genericTable/RoutingSettingDialog";
66
+ import FormattingSettingsDialog from "views/genericTable/FormattingSettingsDialog";
67
+ import ColumnConfiguratorDialog from "views/genericTable/ColumnConfiguratorDialog";
68
+ import ReportSettingsDialog from "views/genericTable/ReportSettingsDialog";
69
+ import {DragDropContext, Droppable, Draggable} from 'react-beautiful-dnd';
65
70
 
66
71
  const ReportBuilder = () => {
67
- const [models, setModels] = useState([])
68
- const [modelFields, setModelFields] = useState([])
69
- const [searchQuery, setSearchQuery] = useState('')
70
- const [selectedCollection, setSelectedCollection] = useState()
71
- const [editingHeaderPath, setEditingHeaderPath] = useState(null)
72
- const [isLoading, setIsLoading] = useState(false)
72
+ const [models, setModels] = useState([]);
73
+ const [modelFields, setModelFields] = useState([]);
74
+ const [searchQuery, setSearchQuery] = useState('');
75
+ const [selectedCollection, setSelectedCollection] = useState();
76
+ const [editingHeaderPath, setEditingHeaderPath] = useState(null);
77
+ const [isLoading, setIsLoading] = useState(false);
73
78
  const router = useRouter()
74
- const { id } = router.query
79
+ const {id} = router.query
75
80
  const [builderMetadata, setBuilderMetadata] = useState({
76
81
  id: 0,
77
82
  name: '',
78
83
  description: '',
79
- isNew: true
80
- })
84
+ isNew: true,
85
+ });
81
86
  const [builderModel, setBuilderModel] = useState({
82
87
  reportSource: null,
83
88
  selectedFields: [],
@@ -85,14 +90,17 @@ const ReportBuilder = () => {
85
90
  isRaw: false,
86
91
  filter: {
87
92
  Tfilter: [],
88
- LocalTfilter: []
93
+ LocalTfilter: [],
89
94
  },
90
95
  searchFilter: [],
91
96
  rawSql: '',
92
- routingSettings: []
93
- })
94
- const [breadcrumbs, setBreadcrumbs] = useState([])
95
- const [isPreview, setIsPreview] = useState(false)
97
+ routingSettings: [],
98
+ settings: {
99
+ rowUniqueId: []
100
+ }
101
+ });
102
+ const [breadcrumbs, setBreadcrumbs] = useState([]);
103
+ const [isPreview, setIsPreview] = useState(false);
96
104
  const [openDialogs, setOpenDialogs] = useState({
97
105
  expression: false,
98
106
  params: false,
@@ -100,12 +108,19 @@ const ReportBuilder = () => {
100
108
  filter: false,
101
109
  searchFilter: false,
102
110
  routing: false,
103
- fixedFilter: false
104
- })
105
- const [selectedRow, setSelectedRow] = useState(null)
111
+ fixedFilter: false,
112
+ formatting: false,
113
+ columnConfig: false,
114
+ settings: false
115
+ });
116
+ const [selectedRow, setSelectedRow] = useState(null);
117
+ const [columnConfigResult, setColumnConfigResult] = useState(null);
106
118
 
107
119
  // File input ref for uploading builder model JSON
108
- const fileInputRef = useRef(null)
120
+ const fileInputRef = useRef(null);
121
+
122
+ // UpdateRef for tracking field changes in the grid (array structure)
123
+ const updateRef = useRef([]);
109
124
 
110
125
  // Download current builderModel as JSON file
111
126
  const handleDownloadModel = () => {
@@ -113,121 +128,122 @@ const ReportBuilder = () => {
113
128
  const replacer = (key, value) => {
114
129
  // Convert Dayjs instances to Date so JSON.stringify uses ISO via toJSON
115
130
  if (value && typeof value === 'object') {
116
- if (dayjs.isDayjs(value)) return value.toDate()
117
- if (value instanceof Date) return value // keep as Date
131
+ if (dayjs.isDayjs(value)) return value.toDate();
132
+ if (value instanceof Date) return value; // keep as Date
118
133
  }
119
- return value
120
- }
121
- const json = JSON.stringify(builderModel, replacer, 2)
122
- const blob = new Blob([json], { type: 'application/json' })
123
- const url = URL.createObjectURL(blob)
124
- const a = document.createElement('a')
125
- const ts = new Date().toISOString().replace(/[:.]/g, '-')
126
- a.href = url
127
- a.download = `builderModel-${ts}.json`
128
- document.body.appendChild(a)
129
- a.click()
130
- document.body.removeChild(a)
131
- URL.revokeObjectURL(url)
134
+ return value;
135
+ };
136
+ const json = JSON.stringify(builderModel, replacer, 2);
137
+ const blob = new Blob([json], {type: 'application/json'});
138
+ const url = URL.createObjectURL(blob);
139
+ const a = document.createElement('a');
140
+ const ts = new Date().toISOString().replace(/[:.]/g, '-');
141
+ a.href = url;
142
+ a.download = `builderModel-${ts}.json`;
143
+ document.body.appendChild(a);
144
+ a.click();
145
+ document.body.removeChild(a);
146
+ URL.revokeObjectURL(url);
132
147
  } catch (err) {
133
- console.error('Failed to download builder model:', err)
148
+ console.error('Failed to download builder model:', err);
134
149
  }
135
- }
150
+ };
136
151
 
137
152
  // Trigger hidden file input
138
153
  const handleUploadClick = () => {
139
154
  try {
140
- fileInputRef.current?.click()
155
+ fileInputRef.current?.click();
141
156
  } catch (e) {
142
- console.error(e)
157
+ console.error(e);
143
158
  }
144
- }
159
+ };
145
160
 
146
161
  // Handle JSON file selection and load into builderModel
147
- const handleFileChange = e => {
148
- const file = e?.target?.files?.[0]
149
- if (!file) return
150
- const reader = new FileReader()
162
+ const handleFileChange = (e) => {
163
+ const file = e?.target?.files?.[0];
164
+ if (!file) return;
165
+ const reader = new FileReader();
151
166
  reader.onload = () => {
152
167
  try {
153
- const text = reader.result || ''
154
- const obj = JSON.parse(text)
168
+ const text = reader.result || '';
169
+ const obj = JSON.parse(text);
155
170
  // Basic validation: ensure it's an object
156
171
  if (obj && typeof obj === 'object') {
157
- setBuilderModel(obj)
172
+ setBuilderModel(obj);
158
173
  } else {
159
- console.error('Uploaded file is not a valid builder model object')
174
+ console.error('Uploaded file is not a valid builder model object');
160
175
  }
161
176
  } catch (err) {
162
- console.error('Failed to parse uploaded JSON:', err)
177
+ console.error('Failed to parse uploaded JSON:', err);
163
178
  } finally {
164
- if (e?.target) e.target.value = ''
179
+ if (e?.target) e.target.value = '';
165
180
  }
166
- }
167
- reader.readAsText(file)
168
- }
181
+ };
182
+ reader.readAsText(file);
183
+ };
169
184
 
170
- const { control, handleSubmit, reset } = useForm({
185
+ const {control, handleSubmit, reset} = useForm({
171
186
  defaultValues: {
172
187
  name: '',
173
188
  type: '',
174
- expression: ''
175
- }
176
- })
189
+ expression: '',
190
+ },
191
+ });
177
192
 
178
193
  const handleToggleDialogs = dialog => {
179
194
  handleChange(setOpenDialogs, dialog, !openDialogs[dialog])
180
195
  }
181
196
 
182
- const isInSearchFilter = fullPath => (builderModel.searchFilter ?? []).some(f => f.fullPath === fullPath)
197
+ const isInSearchFilter = (fullPath) =>
198
+ (builderModel.searchFilter ?? []).some(f => f.fullPath === fullPath);
183
199
 
184
- const toggleSearchFilterByFullPath = payload => {
200
+ const toggleSearchFilterByFullPath = (payload) => {
185
201
  setBuilderModel(prev => {
186
- const exists = (prev.searchFilter ?? []).some(f => f.fullPath === payload.fullPath)
202
+ const exists = (prev.searchFilter ?? []).some(f => f.fullPath === payload.fullPath);
187
203
  const updated = exists
188
204
  ? prev.searchFilter.filter(f => f.fullPath !== payload.fullPath)
189
- : [...(prev.searchFilter ?? []), payload]
205
+ : [...(prev.searchFilter ?? []), payload];
190
206
 
191
207
  return {
192
208
  ...prev,
193
209
  searchFilter: updated
194
- }
195
- })
196
- }
210
+ };
211
+ });
212
+ };
197
213
 
198
214
  const handleGetModels = async () => {
199
215
  try {
200
- setIsLoading(true)
201
- const response = await Services.PostService(Endpoints.ReportBuilder.Post.GetModels, false, {})
216
+ setIsLoading(true);
217
+ const response = await Services.PostService(Endpoints.ReportBuilder.Post.GetModels, false, {});
202
218
  if (response) {
203
- setModels(response)
219
+ setModels(response);
204
220
  }
205
221
  } catch (error) {
206
- console.error(error)
222
+ console.error(error);
207
223
  } finally {
208
- setIsLoading(false)
224
+ setIsLoading(false);
209
225
  }
210
- }
226
+ };
211
227
 
212
228
  const handleGetFields = async (modelFullName, friendlyName = null, propertyType, isPrevious) => {
213
229
  try {
214
- setIsLoading(true)
230
+ setIsLoading(true);
215
231
  const response = await Services.PostService(
216
232
  Endpoints.ReportBuilder.Post.GetModelFields,
217
233
  false,
218
234
  {},
219
- { modelFullName }
220
- )
235
+ {modelFullName}
236
+ );
221
237
  if (response) {
222
- setModelFields(response.data)
223
- const modelObject = models.find(m => m.fullName === modelFullName)
238
+ setModelFields(response.data);
239
+ const modelObject = models.find(m => m.fullName === modelFullName);
224
240
 
225
- console.log(modelObject)
241
+ console.log(modelObject);
226
242
  setBreadcrumbs(prev => {
227
- const exists = prev.find(b => b.fullName === modelFullName)
243
+ const exists = prev.find(b => b.fullName === modelFullName);
228
244
  if (exists && isPrevious) {
229
- const index = prev.findIndex(b => b.fullName === modelFullName)
230
- return prev.slice(0, index + 1)
245
+ const index = prev.findIndex(b => b.fullName === modelFullName);
246
+ return prev.slice(0, index + 1);
231
247
  }
232
248
  console.log(prev)
233
249
  return [
@@ -235,69 +251,73 @@ const ReportBuilder = () => {
235
251
  {
236
252
  fullName: modelFullName,
237
253
  friendlyName: friendlyName ?? modelObject?.friendlyName ?? modelFullName,
238
- propertyType: propertyType ?? modelObject?.propertyType ?? null
239
- }
240
- ]
241
- })
254
+ propertyType: propertyType ?? modelObject?.propertyType ?? null,
255
+ },
256
+ ];
257
+ });
242
258
  }
243
259
  } catch (error) {
244
- console.error(error)
260
+ console.error(error);
245
261
  } finally {
246
- setIsLoading(false)
262
+ setIsLoading(false);
247
263
  }
248
- }
264
+ };
249
265
 
250
266
  // 1) Trim a full field‐path for *leaf* fields:
251
- // • always drop the root segment
252
- // • if there are any collections, drop everything up through the *last* collection
267
+ // • always drop the root segment
268
+ // • if there are any collections, drop everything up through the *last* collection
253
269
  const getLeafTrimmedPath = (fullPath, collectionBreadcrumbs) => {
254
- const parts = fullPath.split('.')
255
- const afterRoot = parts.slice(1)
270
+ const parts = fullPath.split('.');
271
+ const afterRoot = parts.slice(1);
256
272
  if (!collectionBreadcrumbs.length) {
257
- return afterRoot.join('.')
273
+ return afterRoot.join('.');
258
274
  }
259
- const lastColl = collectionBreadcrumbs[collectionBreadcrumbs.length - 1].friendlyName
260
- const idx = afterRoot.lastIndexOf(lastColl)
261
- return idx >= 0 ? afterRoot.slice(idx + 1).join('.') : afterRoot.join('.')
262
- }
263
-
264
- // 2) Trim a *collection* node’s path:
265
- // • drop the root segment
266
- // then drop *exactly* the first collection (if present), keep everything else
275
+ const lastColl = collectionBreadcrumbs[collectionBreadcrumbs.length - 1].friendlyName;
276
+ const idx = afterRoot.lastIndexOf(lastColl);
277
+ return idx >= 0
278
+ ? afterRoot.slice(idx + 1).join('.')
279
+ : afterRoot.join('.');
280
+ };
281
+
282
+ // 2) Trim a *collection* node’s path:
283
+ // • drop the root segment
284
+ // • then drop *exactly* the first collection (if present), keep everything else
267
285
  const getCollectionTrimmedPath = (fullCollectionPath, collectionBreadcrumbs) => {
268
- const parts = fullCollectionPath.split('.')
269
- const afterRoot = parts.slice(1)
286
+ const parts = fullCollectionPath.split('.');
287
+ const afterRoot = parts.slice(1);
270
288
  if (!collectionBreadcrumbs.length) {
271
- return afterRoot.join('.')
289
+ return afterRoot.join('.');
272
290
  }
273
- const firstColl = collectionBreadcrumbs[0].friendlyName
291
+ const firstColl = collectionBreadcrumbs[0].friendlyName;
274
292
  // if the very first segment after root is our first collection, drop it
275
293
  if (afterRoot[0] === firstColl) {
276
- const rest = afterRoot.slice(1)
294
+ const rest = afterRoot.slice(1);
277
295
  // if that was the only segment, fall back to the collection name
278
- return rest.length ? rest.join('.') : firstColl
296
+ return rest.length ? rest.join('.') : firstColl;
279
297
  }
280
- return afterRoot.join('.')
281
- }
298
+ return afterRoot.join('.');
299
+ };
282
300
 
283
- const handleAddStaticField = field => {
301
+ const handleAddStaticField = (field) => {
284
302
  console.log(builderModel.selectedFields)
285
303
  // build fullPath & identify collection crumbs
286
- const fullPathParts = [...breadcrumbs.map(b => b.friendlyName), field.friendlyName]
287
- const fullPath = fullPathParts.join('.')
304
+ const fullPathParts = [
305
+ ...breadcrumbs.map(b => b.friendlyName),
306
+ field.friendlyName
307
+ ];
308
+ const fullPath = fullPathParts.join('.');
288
309
  const collectionBreadcrumbs = breadcrumbs
289
310
  .map((b, i) => ({
290
311
  ...b,
291
- fullPath: breadcrumbs
292
- .slice(0, i + 1)
312
+ fullPath: breadcrumbs.slice(0, i + 1)
293
313
  .map(x => x.friendlyName)
294
314
  .join('.')
295
315
  }))
296
- .filter(b => b.propertyType === 'Collection')
316
+ .filter(b => b.propertyType === 'Collection');
297
317
 
298
318
  // compute leaf path & header
299
- const trimmedPath = getLeafTrimmedPath(fullPath, collectionBreadcrumbs)
300
- const headerName = trimmedPath.replace(/\./g, '_')
319
+ const trimmedPath = getLeafTrimmedPath(fullPath, collectionBreadcrumbs);
320
+ const headerName = trimmedPath.replace(/\./g, '_');
301
321
  console.log(field)
302
322
  const newLeafField = {
303
323
  fullPath: fullPath,
@@ -309,19 +329,21 @@ const ReportBuilder = () => {
309
329
  propertyType: field.propertyType,
310
330
  enumName: field.enumName,
311
331
  hidden: false,
312
- image: false
313
- }
332
+ image: false,
333
+ };
314
334
 
315
335
  setBuilderModel(prev => {
316
- const clone = [...prev.selectedFields]
336
+ const clone = [...prev.selectedFields];
317
337
 
318
338
  const insertIntoCollectionsOnly = (nodes, crumbs, depth = 0) => {
319
- const crumb = crumbs[depth]
320
- const collFull = crumb.fullPath
321
- const collTrimmed = getCollectionTrimmedPath(collFull, crumbs)
322
- const collHeader = collTrimmed.replace(/\./g, '_')
323
-
324
- let node = nodes.find(n => n.propertyType === 'Collection' && n.path === collTrimmed)
339
+ const crumb = crumbs[depth];
340
+ const collFull = crumb.fullPath;
341
+ const collTrimmed = getCollectionTrimmedPath(collFull, crumbs);
342
+ const collHeader = collTrimmed.replace(/\./g, '_');
343
+
344
+ let node = nodes.find(n =>
345
+ n.propertyType === 'Collection' && n.path === collTrimmed
346
+ );
325
347
  if (!node) {
326
348
  node = {
327
349
  fullPath: fullPath,
@@ -329,33 +351,34 @@ const ReportBuilder = () => {
329
351
  headerName: collHeader,
330
352
  propertyType: 'Collection',
331
353
  children: []
332
- }
333
- nodes.push(node)
354
+ };
355
+ nodes.push(node);
334
356
  }
335
357
 
336
- const isLast = depth === crumbs.length - 1
358
+ const isLast = depth === crumbs.length - 1;
337
359
  if (isLast) {
338
360
  if (!node.children.some(f => f.path === trimmedPath)) {
339
- node.children.push(newLeafField)
361
+ node.children.push(newLeafField);
340
362
  }
341
363
  } else {
342
- insertIntoCollectionsOnly(node.children, crumbs, depth + 1)
364
+ insertIntoCollectionsOnly(node.children, crumbs, depth + 1);
343
365
  }
344
- }
366
+ };
345
367
 
346
368
  if (!collectionBreadcrumbs.length) {
347
369
  // no collections ⇒ flat insert
348
370
  if (!clone.some(f => f.path === trimmedPath)) {
349
- return { ...prev, selectedFields: [...clone, newLeafField] }
371
+ return {...prev, selectedFields: [...clone, newLeafField]};
350
372
  }
351
- return prev
373
+ return prev;
352
374
  }
353
375
 
354
376
  // otherwise build the nested collection node(s)
355
- insertIntoCollectionsOnly(clone, collectionBreadcrumbs)
356
- return { ...prev, selectedFields: clone }
357
- })
358
- }
377
+ insertIntoCollectionsOnly(clone, collectionBreadcrumbs);
378
+ return {...prev, selectedFields: clone};
379
+ });
380
+ };
381
+
359
382
 
360
383
  // (1) Helper: insert a node into the right collection, by `collectionPath`
361
384
  function insertIntoCollection(nodes, collectionPath, newField) {
@@ -366,19 +389,19 @@ const ReportBuilder = () => {
366
389
  return {
367
390
  ...node,
368
391
  children: [...(node.children || []), newField]
369
- }
392
+ };
370
393
  }
371
394
  // otherwise recurse
372
395
  return {
373
396
  ...node,
374
397
  children: insertIntoCollection(node.children || [], collectionPath, newField)
375
- }
398
+ };
376
399
  }
377
- return node
378
- })
400
+ return node;
401
+ });
379
402
  }
380
403
 
381
- // (2) Add computed field — either top‐level or inside the selectedCollection
404
+ // (2) Add computed field — either top‐level or inside the selectedCollection
382
405
  const handleAddComputedField = (expression, headerName, propertyType, title) => {
383
406
  const newField = {
384
407
  path: headerName,
@@ -388,221 +411,230 @@ const ReportBuilder = () => {
388
411
  expression,
389
412
  title,
390
413
  hidden: false,
391
- image: false
392
- }
414
+ image: false,
415
+ };
393
416
 
394
417
  setBuilderModel(prev => {
395
- const { selectedFields } = prev
418
+ const {selectedFields} = prev;
396
419
  // if no collection selected, append at root
397
420
  if (!selectedCollection) {
398
421
  return {
399
422
  ...prev,
400
423
  selectedFields: [...selectedFields, newField]
401
- }
424
+ };
402
425
  }
403
426
  // otherwise insert under the chosen collection
404
- const updated = insertIntoCollection(selectedFields, selectedCollection.path, newField)
405
- return { ...prev, selectedFields: updated }
406
- })
407
- setSelectedCollection(null)
408
- }
409
-
410
- // (3) Update computed field — likewise drill into the right spot
411
- const handleUpdateComputedField = (oldHeaderName, expression, headerName, propertyType, title) => {
427
+ const updated = insertIntoCollection(
428
+ selectedFields,
429
+ selectedCollection.path,
430
+ newField
431
+ );
432
+ return {...prev, selectedFields: updated};
433
+ });
434
+ setSelectedCollection(null);
435
+
436
+ };
437
+
438
+ // (3) Update computed field — likewise drill into the right spot
439
+ const handleUpdateComputedField = (
440
+ oldHeaderName,
441
+ expression,
442
+ headerName,
443
+ propertyType,
444
+ title
445
+ ) => {
412
446
  setBuilderModel(prev => {
413
447
  const updateNode = node => {
414
448
  if (node.type === 'computed' && node.headerName === oldHeaderName) {
415
- return { ...node, headerName, expression, propertyType, title, path: headerName }
449
+ return {...node, headerName, expression, propertyType, title, path: headerName};
416
450
  }
417
451
  if (node.propertyType === 'Collection') {
418
452
  return {
419
453
  ...node,
420
454
  children: (node.children || []).map(updateNode)
421
- }
455
+ };
422
456
  }
423
- return node
424
- }
457
+ return node;
458
+ };
425
459
 
426
460
  return {
427
461
  ...prev,
428
462
  selectedFields: prev.selectedFields.map(updateNode)
429
- }
430
- })
431
- setSelectedCollection(null)
432
- }
463
+ };
464
+ });
465
+ setSelectedCollection(null);
466
+
467
+ };
468
+
433
469
 
434
470
  function removeFieldByPath(fields, pathToRemove) {
435
471
  return fields.reduce((acc, f) => {
436
472
  if (f.propertyType === 'Collection') {
437
473
  // first, recurse into its children
438
- const filteredChildren = removeFieldByPath(f.children || [], pathToRemove)
474
+ const filteredChildren = removeFieldByPath(f.children || [], pathToRemove);
439
475
  // only keep this collection if it still has children
440
476
  if (filteredChildren.length > 0) {
441
- acc.push({ ...f, children: filteredChildren })
477
+ acc.push({...f, children: filteredChildren});
442
478
  }
443
479
  } else {
444
480
  // leaf field: only keep it if paths don't match
445
481
  if (f.path !== pathToRemove) {
446
- acc.push(f)
482
+ acc.push(f);
447
483
  }
448
484
  }
449
- return acc
450
- }, [])
485
+ return acc;
486
+ }, []);
451
487
  }
452
488
 
453
489
  function handleFilterChange(field, value) {
454
- console.log(field, value)
490
+ console.log(field, value);
455
491
  setBuilderModel(prev => ({
456
492
  ...prev,
457
493
  filter: {
458
494
  ...prev.filter,
459
- [field]: value // <-- computed key on the nested object
460
- }
461
- }))
495
+ [field]: value, // <-- computed key on the nested object
496
+ },
497
+ }));
462
498
  }
463
499
 
464
- const handleDragEnd = result => {
465
- const { source, destination } = result || {}
466
- if (!destination) return
467
- if (source.droppableId !== destination.droppableId) return
468
- const droppableId = source.droppableId
500
+
501
+ const handleDragEnd = (result) => {
502
+ const {source, destination} = result || {};
503
+ if (!destination) return;
504
+ if (source.droppableId !== destination.droppableId) return;
505
+ const droppableId = source.droppableId;
469
506
 
470
507
  setBuilderModel(prev => {
471
508
  const reorderLeaves = (arr, from, to) => {
472
- const leaves = arr.filter(n => !n.children)
473
- const collections = arr.filter(n => n.children)
474
- if (from < 0 || to < 0 || from >= leaves.length || to >= leaves.length) return arr
475
- const leafMap = Object.fromEntries(leaves.map(n => [n.path, n]))
476
- const order = leaves.map(n => n.path)
477
- const [moved] = order.splice(from, 1)
478
- order.splice(to, 0, moved)
479
- const orderQueue = order.slice()
509
+ const leaves = arr.filter(n => !n.children);
510
+ const collections = arr.filter(n => n.children);
511
+ if (from < 0 || to < 0 || from >= leaves.length || to >= leaves.length) return arr;
512
+ const leafMap = Object.fromEntries(leaves.map(n => [n.path, n]));
513
+ const order = leaves.map(n => n.path);
514
+ const [moved] = order.splice(from, 1);
515
+ order.splice(to, 0, moved);
516
+ const orderQueue = order.slice();
480
517
  // rebuild original array: keep collections in place, leaves in new order
481
518
  return arr.map(node => {
482
- if (node.children) return node
483
- const nextPath = orderQueue.shift()
484
- return leafMap[nextPath] || node
485
- })
486
- }
487
-
488
- const updateCollections = nodes =>
489
- nodes.map(n => {
490
- if (n.propertyType === 'Collection') {
491
- if (n.path === droppableId) {
492
- const newChildren = reorderLeaves(n.children || [], source.index, destination.index)
493
- return { ...n, children: newChildren }
494
- }
495
- return { ...n, children: updateCollections(n.children || []) }
519
+ if (node.children) return node;
520
+ const nextPath = orderQueue.shift();
521
+ return leafMap[nextPath] || node;
522
+ });
523
+ };
524
+
525
+ const updateCollections = (nodes) => nodes.map(n => {
526
+ if (n.propertyType === 'Collection') {
527
+ if (n.path === droppableId) {
528
+ const newChildren = reorderLeaves(n.children || [], source.index, destination.index);
529
+ return {...n, children: newChildren};
496
530
  }
497
- return n
498
- })
531
+ return {...n, children: updateCollections(n.children || [])};
532
+ }
533
+ return n;
534
+ });
499
535
 
500
536
  if (droppableId === 'root') {
501
- return { ...prev, selectedFields: reorderLeaves(prev.selectedFields, source.index, destination.index) }
537
+ return {...prev, selectedFields: reorderLeaves(prev.selectedFields, source.index, destination.index)};
502
538
  } else {
503
- return { ...prev, selectedFields: updateCollections(prev.selectedFields) }
539
+ return {...prev, selectedFields: updateCollections(prev.selectedFields)};
504
540
  }
505
- })
506
- }
541
+ });
542
+ };
507
543
 
508
544
  const renderSelectedFields = (nodes, level = 0, droppableId = 'root') => {
509
545
  // Count leaf-only index for Draggable indices
510
- let leafIndexCounter = 0
546
+ let leafIndexCounter = 0;
511
547
  return (
512
548
  <Droppable droppableId={droppableId}>
513
- {provided => (
514
- <List dense disablePadding sx={{ pl: level * 2 }} ref={provided.innerRef} {...provided.droppableProps}>
515
- {nodes.map(item =>
549
+ {(provided) => (
550
+ <List dense disablePadding sx={{pl: level * 2}} ref={provided.innerRef} {...provided.droppableProps}>
551
+ {nodes.map((item) => (
516
552
  item.children ? (
517
- <Accordion key={item.headerName} disableGutters sx={{ mb: 1 }}>
518
- <AccordionSummary expandIcon={<Expand />}>
553
+ <Accordion key={item.headerName} disableGutters sx={{mb: 1}}>
554
+ <AccordionSummary expandIcon={<Expand/>}>
519
555
  <Box
520
556
  sx={{
521
557
  display: 'flex',
522
558
  alignItems: 'center',
523
559
  justifyContent: 'space-between',
524
- width: '100%'
560
+ width: '100%',
525
561
  }}
526
562
  >
527
- <Typography variant='subtitle2' fontWeight='bold'>
563
+ <Typography variant="subtitle2" fontWeight="bold">
528
564
  {item.headerName ?? item.path}
529
565
  </Typography>
530
566
  <IconButton
531
- size='small'
532
- onClick={e => {
533
- e.stopPropagation()
534
- setSelectedCollection(item)
535
- setSelectedRow(null)
536
- setOpenDialogs(prev => ({ ...prev, expression: true }))
567
+ size="small"
568
+ onClick={(e) => {
569
+ e.stopPropagation();
570
+ setSelectedCollection(item);
571
+ setSelectedRow(null);
572
+ setOpenDialogs(prev => ({...prev, expression: true}));
537
573
  }}
538
- title='Add computed field to this collection'
574
+ title="Add computed field to this collection"
539
575
  >
540
- <AddBox fontSize='small' />
576
+ <AddBox fontSize="small"/>
541
577
  </IconButton>
542
578
  </Box>
543
579
  </AccordionSummary>
544
- <AccordionDetails>{renderSelectedFields(item.children, level + 1, item.path)}</AccordionDetails>
580
+ <AccordionDetails>
581
+ {renderSelectedFields(item.children, level + 1, item.path)}
582
+ </AccordionDetails>
545
583
  </Accordion>
546
584
  ) : (
547
- <Draggable
548
- key={`${droppableId}::${item.path}`}
549
- draggableId={`${droppableId}::${item.path}`}
550
- index={leafIndexCounter++}
551
- >
552
- {providedDrag => (
585
+ <Draggable key={`${droppableId}::${item.path}`} draggableId={`${droppableId}::${item.path}`}
586
+ index={leafIndexCounter++}>
587
+ {(providedDrag) => (
553
588
  <ListItem
554
- ref={providedDrag.innerRef}
555
- {...providedDrag.draggableProps}
556
- {...providedDrag.dragHandleProps}
557
- divider
558
- >
589
+ ref={providedDrag.innerRef} {...providedDrag.draggableProps} {...providedDrag.dragHandleProps}
590
+ divider>
559
591
  <ListItemText
560
592
  primary={
561
593
  editingHeaderPath === item.path ? (
562
594
  <TextField
563
- size='small'
595
+ size="small"
564
596
  autoFocus
565
- variant='standard'
597
+ variant="standard"
566
598
  value={item.title}
567
- onChange={e => {
568
- const newHeaderName = e.target.value
599
+ onChange={(e) => {
600
+ const newHeaderName = e.target.value;
569
601
 
570
602
  setBuilderModel(prev => {
571
- const updateNode = node => {
603
+ const updateNode = (node) => {
572
604
  if (node.path === item.path && !node.children) {
573
- return { ...node, title: newHeaderName }
605
+ return {...node, title: newHeaderName};
574
606
  }
575
607
  if (node.propertyType === 'Collection') {
576
- return { ...node, children: (node.children || []).map(updateNode) }
608
+ return {...node, children: (node.children || []).map(updateNode)};
577
609
  }
578
- return node
579
- }
610
+ return node;
611
+ };
580
612
 
581
613
  return {
582
614
  ...prev,
583
615
  selectedFields: prev.selectedFields.map(updateNode)
584
- }
585
- })
616
+ };
617
+ });
586
618
  }}
587
619
  onBlur={() => setEditingHeaderPath(null)}
588
- onKeyDown={e => {
620
+ onKeyDown={(e) => {
589
621
  if (e.key === 'Enter' || e.key === 'Escape') {
590
- setEditingHeaderPath(null)
622
+ setEditingHeaderPath(null);
591
623
  }
592
624
  }}
593
625
  inputProps={{
594
626
  style: {
595
627
  fontWeight: 'bold',
596
- fontSize: '0.875rem'
628
+ fontSize: '0.875rem',
597
629
  }
598
630
  }}
599
631
  />
600
632
  ) : (
601
633
  <Typography
602
- variant='subtitle2'
603
- fontWeight='bold'
634
+ variant="subtitle2"
635
+ fontWeight="bold"
604
636
  onDoubleClick={() => setEditingHeaderPath(item.path)}
605
- sx={{ cursor: 'pointer' }}
637
+ sx={{cursor: 'pointer'}}
606
638
  >
607
639
  {item.title ?? item.headerName}
608
640
  </Typography>
@@ -610,153 +642,175 @@ const ReportBuilder = () => {
610
642
  }
611
643
  secondary={item.path}
612
644
  />
613
- <Box sx={{ display: 'flex', gap: 1 }}>
645
+ <Box sx={{display: 'flex', gap: 1}}>
614
646
  {item.type === 'computed' && (
615
647
  <IconButton
616
- size='small'
648
+ size="small"
617
649
  onClick={() => {
618
- setSelectedRow(item)
619
- setOpenDialogs(prev => ({ ...prev, expression: true }))
650
+ setSelectedRow(item);
651
+ setOpenDialogs(prev => ({...prev, expression: true}));
620
652
  }}
621
- title='Edit computed field'
653
+ title="Edit computed field"
622
654
  >
623
- <PencilOutline fontSize='small' />
655
+ <PencilOutline fontSize="small"/>
624
656
  </IconButton>
625
657
  )}
626
658
 
627
- {(item?.field?.propertyType === 'String' ||
628
- item?.field?.propertyType === 'Int' ||
629
- item?.field?.propertyType === 'Guid') &&
630
- item?.type === 'static' && (
631
- <IconButton
632
- size='small'
633
- onClick={() => {
634
- console.log(item, level)
635
- toggleSearchFilterByFullPath({
636
- fullPath: item.fullPath,
637
- path: item.path || item.headerName || item.fullPath,
638
- propertyType: item.propertyType,
639
- isWithinCollection: level !== 0
640
- })
641
- }}
642
- title={
643
- isInSearchFilter(item.fullPath) ? 'Remove from search filter' : 'Add to search filter'
644
- }
645
- sx={{
646
- color: isInSearchFilter(item.fullPath) ? 'primary.main' : 'text.secondary',
647
- '&:hover': {
648
- backgroundColor: 'transparent',
649
- color: isInSearchFilter(item.fullPath) ? 'primary.main' : 'info.main'
650
- }
651
- }}
652
- >
653
- <Search fontSize='small' />
654
- </IconButton>
655
- )}
659
+ {((item?.field?.propertyType === 'String' || item?.field?.propertyType === 'Int' || item?.field?.propertyType === 'Guid') && item?.type === 'static') && (
660
+ <IconButton
661
+ size="small"
662
+ onClick={() => {
663
+ console.log(item, level)
664
+ toggleSearchFilterByFullPath({
665
+ fullPath: item.fullPath,
666
+ path: item.path || item.headerName || item.fullPath,
667
+ propertyType: item.propertyType,
668
+ isWithinCollection: level !== 0
669
+ });
670
+ }}
671
+ title={
672
+ isInSearchFilter(item.fullPath)
673
+ ? 'Remove from search filter'
674
+ : 'Add to search filter'
675
+ }
676
+ sx={{
677
+ color: isInSearchFilter(item.fullPath) ? 'primary.main' : 'text.secondary',
678
+ '&:hover': {
679
+ backgroundColor: 'transparent',
680
+ color: isInSearchFilter(item.fullPath) ? 'primary.main' : 'info.main',
681
+ },
682
+ }}
683
+ >
684
+ <Search fontSize="small"/>
685
+ </IconButton>
686
+ )}
656
687
  <IconButton
657
- size='small'
688
+ size="small"
658
689
  onClick={() => {
659
690
  setBuilderModel(prev => {
660
- const toggleHidden = node => {
691
+ const toggleHidden = (node) => {
661
692
  if (node.propertyType === 'Collection') {
662
693
  return {
663
694
  ...node,
664
695
  children: (node.children || []).map(toggleHidden)
665
- }
696
+ };
666
697
  }
667
698
  if (node.path === item.path) {
668
- return { ...node, hidden: !node.hidden }
699
+ return {...node, hidden: !node.hidden};
669
700
  }
670
- return node
671
- }
701
+ return node;
702
+ };
672
703
  return {
673
704
  ...prev,
674
705
  selectedFields: prev.selectedFields.map(toggleHidden)
675
- }
676
- })
706
+ };
707
+ });
677
708
  }}
678
- title={item.hidden ? 'Show column' : 'Hide column'}
709
+ title={item.hidden ? "Show column" : "Hide column"}
679
710
  sx={{
680
711
  color: item.hidden ? 'warning.main' : 'text.secondary',
681
712
  '&:hover': {
682
713
  backgroundColor: 'transparent',
683
- color: item.hidden ? 'warning.main' : 'info.main'
684
- }
714
+ color: item.hidden ? 'warning.main' : 'info.main',
715
+ },
685
716
  }}
686
717
  >
687
- {item.hidden ? <VisibilityOff fontSize='small' /> : <Visibility fontSize='small' />}
718
+ {item.hidden ? <VisibilityOff fontSize="small"/> : <Visibility fontSize="small"/>}
688
719
  </IconButton>
689
720
  <IconButton
690
- size='small'
721
+ size="small"
691
722
  onClick={() => {
692
723
  setBuilderModel(prev => {
693
- const toggleImage = node => {
724
+ const toggleImage = (node) => {
694
725
  if (node.propertyType === 'Collection') {
695
- return { ...node, children: (node.children || []).map(toggleImage) }
726
+ return {...node, children: (node.children || []).map(toggleImage)};
696
727
  }
697
728
  if (node.path === item.path) {
698
- return { ...node, image: !node.image }
729
+ return {...node, image: !node.image};
699
730
  }
700
- return node
701
- }
731
+ return node;
732
+ };
702
733
  return {
703
734
  ...prev,
704
735
  selectedFields: prev.selectedFields.map(toggleImage)
705
- }
706
- })
736
+ };
737
+ });
707
738
  }}
708
- title={item.image ? 'Unset image' : 'Render as image'}
739
+ title={item.image ? "Unset image" : "Render as image"}
709
740
  sx={{
710
741
  color: item.image ? 'success.main' : 'text.secondary',
711
742
  '&:hover': {
712
743
  backgroundColor: 'transparent',
713
- color: item.image ? 'success.main' : 'info.main'
714
- }
744
+ color: item.image ? 'success.main' : 'info.main',
745
+ },
746
+ }}
747
+ >
748
+ <ImageIcon fontSize="small"/>
749
+ </IconButton>
750
+ <IconButton
751
+ size="small"
752
+ onClick={() => {
753
+ setSelectedRow(item);
754
+ setOpenDialogs(prev => ({...prev, formatting: true}));
755
+ }}
756
+ title="Formatting Settings"
757
+ sx={{
758
+ color: item.formatting ? 'primary.main' : 'text.secondary',
759
+ '&:hover': {
760
+ backgroundColor: 'transparent',
761
+ color: item.formatting ? 'primary.main' : 'info.main',
762
+ },
715
763
  }}
716
764
  >
717
- <ImageIcon fontSize='small' />
765
+ <FilterVintageOutlined fontSize="small"/>
718
766
  </IconButton>
719
767
  <IconButton
720
- size='small'
768
+ size="small"
721
769
  onClick={() =>
722
770
  setBuilderModel(prev => ({
723
771
  ...prev,
724
772
  selectedFields: removeFieldByPath(prev.selectedFields, item.path)
725
773
  }))
726
774
  }
727
- title='Remove field'
775
+ title="Remove field"
728
776
  >
729
- <DeleteOutline fontSize='small' />
777
+ <DeleteOutlined fontSize="small"/>
730
778
  </IconButton>
731
779
  </Box>
732
780
  </ListItem>
733
781
  )}
734
782
  </Draggable>
735
783
  )
736
- )}
784
+ ))}
737
785
  {provided.placeholder}
738
786
  </List>
739
787
  )}
740
788
  </Droppable>
741
- )
742
- }
789
+ );
790
+ };
743
791
 
744
792
  const isFullPathSelected = (nodes, targetFullPath) => {
745
793
  for (const node of nodes) {
746
- if (node.fullPath === targetFullPath) return true
794
+ if (node.fullPath === targetFullPath) return true;
747
795
  if (node.children && isFullPathSelected(node.children, targetFullPath)) {
748
- return true
796
+ return true;
749
797
  }
750
798
  }
751
- return false
752
- }
799
+ return false;
800
+ };
753
801
 
754
- const handleGetReport = async id => {
802
+
803
+ const handleGetReport = async (id) => {
755
804
  try {
756
- setIsLoading(true)
757
- const response = await Services.PostService(Endpoints.ReportBuilder.Post.GetReportDetails, false, {}, { id: id })
805
+ setIsLoading(true);
806
+ const response = await Services.PostService(
807
+ Endpoints.ReportBuilder.Post.GetReportDetails,
808
+ false,
809
+ {},
810
+ {id: id}
811
+ )
758
812
  if (response) {
759
- setBuilderModel(JSON.parse(response.data.value))
813
+ setBuilderModel(JSON.parse(response.data.value));
760
814
  setBuilderMetadata({
761
815
  id: response.data.id,
762
816
  name: response.data.name,
@@ -769,22 +823,24 @@ const ReportBuilder = () => {
769
823
  } catch (error) {
770
824
  console.error(error)
771
825
  } finally {
772
- setIsLoading(false)
826
+ setIsLoading(false);
773
827
  }
774
828
  }
775
829
 
776
830
 
777
831
  useEffect(() => {
778
- handleGetModels()
779
- }, [])
832
+ handleGetModels();
833
+ }, []);
780
834
  useEffect(() => {
781
835
  if (id != null) {
782
- handleGetReport(id)
836
+
837
+ handleGetReport(id);
783
838
  }
784
- }, [id])
839
+ }, [id]);
840
+
785
841
 
786
842
  return (
787
- <div dir='ltr' style={{ direction: 'ltr', textAlign: 'left', width: '100%', height: '100%' }}>
843
+ <div dir="ltr" style={{direction: 'ltr', textAlign: 'left', width: '100%', height: '100%'}}>
788
844
  <style>
789
845
  {`
790
846
  .MuiListItemText-primary,
@@ -796,8 +852,8 @@ const ReportBuilder = () => {
796
852
  `}
797
853
  </style>
798
854
 
799
- <CssBaseline />
800
- <Box sx={{ display: 'flex', height: '100vh', overflow: 'hidden' }}>
855
+ <CssBaseline/>
856
+ <Box sx={{display: 'flex', height: '100vh', overflow: 'hidden'}}>
801
857
  <Paper
802
858
  elevation={3}
803
859
  sx={{
@@ -807,84 +863,86 @@ const ReportBuilder = () => {
807
863
  borderRight: '1px solid #eee',
808
864
  borderRadius: '0px',
809
865
  p: 2,
810
- bgcolor: 'white'
866
+ bgcolor: 'white',
811
867
  }}
812
868
  >
813
- <Box display='flex' alignItems='center' gap={1} justifyContent='space-between'>
814
- <Box display='flex' alignItems='center' gap={1}>
815
- <Typography variant='h6'>Report Configuration</Typography>
816
- <Chip variant={'filled'} label='Beta' color='warning' size='small' />
869
+ <Box display="flex" alignItems="center" gap={1} justifyContent="space-between">
870
+ <Box display="flex" alignItems="center" gap={1}>
871
+ <Typography variant="h6">
872
+ Report Configuration
873
+ </Typography>
874
+ <Chip variant={'filled'} label="Beta" color="warning" size="small"/>
817
875
  </Box>
818
876
  <Box>
819
- <IconButton
820
- onClick={() => {
821
- setBuilderMetadata(preValue => ({
822
- ...preValue,
823
- isNew: id == null
824
- }))
825
- handleToggleDialogs('save')
826
- }}
827
- >
828
- <SaveAsOutlined color={'primary'} />
877
+ <IconButton onClick={() => {
878
+ setBuilderMetadata(preValue => ({
879
+ ...preValue,
880
+ isNew: (id == null),
881
+ }))
882
+ handleToggleDialogs('save')
883
+ }}>
884
+ <SaveAsOutlined color={'primary'}/>
829
885
  </IconButton>
830
- {builderMetadata.id !== 0 && (
831
- <IconButton
832
- onClick={() => {
833
- setBuilderMetadata(preValue => ({
834
- ...preValue,
835
- isNew: false
836
- }))
837
- handleToggleDialogs('save')
838
- }}
839
- >
840
- <SaveOutlined color={'primary'} />
841
- </IconButton>
842
- )}
843
-
844
- <IconButton
845
- onClick={() => {
846
- router.push('/reportModule/reportBuilder/reports')
847
- }}
848
- >
849
- <AssessmentOutlined color={'primary'} />
886
+ {builderMetadata.id !== 0 && <IconButton onClick={() => {
887
+ setBuilderMetadata(preValue => ({
888
+ ...preValue,
889
+ isNew: false,
890
+ }))
891
+ handleToggleDialogs('save')
892
+ }}><SaveOutlined color={'primary'}/></IconButton>}
893
+
894
+ <IconButton onClick={() => {
895
+ router.push('/builders/report/list')
896
+ }}>
897
+ <AssessmentOutlined color={'primary'}/>
850
898
  </IconButton>
851
899
  </Box>
900
+
852
901
  </Box>
853
902
  <Autocomplete
854
- size='small'
903
+ size="small"
855
904
  value={builderModel.reportSource}
856
905
  options={models}
857
906
  getOptionLabel={option => option.tableName || ''}
858
907
  onChange={(e, value) => {
859
908
  if (value) {
860
- setBuilderModel(preValue => ({ ...preValue, reportSource: value }))
861
- setBreadcrumbs([])
862
- handleGetFields(value.fullName, value.friendlyName, value.propertyType)
909
+ setBuilderModel(preValue => ({...preValue, reportSource: value}))
910
+ setBreadcrumbs([]);
911
+ handleGetFields(value.fullName, value.friendlyName, value.propertyType);
863
912
  }
864
913
  }}
865
914
  renderOption={(props, option) => (
866
- <Box sx={{ direction: 'rtl' }} component='li' {...props}>
915
+ <Box sx={{direction: 'rtl'}} component="li" {...props}>
867
916
  <Box>
868
- <Typography sx={{ color: 'primary.dark' }}>{option.tableName}</Typography>
869
- <Typography variant='body2' color='text.secondary'>
917
+ <Typography sx={{color: 'primary.dark'}}>
918
+ {option.tableName}
919
+ </Typography>
920
+ <Typography variant="body2" color="text.secondary">
870
921
  {option.friendlyName}
871
922
  </Typography>
872
923
  </Box>
873
924
  </Box>
874
925
  )}
875
- renderInput={params => <TextField {...params} variant='outlined' label='Select Source Model' fullWidth />}
876
- sx={{ mb: 2, mt: 2 }}
926
+ renderInput={(params) => (
927
+ <TextField
928
+ {...params}
929
+ variant="outlined"
930
+ label="Select Source Model"
931
+ fullWidth
932
+ />
933
+ )}
934
+ sx={{mb: 2, mt: 2}}
877
935
  />
878
936
 
879
937
  {breadcrumbs.length > 0 && (
880
- <Breadcrumbs separator='' sx={{ mb: 2 }} aria-label='breadcrumb'>
938
+ <Breadcrumbs separator="" sx={{mb: 2}} aria-label="breadcrumb">
881
939
  {breadcrumbs.map((crumb, i) => (
882
940
  <Link
883
941
  key={crumb.fullName}
884
- underline='hover'
942
+ underline="hover"
885
943
  color={i === breadcrumbs.length - 1 ? 'primary.main' : 'inherit'}
886
944
  onClick={() => handleGetFields(crumb.fullName, crumb.friendlyName, crumb.propertyType, true)}
887
- sx={{ cursor: 'pointer', fontSize: '0.875rem' }}
945
+ sx={{cursor: 'pointer', fontSize: '0.875rem'}}
888
946
  >
889
947
  {crumb.friendlyName}
890
948
  </Link>
@@ -892,45 +950,51 @@ const ReportBuilder = () => {
892
950
  </Breadcrumbs>
893
951
  )}
894
952
 
895
- <Box sx={{ display: 'flex', flexDirection: 'column', gap: 1, mb: 2 }}>
896
- <Typography variant='subtitle1' gutterBottom>
953
+ <Box sx={{display: 'flex', flexDirection: 'column', gap: 1, mb: 2}}>
954
+ <Typography variant="subtitle1" gutterBottom>
897
955
  Available Fields
898
956
  </Typography>
899
957
  <TextField
900
- variant='outlined'
901
- size='small'
902
- placeholder='Search fields...'
958
+ variant="outlined"
959
+ size="small"
960
+ placeholder="Search fields..."
903
961
  fullWidth
904
962
  value={searchQuery}
905
- onChange={e => setSearchQuery(e.target.value)}
963
+ onChange={(e) => setSearchQuery(e.target.value)}
906
964
  />
907
965
  </Box>
908
966
 
909
- <Box sx={{ flexGrow: 1, overflowY: 'auto' }}>
967
+ <Box sx={{flexGrow: 1, overflowY: 'auto'}}>
910
968
  <List dense disablePadding>
911
969
  {modelFields
912
- .filter(
913
- field =>
914
- field.friendlyName?.toLowerCase().includes(searchQuery.toLowerCase()) ||
915
- field.path?.toLowerCase().includes(searchQuery.toLowerCase())
970
+ .filter(field =>
971
+ field.friendlyName?.toLowerCase().includes(searchQuery.toLowerCase()) ||
972
+ field.path?.toLowerCase().includes(searchQuery.toLowerCase())
916
973
  )
917
974
  .map((field, index) => {
975
+
918
976
  // Now check against your selectedFields by their stored 'path'
919
- const fullPath = [...breadcrumbs.map(b => b.friendlyName), field.friendlyName].join('.')
977
+ const fullPath = [
978
+ ...breadcrumbs.map(b => b.friendlyName),
979
+ field.friendlyName
980
+ ].join('.');
920
981
 
921
982
  // now check *that*:
922
- const isSelected = isFullPathSelected(builderModel.selectedFields, fullPath)
983
+ const isSelected = isFullPathSelected(
984
+ builderModel.selectedFields,
985
+ fullPath
986
+ );
923
987
  return (
924
988
  <ListItem key={index} divider>
925
989
  <ListItemText
926
990
  primary={
927
- <Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
991
+ <Box sx={{display: 'flex', alignItems: 'center', gap: 1}}>
928
992
  {field.friendlyName}
929
993
  {isSelected && (
930
- <CheckCircleOutline
931
- fontSize='small'
932
- color='success'
933
- titleAccess='Field already selected'
994
+ <CheckCircleOutlined
995
+ fontSize="small"
996
+ color="success"
997
+ titleAccess="Field already selected"
934
998
  />
935
999
  )}
936
1000
  </Box>
@@ -940,7 +1004,7 @@ const ReportBuilder = () => {
940
1004
  sx: {
941
1005
  textAlign: 'left',
942
1006
  direction: 'ltr',
943
- display: 'block'
1007
+ display: 'block',
944
1008
  }
945
1009
  }}
946
1010
  secondaryTypographyProps={{
@@ -949,7 +1013,7 @@ const ReportBuilder = () => {
949
1013
  color: 'red',
950
1014
  textAlign: 'left',
951
1015
  direction: 'ltr',
952
- display: 'block'
1016
+ display: 'block',
953
1017
  }
954
1018
  }}
955
1019
  />
@@ -960,12 +1024,12 @@ const ReportBuilder = () => {
960
1024
  alignItems: 'center',
961
1025
  gap: 1,
962
1026
  ml: 1,
963
- direction: 'ltr'
1027
+ direction: 'ltr',
964
1028
  }}
965
1029
  >
966
1030
  {(field.propertyType === 'Class' || field.propertyType === 'Collection') && (
967
1031
  <IconButton
968
- size='small'
1032
+ size="small"
969
1033
  onClick={() => {
970
1034
  handleGetFields(field.modelClassName, field.friendlyName, field.propertyType)
971
1035
  setSearchQuery('')
@@ -974,90 +1038,98 @@ const ReportBuilder = () => {
974
1038
  color: 'text.secondary',
975
1039
  '&:hover': {
976
1040
  backgroundColor: 'transparent',
977
- color: 'success.main'
978
- }
1041
+ color: 'success.main',
1042
+ },
979
1043
  }}
980
- title='Navigate into nested fields'
1044
+ title="Navigate into nested fields"
981
1045
  >
982
- <ArrowForwardSharp fontSize='inherit' />
1046
+ <ArrowForwardSharp fontSize="inherit"/>
983
1047
  </IconButton>
984
1048
  )}
985
1049
 
1050
+
986
1051
  {field.propertyType !== 'Class' && field.propertyType !== 'Collection' && (
987
1052
  <IconButton
988
1053
  onClick={() => {
989
1054
  handleAddStaticField(field)
990
1055
  }}
991
- size='small'
1056
+ size="small"
992
1057
  sx={{
993
1058
  color: 'text.secondary',
994
1059
  '&:hover': {
995
1060
  backgroundColor: 'transparent',
996
- color: 'primary.main'
997
- }
1061
+ color: 'primary.main',
1062
+ },
998
1063
  }}
999
- title='Add field to report'
1064
+ title="Add field to report"
1000
1065
  >
1001
- <AddBox fontSize='inherit' />
1066
+ <AddBox fontSize="inherit"/>
1002
1067
  </IconButton>
1003
1068
  )}
1069
+
1004
1070
  </Box>
1005
1071
  </ListItem>
1006
- )
1072
+ );
1007
1073
  })}
1008
1074
  </List>
1075
+
1009
1076
  </Box>
1010
1077
 
1011
1078
  {isLoading && (
1012
- <Box sx={{ display: 'flex', justifyContent: 'center', mt: 2 }}>
1013
- <CircularProgress size={24} />
1079
+ <Box sx={{display: 'flex', justifyContent: 'center', mt: 2}}>
1080
+ <CircularProgress size={24}/>
1014
1081
  </Box>
1015
1082
  )}
1016
1083
  </Paper>
1017
1084
 
1018
- <Box sx={{ flexGrow: 1, p: 3, overflowY: 'auto' }}>
1085
+ <Box sx={{flexGrow: 1, p: 3, overflowY: 'auto'}}>
1086
+
1019
1087
  <Grid container spacing={2}>
1020
- <Box sx={{ flexGrow: 1, p: 3, overflowY: 'auto' }}>
1021
- <Box sx={{ mb: 3 }}>
1088
+ <Box sx={{flexGrow: 1, p: 3, overflowY: 'auto'}}>
1089
+ <Box sx={{mb: 3}}>
1022
1090
  {/* Top row: Title (left) and Preview icon (right) */}
1023
1091
  <Box
1024
1092
  sx={{
1025
1093
  display: 'flex',
1026
1094
  justifyContent: 'space-between',
1027
1095
  alignItems: 'center',
1028
- mb: 2
1096
+ mb: 2,
1029
1097
  }}
1030
1098
  >
1031
- <Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
1032
- <Typography variant='h5' sx={{ fontWeight: 600 }}>
1099
+ <Box sx={{display: 'flex', alignItems: 'center', gap: 2}}>
1100
+ <Typography variant="h5" sx={{fontWeight: 600}}>
1033
1101
  Builder
1034
1102
  </Typography>
1035
1103
 
1036
1104
  <FormControlLabel
1037
1105
  control={
1038
1106
  <Switch
1039
- size='small'
1107
+ size="small"
1040
1108
  checked={builderModel.isRaw}
1041
- onChange={() => setBuilderModel(prev => ({ ...prev, isRaw: !prev.isRaw }))}
1042
- color='primary'
1109
+ onChange={() =>
1110
+ setBuilderModel(prev => ({...prev, isRaw: !prev.isRaw}))
1111
+ }
1112
+ color="primary"
1043
1113
  />
1044
1114
  }
1045
- label='Raw'
1115
+ label="Raw"
1046
1116
  />
1047
1117
  </Box>
1048
- <Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
1118
+ <Box sx={{display: 'flex', alignItems: 'center', gap: 2}}>
1049
1119
  <Tooltip title={'تصفية رئيسية'}>
1120
+
1050
1121
  <IconButton
1051
1122
  sx={{
1052
1123
  color: isPreview ? 'primary.main' : 'text.secondary',
1053
1124
  '&:hover': {
1054
1125
  backgroundColor: 'transparent',
1055
- color: 'primary.main'
1056
- }
1126
+ color: 'primary.main',
1127
+ },
1057
1128
  }}
1058
- onClick={() => handleToggleDialogs('filter')}
1129
+ onClick={() => handleToggleDialogs('filter')
1130
+ }
1059
1131
  >
1060
- <FilterAlt />
1132
+ <FilterAlt/>
1061
1133
  </IconButton>
1062
1134
  </Tooltip>
1063
1135
  <IconButton
@@ -1065,14 +1137,15 @@ const ReportBuilder = () => {
1065
1137
  color: isPreview ? 'primary.main' : 'text.secondary',
1066
1138
  '&:hover': {
1067
1139
  backgroundColor: 'transparent',
1068
- color: 'primary.main'
1069
- }
1140
+ color: 'primary.main',
1141
+ },
1070
1142
  }}
1071
1143
  onClick={() => setIsPreview(prev => !prev)}
1072
1144
  >
1073
- <PreviewOutlined />
1145
+ <PreviewOutlined/>
1074
1146
  </IconButton>
1075
1147
  </Box>
1148
+
1076
1149
  </Box>
1077
1150
 
1078
1151
  {/* Actions row: Just the Add Computed Field button aligned right */}
@@ -1085,22 +1158,22 @@ const ReportBuilder = () => {
1085
1158
  borderRadius: '8px',
1086
1159
  display: 'flex',
1087
1160
  justifyContent: 'space-between',
1088
- backgroundColor: 'background.paper'
1161
+ backgroundColor: 'background.paper',
1089
1162
  }}
1090
1163
  >
1091
1164
  <Button
1092
- variant='outlined'
1093
- color='primary'
1165
+ variant="outlined"
1166
+ color="primary"
1094
1167
  onClick={() => {
1095
- console.log(breadcrumbs)
1168
+ console.log(breadcrumbs);
1096
1169
  handleToggleDialogs('expression')
1097
1170
  }}
1098
1171
  >
1099
1172
  Add Computed Field
1100
1173
  </Button>
1101
1174
  <Button
1102
- variant='outlined'
1103
- color='primary'
1175
+ variant="outlined"
1176
+ color="primary"
1104
1177
  onClick={() => {
1105
1178
  setSelectedRow(null) // reset edit
1106
1179
  handleToggleDialogs('routing')
@@ -1109,38 +1182,56 @@ const ReportBuilder = () => {
1109
1182
  Add Routing
1110
1183
  </Button>
1111
1184
  <Button
1112
- variant='outlined'
1113
- color='primary'
1185
+ variant="outlined"
1186
+ color="primary"
1114
1187
  onClick={() => {
1115
- console.log(breadcrumbs)
1188
+ console.log(breadcrumbs);
1116
1189
  handleToggleDialogs('params')
1117
1190
  }}
1118
1191
  >
1119
1192
  Global Parameters
1120
1193
  </Button>
1121
- <Button variant='outlined' color='secondary' onClick={() => handleToggleDialogs('fixedFilter')}>
1194
+ <Button
1195
+ variant="outlined"
1196
+ color="secondary"
1197
+ onClick={() => handleToggleDialogs('fixedFilter')}
1198
+ >
1122
1199
  Fixed Filter
1123
1200
  </Button>
1201
+ <Button
1202
+ variant="outlined"
1203
+ color="info"
1204
+ onClick={() => handleToggleDialogs('columnConfig')}
1205
+ >
1206
+ Column Configurator
1207
+ </Button>
1208
+ <Button
1209
+ variant="outlined"
1210
+ color="warning"
1211
+ onClick={() => handleToggleDialogs('settings')}
1212
+ >
1213
+ Report Settings
1214
+ </Button>
1124
1215
  {/* Hidden input for uploading builder model */}
1125
1216
  <input
1126
- type='file'
1127
- accept='application/json,.json'
1217
+ type="file"
1218
+ accept="application/json,.json"
1128
1219
  ref={fileInputRef}
1129
- style={{ display: 'none' }}
1220
+ style={{display: 'none'}}
1130
1221
  onChange={handleFileChange}
1131
1222
  />
1132
1223
  <Button
1133
- variant='outlined'
1134
- color='secondary'
1135
- startIcon={<CloudDownloadOutlined />}
1224
+ variant="outlined"
1225
+ color="secondary"
1226
+ startIcon={<CloudDownloadOutlined/>}
1136
1227
  onClick={handleDownloadModel}
1137
1228
  >
1138
1229
  Download Model
1139
1230
  </Button>
1140
1231
  <Button
1141
- variant='outlined'
1142
- color='secondary'
1143
- startIcon={<CloudUploadOutlined />}
1232
+ variant="outlined"
1233
+ color="secondary"
1234
+ startIcon={<CloudUploadOutlined/>}
1144
1235
  onClick={handleUploadClick}
1145
1236
  >
1146
1237
  Upload Model
@@ -1148,35 +1239,31 @@ const ReportBuilder = () => {
1148
1239
  </Box>
1149
1240
  </Box>
1150
1241
 
1151
- {!isPreview ? (
1152
- builderModel.isRaw ? (
1153
- <Box>
1154
- <SqlEditor builderModel={builderModel} setBuilderModel={setBuilderModel} />
1155
- </Box>
1156
- ) : (
1157
- <Box>
1158
- <DragDropContext onDragEnd={handleDragEnd}>
1159
- {renderSelectedFields(builderModel.selectedFields)}
1160
- </DragDropContext>
1161
- </Box>
1162
- )
1163
- ) : (
1242
+ {!isPreview ? builderModel.isRaw ?
1243
+ <Box><SqlEditor builderModel={builderModel} setBuilderModel={setBuilderModel}/></Box> :
1164
1244
  <Box>
1165
- <SGrid builderModel={builderModel} />
1166
- </Box>
1167
- )}
1245
+ <DragDropContext onDragEnd={handleDragEnd}>
1246
+ {renderSelectedFields(builderModel.selectedFields)}
1247
+ </DragDropContext>
1248
+ </Box> : <Box>
1249
+ <SGrid
1250
+ builderModel={builderModel}
1251
+ filter={builderModel.filter}
1252
+ extraCols={columnConfigResult?.extraCols ?? []}
1253
+ columnsConfig={columnConfigResult?.columnsConfig ?? []}
1254
+ updateRef={updateRef}
1255
+ />
1256
+ </Box>}
1168
1257
  </Box>
1169
1258
  </Grid>
1170
- {!isPreview && (
1171
- <Box
1172
- sx={{ mt: 4, backgroundColor: '#fff', borderRadius: '12px', p: '10px', border: '1px solid lightgrey' }}
1173
- >
1174
- <Typography variant='h6' gutterBottom>
1259
+ {!isPreview &&
1260
+ <Box sx={{mt: 4, backgroundColor: '#fff', borderRadius: '12px', p: '10px', border: '1px solid lightgrey'}}>
1261
+ <Typography variant="h6" gutterBottom>
1175
1262
  Routing Settings
1176
1263
  </Typography>
1177
1264
 
1178
1265
  {builderModel.routingSettings?.length === 0 && (
1179
- <Typography variant='body2' color='text.secondary'>
1266
+ <Typography variant="body2" color="text.secondary">
1180
1267
  No routing settings defined yet.
1181
1268
  </Typography>
1182
1269
  )}
@@ -1189,37 +1276,37 @@ const ReportBuilder = () => {
1189
1276
  display: 'flex',
1190
1277
  alignItems: 'center',
1191
1278
  justifyContent: 'space-between',
1192
- width: '100%'
1279
+ width: '100%',
1193
1280
  }}
1194
1281
  >
1195
1282
  {/* Left side: routing info */}
1196
1283
  <Box>
1197
- <Typography variant='body1'>
1198
- {route.fieldName} → {route.pattern}
1284
+ <Typography variant="body1">
1285
+ {route.name ? `${route.name} (${route.fieldName})` : route.fieldName} → {route.type === 'Filter' ? `Page: ${route.pageId}` : route.pattern}
1199
1286
  </Typography>
1200
- <Typography variant='body2' color='text.secondary'>
1201
- Params: {route.params.join(', ')}
1287
+ <Typography variant="body2" color="text.secondary">
1288
+ Params: {(route.params || []).join(', ')}
1202
1289
  </Typography>
1203
1290
  </Box>
1204
1291
 
1205
1292
  {/* Right side: action buttons */}
1206
- <Box sx={{ display: 'flex', gap: 1 }}>
1293
+ <Box sx={{display: 'flex', gap: 1}}>
1207
1294
  <Button
1208
- size='small'
1295
+ size="small"
1209
1296
  onClick={() => {
1210
- setSelectedRow({ ...route, index: idx })
1297
+ setSelectedRow({...route, index: idx})
1211
1298
  handleToggleDialogs('routing')
1212
1299
  }}
1213
1300
  >
1214
1301
  Update
1215
1302
  </Button>
1216
1303
  <Button
1217
- size='small'
1218
- color='error'
1304
+ size="small"
1305
+ color="error"
1219
1306
  onClick={() =>
1220
- setBuilderModel(prev => ({
1307
+ setBuilderModel((prev) => ({
1221
1308
  ...prev,
1222
- routingSettings: prev.routingSettings.filter((_, i) => i !== idx)
1309
+ routingSettings: prev.routingSettings.filter((_, i) => i !== idx),
1223
1310
  }))
1224
1311
  }
1225
1312
  >
@@ -1230,9 +1317,40 @@ const ReportBuilder = () => {
1230
1317
  </ListItem>
1231
1318
  ))}
1232
1319
  </List>
1233
- </Box>
1234
- )}
1320
+
1321
+ </Box>}
1322
+
1323
+ {!isPreview && columnConfigResult &&
1324
+ <Box sx={{mt: 4, backgroundColor: '#fff', borderRadius: '12px', p: '10px', border: '1px solid lightgrey'}}>
1325
+ <Box sx={{display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2}}>
1326
+ <Typography variant="h6">
1327
+ Column Configurator Result (Testing)
1328
+ </Typography>
1329
+ <Button
1330
+ size="small"
1331
+ color="error"
1332
+ onClick={() => setColumnConfigResult(null)}
1333
+ >
1334
+ Clear
1335
+ </Button>
1336
+ </Box>
1337
+ <Box
1338
+ component="pre"
1339
+ sx={{
1340
+ p: 2,
1341
+ bgcolor: 'grey.900',
1342
+ color: 'grey.100',
1343
+ borderRadius: 1,
1344
+ overflow: 'auto',
1345
+ maxHeight: 400,
1346
+ fontSize: '0.875rem'
1347
+ }}
1348
+ >
1349
+ {JSON.stringify(columnConfigResult, null, 2)}
1350
+ </Box>
1351
+ </Box>}
1235
1352
  </Box>
1353
+
1236
1354
  </Box>
1237
1355
 
1238
1356
  <Dialog
@@ -1240,46 +1358,35 @@ const ReportBuilder = () => {
1240
1358
  onClose={() => {
1241
1359
  handleToggleDialogs('expression')
1242
1360
  setSelectedRow(null)
1243
- setSelectedCollection(null)
1244
- }}
1245
- maxWidth='lg'
1246
- fullWidth
1247
- >
1361
+ setSelectedCollection(null);
1362
+ }} maxWidth="lg" fullWidth>
1248
1363
  <ExpressionEditor
1249
1364
  oldValue={selectedRow}
1250
1365
  addComputedField={handleAddComputedField}
1251
1366
  handleUpdateComputedField={handleUpdateComputedField}
1252
1367
  selectionParams={builderModel.selectionParams}
1253
- setSelectionParams={params => setBuilderModel(prev => ({ ...prev, selectionParams: params }))}
1368
+ setSelectionParams={(params) =>
1369
+ setBuilderModel(prev => ({...prev, selectionParams: params}))
1370
+ }
1254
1371
  />
1255
1372
  </Dialog>
1256
- <Dialog
1257
- open={openDialogs.params}
1258
- onClose={() => {
1259
- handleToggleDialogs('params')
1260
- setSelectedRow(null)
1261
- }}
1262
- maxWidth='lg'
1263
- fullWidth
1264
- >
1373
+ <Dialog open={openDialogs.params} onClose={() => {
1374
+ handleToggleDialogs('params')
1375
+ setSelectedRow(null)
1376
+ }} maxWidth="lg" fullWidth>
1265
1377
  <DynamicValueList
1266
1378
  items={builderModel.selectionParams}
1267
1379
  onChange={newParams => {
1268
1380
  setBuilderModel(prev => ({
1269
1381
  ...prev,
1270
1382
  selectionParams: newParams
1271
- }))
1383
+ }));
1272
1384
  }}
1273
1385
  />
1274
1386
  </Dialog>
1275
- <Dialog
1276
- open={openDialogs.save}
1277
- onClose={() => {
1278
- handleToggleDialogs('save')
1279
- }}
1280
- maxWidth='lg'
1281
- fullWidth
1282
- >
1387
+ <Dialog open={openDialogs.save} onClose={() => {
1388
+ handleToggleDialogs('save')
1389
+ }} maxWidth="lg" fullWidth>
1283
1390
  <ReportBuilderSaveForm
1284
1391
  builderMetadata={builderMetadata}
1285
1392
  setBuilderMetadata={setBuilderMetadata}
@@ -1296,15 +1403,18 @@ const ReportBuilder = () => {
1296
1403
  scroll='body'
1297
1404
  // onClose={() => handleToggleDialogs('CustomFilter')}
1298
1405
  >
1299
- <CustomFilterDialog
1300
- handleToggleDialogs={handleToggleDialogs}
1301
- Filter={[...(builderModel.filter?.LocalTfilter || [])]}
1302
- handleFilterChange={handleFilterChange}
1303
- className={builderModel?.reportSource?.fullName}
1304
- LocalFilter={false}
1305
- selectTFilter={[]}
1306
- selectParamsMeta={builderModel.selectionParams}
1307
- />
1406
+ {openDialogs.filter && builderModel.reportSource && (
1407
+ <CustomFilterDialog
1408
+ handleToggleDialogs={handleToggleDialogs}
1409
+ Filter={builderModel.filter?.LocalTfilter || []}
1410
+ customFilterCode={builderModel.filter?.customFilterCode}
1411
+ handleFilterChange={handleFilterChange}
1412
+ className={builderModel?.reportSource?.fullName}
1413
+ LocalFilter={false}
1414
+ selectTFilter={[]}
1415
+ // selectParamsMeta={builderModel.selectionParams}
1416
+ />
1417
+ )}
1308
1418
  </Dialog>
1309
1419
  <Dialog
1310
1420
  fullWidth
@@ -1316,7 +1426,7 @@ const ReportBuilder = () => {
1316
1426
  <FixedFilterDialog
1317
1427
  className={builderModel?.reportSource?.fullName}
1318
1428
  value={builderModel?.filter?.fixedTFilter || []}
1319
- onSave={list => {
1429
+ onSave={(list) => {
1320
1430
  setBuilderModel(prev => ({
1321
1431
  ...prev,
1322
1432
  filter: {
@@ -1328,11 +1438,16 @@ const ReportBuilder = () => {
1328
1438
  onClose={() => handleToggleDialogs('fixedFilter')}
1329
1439
  />
1330
1440
  </Dialog>
1331
- <Dialog open={openDialogs.routing} onClose={() => handleToggleDialogs('routing')} maxWidth='sm' fullWidth>
1441
+ <Dialog
1442
+ open={openDialogs.routing}
1443
+ onClose={() => handleToggleDialogs('routing')}
1444
+ maxWidth="sm"
1445
+ fullWidth
1446
+ >
1332
1447
  <RoutingSettingDialog
1333
- value={selectedRow || { fieldName: '', pattern: '', params: [] }}
1334
- onChange={newValue => {
1335
- setBuilderModel(prev => {
1448
+ value={selectedRow || {fieldName: '', pattern: '', params: []}}
1449
+ onChange={(newValue) => {
1450
+ setBuilderModel((prev) => {
1336
1451
  const clone = [...(prev.routingSettings || [])]
1337
1452
  if (selectedRow?.index != null) {
1338
1453
  // Update existing
@@ -1341,21 +1456,66 @@ const ReportBuilder = () => {
1341
1456
  // Add new
1342
1457
  clone.push(newValue)
1343
1458
  }
1344
- return { ...prev, routingSettings: clone }
1459
+ return {...prev, routingSettings: clone}
1345
1460
  })
1346
1461
  }}
1347
1462
  onClose={() => handleToggleDialogs('routing')}
1348
1463
  />
1349
1464
  </Dialog>
1465
+ <FormattingSettingsDialog
1466
+ open={openDialogs.formatting}
1467
+ onClose={() => setOpenDialogs(prev => ({...prev, formatting: false}))}
1468
+ field={selectedRow ? {
1469
+ ...selectedRow,
1470
+ parentFields: builderModel.selectedFields.filter(f => f.path !== selectedRow.path && !f.children)
1471
+ } : null}
1472
+ onSave={(formatting) => {
1473
+ setBuilderModel(prev => {
1474
+ const updateNode = (node) => {
1475
+ if (node.propertyType === 'Collection') {
1476
+ return {...node, children: (node.children || []).map(updateNode)};
1477
+ }
1478
+ if (node.path === selectedRow.path) {
1479
+ return {...node, formatting};
1480
+ }
1481
+ return node;
1482
+ };
1483
+ return {
1484
+ ...prev,
1485
+ selectedFields: prev.selectedFields.map(updateNode)
1486
+ };
1487
+ });
1488
+ }}
1489
+ />
1490
+ <ColumnConfiguratorDialog
1491
+ open={openDialogs.columnConfig}
1492
+ onClose={() => handleToggleDialogs('columnConfig')}
1493
+ onResult={(result) => {
1494
+ console.log('Column Configuration Result:', result);
1495
+ setColumnConfigResult(result);
1496
+ handleToggleDialogs('columnConfig');
1497
+ }}
1498
+ />
1499
+ <ReportSettingsDialog
1500
+ open={openDialogs.settings}
1501
+ onClose={() => handleToggleDialogs('settings')}
1502
+ settings={builderModel.settings}
1503
+ onSave={(newSettings) => {
1504
+ setBuilderModel(prev => ({
1505
+ ...prev,
1506
+ settings: newSettings
1507
+ }));
1508
+ }}
1509
+ />
1350
1510
  </div>
1351
1511
  )
1352
- }
1512
+ };
1353
1513
 
1354
1514
  ReportBuilder.acl = {
1355
1515
  action: 'view',
1356
- subject: PermissionsSubjects.ReportBuilderPage
1357
- }
1516
+ subject: PermissionsSubjects.ReportBuilder
1517
+ };
1358
1518
 
1359
- ReportBuilder.getLayout = page => <BlankLayout>{page}</BlankLayout>
1519
+ ReportBuilder.getLayout = (page) => <BlankLayout>{page}</BlankLayout>;
1360
1520
 
1361
- export default ReportBuilder
1521
+ export default ReportBuilder;