robobyte-front-builder 1.0.19 → 1.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/INTEGRATION.md +1586 -0
- package/README.md +928 -0
- package/RoboByteBuilder_User_Manual.docx +0 -0
- package/next.config.js +19 -48
- package/package.json +42 -86
- package/src/context/BuilderContext.jsx +191 -7
- package/src/context/SystemContext.js +2 -2
- package/src/hooks/useGlobalStore.js +36 -0
- package/src/hooks/useTimerEngine.js +54 -0
- package/src/lib/index.js +11 -3
- package/src/lib/layouts/BlankLayout.jsx +13 -0
- package/src/lib/providers/RoboByteFrontBuilderProvider.jsx +61 -7
- package/src/lib/themes/builderTheme.js +41 -0
- package/src/pages/_app.js +32 -134
- package/src/pages/api/ai.js +107 -0
- package/src/pages/builders/report/index.js +1 -0
- package/src/pages/builders/report/list/index.js +1 -0
- package/src/pages/builders/report/viewer/index.js +1 -0
- package/src/pages/index.js +88 -37
- package/src/pages/printBuilder/index.jsx +263 -0
- package/src/pages/printBuilder/layouts/index.jsx +298 -0
- package/src/pages/reportModule/reportBuilder/index.js +8 -6
- package/src/pages/reportModule/reportBuilder/reportViewer/index.js +92 -25
- package/src/pages/reportModule/reportBuilder/reports/index.js +3 -5
- package/src/pages/reportModule/reportBuilder/reportsPermissions/index.js +2 -3
- package/src/pages/viewBuilder/index.jsx +117 -32
- package/src/pages/viewBuilder/views/index.js +3 -3
- package/src/pages/viewer/[id]/index.js +2 -1
- package/src/services/DeleteService.js +31 -60
- package/src/services/Endpoints/PrintLayoutEndpoints.js +42 -0
- package/src/services/Endpoints/ReportBuilderEndpoints.js +7 -7
- package/src/services/Endpoints.js +2 -0
- package/src/services/GetService.js +33 -54
- package/src/services/PatchService.js +38 -65
- package/src/services/PostService.js +37 -63
- package/src/services/UpdateService.js +39 -65
- package/src/services/builderHelper/actionExecutor.js +141 -25
- package/src/services/builderHelper/builderHelper.js +92 -0
- package/src/services/builderHelper/colorSchema.js +95 -0
- package/src/services/builderHelper/iconResolver.js +50 -0
- package/src/services/builderHelper/jsExecutor.js +212 -46
- package/src/services/builderHelper/nodeFactory.js +32 -15
- package/src/services/builderHelper/numberFormat.js +123 -0
- package/src/services/builderHelper/resolveProps.js +73 -4
- package/src/services/builderHelper/thresholdEngine.js +77 -0
- package/src/services/builderHelper/tree.js +31 -0
- package/src/services/components/agGridAutoComplete.js +5 -9
- package/src/services/config.js +9 -1
- package/src/services/globalStore.js +80 -0
- package/src/services/helper/multiSelectEditor.js +5 -9
- package/src/services/helper/multiSelectEditorByBuilder.js +5 -9
- package/src/services/reportData/fetchReportData.js +69 -28
- package/src/services/routerRef.js +35 -0
- package/src/services/sessionLog.js +171 -0
- package/src/views/ConfirmDialog.js +2 -2
- package/src/views/builder/JSEditor.js +105 -107
- package/src/views/builder/SessionLogDialog.jsx +350 -0
- package/src/views/builder/UnsavedChangesGuard.jsx +103 -0
- package/src/views/builder/inspector/Inspector.jsx +6 -9
- package/src/views/builder/inspector/Tabs/ComponentActionsTab.jsx +7 -13
- package/src/views/builder/inspector/Tabs/MainTab.jsx +143 -25
- package/src/views/builder/inspector/Tabs/RulesTab.jsx +9 -24
- package/src/views/builder/inspector/Tabs/StyleTab.jsx +9 -24
- package/src/views/builder/inspector/definitions/autocomplete/main.js +4 -6
- package/src/views/builder/inspector/definitions/banner/actions.js +7 -0
- package/src/views/builder/inspector/definitions/banner/main.js +22 -0
- package/src/views/builder/inspector/definitions/banner/rules.js +1 -0
- package/src/views/builder/inspector/definitions/banner/style.js +1 -0
- package/src/views/builder/inspector/definitions/breadcrumb/main.js +43 -6
- package/src/views/builder/inspector/definitions/button/main.js +11 -12
- package/src/views/builder/inspector/definitions/button/style.js +18 -30
- package/src/views/builder/inspector/definitions/checkbox/actions.js +3 -1
- package/src/views/builder/inspector/definitions/checkbox/main.js +4 -6
- package/src/views/builder/inspector/definitions/common/main.js +13 -2
- package/src/views/builder/inspector/definitions/dataGrid/main.js +23 -0
- package/src/views/builder/inspector/definitions/dataTableViewer/main.js +46 -0
- package/src/views/builder/inspector/definitions/datepicker/actions.js +3 -1
- package/src/views/builder/inspector/definitions/datepicker/main.js +6 -14
- package/src/views/builder/inspector/definitions/dialog/main.js +36 -0
- package/src/views/builder/inspector/definitions/dropdown/main.js +5 -8
- package/src/views/builder/inspector/definitions/excelUpload/actions.js +23 -0
- package/src/views/builder/inspector/definitions/excelUpload/main.js +17 -0
- package/src/views/builder/inspector/definitions/excelUpload/rules.js +1 -0
- package/src/views/builder/inspector/definitions/excelUpload/style.js +45 -0
- package/src/views/builder/inspector/definitions/header/main.js +10 -1
- package/src/views/builder/inspector/definitions/index.js +106 -19
- package/src/views/builder/inspector/definitions/input/actions.js +4 -1
- package/src/views/builder/inspector/definitions/input/main.js +20 -11
- package/src/views/builder/inspector/definitions/kpi/avatarGroup.js +22 -0
- package/src/views/builder/inspector/definitions/kpi/badge.js +17 -0
- package/src/views/builder/inspector/definitions/kpi/bulletChart.js +47 -0
- package/src/views/builder/inspector/definitions/kpi/chart.js +55 -0
- package/src/views/builder/inspector/definitions/kpi/colorScale.js +60 -0
- package/src/views/builder/inspector/definitions/kpi/comparisonBars.js +41 -0
- package/src/views/builder/inspector/definitions/kpi/countdown.js +46 -0
- package/src/views/builder/inspector/definitions/kpi/donut.js +51 -0
- package/src/views/builder/inspector/definitions/kpi/funnel.js +25 -0
- package/src/views/builder/inspector/definitions/kpi/gauge.js +39 -0
- package/src/views/builder/inspector/definitions/kpi/heatmapGrid.js +96 -0
- package/src/views/builder/inspector/definitions/kpi/iconBox.js +20 -0
- package/src/views/builder/inspector/definitions/kpi/metric.js +45 -0
- package/src/views/builder/inspector/definitions/kpi/rating.js +27 -0
- package/src/views/builder/inspector/definitions/kpi/statusDot.js +18 -0
- package/src/views/builder/inspector/definitions/kpi/stepStage.js +65 -0
- package/src/views/builder/inspector/definitions/kpi/tagList.js +32 -0
- package/src/views/builder/inspector/definitions/kpi/timeline.js +80 -0
- package/src/views/builder/inspector/definitions/kpi/trend.js +20 -0
- package/src/views/builder/inspector/definitions/label/main.js +10 -1
- package/src/views/builder/inspector/definitions/layout/main.js +27 -3
- package/src/views/builder/inspector/definitions/number/main.js +6 -14
- package/src/views/builder/inspector/definitions/pageNumber/main.js +21 -0
- package/src/views/builder/inspector/definitions/popover/main.js +71 -0
- package/src/views/builder/inspector/definitions/radio/main.js +5 -8
- package/src/views/builder/inspector/definitions/repeater/main.js +31 -0
- package/src/views/builder/inspector/definitions/reportViewer/main.js +28 -1
- package/src/views/builder/inspector/definitions/richtext/main.js +5 -8
- package/src/views/builder/inspector/definitions/signature/main.js +4 -1
- package/src/views/builder/inspector/definitions/tag/main.js +5 -8
- package/src/views/builder/inspector/definitions/textarea/actions.js +4 -1
- package/src/views/builder/inspector/definitions/textarea/main.js +5 -7
- package/src/views/builder/inspector/definitions/time/main.js +5 -8
- package/src/views/builder/inspector/definitions/toggle/main.js +5 -19
- package/src/views/builder/inspector/definitions/treeView/main.js +61 -0
- package/src/views/builder/inspector/definitions/viewRenderer/main.js +53 -0
- package/src/views/builder/inspector/definitions/wizard/main.js +68 -0
- package/src/views/builder/inspector/definitions/wizard-step/main.js +25 -0
- package/src/views/builder/inspector/fields/ActionsConfigEditor.jsx +426 -0
- package/src/views/builder/inspector/fields/ColorSchemaField.jsx +140 -0
- package/src/views/builder/inspector/fields/ColumnFunctionEditor.jsx +238 -0
- package/src/views/builder/inspector/fields/ColumnMappingEditor.jsx +105 -0
- package/src/views/builder/inspector/fields/ColumnsConfigEditor.jsx +506 -0
- package/src/views/builder/inspector/fields/DonutRingsEditorField.jsx +337 -0
- package/src/views/builder/inspector/fields/ExtraColsEditor.jsx +618 -0
- package/src/views/builder/inspector/fields/FunctionHelpPopover.jsx +295 -0
- package/src/views/builder/inspector/fields/IconEditor.jsx +64 -0
- package/src/views/builder/inspector/fields/KpiActionField.jsx +223 -0
- package/src/views/builder/inspector/fields/MarkersEditorField.jsx +173 -0
- package/src/views/builder/inspector/fields/SelectEditor.jsx +9 -5
- package/src/views/builder/inspector/fields/SeriesEditorField.jsx +363 -0
- package/src/views/builder/inspector/fields/TableColumnsEditor.jsx +104 -0
- package/src/views/builder/inspector/fields/ThresholdsEditor.jsx +247 -0
- package/src/views/builder/inspector/fields/ValueFunctionsRefPanel.jsx +217 -0
- package/src/views/builder/inspector/fields/columnEditorShared.jsx +217 -0
- package/src/views/builder/sidebar/Sidebar.jsx +4 -2
- package/src/views/builder/sidebar/SidebarTabs.jsx +28 -17
- package/src/views/builder/sidebar/tabs/ActionsTab.jsx +7 -3
- package/src/views/builder/sidebar/tabs/AiTab/AiPreviewDialog.jsx +193 -0
- package/src/views/builder/sidebar/tabs/AiTab/aiProvider.js +53 -0
- package/src/views/builder/sidebar/tabs/AiTab/index.jsx +409 -0
- package/src/views/builder/sidebar/tabs/AiTab/schemaTransformer.js +167 -0
- package/src/views/builder/sidebar/tabs/AiTab/schemaValidator.js +64 -0
- package/src/views/builder/sidebar/tabs/AiTab/systemPrompt.js +1151 -0
- package/src/views/builder/sidebar/tabs/AiTab/trainingExport.js +131 -0
- package/src/views/builder/sidebar/tabs/Components/ComponentsTab.jsx +31 -31
- package/src/views/builder/sidebar/tabs/Components/componentCatalog.js +43 -21
- package/src/views/builder/sidebar/tabs/Components/printComponentCatalog.js +81 -0
- package/src/views/builder/sidebar/tabs/TimersTab.jsx +338 -0
- package/src/views/builder/sidebar/tabs/TreeTab.jsx +13 -4
- package/src/views/builder/sidebar/tabs/ViewTab.jsx +173 -13
- package/src/views/builder/viewer/AdornedLabel.jsx +82 -0
- package/src/views/builder/viewer/ComponentRenderer.jsx +98 -24
- package/src/views/builder/viewer/DialogsZone.jsx +259 -0
- package/src/views/builder/viewer/FieldLabel.jsx +106 -0
- package/src/views/builder/viewer/PrintDialog.jsx +481 -0
- package/src/views/builder/viewer/ProductionViewer.jsx +80 -5
- package/src/views/builder/viewer/Viewer.jsx +106 -8
- package/src/views/builder/viewer/ViewerComponentWrapper.jsx +70 -9
- package/src/views/builder/viewer/ViewerToolbar.jsx +285 -56
- package/src/views/builder/viewer/renderers/AutoCompleteRenderer.jsx +26 -22
- package/src/views/builder/viewer/renderers/AvatarGroupRenderer.jsx +112 -0
- package/src/views/builder/viewer/renderers/BadgeRenderer.jsx +79 -0
- package/src/views/builder/viewer/renderers/BannerRenderer.jsx +62 -0
- package/src/views/builder/viewer/renderers/BreadcrumbRenderer.jsx +203 -15
- package/src/views/builder/viewer/renderers/BulletChartRenderer.jsx +147 -0
- package/src/views/builder/viewer/renderers/ButtonRenderer.jsx +98 -39
- package/src/views/builder/viewer/renderers/CardRenderer.jsx +1 -1
- package/src/views/builder/viewer/renderers/ChartRenderer.jsx +388 -0
- package/src/views/builder/viewer/renderers/CheckboxRenderer.jsx +17 -9
- package/src/views/builder/viewer/renderers/ColorScaleRenderer.jsx +300 -0
- package/src/views/builder/viewer/renderers/ComparisonBarsRenderer.jsx +133 -0
- package/src/views/builder/viewer/renderers/ContainerRenderer.jsx +3 -1
- package/src/views/builder/viewer/renderers/CountdownRenderer.jsx +249 -0
- package/src/views/builder/viewer/renderers/DataGridRenderer.jsx +380 -0
- package/src/views/builder/viewer/renderers/DataTableViewerRenderer.jsx +240 -0
- package/src/views/builder/viewer/renderers/DatePickerRenderer.jsx +25 -24
- package/src/views/builder/viewer/renderers/DialogRenderer.jsx +327 -0
- package/src/views/builder/viewer/renderers/DividerRenderer.jsx +1 -1
- package/src/views/builder/viewer/renderers/DonutRenderer.jsx +294 -0
- package/src/views/builder/viewer/renderers/DropdownRenderer.jsx +36 -44
- package/src/views/builder/viewer/renderers/ExcelUploadRenderer.jsx +639 -0
- package/src/views/builder/viewer/renderers/FunnelRenderer.jsx +93 -0
- package/src/views/builder/viewer/renderers/GaugeRenderer.jsx +159 -0
- package/src/views/builder/viewer/renderers/HeaderRenderer.jsx +31 -9
- package/src/views/builder/viewer/renderers/HeatmapGridRenderer.jsx +432 -0
- package/src/views/builder/viewer/renderers/IconBoxRenderer.jsx +59 -0
- package/src/views/builder/viewer/renderers/ImageRenderer.jsx +1 -1
- package/src/views/builder/viewer/renderers/InputRenderer.jsx +75 -18
- package/src/views/builder/viewer/renderers/LabelRenderer.jsx +35 -9
- package/src/views/builder/viewer/renderers/LayoutCellRenderer.jsx +102 -40
- package/src/views/builder/viewer/renderers/LayoutContextMenu.jsx +8 -8
- package/src/views/builder/viewer/renderers/LayoutRenderer.jsx +48 -6
- package/src/views/builder/viewer/renderers/LinkRenderer.jsx +1 -1
- package/src/views/builder/viewer/renderers/MenuRenderer.jsx +2 -2
- package/src/views/builder/viewer/renderers/MetricRenderer.jsx +80 -0
- package/src/views/builder/viewer/renderers/NumberFormatRenderer.jsx +21 -30
- package/src/views/builder/viewer/renderers/PageNumberRenderer.jsx +76 -0
- package/src/views/builder/viewer/renderers/PopoverRenderer.jsx +350 -0
- package/src/views/builder/viewer/renderers/ProgressCircleRenderer.jsx +1 -1
- package/src/views/builder/viewer/renderers/ProgressLineRenderer.jsx +1 -1
- package/src/views/builder/viewer/renderers/RadioGroupRenderer.jsx +28 -39
- package/src/views/builder/viewer/renderers/RatingRenderer.jsx +80 -0
- package/src/views/builder/viewer/renderers/RepeaterRenderer.jsx +297 -38
- package/src/views/builder/viewer/renderers/ReportViewerRenderer.jsx +263 -5
- package/src/views/builder/viewer/renderers/RichTextRenderer.jsx +60 -66
- package/src/views/builder/viewer/renderers/RowActionsCell.jsx +308 -0
- package/src/views/builder/viewer/renderers/SignatureRenderer.jsx +33 -62
- package/src/views/builder/viewer/renderers/StatusDotRenderer.jsx +75 -0
- package/src/views/builder/viewer/renderers/StepStageRenderer.jsx +348 -0
- package/src/views/builder/viewer/renderers/TagListRenderer.jsx +115 -0
- package/src/views/builder/viewer/renderers/TagPickerRenderer.jsx +31 -45
- package/src/views/builder/viewer/renderers/TextAreaRenderer.jsx +25 -18
- package/src/views/builder/viewer/renderers/TextRenderer.jsx +7 -1
- package/src/views/builder/viewer/renderers/TimePickerRenderer.jsx +25 -24
- package/src/views/builder/viewer/renderers/TimelineRenderer.jsx +525 -0
- package/src/views/builder/viewer/renderers/ToggleRenderer.jsx +21 -27
- package/src/views/builder/viewer/renderers/TreeViewRenderer.jsx +832 -0
- package/src/views/builder/viewer/renderers/TrendRenderer.jsx +66 -0
- package/src/views/builder/viewer/renderers/ViewRendererRenderer.jsx +315 -0
- package/src/views/builder/viewer/renderers/WizardRenderer.jsx +380 -64
- package/src/views/builder/viewer/renderers/WizardStepRenderer.jsx +21 -12
- package/src/views/builder/viewer/renderers/dataGridComponents.jsx +824 -0
- package/src/views/customFilter/CustomFilterDialog.js +1023 -660
- package/src/views/customFilter/FixedFilterDialog.js +649 -0
- package/src/views/customFilter/SearchFilterDialog.js +248 -0
- package/src/views/genericTable/BuilderExpressionParams.js +3 -3
- package/src/views/genericTable/ColumnConfiguratorDialog.js +33 -24
- package/src/views/genericTable/FixedFilterDialog.js +3 -2
- package/src/views/genericTable/FormattingSettingsDialog.js +8 -3
- package/src/views/genericTable/SGrid.js +821 -448
- package/src/views/genericTable/SearchFilterDialog.js +3 -2
- package/src/views/genericTable/cellEditors/autocompleteEditor.js +5 -9
- package/src/views/genericTable/convertStringFunctions.js +274 -138
- package/src/views/genericTable/statusBar/rowCountStatusBar.js +3 -1
- package/src/views/genericTable/updateRefHelpers.js +9 -6
- package/src/views/printBuilder/PrintBuilderViewer.jsx +627 -0
- package/src/views/printBuilder/PrintPreviewCanvas.jsx +157 -0
- package/src/views/rolePermissions/UpdateReportPermissionDialog.js +3 -2
- package/src/@core/components/auth/AclGuard.js +0 -55
- package/src/@core/components/auth/AuthGuard.js +0 -40
- package/src/@core/components/auth/GuestGuard.js +0 -30
- package/src/@core/components/custom-inputs/Horizontal.jsx +0 -143
- package/src/@core/components/custom-inputs/Image.jsx +0 -78
- package/src/@core/components/custom-inputs/Vertical.jsx +0 -113
- package/src/@core/components/customizer/index.jsx +0 -470
- package/src/@core/components/customizer/styles.module.css +0 -169
- package/src/@core/components/mui/Avatar.jsx +0 -41
- package/src/@core/components/mui/Badge.jsx +0 -20
- package/src/@core/components/mui/IconButton.jsx +0 -74
- package/src/@core/components/mui/TabList.jsx +0 -60
- package/src/@core/components/option-menu/index.jsx +0 -137
- package/src/@core/components/scroll-to-top/index.jsx +0 -43
- package/src/@core/components/spinner/index.js +0 -26
- package/src/@core/components/window-wrapper/index.js +0 -27
- package/src/@core/contexts/settingsContext.jsx +0 -98
- package/src/@core/hooks/useBgColor.js +0 -63
- package/src/@core/hooks/useImageVariant.js +0 -27
- package/src/@core/hooks/useLayoutInit.js +0 -37
- package/src/@core/hooks/useObjectCookie.js +0 -18
- package/src/@core/hooks/useSettings.jsx +0 -15
- package/src/@core/layouts/BlankLayout.js +0 -37
- package/src/@core/layouts/BlankLayoutWithAppBar.js +0 -51
- package/src/@core/layouts/HorizontalLayout.jsx +0 -151
- package/src/@core/layouts/Layout.js +0 -39
- package/src/@core/layouts/VerticalLayout.jsx +0 -124
- package/src/@core/layouts/components/blank-layout-with-appBar/index.js +0 -115
- package/src/@core/layouts/components/horizontal/app-bar-content/index.js +0 -67
- package/src/@core/layouts/components/horizontal/navigation/HorizontalNavGroup.js +0 -352
- package/src/@core/layouts/components/horizontal/navigation/HorizontalNavItems.js +0 -21
- package/src/@core/layouts/components/horizontal/navigation/HorizontalNavLink.js +0 -195
- package/src/@core/layouts/components/horizontal/navigation/index.js +0 -31
- package/src/@core/layouts/components/shared-components/LanguageDropdown.js +0 -96
- package/src/@core/layouts/components/shared-components/ModeToggler.js +0 -32
- package/src/@core/layouts/components/shared-components/NotificationDropdown.js +0 -226
- package/src/@core/layouts/components/shared-components/UserDropdown.js +0 -177
- package/src/@core/layouts/components/shared-components/footer/FooterContent.js +0 -46
- package/src/@core/layouts/components/shared-components/footer/index.js +0 -61
- package/src/@core/layouts/components/vertical/appBar/index.js +0 -74
- package/src/@core/layouts/components/vertical/navigation/Drawer.js +0 -122
- package/src/@core/layouts/components/vertical/navigation/VerticalNavGroup.js +0 -435
- package/src/@core/layouts/components/vertical/navigation/VerticalNavHeader.js +0 -180
- package/src/@core/layouts/components/vertical/navigation/VerticalNavItems.js +0 -26
- package/src/@core/layouts/components/vertical/navigation/VerticalNavLink.js +0 -258
- package/src/@core/layouts/components/vertical/navigation/VerticalNavSectionTitle.js +0 -102
- package/src/@core/layouts/components/vertical/navigation/index.js +0 -169
- package/src/@core/layouts/utils.js +0 -69
- package/src/@core/styles/Table.module.css +0 -93
- package/src/@core/styles/horizontal/menuItemStyles.js +0 -100
- package/src/@core/styles/horizontal/menuRootStyles.js +0 -19
- package/src/@core/styles/libs/fullcalendar/index.js +0 -461
- package/src/@core/styles/libs/keen-slider/index.js +0 -111
- package/src/@core/styles/libs/react-apexcharts/index.js +0 -107
- package/src/@core/styles/libs/react-cleave/index.js +0 -33
- package/src/@core/styles/libs/react-credit-cards/index.js +0 -11
- package/src/@core/styles/libs/react-datepicker/index.js +0 -388
- package/src/@core/styles/libs/react-draft-wysiwyg/index.js +0 -144
- package/src/@core/styles/libs/react-dropzone/index.js +0 -76
- package/src/@core/styles/libs/react-hot-toast/index.js +0 -37
- package/src/@core/styles/libs/recharts/index.js +0 -47
- package/src/@core/styles/stepper.js +0 -103
- package/src/@core/styles/vertical/menuItemStyles.js +0 -138
- package/src/@core/styles/vertical/menuSectionStyles.js +0 -54
- package/src/@core/styles/vertical/navigationCustomStyles.js +0 -62
- package/src/@core/svg/ContentCompact.jsx +0 -17
- package/src/@core/svg/ContentWide.jsx +0 -17
- package/src/@core/svg/DirectionLtr.jsx +0 -93
- package/src/@core/svg/DirectionRtl.jsx +0 -93
- package/src/@core/svg/LayoutCollapsed.jsx +0 -59
- package/src/@core/svg/LayoutHorizontal.jsx +0 -42
- package/src/@core/svg/LayoutVertical.jsx +0 -59
- package/src/@core/svg/Logo.jsx +0 -76
- package/src/@core/svg/SkinBordered.jsx +0 -54
- package/src/@core/svg/SkinDefault.jsx +0 -59
- package/src/@core/tailwind/plugin.js +0 -78
- package/src/@core/theme/ThemeComponent.js +0 -63
- package/src/@core/theme/ThemeOptions.js +0 -71
- package/src/@core/theme/breakpoints/index.js +0 -11
- package/src/@core/theme/colorSchemes.js +0 -326
- package/src/@core/theme/customShadows.js +0 -11
- package/src/@core/theme/globalStyles.js +0 -81
- package/src/@core/theme/index.js +0 -42
- package/src/@core/theme/overrides/accordion.js +0 -51
- package/src/@core/theme/overrides/accordion.jsx +0 -85
- package/src/@core/theme/overrides/alerts.js +0 -110
- package/src/@core/theme/overrides/alerts.jsx +0 -180
- package/src/@core/theme/overrides/autocomplete.js +0 -14
- package/src/@core/theme/overrides/autocomplete.jsx +0 -68
- package/src/@core/theme/overrides/avatar.js +0 -38
- package/src/@core/theme/overrides/avatars.js +0 -27
- package/src/@core/theme/overrides/backdrop.js +0 -22
- package/src/@core/theme/overrides/badges.js +0 -16
- package/src/@core/theme/overrides/breadcrumbs.js +0 -11
- package/src/@core/theme/overrides/button-group.js +0 -84
- package/src/@core/theme/overrides/button.js +0 -93
- package/src/@core/theme/overrides/buttonGroup.js +0 -9
- package/src/@core/theme/overrides/card.js +0 -83
- package/src/@core/theme/overrides/checkbox.jsx +0 -95
- package/src/@core/theme/overrides/chip.js +0 -72
- package/src/@core/theme/overrides/dataGrid.js +0 -114
- package/src/@core/theme/overrides/dateTimePicker.js +0 -65
- package/src/@core/theme/overrides/dialog.js +0 -120
- package/src/@core/theme/overrides/divider.js +0 -13
- package/src/@core/theme/overrides/drawer.js +0 -20
- package/src/@core/theme/overrides/fab.js +0 -13
- package/src/@core/theme/overrides/form-control-label.js +0 -19
- package/src/@core/theme/overrides/icon-button.js +0 -145
- package/src/@core/theme/overrides/index.js +0 -103
- package/src/@core/theme/overrides/input.js +0 -72
- package/src/@core/theme/overrides/link.js +0 -9
- package/src/@core/theme/overrides/list.js +0 -44
- package/src/@core/theme/overrides/menu.js +0 -25
- package/src/@core/theme/overrides/pagination.js +0 -41
- package/src/@core/theme/overrides/paper.js +0 -9
- package/src/@core/theme/overrides/popover.js +0 -16
- package/src/@core/theme/overrides/progress.js +0 -38
- package/src/@core/theme/overrides/radio.jsx +0 -80
- package/src/@core/theme/overrides/rating.js +0 -16
- package/src/@core/theme/overrides/rating.jsx +0 -32
- package/src/@core/theme/overrides/select.js +0 -19
- package/src/@core/theme/overrides/select.jsx +0 -52
- package/src/@core/theme/overrides/slider.js +0 -97
- package/src/@core/theme/overrides/snackbar.js +0 -19
- package/src/@core/theme/overrides/switch.js +0 -73
- package/src/@core/theme/overrides/switches.js +0 -25
- package/src/@core/theme/overrides/table-pagination.js +0 -39
- package/src/@core/theme/overrides/table.js +0 -81
- package/src/@core/theme/overrides/tabs.js +0 -30
- package/src/@core/theme/overrides/timeline.js +0 -80
- package/src/@core/theme/overrides/toggle-button.js +0 -33
- package/src/@core/theme/overrides/toggleButton.js +0 -16
- package/src/@core/theme/overrides/tooltip.js +0 -21
- package/src/@core/theme/overrides/typography.js +0 -13
- package/src/@core/theme/palette/index.js +0 -107
- package/src/@core/theme/shadows/index.js +0 -61
- package/src/@core/theme/shadows.js +0 -12
- package/src/@core/theme/spacing/index.js +0 -3
- package/src/@core/theme/spacing.js +0 -5
- package/src/@core/theme/typography/index.js +0 -65
- package/src/@core/theme/typography.js +0 -84
- package/src/@core/utils/create-emotion-cache.js +0 -5
- package/src/@core/utils/hex-to-rgba.js +0 -11
- package/src/@core/utils/serverHelpers.js +0 -45
- package/src/@menu/components/RouterLink.jsx +0 -18
- package/src/@menu/components/horizontal-menu/HorizontalNav.jsx +0 -88
- package/src/@menu/components/horizontal-menu/Menu.jsx +0 -83
- package/src/@menu/components/horizontal-menu/MenuButton.jsx +0 -100
- package/src/@menu/components/horizontal-menu/MenuItem.jsx +0 -183
- package/src/@menu/components/horizontal-menu/SubMenu.jsx +0 -418
- package/src/@menu/components/horizontal-menu/SubMenuContent.jsx +0 -41
- package/src/@menu/components/horizontal-menu/VerticalNavInHorizontal.jsx +0 -20
- package/src/@menu/components/vertical-menu/Menu.jsx +0 -161
- package/src/@menu/components/vertical-menu/MenuButton.jsx +0 -95
- package/src/@menu/components/vertical-menu/MenuItem.jsx +0 -180
- package/src/@menu/components/vertical-menu/MenuSection.jsx +0 -124
- package/src/@menu/components/vertical-menu/NavCollapseIcons.jsx +0 -70
- package/src/@menu/components/vertical-menu/NavHeader.jsx +0 -39
- package/src/@menu/components/vertical-menu/SubMenu.jsx +0 -420
- package/src/@menu/components/vertical-menu/SubMenuContent.jsx +0 -101
- package/src/@menu/components/vertical-menu/VerticalNav.jsx +0 -216
- package/src/@menu/contexts/horizontalNavContext.jsx +0 -29
- package/src/@menu/contexts/verticalNavContext.jsx +0 -65
- package/src/@menu/defaultConfigs.js +0 -12
- package/src/@menu/hooks/useHorizontalMenu.jsx +0 -19
- package/src/@menu/hooks/useHorizontalNav.jsx +0 -19
- package/src/@menu/hooks/useMediaQuery.jsx +0 -29
- package/src/@menu/hooks/useVerticalMenu.jsx +0 -19
- package/src/@menu/hooks/useVerticalNav.jsx +0 -19
- package/src/@menu/horizontal-menu/index.jsx +0 -8
- package/src/@menu/styles/StyledBackdrop.jsx +0 -15
- package/src/@menu/styles/StyledMenuIcon.jsx +0 -12
- package/src/@menu/styles/StyledMenuLabel.jsx +0 -16
- package/src/@menu/styles/StyledMenuPrefix.jsx +0 -10
- package/src/@menu/styles/StyledMenuSectionLabel.jsx +0 -21
- package/src/@menu/styles/StyledMenuSuffix.jsx +0 -10
- package/src/@menu/styles/StyledSubMenuContent.jsx +0 -43
- package/src/@menu/styles/horizontal/StyledHorizontalMenu.jsx +0 -13
- package/src/@menu/styles/horizontal/StyledHorizontalMenuItem.jsx +0 -26
- package/src/@menu/styles/horizontal/StyledHorizontalNav.jsx +0 -11
- package/src/@menu/styles/horizontal/StyledHorizontalNavExpandIcon.jsx +0 -33
- package/src/@menu/styles/horizontal/StyledHorizontalSubMenuContent.jsx +0 -18
- package/src/@menu/styles/horizontal/StyledHorizontalSubMenuContentWrapper.jsx +0 -10
- package/src/@menu/styles/horizontal/horizontalUl.module.css +0 -15
- package/src/@menu/styles/styles.module.css +0 -5
- package/src/@menu/styles/vertical/StyledVerticalMenu.jsx +0 -16
- package/src/@menu/styles/vertical/StyledVerticalMenuItem.jsx +0 -28
- package/src/@menu/styles/vertical/StyledVerticalMenuSection.jsx +0 -23
- package/src/@menu/styles/vertical/StyledVerticalNav.jsx +0 -67
- package/src/@menu/styles/vertical/StyledVerticalNavBgColorContainer.jsx +0 -15
- package/src/@menu/styles/vertical/StyledVerticalNavContainer.jsx +0 -23
- package/src/@menu/styles/vertical/StyledVerticalNavExpandIcon.jsx +0 -25
- package/src/@menu/styles/vertical/verticalNavBgImage.module.css +0 -10
- package/src/@menu/svg/ChevronRight.jsx +0 -9
- package/src/@menu/svg/Close.jsx +0 -12
- package/src/@menu/svg/RadioCircle.jsx +0 -12
- package/src/@menu/svg/RadioCircleMarked.jsx +0 -13
- package/src/@menu/utils/menuClasses.js +0 -44
- package/src/@menu/utils/menuUtils.jsx +0 -145
- package/src/@menu/vertical-menu/index.jsx +0 -11
- package/src/configs/acl.js +0 -115
- package/src/configs/auth.js +0 -5
- package/src/configs/aws-exports.js +0 -30
- package/src/configs/firebase.js +0 -25
- package/src/configs/i18n.js +0 -34
- package/src/configs/primaryColorConfig.js +0 -35
- package/src/configs/themeConfig.js +0 -44
- package/src/layouts/UserLayout.js +0 -94
- package/src/layouts/UserThemeOptions.js +0 -191
- package/src/layouts/components/Direction.js +0 -30
- package/src/layouts/components/HtmlTooltip.js +0 -15
- package/src/layouts/components/Translations.js +0 -11
- package/src/layouts/components/UserDropdown.js +0 -217
- package/src/layouts/components/UserIcon.js +0 -40
- package/src/layouts/components/acl/Can.js +0 -6
- package/src/layouts/components/acl/CanViewNavGroup.js +0 -36
- package/src/layouts/components/acl/CanViewNavLink.js +0 -17
- package/src/layouts/components/acl/CanViewNavSectionTitle.js +0 -17
- package/src/layouts/components/horizontal/AppBarContent.js +0 -39
- package/src/layouts/components/horizontal/ServerSideNavItems.js +0 -44
- package/src/layouts/components/mui/StepperComps.js +0 -55
- package/src/layouts/components/vertical/AppBarContent.js +0 -35
- package/src/layouts/components/vertical/ServerSideNavItems.js +0 -44
- package/src/libs/ApexCharts.jsx +0 -5
- package/src/libs/ReactPlayer.jsx +0 -5
- package/src/libs/Recharts.jsx +0 -4
- package/src/libs/auth.js +0 -124
- package/src/libs/styles/AppFullCalendar.js +0 -505
- package/src/libs/styles/AppKeenSlider.js +0 -116
- package/src/libs/styles/AppReactApexCharts.jsx +0 -110
- package/src/libs/styles/AppReactDatepicker.jsx +0 -470
- package/src/libs/styles/AppReactDropzone.js +0 -76
- package/src/libs/styles/AppReactToastify.jsx +0 -108
- package/src/libs/styles/AppRecharts.js +0 -55
- package/src/libs/styles/inputOtp.module.css +0 -39
- package/src/libs/styles/tiptapEditor.css +0 -72
- package/src/navigation/horizontal/index.js +0 -246
- package/src/navigation/vertical/index.js +0 -253
- package/src/pages/401.js +0 -70
- package/src/pages/404.js +0 -67
- package/src/pages/500.js +0 -68
- package/src/pages/[slug].js +0 -115
- package/src/pages/_document.js +0 -72
- package/src/pages/api/navigation/regenerate-registry.js +0 -116
- package/src/pages/api/navigation/save.js +0 -218
- package/src/pages/authModule/acl/index.js +0 -48
- package/src/pages/authModule/forgot-password/index.js +0 -228
- package/src/pages/authModule/permissions/rolePermissions/[id]/rolePermissionsUser/index.js +0 -392
- package/src/pages/authModule/permissions/rolePermissions/index.js +0 -343
- package/src/pages/authModule/permissions/systemPermissions/index.js +0 -354
- package/src/pages/authModule/privacy/index.js +0 -721
- package/src/pages/authModule/users/index.js +0 -210
- package/src/pages/login/index.js +0 -328
- package/src/pages/mainHome/index.js +0 -181
- package/src/views/builder/inspector/definitions/cell/main.js +0 -4
- package/src/views/builder/inspector/definitions/column/main.js +0 -9
- package/src/views/builder/inspector/definitions/column-group/main.js +0 -18
- package/src/views/builder/inspector/definitions/header-cell/main.js +0 -5
- package/src/views/builder/inspector/definitions/table/main.js +0 -9
- package/src/views/builder/viewer/renderers/CellRenderer.jsx +0 -71
- package/src/views/builder/viewer/renderers/ColumnGroupRenderer.jsx +0 -96
- package/src/views/builder/viewer/renderers/ColumnRenderer.jsx +0 -71
- package/src/views/builder/viewer/renderers/HeaderCellRenderer.jsx +0 -78
- package/src/views/builder/viewer/renderers/TabRenderer.jsx +0 -82
- package/src/views/builder/viewer/renderers/TableRenderer.jsx +0 -92
- package/src/views/pages/auth/FooterIllustrationsV2.js +0 -40
- package/src/views/pages/misc/FooterIllustrations.js +0 -47
- package/src/views/pages/misc/muiTable/CustomPagination.js +0 -34
- package/src/views/pages/users/UserManageDialog.js +0 -283
- package/src/views/pages/users/UserViewPage.js +0 -199
- package/src/views/users/AddUserNameDialog.js +0 -162
- package/src/views/users/ContactManage.js +0 -449
- package/src/views/users/ResetPasswordDialog.js +0 -242
|
@@ -0,0 +1,824 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom AG Grid cell renderers and editors for DataGridRenderer.
|
|
3
|
+
*
|
|
4
|
+
* Register via the `components` prop on <AgGridReact>.
|
|
5
|
+
* Reference by string name in colDef: cellRenderer: 'ChipRenderer', etc.
|
|
6
|
+
*
|
|
7
|
+
* ── Cell Renderers ────────────────────────────────────────────────────────────
|
|
8
|
+
* All renderers accept either a single value or an array of strings/values.
|
|
9
|
+
* valueFormatter controls what arrives — if it returns a string or array of
|
|
10
|
+
* strings the renderer will handle both transparently.
|
|
11
|
+
* - Multi-item renderers (ChipRenderer, LinkRenderer, IconRenderer) render one
|
|
12
|
+
* component per array element.
|
|
13
|
+
* - Scalar renderers (BooleanRenderer, CurrencyRenderer, DateRenderer,
|
|
14
|
+
* ProgressRenderer, AvatarRenderer) use the first array element.
|
|
15
|
+
*
|
|
16
|
+
* ChipRenderer — MUI Chip with color mapping per value
|
|
17
|
+
* BooleanRenderer — check / cross icon for truthy/falsy values
|
|
18
|
+
* LinkRenderer — clickable anchor; href from params or value
|
|
19
|
+
* CurrencyRenderer — formatted number with prefix/suffix/decimals
|
|
20
|
+
* DateRenderer — formatted date string
|
|
21
|
+
* ProgressRenderer — LinearProgress bar (value 0-100 or custom max)
|
|
22
|
+
* AvatarRenderer — circular image or initials avatar
|
|
23
|
+
* IconRenderer — MUI icon by name stored in the cell value
|
|
24
|
+
*
|
|
25
|
+
* ── Cell Editors ─────────────────────────────────────────────────────────────
|
|
26
|
+
* SelectEditor — MUI Select with options list
|
|
27
|
+
* AutocompleteEditor — MUI Autocomplete (searchable Select)
|
|
28
|
+
* CheckboxEditor — boolean MUI Checkbox
|
|
29
|
+
* DateEditor — native <input type="date">
|
|
30
|
+
* NumberEditor — numeric input with min / max / step
|
|
31
|
+
*
|
|
32
|
+
* ── cellRendererParams reference ─────────────────────────────────────────────
|
|
33
|
+
* ChipRenderer: { colorMap: { Active:'success', Closed:'error' }, defaultColor:'default', size:'small'|'medium', variant:'filled'|'outlined' }
|
|
34
|
+
* BooleanRenderer: { trueColor:'success.main', falseColor:'error.main', trueIcon:'CheckCircle', falseIcon:'Cancel' }
|
|
35
|
+
* LinkRenderer: { href: 'https://...', hrefField:'url', target:'_blank', label:'Open' }
|
|
36
|
+
* CurrencyRenderer: { prefix:'$', suffix:'', decimals:2, locale:'en-US' }
|
|
37
|
+
* DateRenderer: { format:'short'|'medium'|'long'|'iso' | Intl options object, locale:'en-US' }
|
|
38
|
+
* ProgressRenderer: { max:100, color:'primary'|'secondary'|'success'|'error'|'warning'|'info', showLabel:true }
|
|
39
|
+
* AvatarRenderer: { srcField:'avatarUrl', size:32, shape:'circle'|'square' }
|
|
40
|
+
* IconRenderer: { size:'small'|'medium'|'large', color:'inherit'|'primary'|'error'|... }
|
|
41
|
+
*
|
|
42
|
+
* ── cellEditorParams reference ────────────────────────────────────────────────
|
|
43
|
+
* SelectEditor: { options: ['A','B'] | [{ value, label }], placeholder:'Select...' }
|
|
44
|
+
* AutocompleteEditor: { options: ['A','B'] | [{ value, label }], placeholder:'Search...' }
|
|
45
|
+
* CheckboxEditor: { color:'primary'|'secondary'|'success'|'error' }
|
|
46
|
+
* DateEditor: { min:'2020-01-01', max:'2099-12-31' }
|
|
47
|
+
* NumberEditor: { min:0, max:100, step:1, decimals:2 }
|
|
48
|
+
* MultiSelectEditor: Static options via settings; overridable with async code.
|
|
49
|
+
* options — static array: string[] | object[] (configured in column settings)
|
|
50
|
+
* asyncFetchOptions — async (searchTerm?) => object[] (code override, takes precedence)
|
|
51
|
+
* isSingle — boolean, default false (multi-select)
|
|
52
|
+
* fieldName — string | string[] property path(s) to use as label (default 'name')
|
|
53
|
+
* groupByField — string property path to group options by
|
|
54
|
+
* targetValue — string | string[] property path(s) to extract as final getValue() result
|
|
55
|
+
*/
|
|
56
|
+
|
|
57
|
+
import { forwardRef, useImperativeHandle, useRef, useState, useEffect } from 'react'
|
|
58
|
+
import {
|
|
59
|
+
Chip, Box, LinearProgress, Typography, Avatar,
|
|
60
|
+
Checkbox, Select, MenuItem, TextField, Autocomplete,
|
|
61
|
+
} from '@mui/material'
|
|
62
|
+
import {
|
|
63
|
+
CheckCircleOutlined, CancelOutlined, OpenInNew,
|
|
64
|
+
} from '@mui/icons-material'
|
|
65
|
+
import { resolveIcon } from 'services/builderHelper/iconResolver'
|
|
66
|
+
|
|
67
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
68
|
+
// Helpers
|
|
69
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
70
|
+
|
|
71
|
+
const MUI_COLOR_MAP = {
|
|
72
|
+
success: 'success', error: 'error', warning: 'warning',
|
|
73
|
+
info: 'info', primary: 'primary', secondary: 'secondary', default: 'default',
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function normaliseMuiColor(c) { return MUI_COLOR_MAP[c] ?? 'default' }
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Normalise a cell value to a non-empty array of primitives.
|
|
80
|
+
* Handles: undefined, null, '', single value, array.
|
|
81
|
+
* Objects are skipped — use valueFormatter to extract the display string first.
|
|
82
|
+
*/
|
|
83
|
+
function toArray(value) {
|
|
84
|
+
if (value === null || value === undefined || value === '') return []
|
|
85
|
+
const arr = Array.isArray(value) ? value : [value]
|
|
86
|
+
return arr.filter(v => v !== null && v !== undefined && v !== '' && typeof v !== 'object')
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Resolve the display value for a renderer.
|
|
91
|
+
* AG Grid passes the RAW value as `value` and the valueFormatter result as `valueFormatted`.
|
|
92
|
+
* Prefer `valueFormatted` so formatters that return arrays of strings are honoured.
|
|
93
|
+
*/
|
|
94
|
+
function resolveDisplay(value, valueFormatted) {
|
|
95
|
+
// If formatter returned something useful (string or array), use it
|
|
96
|
+
if (valueFormatted !== null && valueFormatted !== undefined && valueFormatted !== '') {
|
|
97
|
+
return valueFormatted
|
|
98
|
+
}
|
|
99
|
+
return value
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
103
|
+
// ── Cell Renderers ────────────────────────────────────────────────────────────
|
|
104
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* ChipRenderer
|
|
108
|
+
* Renders a MUI Chip whose color is looked up from `colorMap[value]`.
|
|
109
|
+
* colorMap values should be MUI palette keys: success | error | warning | info | primary | secondary | default
|
|
110
|
+
*/
|
|
111
|
+
export function ChipRenderer({ value, valueFormatted, colDef }) {
|
|
112
|
+
const p = colDef?.cellRendererParams ?? {}
|
|
113
|
+
const items = toArray(resolveDisplay(value, valueFormatted))
|
|
114
|
+
if (!items.length) return null
|
|
115
|
+
return (
|
|
116
|
+
<Box sx={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap', gap: 0.5, height: '100%' }}>
|
|
117
|
+
{items.map((item, i) => (
|
|
118
|
+
<Chip
|
|
119
|
+
key={i}
|
|
120
|
+
label={String(item)}
|
|
121
|
+
color={normaliseMuiColor(p.colorMap?.[item] ?? p.defaultColor)}
|
|
122
|
+
size={p.size ?? 'small'}
|
|
123
|
+
variant={p.variant ?? 'filled'}
|
|
124
|
+
/>
|
|
125
|
+
))}
|
|
126
|
+
</Box>
|
|
127
|
+
)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* BooleanRenderer
|
|
132
|
+
* Shows a check or cross icon for truthy/falsy values.
|
|
133
|
+
*/
|
|
134
|
+
export function BooleanRenderer({ value, valueFormatted, colDef }) {
|
|
135
|
+
const p = colDef?.cellRendererParams ?? {}
|
|
136
|
+
const display = resolveDisplay(value, valueFormatted)
|
|
137
|
+
// For arrays use the first element; an array itself is truthy so unwrap first
|
|
138
|
+
const scalar = Array.isArray(display) ? display[0] : display
|
|
139
|
+
const isTrue = Boolean(scalar)
|
|
140
|
+
const TrueIcon = resolveIcon(p.trueIcon ?? 'CheckCircleOutlined') ?? CheckCircleOutlined
|
|
141
|
+
const FalseIcon = resolveIcon(p.falseIcon ?? 'CancelOutlined') ?? CancelOutlined
|
|
142
|
+
const Icon = isTrue ? TrueIcon : FalseIcon
|
|
143
|
+
const color = isTrue ? (p.trueColor ?? 'success.main') : (p.falseColor ?? 'error.main')
|
|
144
|
+
return (
|
|
145
|
+
<Box sx={{ display: 'flex', alignItems: 'center', height: '100%' }}>
|
|
146
|
+
<Icon sx={{ fontSize: 18, color }} />
|
|
147
|
+
</Box>
|
|
148
|
+
)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* LinkRenderer
|
|
153
|
+
* Renders the cell value as a hyperlink.
|
|
154
|
+
* href is resolved from: colDef.cellRendererParams.href (static)
|
|
155
|
+
* OR colDef.cellRendererParams.hrefField (row field name)
|
|
156
|
+
* OR the cell value itself (if it looks like a URL).
|
|
157
|
+
*/
|
|
158
|
+
export function LinkRenderer({ value, valueFormatted, data, colDef }) {
|
|
159
|
+
const p = colDef?.cellRendererParams ?? {}
|
|
160
|
+
const display = resolveDisplay(value, valueFormatted)
|
|
161
|
+
// Static href / hrefField always renders a single link regardless of value type
|
|
162
|
+
const staticHref = p.href ?? (p.hrefField ? data?.[p.hrefField] : null)
|
|
163
|
+
const items = staticHref ? [{ href: staticHref, label: p.label ?? (Array.isArray(display) ? display.join(', ') : display) }]
|
|
164
|
+
: toArray(display).map(v => ({ href: String(v), label: p.label ?? v }))
|
|
165
|
+
if (!items.length) return null
|
|
166
|
+
return (
|
|
167
|
+
<Box sx={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap', gap: 0.5, height: '100%' }}>
|
|
168
|
+
{items.map((item, i) => (
|
|
169
|
+
<a
|
|
170
|
+
key={i}
|
|
171
|
+
href={String(item.href)}
|
|
172
|
+
target={p.target ?? '_blank'}
|
|
173
|
+
rel='noreferrer'
|
|
174
|
+
style={{ display: 'inline-flex', alignItems: 'center', gap: 4, color: 'inherit', textDecoration: 'underline' }}
|
|
175
|
+
onClick={e => e.stopPropagation()}
|
|
176
|
+
>
|
|
177
|
+
{item.label}
|
|
178
|
+
{(p.target ?? '_blank') === '_blank' && <OpenInNew sx={{ fontSize: 12 }} />}
|
|
179
|
+
</a>
|
|
180
|
+
))}
|
|
181
|
+
</Box>
|
|
182
|
+
)
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* CurrencyRenderer
|
|
187
|
+
* Formats the value as a number with a prefix, suffix, and decimal places.
|
|
188
|
+
*/
|
|
189
|
+
export function CurrencyRenderer({ value, valueFormatted, colDef }) {
|
|
190
|
+
const p = colDef?.cellRendererParams ?? {}
|
|
191
|
+
const display = resolveDisplay(value, valueFormatted)
|
|
192
|
+
// Use first element if array
|
|
193
|
+
const scalar = Array.isArray(display) ? display[0] : display
|
|
194
|
+
if (scalar === null || scalar === undefined || scalar === '') return null
|
|
195
|
+
const num = Number(scalar)
|
|
196
|
+
if (isNaN(num)) return <span>{String(scalar)}</span>
|
|
197
|
+
const decimals = p.decimals ?? 2
|
|
198
|
+
const formatted = num.toLocaleString(p.locale ?? 'en-US', {
|
|
199
|
+
minimumFractionDigits: decimals,
|
|
200
|
+
maximumFractionDigits: decimals,
|
|
201
|
+
})
|
|
202
|
+
return (
|
|
203
|
+
<Box sx={{ display: 'flex', alignItems: 'center', height: '100%', justifyContent: 'flex-end' }}>
|
|
204
|
+
<span>{(p.prefix ?? '') + formatted + (p.suffix ?? '')}</span>
|
|
205
|
+
</Box>
|
|
206
|
+
)
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* DateRenderer
|
|
211
|
+
* Formats the value as a localised date string.
|
|
212
|
+
* format: 'short' | 'medium' | 'long' | 'iso' | Intl.DateTimeFormat options object
|
|
213
|
+
*/
|
|
214
|
+
export function DateRenderer({ value, valueFormatted, colDef }) {
|
|
215
|
+
const p = colDef?.cellRendererParams ?? {}
|
|
216
|
+
const display = resolveDisplay(value, valueFormatted)
|
|
217
|
+
// Use first element if array
|
|
218
|
+
const scalar = Array.isArray(display) ? display[0] : display
|
|
219
|
+
if (!scalar) return null
|
|
220
|
+
try {
|
|
221
|
+
const date = new Date(scalar)
|
|
222
|
+
if (isNaN(date.getTime())) return <span>{String(scalar)}</span>
|
|
223
|
+
|
|
224
|
+
let display
|
|
225
|
+
const fmt = p.format ?? 'short'
|
|
226
|
+
if (fmt === 'iso') {
|
|
227
|
+
display = date.toISOString().slice(0, 10)
|
|
228
|
+
} else {
|
|
229
|
+
const presets = {
|
|
230
|
+
short: { year: 'numeric', month: 'short', day: '2-digit' },
|
|
231
|
+
medium: { year: 'numeric', month: 'long', day: '2-digit' },
|
|
232
|
+
long: { year: 'numeric', month: 'long', day: '2-digit', weekday: 'long' },
|
|
233
|
+
}
|
|
234
|
+
const opts = (typeof fmt === 'object' && fmt !== null) ? fmt : (presets[fmt] ?? presets.short)
|
|
235
|
+
display = date.toLocaleDateString(p.locale ?? undefined, opts)
|
|
236
|
+
}
|
|
237
|
+
return (
|
|
238
|
+
<Box sx={{ display: 'flex', alignItems: 'center', height: '100%' }}>
|
|
239
|
+
<span>{display}</span>
|
|
240
|
+
</Box>
|
|
241
|
+
)
|
|
242
|
+
} catch {
|
|
243
|
+
return <span>{String(scalar)}</span>
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* ProgressRenderer
|
|
249
|
+
* Renders value as a LinearProgress bar (0–max, default max=100).
|
|
250
|
+
*/
|
|
251
|
+
export function ProgressRenderer({ value, valueFormatted, colDef }) {
|
|
252
|
+
const p = colDef?.cellRendererParams ?? {}
|
|
253
|
+
const max = p.max ?? 100
|
|
254
|
+
const display = resolveDisplay(value, valueFormatted)
|
|
255
|
+
// Use first element if array
|
|
256
|
+
const scalar = Array.isArray(display) ? display[0] : display
|
|
257
|
+
const num = Math.min(Math.max(Number(scalar) || 0, 0), max)
|
|
258
|
+
const pct = (num / max) * 100
|
|
259
|
+
const color = p.color ?? 'primary'
|
|
260
|
+
return (
|
|
261
|
+
<Box sx={{ display: 'flex', alignItems: 'center', height: '100%', gap: 1, width: '100%', pr: 1 }}>
|
|
262
|
+
<LinearProgress
|
|
263
|
+
variant='determinate'
|
|
264
|
+
value={pct}
|
|
265
|
+
color={color}
|
|
266
|
+
sx={{ flexGrow: 1, borderRadius: 1, height: 6 }}
|
|
267
|
+
/>
|
|
268
|
+
{p.showLabel !== false && (
|
|
269
|
+
<Typography variant='caption' sx={{ whiteSpace: 'nowrap', minWidth: 32, textAlign: 'right' }}>
|
|
270
|
+
{num}{p.unit ?? ''}
|
|
271
|
+
</Typography>
|
|
272
|
+
)}
|
|
273
|
+
</Box>
|
|
274
|
+
)
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* AvatarRenderer
|
|
279
|
+
* Renders an Avatar: image from `srcField` row property, or initials from value.
|
|
280
|
+
*/
|
|
281
|
+
export function AvatarRenderer({ value, valueFormatted, data, colDef }) {
|
|
282
|
+
const p = colDef?.cellRendererParams ?? {}
|
|
283
|
+
const src = p.srcField ? data?.[p.srcField] : null
|
|
284
|
+
const size = p.size ?? 28
|
|
285
|
+
const display = resolveDisplay(value, valueFormatted)
|
|
286
|
+
// Use first element if array
|
|
287
|
+
const scalar = Array.isArray(display) ? display[0] : display
|
|
288
|
+
const initials = scalar
|
|
289
|
+
? String(scalar).split(' ').slice(0, 2).map(w => w[0]).join('').toUpperCase()
|
|
290
|
+
: '?'
|
|
291
|
+
return (
|
|
292
|
+
<Box sx={{ display: 'flex', alignItems: 'center', height: '100%', gap: 1 }}>
|
|
293
|
+
<Avatar
|
|
294
|
+
src={src ?? undefined}
|
|
295
|
+
sx={{
|
|
296
|
+
width: size, height: size, fontSize: size * 0.4,
|
|
297
|
+
borderRadius: p.shape === 'square' ? 1 : '50%',
|
|
298
|
+
}}
|
|
299
|
+
>
|
|
300
|
+
{!src && initials}
|
|
301
|
+
</Avatar>
|
|
302
|
+
{scalar && <span>{String(scalar)}</span>}
|
|
303
|
+
</Box>
|
|
304
|
+
)
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* IconRenderer
|
|
309
|
+
* Renders an MUI icon whose name is the cell value.
|
|
310
|
+
* e.g. value = 'CheckCircle' renders the CheckCircle icon.
|
|
311
|
+
*/
|
|
312
|
+
export function IconRenderer({ value, valueFormatted, colDef }) {
|
|
313
|
+
const p = colDef?.cellRendererParams ?? {}
|
|
314
|
+
const items = toArray(resolveDisplay(value, valueFormatted))
|
|
315
|
+
if (!items.length) return null
|
|
316
|
+
return (
|
|
317
|
+
<Box sx={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap', gap: 0.5, height: '100%' }}>
|
|
318
|
+
{items.map((item, i) => {
|
|
319
|
+
const Icon = resolveIcon(String(item))
|
|
320
|
+
return Icon
|
|
321
|
+
? <Icon key={i} fontSize={p.size ?? 'small'} color={p.color ?? 'inherit'} />
|
|
322
|
+
: <span key={i}>{String(item)}</span>
|
|
323
|
+
})}
|
|
324
|
+
</Box>
|
|
325
|
+
)
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
329
|
+
// ── Cell Editors ─────────────────────────────────────────────────────────────
|
|
330
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* SelectEditor
|
|
334
|
+
* A MUI Select populated from cellEditorParams.options.
|
|
335
|
+
* options: string[] | { value, label }[]
|
|
336
|
+
*/
|
|
337
|
+
export const SelectEditor = forwardRef(function SelectEditor(props, ref) {
|
|
338
|
+
const p = props.colDef?.cellEditorParams ?? {}
|
|
339
|
+
const rawOptions = p.options ?? []
|
|
340
|
+
const options = rawOptions.map(o =>
|
|
341
|
+
typeof o === 'object' && o !== null ? o : { value: o, label: String(o) }
|
|
342
|
+
)
|
|
343
|
+
|
|
344
|
+
const [value, setValue] = useState(props.value ?? '')
|
|
345
|
+
|
|
346
|
+
useImperativeHandle(ref, () => ({
|
|
347
|
+
getValue() { return value },
|
|
348
|
+
isCancelBeforeStart() { return false },
|
|
349
|
+
}))
|
|
350
|
+
|
|
351
|
+
return (
|
|
352
|
+
<Select
|
|
353
|
+
value={value}
|
|
354
|
+
onChange={e => setValue(e.target.value)}
|
|
355
|
+
size='small'
|
|
356
|
+
autoFocus
|
|
357
|
+
open
|
|
358
|
+
displayEmpty
|
|
359
|
+
sx={{ width: '100%', height: '100%', '& .MuiSelect-select': { py: 0.5 } }}
|
|
360
|
+
>
|
|
361
|
+
{p.placeholder && <MenuItem value=''><em>{p.placeholder}</em></MenuItem>}
|
|
362
|
+
{options.map(o => (
|
|
363
|
+
<MenuItem key={o.value} value={o.value}>{o.label}</MenuItem>
|
|
364
|
+
))}
|
|
365
|
+
</Select>
|
|
366
|
+
)
|
|
367
|
+
})
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* AutocompleteEditor
|
|
371
|
+
* A MUI Autocomplete (searchable) populated from cellEditorParams.options.
|
|
372
|
+
*/
|
|
373
|
+
export const AutocompleteEditor = forwardRef(function AutocompleteEditor(props, ref) {
|
|
374
|
+
const p = props.colDef?.cellEditorParams ?? {}
|
|
375
|
+
const rawOptions = p.options ?? []
|
|
376
|
+
const options = rawOptions.map(o =>
|
|
377
|
+
typeof o === 'object' && o !== null ? o : { value: o, label: String(o) }
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
const initialOpt = options.find(o => o.value === props.value) ?? { value: props.value ?? '', label: String(props.value ?? '') }
|
|
381
|
+
const [selected, setSelected] = useState(initialOpt)
|
|
382
|
+
const inputRef = useRef(null)
|
|
383
|
+
|
|
384
|
+
useEffect(() => { setTimeout(() => inputRef.current?.focus(), 0) }, [])
|
|
385
|
+
|
|
386
|
+
useImperativeHandle(ref, () => ({
|
|
387
|
+
getValue() { return selected?.value ?? '' },
|
|
388
|
+
isCancelBeforeStart() { return false },
|
|
389
|
+
}))
|
|
390
|
+
|
|
391
|
+
return (
|
|
392
|
+
<Autocomplete
|
|
393
|
+
options={options}
|
|
394
|
+
value={selected}
|
|
395
|
+
onChange={(_, newVal) => setSelected(newVal ?? { value: '', label: '' })}
|
|
396
|
+
getOptionLabel={o => o?.label ?? ''}
|
|
397
|
+
isOptionEqualToValue={(o, v) => o?.value === v?.value}
|
|
398
|
+
openOnFocus
|
|
399
|
+
disableClearable
|
|
400
|
+
size='small'
|
|
401
|
+
sx={{ width: '100%' }}
|
|
402
|
+
renderInput={params => (
|
|
403
|
+
<TextField
|
|
404
|
+
{...params}
|
|
405
|
+
inputRef={inputRef}
|
|
406
|
+
placeholder={p.placeholder ?? 'Search...'}
|
|
407
|
+
variant='outlined'
|
|
408
|
+
size='small'
|
|
409
|
+
sx={{ '& .MuiInputBase-root': { height: '100%' } }}
|
|
410
|
+
/>
|
|
411
|
+
)}
|
|
412
|
+
/>
|
|
413
|
+
)
|
|
414
|
+
})
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* CheckboxEditor
|
|
418
|
+
* Toggles a boolean value in-cell.
|
|
419
|
+
*/
|
|
420
|
+
export const CheckboxEditor = forwardRef(function CheckboxEditor(props, ref) {
|
|
421
|
+
const p = props.colDef?.cellEditorParams ?? {}
|
|
422
|
+
const [checked, setChecked] = useState(Boolean(props.value))
|
|
423
|
+
|
|
424
|
+
useImperativeHandle(ref, () => ({
|
|
425
|
+
getValue() { return checked },
|
|
426
|
+
isCancelBeforeStart() { return false },
|
|
427
|
+
}))
|
|
428
|
+
|
|
429
|
+
return (
|
|
430
|
+
<Box sx={{ display: 'flex', alignItems: 'center', height: '100%', px: 0.5 }}>
|
|
431
|
+
<Checkbox
|
|
432
|
+
checked={checked}
|
|
433
|
+
onChange={e => setChecked(e.target.checked)}
|
|
434
|
+
color={p.color ?? 'primary'}
|
|
435
|
+
size='small'
|
|
436
|
+
autoFocus
|
|
437
|
+
/>
|
|
438
|
+
</Box>
|
|
439
|
+
)
|
|
440
|
+
})
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* DateEditor
|
|
444
|
+
* Native date input — lightweight, no extra MUI dependency.
|
|
445
|
+
* Stores value as ISO date string (YYYY-MM-DD).
|
|
446
|
+
*/
|
|
447
|
+
export const DateEditor = forwardRef(function DateEditor(props, ref) {
|
|
448
|
+
const p = props.colDef?.cellEditorParams ?? {}
|
|
449
|
+
// Normalise stored value to YYYY-MM-DD for the input
|
|
450
|
+
const toInputValue = v => {
|
|
451
|
+
if (!v) return ''
|
|
452
|
+
try {
|
|
453
|
+
const d = new Date(v)
|
|
454
|
+
if (isNaN(d.getTime())) return v
|
|
455
|
+
return d.toISOString().slice(0, 10)
|
|
456
|
+
} catch { return v }
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
const [value, setValue] = useState(toInputValue(props.value))
|
|
460
|
+
const inputRef = useRef(null)
|
|
461
|
+
useEffect(() => { inputRef.current?.focus() }, [])
|
|
462
|
+
|
|
463
|
+
useImperativeHandle(ref, () => ({
|
|
464
|
+
getValue() { return value },
|
|
465
|
+
isCancelBeforeStart() { return false },
|
|
466
|
+
}))
|
|
467
|
+
|
|
468
|
+
return (
|
|
469
|
+
<input
|
|
470
|
+
ref={inputRef}
|
|
471
|
+
type='date'
|
|
472
|
+
value={value}
|
|
473
|
+
min={p.min ?? undefined}
|
|
474
|
+
max={p.max ?? undefined}
|
|
475
|
+
onChange={e => setValue(e.target.value)}
|
|
476
|
+
style={{
|
|
477
|
+
width: '100%', height: '100%', border: 'none', outline: 'none',
|
|
478
|
+
padding: '0 8px', fontSize: 13, background: 'transparent',
|
|
479
|
+
boxSizing: 'border-box', cursor: 'pointer',
|
|
480
|
+
}}
|
|
481
|
+
/>
|
|
482
|
+
)
|
|
483
|
+
})
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* NumberEditor
|
|
487
|
+
* Numeric text input with optional min / max / step / decimals.
|
|
488
|
+
*/
|
|
489
|
+
export const NumberEditor = forwardRef(function NumberEditor(props, ref) {
|
|
490
|
+
const p = props.colDef?.cellEditorParams ?? {}
|
|
491
|
+
const [value, setValue] = useState(props.value ?? '')
|
|
492
|
+
const inputRef = useRef(null)
|
|
493
|
+
useEffect(() => { inputRef.current?.focus(); inputRef.current?.select() }, [])
|
|
494
|
+
|
|
495
|
+
useImperativeHandle(ref, () => ({
|
|
496
|
+
getValue() {
|
|
497
|
+
const num = parseFloat(value)
|
|
498
|
+
if (isNaN(num)) return props.value ?? null
|
|
499
|
+
const dec = p.decimals ?? null
|
|
500
|
+
return dec !== null ? parseFloat(num.toFixed(dec)) : num
|
|
501
|
+
},
|
|
502
|
+
isCancelBeforeStart() { return false },
|
|
503
|
+
}))
|
|
504
|
+
|
|
505
|
+
return (
|
|
506
|
+
<input
|
|
507
|
+
ref={inputRef}
|
|
508
|
+
type='number'
|
|
509
|
+
value={value}
|
|
510
|
+
min={p.min ?? undefined}
|
|
511
|
+
max={p.max ?? undefined}
|
|
512
|
+
step={p.step ?? 'any'}
|
|
513
|
+
onChange={e => setValue(e.target.value)}
|
|
514
|
+
style={{
|
|
515
|
+
width: '100%', height: '100%', border: 'none', outline: 'none',
|
|
516
|
+
padding: '0 8px', fontSize: 13, background: 'transparent',
|
|
517
|
+
boxSizing: 'border-box', textAlign: 'right',
|
|
518
|
+
}}
|
|
519
|
+
/>
|
|
520
|
+
)
|
|
521
|
+
})
|
|
522
|
+
|
|
523
|
+
/**
|
|
524
|
+
* MultiSelectEditor
|
|
525
|
+
*
|
|
526
|
+
* Rendered as an AG Grid popup editor (isPopup = true).
|
|
527
|
+
* AG Grid's popup mode means it does NOT close the editor when the user clicks
|
|
528
|
+
* inside it — no event propagation fights needed.
|
|
529
|
+
*
|
|
530
|
+
* cellEditorParams shape:
|
|
531
|
+
* options string[] | object[] static options
|
|
532
|
+
* asyncFetchOptions async (search?: string) => [] dynamic options (takes precedence)
|
|
533
|
+
* isSingle boolean single vs multi default: false
|
|
534
|
+
* fieldName string | string[] label path default: 'name'
|
|
535
|
+
* groupByField string group-by path
|
|
536
|
+
* targetValue string | string[] getValue() extraction path
|
|
537
|
+
*/
|
|
538
|
+
export const MultiSelectEditor = forwardRef(function MultiSelectEditor(props, ref) {
|
|
539
|
+
const rawCep = props.colDef?.cellEditorParams
|
|
540
|
+
const cepObj = (rawCep && typeof rawCep === 'object' && typeof rawCep !== 'function') ? rawCep : {}
|
|
541
|
+
|
|
542
|
+
// Params come from props root when cellEditorParams was a function (AG Grid merges result),
|
|
543
|
+
// or from cepObj when it was a plain object.
|
|
544
|
+
const asyncFetchOptions = props.asyncFetchOptions ?? cepObj.asyncFetchOptions ?? null
|
|
545
|
+
const isSingle = props.isSingle ?? cepObj.isSingle ?? false
|
|
546
|
+
const fieldName = props.fieldName ?? cepObj.fieldName ?? 'name'
|
|
547
|
+
const targetValue = props.targetValue ?? cepObj.targetValue ?? null
|
|
548
|
+
const groupByField = props.groupByField ?? cepObj.groupByField ?? null
|
|
549
|
+
const staticOptions = props.options ?? cepObj.options ?? []
|
|
550
|
+
|
|
551
|
+
// getViewerContext() returns the latest viewerContext from DataGridRenderer —
|
|
552
|
+
// used to provide fresh data / setData / reportRefs to asyncFetchOptions.
|
|
553
|
+
const getViewerContext = props.context?.getViewerContext ?? (() => ({}))
|
|
554
|
+
|
|
555
|
+
const initialValue = props.value ?? (isSingle ? null : [])
|
|
556
|
+
const selectedRef = useRef(initialValue) // sync ref for getValue()
|
|
557
|
+
const [selected, setSelected] = useState(initialValue)
|
|
558
|
+
const [options, setOptions] = useState(staticOptions)
|
|
559
|
+
const [search, setSearch] = useState('')
|
|
560
|
+
const [debSearch, setDebSearch] = useState('')
|
|
561
|
+
const [loading, setLoading] = useState(false)
|
|
562
|
+
const searchRef = useRef(null)
|
|
563
|
+
|
|
564
|
+
// Build the second-arg scope for asyncFetchOptions — mirrors what convertStringToFunction injects.
|
|
565
|
+
// This lets users write: async (search, { data, setData, dataRef, reportRefs }) => { ... }
|
|
566
|
+
// and get live values even when called without the second argument.
|
|
567
|
+
const buildAsyncScope = () => {
|
|
568
|
+
const vCtx = getViewerContext()
|
|
569
|
+
return {
|
|
570
|
+
data: vCtx.data ?? {},
|
|
571
|
+
setData: vCtx.setData ?? (() => {}),
|
|
572
|
+
dataRef: vCtx.dataRef ?? { current: {} },
|
|
573
|
+
reportRefs: vCtx.reportRefs ?? { current: {} },
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
useEffect(() => { setTimeout(() => searchRef.current?.focus(), 0) }, [])
|
|
578
|
+
|
|
579
|
+
// Debounce search
|
|
580
|
+
useEffect(() => {
|
|
581
|
+
const t = setTimeout(() => setDebSearch(search), 300)
|
|
582
|
+
return () => clearTimeout(t)
|
|
583
|
+
}, [search])
|
|
584
|
+
|
|
585
|
+
// Initial async fetch
|
|
586
|
+
useEffect(() => {
|
|
587
|
+
if (!asyncFetchOptions) return
|
|
588
|
+
setLoading(true)
|
|
589
|
+
Promise.resolve(asyncFetchOptions('', buildAsyncScope()))
|
|
590
|
+
.then(res => setOptions(Array.isArray(res) ? res : []))
|
|
591
|
+
.catch(e => console.error('[MultiSelectEditor] asyncFetchOptions error:', e))
|
|
592
|
+
.finally(() => setLoading(false))
|
|
593
|
+
}, []) // eslint-disable-line react-hooks/exhaustive-deps
|
|
594
|
+
|
|
595
|
+
// Re-fetch on debounced search (async only; static filtered client-side below)
|
|
596
|
+
useEffect(() => {
|
|
597
|
+
if (!asyncFetchOptions || debSearch === '') return
|
|
598
|
+
setLoading(true)
|
|
599
|
+
Promise.resolve(asyncFetchOptions(debSearch, buildAsyncScope()))
|
|
600
|
+
.then(res => setOptions(Array.isArray(res) ? res : []))
|
|
601
|
+
.catch(e => console.error('[MultiSelectEditor] asyncFetchOptions search error:', e))
|
|
602
|
+
.finally(() => setLoading(false))
|
|
603
|
+
}, [debSearch]) // eslint-disable-line react-hooks/exhaustive-deps
|
|
604
|
+
|
|
605
|
+
function getNestedProperty(obj, path) {
|
|
606
|
+
if (!path || !obj) return obj
|
|
607
|
+
if (Array.isArray(path)) {
|
|
608
|
+
return path.map(k => k.split('.').reduce((a, p) => a?.[p], obj)).filter(Boolean).join(' - ')
|
|
609
|
+
}
|
|
610
|
+
return path.split('.').reduce((a, k) => a?.[k], obj)
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
function getLabel(opt) {
|
|
614
|
+
if (opt === null || opt === undefined) return ''
|
|
615
|
+
if (typeof opt !== 'object') return String(opt)
|
|
616
|
+
const label = Array.isArray(fieldName)
|
|
617
|
+
? fieldName.map(f => getNestedProperty(opt, f)).filter(Boolean).join(' - ')
|
|
618
|
+
: (getNestedProperty(opt, fieldName) ?? opt?.name ?? '')
|
|
619
|
+
return label != null ? String(label) : ''
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
function optionId(opt) {
|
|
623
|
+
return opt?.id ?? JSON.stringify(opt)
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
function isOptSelected(opt) {
|
|
627
|
+
if (isSingle) return optionId(selectedRef.current) === optionId(opt)
|
|
628
|
+
return (Array.isArray(selectedRef.current) ? selectedRef.current : [])
|
|
629
|
+
.some(s => optionId(s) === optionId(opt))
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
// Compute the final committed value — mirrors what getValue() exposes via the ref.
|
|
633
|
+
// Called directly inside commit() because AG Grid v33 React destroys the popup
|
|
634
|
+
// component before invoking getValue() through the ref, so we can't rely on that path.
|
|
635
|
+
const getEditorValue = () => {
|
|
636
|
+
const val = selectedRef.current
|
|
637
|
+
if (targetValue != null && val != null) {
|
|
638
|
+
if (Array.isArray(val)) return val.map(v => getNestedProperty(v, targetValue))
|
|
639
|
+
return getNestedProperty(val, targetValue)
|
|
640
|
+
}
|
|
641
|
+
return val
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
useImperativeHandle(ref, () => ({
|
|
645
|
+
// Kept for AG Grid compatibility — may be called in non-popup scenarios.
|
|
646
|
+
getValue() {
|
|
647
|
+
const result = getEditorValue()
|
|
648
|
+
console.log('[MultiSelectEditor] getValue() via ref → returning:', result)
|
|
649
|
+
return result
|
|
650
|
+
},
|
|
651
|
+
isCancelBeforeStart() { return false },
|
|
652
|
+
isPopup() { return true },
|
|
653
|
+
getPopupPosition() { return 'under' },
|
|
654
|
+
}))
|
|
655
|
+
|
|
656
|
+
const commit = () => {
|
|
657
|
+
const value = getEditorValue()
|
|
658
|
+
console.log('[MultiSelectEditor] commit() — final value:', value, 'field:', props.colDef?.field)
|
|
659
|
+
|
|
660
|
+
// AG Grid v33 React destroys popup editors before calling getValue() through the ref.
|
|
661
|
+
// Work around by setting the data value directly, which triggers valueSetter +
|
|
662
|
+
// onCellValueChanged exactly the same as the normal AG Grid commit flow.
|
|
663
|
+
if (props.node && props.colDef?.field) {
|
|
664
|
+
props.node.setDataValue(props.colDef.field, value)
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
// Temporarily remove valueSetter before stopEditing(true) so AG Grid's cancel/revert
|
|
668
|
+
// path does not call it with the old (pre-edit) value and overwrite what we just committed.
|
|
669
|
+
// The revert call is synchronous, so restoring immediately after is safe.
|
|
670
|
+
const savedVS = props.colDef?.valueSetter
|
|
671
|
+
if (props.colDef) delete props.colDef.valueSetter
|
|
672
|
+
|
|
673
|
+
if (typeof props.stopEditing === 'function') {
|
|
674
|
+
props.stopEditing(true)
|
|
675
|
+
} else {
|
|
676
|
+
props.api?.stopEditing?.(true)
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
if (props.colDef && savedVS) props.colDef.valueSetter = savedVS
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
const handleSelect = (opt) => {
|
|
683
|
+
let next
|
|
684
|
+
if (isSingle) {
|
|
685
|
+
next = opt
|
|
686
|
+
} else {
|
|
687
|
+
const cur = Array.isArray(selectedRef.current) ? selectedRef.current : []
|
|
688
|
+
next = isOptSelected(opt)
|
|
689
|
+
? cur.filter(s => optionId(s) !== optionId(opt))
|
|
690
|
+
: [...cur, opt]
|
|
691
|
+
}
|
|
692
|
+
selectedRef.current = next
|
|
693
|
+
setSelected(next)
|
|
694
|
+
console.log('[MultiSelectEditor] handleSelect → next:', next, 'isSingle:', isSingle)
|
|
695
|
+
if (isSingle) setTimeout(commit, 0)
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
// Static options: filter client-side; async options: server filters via debSearch
|
|
699
|
+
const visibleOptions = asyncFetchOptions
|
|
700
|
+
? options
|
|
701
|
+
: options.filter(opt => getLabel(opt).toLowerCase().includes(search.toLowerCase()))
|
|
702
|
+
|
|
703
|
+
const grouped = groupByField
|
|
704
|
+
? visibleOptions.reduce((acc, opt) => {
|
|
705
|
+
const g = getNestedProperty(opt, groupByField) ?? 'Other'
|
|
706
|
+
;(acc[g] = acc[g] ?? []).push(opt)
|
|
707
|
+
return acc
|
|
708
|
+
}, {})
|
|
709
|
+
: null
|
|
710
|
+
|
|
711
|
+
const selectedArr = Array.isArray(selected) ? selected : []
|
|
712
|
+
|
|
713
|
+
return (
|
|
714
|
+
<Box
|
|
715
|
+
sx={{
|
|
716
|
+
width: 260,
|
|
717
|
+
maxHeight: 340,
|
|
718
|
+
bgcolor: '#fff',
|
|
719
|
+
border: '1px solid #e0e0e0',
|
|
720
|
+
borderRadius: 1,
|
|
721
|
+
boxShadow: '0 4px 16px rgba(0,0,0,0.18)',
|
|
722
|
+
display: 'flex',
|
|
723
|
+
flexDirection: 'column',
|
|
724
|
+
overflow: 'hidden',
|
|
725
|
+
}}
|
|
726
|
+
>
|
|
727
|
+
{/* Search */}
|
|
728
|
+
<Box sx={{ p: 0.75, borderBottom: '1px solid #f0f0f0' }}>
|
|
729
|
+
<input
|
|
730
|
+
ref={searchRef}
|
|
731
|
+
value={search}
|
|
732
|
+
onChange={e => setSearch(e.target.value)}
|
|
733
|
+
placeholder='Search…'
|
|
734
|
+
style={{
|
|
735
|
+
width: '100%', border: '1px solid #e0e0e0', borderRadius: 4,
|
|
736
|
+
padding: '4px 8px', fontSize: 13, outline: 'none', boxSizing: 'border-box',
|
|
737
|
+
}}
|
|
738
|
+
/>
|
|
739
|
+
</Box>
|
|
740
|
+
|
|
741
|
+
{/* Options */}
|
|
742
|
+
<Box sx={{ overflowY: 'auto', flex: 1 }}>
|
|
743
|
+
{loading && <Typography sx={{ p: 1, fontSize: 12, color: '#999' }}>Loading…</Typography>}
|
|
744
|
+
{!loading && visibleOptions.length === 0 && (
|
|
745
|
+
<Typography sx={{ p: 1, fontSize: 12, color: '#999' }}>No options</Typography>
|
|
746
|
+
)}
|
|
747
|
+
{!loading && (grouped
|
|
748
|
+
? Object.entries(grouped).map(([group, opts]) => (
|
|
749
|
+
<Box key={group}>
|
|
750
|
+
<Typography sx={{ px: 1.5, py: 0.5, fontSize: 11, fontWeight: 700, color: '#888', textTransform: 'uppercase', letterSpacing: '0.05em', bgcolor: '#fafafa' }}>
|
|
751
|
+
{group}
|
|
752
|
+
</Typography>
|
|
753
|
+
{opts.map((opt, i) => (
|
|
754
|
+
<OptionRow key={optionId(opt) ?? i} opt={opt} selected={isOptSelected(opt)} label={getLabel(opt)} isSingle={isSingle} onSelect={handleSelect} />
|
|
755
|
+
))}
|
|
756
|
+
</Box>
|
|
757
|
+
))
|
|
758
|
+
: visibleOptions.map((opt, i) => (
|
|
759
|
+
<OptionRow key={optionId(opt) ?? i} opt={opt} selected={isOptSelected(opt)} label={getLabel(opt)} isSingle={isSingle} onSelect={handleSelect} />
|
|
760
|
+
))
|
|
761
|
+
)}
|
|
762
|
+
</Box>
|
|
763
|
+
|
|
764
|
+
{/* Footer — multi only */}
|
|
765
|
+
{!isSingle && (
|
|
766
|
+
<Box sx={{ p: 0.75, borderTop: '1px solid #f0f0f0', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
|
767
|
+
<Typography sx={{ fontSize: 11, color: '#888' }}>{selectedArr.length} selected</Typography>
|
|
768
|
+
<Box
|
|
769
|
+
component='button'
|
|
770
|
+
onClick={commit}
|
|
771
|
+
sx={{
|
|
772
|
+
px: 1.5, py: 0.4, fontSize: 12, fontWeight: 600,
|
|
773
|
+
bgcolor: 'primary.main', color: '#fff', border: 'none',
|
|
774
|
+
borderRadius: 1, cursor: 'pointer',
|
|
775
|
+
'&:hover': { bgcolor: 'primary.dark' },
|
|
776
|
+
}}
|
|
777
|
+
>
|
|
778
|
+
Confirm
|
|
779
|
+
</Box>
|
|
780
|
+
</Box>
|
|
781
|
+
)}
|
|
782
|
+
</Box>
|
|
783
|
+
)
|
|
784
|
+
})
|
|
785
|
+
|
|
786
|
+
function OptionRow({ opt, selected, label, isSingle, onSelect }) {
|
|
787
|
+
return (
|
|
788
|
+
<Box
|
|
789
|
+
onClick={() => onSelect(opt)}
|
|
790
|
+
sx={{
|
|
791
|
+
display: 'flex', alignItems: 'center', gap: 1,
|
|
792
|
+
px: 1.5, py: 0.6, cursor: 'pointer', fontSize: 13,
|
|
793
|
+
bgcolor: selected ? '#e8f0fe' : 'transparent',
|
|
794
|
+
'&:hover': { bgcolor: selected ? '#d2e3fc' : '#f5f5f5' },
|
|
795
|
+
}}
|
|
796
|
+
>
|
|
797
|
+
{!isSingle && <Checkbox checked={selected} size='small' sx={{ p: 0 }} readOnly tabIndex={-1} />}
|
|
798
|
+
{label}
|
|
799
|
+
</Box>
|
|
800
|
+
)
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
804
|
+
// AG Grid components map — pass this to <AgGridReact components={AG_COMPONENTS}>
|
|
805
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
806
|
+
|
|
807
|
+
export const AG_COMPONENTS = {
|
|
808
|
+
// Renderers
|
|
809
|
+
ChipRenderer,
|
|
810
|
+
BooleanRenderer,
|
|
811
|
+
LinkRenderer,
|
|
812
|
+
CurrencyRenderer,
|
|
813
|
+
DateRenderer,
|
|
814
|
+
ProgressRenderer,
|
|
815
|
+
AvatarRenderer,
|
|
816
|
+
IconRenderer,
|
|
817
|
+
// Editors
|
|
818
|
+
SelectEditor,
|
|
819
|
+
AutocompleteEditor,
|
|
820
|
+
CheckboxEditor,
|
|
821
|
+
DateEditor,
|
|
822
|
+
NumberEditor,
|
|
823
|
+
MultiSelectEditor,
|
|
824
|
+
}
|