@solidstarters/solid-core-ui 1.1.211 → 1.1.212
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/dist/components/Svg/DevDocs.tsx +9 -0
- package/dist/components/Svg/DocsSvg.tsx +9 -0
- package/dist/components/Svg/ExcelSvg.tsx +15 -0
- package/dist/components/Svg/FieldSvg.tsx +9 -0
- package/dist/components/Svg/FileSvg.tsx +18 -0
- package/dist/components/Svg/HomePageModuleSvg.tsx +179 -0
- package/dist/components/Svg/ModelSvg.tsx +9 -0
- package/dist/components/Svg/ModuleSvg.tsx +9 -0
- package/dist/components/Svg/PDFSvg.tsx +15 -0
- package/dist/components/Svg/RightArrowSvg.tsx +9 -0
- package/dist/components/Svg/SettingsSvg.tsx +9 -0
- package/dist/components/auth/AuthLayout.tsx +223 -0
- package/dist/components/auth/ForgotPasswordThankYou.tsx +33 -0
- package/dist/components/auth/GoogleAuthChecking.tsx +63 -0
- package/dist/components/auth/SolidChangeForcePassword.tsx +222 -0
- package/dist/components/auth/SolidForgotPassword.tsx +127 -0
- package/dist/components/auth/SolidInitialLoginOtp.tsx +271 -0
- package/dist/components/auth/SolidInitiateRegisterOtp.tsx +218 -0
- package/dist/components/auth/SolidLogin.d.ts.map +1 -1
- package/dist/components/auth/SolidLogin.js +14 -8
- package/dist/components/auth/SolidLogin.js.map +1 -1
- package/dist/components/auth/SolidLogin.tsx +428 -0
- package/dist/components/auth/SolidOTPVerify.tsx +133 -0
- package/dist/components/auth/SolidRegister.tsx +454 -0
- package/dist/components/auth/SolidResetPassword.tsx +194 -0
- package/dist/components/common/AuthBanner.tsx +41 -0
- package/dist/components/common/AutoCompleteField.tsx +79 -0
- package/dist/components/common/BackButton.tsx +72 -0
- package/dist/components/common/CancelButton.tsx +61 -0
- package/dist/components/common/CodeEditor.tsx +38 -0
- package/dist/components/common/CreateButton.tsx +17 -0
- package/dist/components/common/DownloadProgressToast.tsx +55 -0
- package/dist/components/common/DropzonePlaceholder.tsx +31 -0
- package/dist/components/common/DropzoneUpload.tsx +11 -0
- package/dist/components/common/FileReaderExt.tsx +20 -0
- package/dist/components/common/GeneralSettings.tsx +1225 -0
- package/dist/components/common/HeaderDynamicTitles.tsx +13 -0
- package/dist/components/common/MarkdownViewer.tsx +84 -0
- package/dist/components/common/MultipleSelectAutoCompleteField.tsx +64 -0
- package/dist/components/common/NotFound.tsx +22 -0
- package/dist/components/common/SingleSelectAutoCompleteField.tsx +73 -0
- package/dist/components/common/SocialMediaLogin.tsx +53 -0
- package/dist/components/common/SolidAdmin.tsx +6 -0
- package/dist/components/common/SolidBreadcrumb.tsx +129 -0
- package/dist/components/common/SolidExport.tsx +563 -0
- package/dist/components/common/SolidExportStepper.tsx +135 -0
- package/dist/components/common/SolidFieldTooltip.tsx +23 -0
- package/dist/components/common/SolidFormHeader.tsx +25 -0
- package/dist/components/common/SolidFormStepper.tsx +350 -0
- package/dist/components/common/SolidModuleHome.tsx +128 -0
- package/dist/components/common/SolidPopupContainer.tsx +37 -0
- package/dist/components/common/SolidSettings/LlmSettings/AnthropicProviderComponent.tsx +45 -0
- package/dist/components/common/SolidSettings/LlmSettings/OpenAiProviderComponent.tsx +45 -0
- package/dist/components/common/SolidSettings/SettingDropzoneActivePlaceholder.tsx +20 -0
- package/dist/components/common/SolidSettings/SettingsImageRemoveButton.tsx +15 -0
- package/dist/components/common/SolidSettings/SolidUploadedImage.tsx +16 -0
- package/dist/components/common/SolidThemeLink.tsx +6 -0
- package/dist/components/common/SolidThemeProvider.tsx +44 -0
- package/dist/components/common/StepperArrows/ActiveArrowStep.tsx +18 -0
- package/dist/components/common/StepperArrows/ActiveBeforeStepArrow.tsx +18 -0
- package/dist/components/common/StepperArrows/InactiveStepArrow.tsx +19 -0
- package/dist/components/common/error.tsx +30 -0
- package/dist/components/common/useHandleFormCustomButtonClick.ts +40 -0
- package/dist/components/common/useHandleListCustomButtonClick.ts +42 -0
- package/dist/components/core/chatter/SolidChatter.tsx +248 -0
- package/dist/components/core/chatter/SolidChatterAuditMessage.tsx +35 -0
- package/dist/components/core/chatter/SolidChatterCustomMessage.tsx +46 -0
- package/dist/components/core/chatter/SolidChatterDateDivider.tsx +16 -0
- package/dist/components/core/chatter/SolidChatterHeader.tsx +218 -0
- package/dist/components/core/chatter/SolidChatterMessageBox.tsx +163 -0
- package/dist/components/core/chatter/SolidMessageComposer.tsx +146 -0
- package/dist/components/core/common/AvatarWidget.tsx +55 -0
- package/dist/components/core/common/DateFieldViewComponent.tsx +36 -0
- package/dist/components/core/common/FilterComponent.tsx +458 -0
- package/dist/components/core/common/LoadDynamicJsxComponent.tsx +70 -0
- package/dist/components/core/common/PDFViewer.tsx +117 -0
- package/dist/components/core/common/SolidAccountSettings/SolidAccountSettings.tsx +89 -0
- package/dist/components/core/common/SolidAccountSettings/SolidChangePassword.tsx +188 -0
- package/dist/components/core/common/SolidAccountSettings/SolidNotifications.tsx +139 -0
- package/dist/components/core/common/SolidAccountSettings/SolidPersonalInfo.tsx +311 -0
- package/dist/components/core/common/SolidCreateButton.tsx +48 -0
- package/dist/components/core/common/SolidGenericImport/DocumentSvg.tsx +15 -0
- package/dist/components/core/common/SolidGenericImport/SolidGenericImport.tsx +64 -0
- package/dist/components/core/common/SolidGenericImport/SolidImportDropzone.tsx +125 -0
- package/dist/components/core/common/SolidGenericImport/SolidImportInstructions.tsx +122 -0
- package/dist/components/core/common/SolidGenericImport/SolidImportStepper.tsx +217 -0
- package/dist/components/core/common/SolidGenericImport/SolidImportTransaction.tsx +205 -0
- package/dist/components/core/common/SolidGenericImport/SolidImportTransactionStatus.tsx +158 -0
- package/dist/components/core/common/SolidGenericImport/SolidImportWrapper.tsx +29 -0
- package/dist/components/core/common/SolidGlobalSearchElement.tsx +1470 -0
- package/dist/components/core/common/SolidLayoutViews.tsx +87 -0
- package/dist/components/core/common/SolidListViewOptions.tsx +31 -0
- package/dist/components/core/common/SolidLoaders/SolidCircularLoader.tsx +7 -0
- package/dist/components/core/common/SolidPasswordHelperText.tsx +34 -0
- package/dist/components/core/common/SolidSaveCustomFilterForm.tsx +75 -0
- package/dist/components/core/common/SolidSearchBox.tsx +17 -0
- package/dist/components/core/common/SolidViewLayoutManager.ts +421 -0
- package/dist/components/core/common/SolidXAiIframe.tsx +77 -0
- package/dist/components/core/dashboard/SolidDashboard.tsx +332 -0
- package/dist/components/core/dashboard/SolidDashboardBody.tsx +117 -0
- package/dist/components/core/dashboard/SolidDashboardFilterRequired.tsx +28 -0
- package/dist/components/core/dashboard/SolidDashboardHeader.tsx +10 -0
- package/dist/components/core/dashboard/SolidDashboardLoading.tsx +55 -0
- package/dist/components/core/dashboard/SolidDashboardNotAvailable.tsx +32 -0
- package/dist/components/core/dashboard/SolidDashboardRenderError.tsx +29 -0
- package/dist/components/core/dashboard/SolidDashboardVariable.tsx +256 -0
- package/dist/components/core/dashboard/SolidQuestionRenderer.tsx +78 -0
- package/dist/components/core/dashboard/chart-renderers/ChartJsRenderer.tsx +18 -0
- package/dist/components/core/dashboard/chart-renderers/PrimeReactDatatableRenderer.tsx +54 -0
- package/dist/components/core/dashboard/chart-renderers/init-chartjs.ts +25 -0
- package/dist/components/core/dashboard/dashboard-utils.ts +39 -0
- package/dist/components/core/extension/solid-core/CustomIcon/StatusIcon.tsx +17 -0
- package/dist/components/core/extension/solid-core/dashboardQuestion/ChartFormPreviewWidget.tsx +36 -0
- package/dist/components/core/extension/solid-core/emailTemplate/emailFormTypeChangeHandler.ts +18 -0
- package/dist/components/core/extension/solid-core/emailTemplate/emailFormTypeLoad.ts +18 -0
- package/dist/components/core/extension/solid-core/modelMetadata/list/DeleteModelRowAction.tsx +114 -0
- package/dist/components/core/extension/solid-core/modelMetadata/list/GenerateModelCodeRowAction.tsx +213 -0
- package/dist/components/core/extension/solid-core/moduleMetadata/list/DeleteModuleRowAction.tsx +138 -0
- package/dist/components/core/extension/solid-core/moduleMetadata/list/GenerateModuleCodeRowAction.tsx +209 -0
- package/dist/components/core/extension/solid-core/roleMetadata/RolePermissionsManyToManyFieldWidget.tsx +131 -0
- package/dist/components/core/field/FieldListViewData.tsx +313 -0
- package/dist/components/core/filter/SolidBooleanFilterElement.tsx +30 -0
- package/dist/components/core/filter/SolidFilterFields.tsx +131 -0
- package/dist/components/core/filter/SolidManyToManyFilterElement.tsx +64 -0
- package/dist/components/core/filter/SolidManyToOneFilterElement.tsx +61 -0
- package/dist/components/core/filter/SolidSelectionDynamicFilterElement.tsx +50 -0
- package/dist/components/core/filter/SolidSelectionStaticFilterElement.tsx +32 -0
- package/dist/components/core/filter/SolidVarInputsFilterElement.tsx +209 -0
- package/dist/components/core/filter/fields/SolidBigintField.tsx +9 -0
- package/dist/components/core/filter/fields/SolidBooleanField.tsx +68 -0
- package/dist/components/core/filter/fields/SolidComputedField.tsx +23 -0
- package/dist/components/core/filter/fields/SolidDateField.tsx +63 -0
- package/dist/components/core/filter/fields/SolidDatetimeField.tsx +54 -0
- package/dist/components/core/filter/fields/SolidDecimalField.tsx +9 -0
- package/dist/components/core/filter/fields/SolidExternalIdField.tsx +52 -0
- package/dist/components/core/filter/fields/SolidFloatField.tsx +9 -0
- package/dist/components/core/filter/fields/SolidIdField.tsx +46 -0
- package/dist/components/core/filter/fields/SolidIntField.tsx +61 -0
- package/dist/components/core/filter/fields/SolidLongTextField.tsx +9 -0
- package/dist/components/core/filter/fields/SolidMediaMultipleField.tsx +60 -0
- package/dist/components/core/filter/fields/SolidMediaSingleField.tsx +62 -0
- package/dist/components/core/filter/fields/SolidRelationField.tsx +17 -0
- package/dist/components/core/filter/fields/SolidRichTextField.tsx +9 -0
- package/dist/components/core/filter/fields/SolidSelectionDynamicField.tsx +52 -0
- package/dist/components/core/filter/fields/SolidSelectionStaticField.tsx +54 -0
- package/dist/components/core/filter/fields/SolidShortTextField.tsx +60 -0
- package/dist/components/core/filter/fields/SolidTimeField.tsx +48 -0
- package/dist/components/core/filter/fields/SolidUuidField.tsx +51 -0
- package/dist/components/core/filter/fields/relations/SolidRelationManyToManyField.tsx +62 -0
- package/dist/components/core/filter/fields/relations/SolidRelationManyToOneField.tsx +84 -0
- package/dist/components/core/form/SolidFormActionHeader.tsx +497 -0
- package/dist/components/core/form/SolidFormFieldRender.tsx +53 -0
- package/dist/components/core/form/SolidFormFieldRenderExtension.tsx +26 -0
- package/dist/components/core/form/SolidFormFooter.tsx +162 -0
- package/dist/components/core/form/SolidFormLayouts.tsx +104 -0
- package/dist/components/core/form/SolidFormUserViewLayout.tsx +84 -0
- package/dist/components/core/form/SolidFormView.tsx +1856 -0
- package/dist/components/core/form/SolidFormViewContextMenuHeaderButton.tsx +52 -0
- package/dist/components/core/form/SolidFormViewNormalHeaderButton.tsx +52 -0
- package/dist/components/core/form/SolidFormViewShimmerLoading.tsx +109 -0
- package/dist/components/core/form/fields/ISolidField.tsx +71 -0
- package/dist/components/core/form/fields/SolidBooleanField.tsx +434 -0
- package/dist/components/core/form/fields/SolidDateField.tsx +247 -0
- package/dist/components/core/form/fields/SolidDateTimeField.tsx +229 -0
- package/dist/components/core/form/fields/SolidDecimalField.tsx +171 -0
- package/dist/components/core/form/fields/SolidEmailField.tsx +176 -0
- package/dist/components/core/form/fields/SolidIntegerField.tsx +282 -0
- package/dist/components/core/form/fields/SolidJsonField.tsx +185 -0
- package/dist/components/core/form/fields/SolidLongTextField.tsx +618 -0
- package/dist/components/core/form/fields/SolidMediaMultipleField.tsx +663 -0
- package/dist/components/core/form/fields/SolidMediaSingleField.tsx +547 -0
- package/dist/components/core/form/fields/SolidPasswordField.tsx +390 -0
- package/dist/components/core/form/fields/SolidRelationField.tsx +56 -0
- package/dist/components/core/form/fields/SolidRichTextField.tsx +188 -0
- package/dist/components/core/form/fields/SolidSelectionDynamicField.tsx +340 -0
- package/dist/components/core/form/fields/SolidSelectionStaticField.tsx +462 -0
- package/dist/components/core/form/fields/SolidShortTextField.tsx +399 -0
- package/dist/components/core/form/fields/SolidTimeField.tsx +245 -0
- package/dist/components/core/form/fields/relations/SolidRelationManyToManyField.tsx +453 -0
- package/dist/components/core/form/fields/relations/SolidRelationManyToOneField.tsx +1036 -0
- package/dist/components/core/form/fields/relations/SolidRelationOneToManyField.tsx +627 -0
- package/dist/components/core/form/fields/relations/widgets/helpers/InlineRelationEntityDialog.tsx +38 -0
- package/dist/components/core/form/fields/relations/widgets/helpers/useRelationEntityHandler.ts +64 -0
- package/dist/components/core/form/fields/widgets/SolidAiInteractionMessageFieldFormWidget.tsx +135 -0
- package/dist/components/core/form/fields/widgets/SolidAiInteractionMetadataFieldFormWidget.tsx +144 -0
- package/dist/components/core/form/fields/widgets/SolidIconEditWidget.tsx +265 -0
- package/dist/components/core/form/fields/widgets/SolidIconViewWidget.tsx +32 -0
- package/dist/components/core/form/fields/widgets/SolidRelationFieldAvatarFormWidget.tsx +50 -0
- package/dist/components/core/form/fields/widgets/SolidS3FileViewerWidget.tsx +222 -0
- package/dist/components/core/form/fields/widgets/SolidShortTextFieldAvatarWidget.tsx +70 -0
- package/dist/components/core/form/widgets/CustomHtml.tsx +20 -0
- package/dist/components/core/kanban/KanbanBoard.tsx +150 -0
- package/dist/components/core/kanban/KanbanCard.tsx +279 -0
- package/dist/components/core/kanban/KanbanColumn.tsx +139 -0
- package/dist/components/core/kanban/KanbanUserViewLayout.tsx +84 -0
- package/dist/components/core/kanban/SolidKanbanView.tsx +894 -0
- package/dist/components/core/kanban/SolidKanbanViewConfigure.tsx +154 -0
- package/dist/components/core/kanban/SolidKanbanViewFields.tsx +164 -0
- package/dist/components/core/kanban/SolidManyToOneFilterElement.tsx +59 -0
- package/dist/components/core/kanban/SolidSelectionDynamicFilterElement.tsx +50 -0
- package/dist/components/core/kanban/SolidSelectionStaticFilterElement.tsx +32 -0
- package/dist/components/core/kanban/SolidVarInputsFilterElement.tsx +184 -0
- package/dist/components/core/kanban/kanban-fields/SolidBigintKanbanField.tsx +9 -0
- package/dist/components/core/kanban/kanban-fields/SolidBooleanKanbanField.tsx +16 -0
- package/dist/components/core/kanban/kanban-fields/SolidComputedKanbanField.tsx +23 -0
- package/dist/components/core/kanban/kanban-fields/SolidDateKanbanField.tsx +14 -0
- package/dist/components/core/kanban/kanban-fields/SolidDatetimeKanbanField.tsx +13 -0
- package/dist/components/core/kanban/kanban-fields/SolidDecimalKanbanField.tsx +9 -0
- package/dist/components/core/kanban/kanban-fields/SolidExternalIdKanbanField.tsx +12 -0
- package/dist/components/core/kanban/kanban-fields/SolidFloatKanbanField.tsx +9 -0
- package/dist/components/core/kanban/kanban-fields/SolidIdKanbanField.tsx +14 -0
- package/dist/components/core/kanban/kanban-fields/SolidIntKanbanField.tsx +20 -0
- package/dist/components/core/kanban/kanban-fields/SolidLongTextKanbanField.tsx +9 -0
- package/dist/components/core/kanban/kanban-fields/SolidMediaMultipleKanbanField.tsx +140 -0
- package/dist/components/core/kanban/kanban-fields/SolidMediaSingleKanbanField.tsx +164 -0
- package/dist/components/core/kanban/kanban-fields/SolidRelationKanbanField.tsx +13 -0
- package/dist/components/core/kanban/kanban-fields/SolidRichTextKanbanField.tsx +9 -0
- package/dist/components/core/kanban/kanban-fields/SolidSelectionDynamicKanbanField.tsx +14 -0
- package/dist/components/core/kanban/kanban-fields/SolidSelectionStaticKanbanField.tsx +14 -0
- package/dist/components/core/kanban/kanban-fields/SolidShortTextKanbanField.tsx +121 -0
- package/dist/components/core/kanban/kanban-fields/SolidTimeKanbanField.tsx +12 -0
- package/dist/components/core/kanban/kanban-fields/SolidUuidKanbanField.tsx +13 -0
- package/dist/components/core/kanban/kanban-fields/relations/SolidRelationManyToOneKanbanField.tsx +16 -0
- package/dist/components/core/list/ListViewRowActionPopup.tsx +41 -0
- package/dist/components/core/list/SolidColumnSelector/SolidListColumnSelector.tsx +242 -0
- package/dist/components/core/list/SolidEmptyListViewPlaceholder.tsx +111 -0
- package/dist/components/core/list/SolidListView.tsx +2007 -0
- package/dist/components/core/list/SolidListViewColumn.tsx +165 -0
- package/dist/components/core/list/SolidListViewConfigure.tsx +339 -0
- package/dist/components/core/list/SolidListViewHeaderButton.tsx +31 -0
- package/dist/components/core/list/SolidListViewHeaderContextMenuButton.tsx +30 -0
- package/dist/components/core/list/SolidListViewRowButtonContextMenu.tsx +41 -0
- package/dist/components/core/list/SolidListViewShimmerLoading.tsx +78 -0
- package/dist/components/core/list/SolidListingHeader.tsx +42 -0
- package/dist/components/core/list/SolidManyToOneFilterElement.tsx +60 -0
- package/dist/components/core/list/SolidSelectionDynamicFilterElement.tsx +50 -0
- package/dist/components/core/list/SolidSelectionStaticFilterElement.tsx +32 -0
- package/dist/components/core/list/SolidTableRowCell.tsx +35 -0
- package/dist/components/core/list/SolidVarInputsFilterElement.tsx +184 -0
- package/dist/components/core/list/columns/SolidBigintColumn.tsx +9 -0
- package/dist/components/core/list/columns/SolidBooleanColumn.tsx +90 -0
- package/dist/components/core/list/columns/SolidComputedColumn.tsx +27 -0
- package/dist/components/core/list/columns/SolidDateColumn.tsx +90 -0
- package/dist/components/core/list/columns/SolidDatetimeColumn.tsx +79 -0
- package/dist/components/core/list/columns/SolidDecimalColumn.tsx +9 -0
- package/dist/components/core/list/columns/SolidExternalIdColumn.tsx +80 -0
- package/dist/components/core/list/columns/SolidFloatColumn.tsx +9 -0
- package/dist/components/core/list/columns/SolidIdColumn.tsx +79 -0
- package/dist/components/core/list/columns/SolidIntColumn.tsx +87 -0
- package/dist/components/core/list/columns/SolidLongTextColumn.tsx +9 -0
- package/dist/components/core/list/columns/SolidMediaMultipleColumn.tsx +301 -0
- package/dist/components/core/list/columns/SolidMediaSingleColumn.tsx +170 -0
- package/dist/components/core/list/columns/SolidRelationColumn.tsx +21 -0
- package/dist/components/core/list/columns/SolidRichTextColumn.tsx +9 -0
- package/dist/components/core/list/columns/SolidSelectionDynamicColumn.tsx +80 -0
- package/dist/components/core/list/columns/SolidSelectionStaticColumn.tsx +81 -0
- package/dist/components/core/list/columns/SolidShortTextColumn.tsx +160 -0
- package/dist/components/core/list/columns/SolidTimeColumn.tsx +78 -0
- package/dist/components/core/list/columns/SolidUuidColumn.tsx +79 -0
- package/dist/components/core/list/columns/relations/SolidRelationManyToManyColumn.tsx +106 -0
- package/dist/components/core/list/columns/relations/SolidRelationManyToOneColumn.tsx +117 -0
- package/dist/components/core/list/columns/relations/SolidRelationOneToManyColumn.tsx +110 -0
- package/dist/components/core/list/widgets/SolidManyToManyRelationAvatarListWidget.tsx +30 -0
- package/dist/components/core/list/widgets/SolidManyToOneRelationAvatarListWidget.tsx +30 -0
- package/dist/components/core/list/widgets/SolidShortTextAvatarWidget.tsx +70 -0
- package/dist/components/core/list/widgets/SolidShortTextFieldImageRenderModeWidget.tsx +21 -0
- package/dist/components/core/locales/SolidChatterLocaleTabView.tsx +91 -0
- package/dist/components/core/locales/SolidLocale.tsx +127 -0
- package/dist/components/core/model/CreateModel.tsx +495 -0
- package/dist/components/core/model/FieldMetaData.tsx +263 -0
- package/dist/components/core/model/FieldMetaDataForm.tsx +3509 -0
- package/dist/components/core/model/FieldSelector.tsx +62 -0
- package/dist/components/core/model/ModelListViewData.tsx +384 -0
- package/dist/components/core/model/ModelMetaData.tsx +921 -0
- package/dist/components/core/module/CreateModule.tsx +617 -0
- package/dist/components/core/module/ModuleListViewData.tsx +431 -0
- package/dist/components/core/solid-ai/SolidAiMainWrapper.tsx +8 -0
- package/dist/components/core/solid-ai/SolidXAIIcon.tsx +37 -0
- package/dist/components/core/users/CreateUser.tsx +467 -0
- package/dist/components/core/users/CreateUserRole.tsx +212 -0
- package/dist/components/core/users/UserListView.tsx +376 -0
- package/dist/components/layout/AdminLayout.tsx +57 -0
- package/dist/components/layout/AdminSidebar.tsx +65 -0
- package/dist/components/layout/AppConfig.tsx +104 -0
- package/dist/components/layout/AppSidebar.tsx +232 -0
- package/dist/components/layout/ButtonLoader.tsx +7 -0
- package/dist/components/layout/CustomPagination.tsx +55 -0
- package/dist/components/layout/DashboardHeader.tsx +89 -0
- package/dist/components/layout/FilterMenu.tsx +122 -0
- package/dist/components/layout/Footer.tsx +13 -0
- package/dist/components/layout/GlobalSearch.tsx +37 -0
- package/dist/components/layout/Header.tsx +8 -0
- package/dist/components/layout/Layout.tsx +205 -0
- package/dist/components/layout/ListingHeader.tsx +204 -0
- package/dist/components/layout/Loader.tsx +16 -0
- package/dist/components/layout/UserSidebar.tsx +53 -0
- package/dist/components/layout/context/layoutcontext.tsx +52 -0
- package/dist/components/layout/navbar-one.tsx +258 -0
- package/dist/components/layout/navbar-two-menu.tsx +72 -0
- package/dist/components/layout/navbar-two.tsx +37 -0
- package/dist/components/layout/user-profile-menu.tsx +213 -0
- package/dist/components/layout/user-profile.tsx +7 -0
- package/dist/components/modelsComponents/filterIcon.tsx +9 -0
- package/dist/constants/error-messages.ts +238 -0
- package/dist/declarations.d.ts +22 -0
- package/dist/helpers/AppTitle.tsx +12 -0
- package/dist/helpers/ToastContainer.tsx +94 -0
- package/dist/helpers/autoCompleteVirtualScroll.ts +41 -0
- package/dist/helpers/countries.tsx +260 -0
- package/dist/helpers/downloadFileWithProgress.ts +91 -0
- package/dist/helpers/downloadMediaFile.tsx +21 -0
- package/dist/helpers/getAcceptedFileTypes.tsx +22 -0
- package/dist/helpers/getRandomColors.tsx +68 -0
- package/dist/helpers/helpers.ts +61 -0
- package/dist/helpers/hydrateRelationRules.ts +120 -0
- package/dist/helpers/permissions.ts +7 -0
- package/dist/helpers/registry.ts +337 -0
- package/dist/helpers/resendOtpHelper.tsx +5 -0
- package/dist/helpers/revalidate.ts +7 -0
- package/dist/helpers/rolesHelper.ts +17 -0
- package/dist/helpers/solidIcons.tsx +1831 -0
- package/dist/helpers/updatePasswordField.ts +41 -0
- package/dist/index.ts +421 -0
- package/dist/nextAuth/authProviders.d.ts.map +1 -1
- package/dist/nextAuth/authProviders.js +6 -5
- package/dist/nextAuth/authProviders.js.map +1 -1
- package/dist/nextAuth/authProviders.tsx +232 -0
- package/dist/nextAuth/handleLogout.tsx +39 -0
- package/dist/nextAuth/refreshAccessToken.tsx +28 -0
- package/dist/redux/api/aiInteractionApi.ts +59 -0
- package/dist/redux/api/authApi.ts +131 -0
- package/dist/redux/api/dashboardApi.ts +56 -0
- package/dist/redux/api/dashboardQuestionApi.ts +17 -0
- package/dist/redux/api/exportTemplateApi.tsx +59 -0
- package/dist/redux/api/fetchBaseQuery.tsx +118 -0
- package/dist/redux/api/fieldApi.ts +86 -0
- package/dist/redux/api/importTransactionApi.tsx +69 -0
- package/dist/redux/api/mediaApi.ts +55 -0
- package/dist/redux/api/mediaStorageProviderApi.ts +55 -0
- package/dist/redux/api/modelApi.ts +80 -0
- package/dist/redux/api/moduleApi.ts +72 -0
- package/dist/redux/api/permissionApi.ts +32 -0
- package/dist/redux/api/pincodeApi.tsx +56 -0
- package/dist/redux/api/roleApi.ts +58 -0
- package/dist/redux/api/solidActionApi.ts +66 -0
- package/dist/redux/api/solidChatterMessageApi.ts +25 -0
- package/dist/redux/api/solidEntityApi.tsx +164 -0
- package/dist/redux/api/solidMenuApi.ts +71 -0
- package/dist/redux/api/solidServiceApi.ts +31 -0
- package/dist/redux/api/solidSettingsApi.tsx +83 -0
- package/dist/redux/api/solidViewApi.ts +73 -0
- package/dist/redux/api/stateApi.tsx +56 -0
- package/dist/redux/api/testApi.ts +21 -0
- package/dist/redux/api/userApi.ts +135 -0
- package/dist/redux/features/authSlice.ts +19 -0
- package/dist/redux/features/dataViewSlice.ts +26 -0
- package/dist/redux/features/navbarSlice.ts +21 -0
- package/dist/redux/features/popupSlice.ts +37 -0
- package/dist/redux/features/settingsSlice.ts +60 -0
- package/dist/redux/features/themeSlice.ts +17 -0
- package/dist/redux/features/userSlice.ts +28 -0
- package/dist/redux/hooks/useSolidPopup.ts +20 -0
- package/dist/redux/store/defaultStoreConfig.ts +62 -0
- package/dist/styles.ts +4 -0
- package/dist/types/handlebars.d.ts +4 -0
- package/dist/types/index.d.ts +76 -0
- package/dist/types/layout.d.ts +94 -0
- package/dist/types/next-auth.d.ts +0 -0
- package/dist/types/next.d.ts +46 -0
- package/dist/types/solid-core.d.ts +320 -0
- package/package.json +1 -1
- package/src/components/auth/SolidLogin.tsx +26 -13
- package/src/nextAuth/authProviders.tsx +9 -5
|
@@ -0,0 +1,1470 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import React, { forwardRef, useEffect, useImperativeHandle, useRef, useState } from "react";
|
|
4
|
+
import { Dialog } from "primereact/dialog";
|
|
5
|
+
import FilterComponent, { FilterOperator, FilterRule, FilterRuleType } from "../../../components/core/common/FilterComponent";
|
|
6
|
+
import { Button } from "primereact/button";
|
|
7
|
+
import { OverlayPanel } from "primereact/overlaypanel";
|
|
8
|
+
import { Divider } from "primereact/divider";
|
|
9
|
+
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
|
10
|
+
import { queryStringToQueryObject } from "../list/SolidListView";
|
|
11
|
+
import { InputText } from "primereact/inputtext";
|
|
12
|
+
import { createSolidEntityApi } from "../../../redux/api/solidEntityApi";
|
|
13
|
+
import qs from "qs";
|
|
14
|
+
import { useSelector } from "react-redux";
|
|
15
|
+
import { SolidSaveCustomFilterForm } from "./SolidSaveCustomFilterForm";
|
|
16
|
+
import { ERROR_MESSAGES } from "../../../constants/error-messages";
|
|
17
|
+
import { hydrateRelationRules } from "../../../helpers/hydrateRelationRules";
|
|
18
|
+
|
|
19
|
+
const getRandomInt = (min: number, max: number) => {
|
|
20
|
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface PredefinedSearch {
|
|
24
|
+
name: string;
|
|
25
|
+
description?: string;
|
|
26
|
+
filters: Record<string, any>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const extractFields = (nodes: any[] = []): any[] => {
|
|
30
|
+
const result: any[] = [];
|
|
31
|
+
|
|
32
|
+
for (const node of nodes) {
|
|
33
|
+
if (node?.type === "field") {
|
|
34
|
+
result.push(node);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (Array.isArray(node?.children)) {
|
|
38
|
+
result.push(...extractFields(node.children));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return result;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
const transformFiltersToRules = (filter: any, parentRule: number | null = null): FilterRule => {
|
|
47
|
+
if (!filter || typeof filter !== "object" || Object.keys(filter).length === 0) {
|
|
48
|
+
throw new Error("Invalid filter: expected a non-null object with properties");
|
|
49
|
+
}
|
|
50
|
+
if (!filter || typeof filter !== "object") {
|
|
51
|
+
throw new Error("Invalid filter: expected a non-null object");
|
|
52
|
+
}
|
|
53
|
+
const currentId = idCounter++;
|
|
54
|
+
if (filter["$or"]) {
|
|
55
|
+
return {
|
|
56
|
+
id: currentId,
|
|
57
|
+
type: FilterRuleType.RULE_GROUP,
|
|
58
|
+
matchOperator: FilterOperator.OR,
|
|
59
|
+
parentRule,
|
|
60
|
+
children: filter["$or"]
|
|
61
|
+
.filter((sub: any) => {
|
|
62
|
+
// Filter out null, undefined, empty strings, and empty objects
|
|
63
|
+
if (sub == null) return false;
|
|
64
|
+
if (typeof sub === "string" && sub.trim() === "") return false;
|
|
65
|
+
if (typeof sub === "object" && Object.keys(sub).length === 0) return false;
|
|
66
|
+
return true;
|
|
67
|
+
})
|
|
68
|
+
.map((subFilter: any) => transformFiltersToRules(subFilter, currentId))
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (filter["$and"]) {
|
|
73
|
+
return {
|
|
74
|
+
id: currentId,
|
|
75
|
+
type: FilterRuleType.RULE_GROUP,
|
|
76
|
+
matchOperator: FilterOperator.AND,
|
|
77
|
+
parentRule,
|
|
78
|
+
children: filter["$and"]
|
|
79
|
+
.filter((sub: any) => {
|
|
80
|
+
// Filter out null, undefined, empty strings, and empty objects
|
|
81
|
+
if (sub == null) return false;
|
|
82
|
+
if (typeof sub === "string" && sub.trim() === "") return false;
|
|
83
|
+
if (typeof sub === "object" && Object.keys(sub).length === 0) return false;
|
|
84
|
+
return true;
|
|
85
|
+
})
|
|
86
|
+
.map((subFilter: any) => transformFiltersToRules(subFilter, currentId))
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Handle single rule condition
|
|
91
|
+
for (const fieldName in filter) {
|
|
92
|
+
const condition = filter[fieldName];
|
|
93
|
+
if (!condition || typeof condition !== "object") {
|
|
94
|
+
throw new Error(`Invalid condition for field '${fieldName}'`);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// CASE 1: relation filter → unwrap first
|
|
98
|
+
if (condition?.id && typeof condition?.id === "object") {
|
|
99
|
+
for (const matchMode in condition.id) {
|
|
100
|
+
const rawValue = condition.id[matchMode];
|
|
101
|
+
const mathcModeValue: any = matchMode
|
|
102
|
+
return {
|
|
103
|
+
id: currentId,
|
|
104
|
+
type: FilterRuleType.RULE,
|
|
105
|
+
fieldName,
|
|
106
|
+
matchMode: mathcModeValue,
|
|
107
|
+
value: Array.isArray(rawValue) ? rawValue : [rawValue],
|
|
108
|
+
parentRule,
|
|
109
|
+
children: []
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// CASE 2: normal field → loop stays
|
|
115
|
+
for (const matchMode in condition) {
|
|
116
|
+
const rawValue = condition[matchMode];
|
|
117
|
+
const mathcModeValue: any = matchMode
|
|
118
|
+
return {
|
|
119
|
+
id: currentId,
|
|
120
|
+
type: FilterRuleType.RULE,
|
|
121
|
+
fieldName,
|
|
122
|
+
matchMode: mathcModeValue,
|
|
123
|
+
value: Array.isArray(rawValue) ? rawValue : [rawValue],
|
|
124
|
+
parentRule,
|
|
125
|
+
children: []
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
}
|
|
131
|
+
throw new Error(ERROR_MESSAGES.INVALID_FILTER_STRUCTURE);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
let idCounter = 1;
|
|
138
|
+
const generateId = () => Date.now() + Math.floor(Math.random() * 1000);
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
const transformRulesToFilters = (input: any, viewData: any) => {
|
|
142
|
+
|
|
143
|
+
// Helper function to process individual rules
|
|
144
|
+
const processRule = (rule: any) => {
|
|
145
|
+
if (rule.value !== undefined && rule.value !== null) {
|
|
146
|
+
|
|
147
|
+
// Ensure rule.value is always an array
|
|
148
|
+
let values = typeof rule.value[0] === "object" ? rule.value.map((i: any) => i?.value ? i?.value : i) : rule?.value;
|
|
149
|
+
if (rule.matchMode !== '$in' && rule.matchMode !== '$notIn' && rule.matchMode !== '$between' && rule.matchMode !== '$null' && rule.matchMode !== '$notNull') {
|
|
150
|
+
values = values[0];
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
const fieldMeta = viewData?.data?.solidFieldsMetadata?.[rule.fieldName];
|
|
155
|
+
const isManyToMany = fieldMeta?.type === 'relation' && fieldMeta?.relationType === 'many-to-many';
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
let transformedRule;
|
|
159
|
+
if (isManyToMany) {
|
|
160
|
+
// For many-to-many relations, always use array format for $in/$notIn
|
|
161
|
+
transformedRule = {
|
|
162
|
+
[rule.fieldName]: {
|
|
163
|
+
id: {
|
|
164
|
+
[rule.matchMode]: values // Keep as array
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
} else {
|
|
169
|
+
// Rule transformation
|
|
170
|
+
transformedRule = {
|
|
171
|
+
[rule.fieldName]: {
|
|
172
|
+
[rule.matchMode]: values // Assuming `value` is always an array with `value` and `label`
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
let processedFields;
|
|
178
|
+
if (rule.children && rule.children.length > 0) {
|
|
179
|
+
processedFields = rule.children.map((child: any) => processRuleGroup(child)).filter((child: any) => child != null);;
|
|
180
|
+
}
|
|
181
|
+
if (processedFields) {
|
|
182
|
+
return { ...transformedRule, processedFields }
|
|
183
|
+
}
|
|
184
|
+
return { ...transformedRule }
|
|
185
|
+
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
// Helper function to process rule groups
|
|
191
|
+
const processRuleGroup = (ruleGroup: any) => {
|
|
192
|
+
const operator = ruleGroup.matchOperator === 'or' ? '$or' : '$and';
|
|
193
|
+
const children = ruleGroup.children.map((child: any) => {
|
|
194
|
+
if (child.type === 'rule') {
|
|
195
|
+
// Process the rule
|
|
196
|
+
return processRule(child);
|
|
197
|
+
} else if (child.type === 'rule_group') {
|
|
198
|
+
// Process the rule group recursively
|
|
199
|
+
return processRuleGroup(child);
|
|
200
|
+
}
|
|
201
|
+
}).filter((child: any) => child != null);
|
|
202
|
+
// If no valid children, return null
|
|
203
|
+
// if (children.length === 0) {
|
|
204
|
+
// return null;
|
|
205
|
+
// }
|
|
206
|
+
|
|
207
|
+
// If only one child, return it directly without wrapping in operator
|
|
208
|
+
// if (children.length === 1) {
|
|
209
|
+
// return children[0];
|
|
210
|
+
// }
|
|
211
|
+
|
|
212
|
+
return {
|
|
213
|
+
[operator]: children
|
|
214
|
+
};
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
// Start processing the root rule group
|
|
219
|
+
const filterObject = processRuleGroup(input);
|
|
220
|
+
|
|
221
|
+
if (!filterObject) {
|
|
222
|
+
return {};
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function liftProcessedFields(filters: any) {
|
|
226
|
+
if (!filters || typeof filters !== 'object') return filters;
|
|
227
|
+
|
|
228
|
+
const processArray = (arr: any) => {
|
|
229
|
+
let newArr = [];
|
|
230
|
+
for (let obj of arr) {
|
|
231
|
+
if (obj && obj.processedFields) {
|
|
232
|
+
let processed: any = processArray(obj.processedFields); // Recursively process nested processedFields
|
|
233
|
+
delete obj.processedFields;
|
|
234
|
+
newArr.push(obj, ...processed);
|
|
235
|
+
} else {
|
|
236
|
+
newArr.push(obj);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
for (let key in obj) {
|
|
240
|
+
if (Array.isArray(obj[key])) {
|
|
241
|
+
obj[key] = processArray(obj[key]);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return newArr;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
for (let key in filters) {
|
|
249
|
+
if (Array.isArray(filters[key])) {
|
|
250
|
+
filters[key] = processArray(filters[key]);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return filters;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
return liftProcessedFields(filterObject)
|
|
259
|
+
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
type GroupedType = {
|
|
264
|
+
values: string[];
|
|
265
|
+
searchField: any;
|
|
266
|
+
matchMode: string;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Build nested condition for relation fields
|
|
270
|
+
function buildNestedCondition(path: string, operatorKey: string, value: any) {
|
|
271
|
+
const keys = path.split(".").filter(Boolean);
|
|
272
|
+
const leaf = { [operatorKey]: value };
|
|
273
|
+
return keys.reduceRight((acc, key) => ({ [key]: acc }), leaf);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const tranformSearchToFilters = (input: any) => {
|
|
277
|
+
if (!input || !input.$and) return input;
|
|
278
|
+
|
|
279
|
+
const grouped: Record<string, GroupedType> = {};
|
|
280
|
+
|
|
281
|
+
input.$and.forEach(({ fieldName, value, searchField, matchMode }: any) => {
|
|
282
|
+
const val = Array.isArray(value) && value.length === 1 ? value[0] : value;
|
|
283
|
+
|
|
284
|
+
if (!grouped[fieldName]) {
|
|
285
|
+
grouped[fieldName] = { values: [], searchField: searchField || "", matchMode: matchMode || "$containsi" };
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (Array.isArray(val)) {
|
|
289
|
+
grouped[fieldName]?.values.push(...val);
|
|
290
|
+
} else {
|
|
291
|
+
grouped[fieldName]?.values.push(val);
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
// return {
|
|
296
|
+
// $and: Object.entries(grouped).map(([fieldName, values]) => ({
|
|
297
|
+
// [fieldName]: {
|
|
298
|
+
// $containsi: values.length === 1 ? values[0] : values
|
|
299
|
+
// }
|
|
300
|
+
// }))
|
|
301
|
+
// };
|
|
302
|
+
|
|
303
|
+
const andFilters: any[] = [];
|
|
304
|
+
|
|
305
|
+
Object.entries(grouped).forEach(([fieldName, value]) => {
|
|
306
|
+
|
|
307
|
+
const isNested = value.searchField ? value.searchField.includes(".") : false;
|
|
308
|
+
|
|
309
|
+
if (isNested) {
|
|
310
|
+
|
|
311
|
+
// NESTED: use $eq and expand dot-notation into nested objects
|
|
312
|
+
if (value.values.length === 1) {
|
|
313
|
+
andFilters.push(buildNestedCondition(value.searchField, value.matchMode, value.values[0]));
|
|
314
|
+
} else {
|
|
315
|
+
andFilters.push({
|
|
316
|
+
$or: value.values.map(v => buildNestedCondition(value.searchField, value.matchMode, v)),
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
} else {
|
|
320
|
+
|
|
321
|
+
if (value.values.length === 1) {
|
|
322
|
+
andFilters.push({
|
|
323
|
+
[fieldName]: {
|
|
324
|
+
$containsi: value.values[0]
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
} else {
|
|
328
|
+
andFilters.push({
|
|
329
|
+
$or: value.values.map((v) => ({
|
|
330
|
+
[fieldName]: { $containsi: v }
|
|
331
|
+
}))
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
return {
|
|
338
|
+
$and: andFilters
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
export const mergeSearchAndCustomFilters = (transformedFilter: any, newFilter: any, transformedFilterName: string, newFilterName: string) => {
|
|
343
|
+
const filters: any = {};
|
|
344
|
+
|
|
345
|
+
// Add only non-null filters
|
|
346
|
+
if (transformedFilter && Object.keys(transformedFilter).length > 0) {
|
|
347
|
+
filters[transformedFilterName] = transformedFilter;
|
|
348
|
+
}
|
|
349
|
+
if (newFilter && Object.keys(newFilter).length > 0) {
|
|
350
|
+
filters[newFilterName] = newFilter;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Return the combined filters object
|
|
354
|
+
return filters;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
export const mergeAllDiffFilters = (customFilter: any, searchFilter: any, savedFilter: any, preDefinedFilter?: any) => {
|
|
359
|
+
const filters: any = {};
|
|
360
|
+
|
|
361
|
+
// Add only non-null filters
|
|
362
|
+
if (customFilter && Object.keys(customFilter).length > 0) {
|
|
363
|
+
filters["custom_filter_predicate"] = customFilter;
|
|
364
|
+
}
|
|
365
|
+
if (searchFilter && Object.keys(searchFilter).length > 0) {
|
|
366
|
+
filters["search_predicate"] = searchFilter;
|
|
367
|
+
}
|
|
368
|
+
if (savedFilter && Object.keys(savedFilter).length > 0) {
|
|
369
|
+
filters["saved_filter_predicate"] = savedFilter;
|
|
370
|
+
}
|
|
371
|
+
if (preDefinedFilter && Object.keys(preDefinedFilter).length > 0) {
|
|
372
|
+
filters["predefined_search_predicate"] = preDefinedFilter;
|
|
373
|
+
}
|
|
374
|
+
// Return the combined filters object
|
|
375
|
+
return filters;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
const SavedFilterList = ({ savedfilter, activeSavedFilter, applySavedFilter, openSavedCustomFilter, setSavedFilterTobeDeleted, setIsDeleteSQDialogVisible }: any) => {
|
|
379
|
+
return (
|
|
380
|
+
<div className="flex align-items-center justify-content-between gap-2">
|
|
381
|
+
<div>
|
|
382
|
+
<Button text size="small" className="text-base py-1 w-full" severity={Number(activeSavedFilter) == savedfilter.id ? "secondary" : "contrast"} onClick={() => applySavedFilter(savedfilter)}>{savedfilter.name}</Button>
|
|
383
|
+
{savedfilter?.description && <p className="text-xs pl-3">{savedfilter?.description}</p>}
|
|
384
|
+
</div>
|
|
385
|
+
<div className="flex align-items-center gap-2">
|
|
386
|
+
<Button
|
|
387
|
+
icon="pi pi-pencil"
|
|
388
|
+
style={{ fontSize: 10 }}
|
|
389
|
+
severity="secondary"
|
|
390
|
+
outlined size="small"
|
|
391
|
+
onClick={() => openSavedCustomFilter(savedfilter)}
|
|
392
|
+
/>
|
|
393
|
+
<Button
|
|
394
|
+
icon="pi pi-trash"
|
|
395
|
+
style={{ fontSize: 10 }}
|
|
396
|
+
severity="secondary"
|
|
397
|
+
outlined size="small"
|
|
398
|
+
onClick={() => {
|
|
399
|
+
setSavedFilterTobeDeleted(savedfilter.id),
|
|
400
|
+
setIsDeleteSQDialogVisible(true);
|
|
401
|
+
|
|
402
|
+
}}
|
|
403
|
+
/>
|
|
404
|
+
</div>
|
|
405
|
+
</div>
|
|
406
|
+
)
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
const replacePlaceholders = (obj: any, searchValue: string): any => {
|
|
410
|
+
if (typeof obj === 'string') {
|
|
411
|
+
return obj.replace(/\{\{search\}\}/g, searchValue);
|
|
412
|
+
}
|
|
413
|
+
if (Array.isArray(obj)) {
|
|
414
|
+
return obj.map(item => replacePlaceholders(item, searchValue));
|
|
415
|
+
}
|
|
416
|
+
if (obj && typeof obj === 'object') {
|
|
417
|
+
const newObj: any = {};
|
|
418
|
+
for (const key in obj) {
|
|
419
|
+
newObj[key] = replacePlaceholders(obj[key], searchValue);
|
|
420
|
+
}
|
|
421
|
+
return newObj;
|
|
422
|
+
}
|
|
423
|
+
return obj;
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
type RelationCache = Map<string, { label: string; value: number }>;
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
export const SolidGlobalSearchElement = forwardRef(({ viewData, handleApplyCustomFilter, filters, clearFilter, showSaveFilterPopup, setShowSaveFilterPopup }: any, ref) => {
|
|
431
|
+
const defaultState: FilterRule[] = [
|
|
432
|
+
{
|
|
433
|
+
id: 1,
|
|
434
|
+
type: FilterRuleType.RULE_GROUP,
|
|
435
|
+
matchOperator: FilterOperator.OR,
|
|
436
|
+
parentRule: null,
|
|
437
|
+
children: [
|
|
438
|
+
{
|
|
439
|
+
id: Date.now() + getRandomInt(1, 500),
|
|
440
|
+
type: FilterRuleType.RULE,
|
|
441
|
+
fieldName: null,
|
|
442
|
+
matchMode: null,
|
|
443
|
+
value: null,
|
|
444
|
+
parentRule: 1,
|
|
445
|
+
children: []
|
|
446
|
+
},
|
|
447
|
+
{
|
|
448
|
+
id: Date.now() + getRandomInt(1, 500),
|
|
449
|
+
type: FilterRuleType.RULE,
|
|
450
|
+
fieldName: null,
|
|
451
|
+
matchMode: null,
|
|
452
|
+
value: null,
|
|
453
|
+
parentRule: 1,
|
|
454
|
+
children: []
|
|
455
|
+
}
|
|
456
|
+
]
|
|
457
|
+
}
|
|
458
|
+
];
|
|
459
|
+
const [initialState, setInitialState] = useState(defaultState);
|
|
460
|
+
const pathname = usePathname();
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
const searchParams = useSearchParams() // Converts the query params to a string
|
|
464
|
+
const activeSavedFilter = searchParams?.get("savedQuery");
|
|
465
|
+
|
|
466
|
+
const router = useRouter();
|
|
467
|
+
|
|
468
|
+
const chipsRef = useRef<HTMLDivElement | null | any>(null);
|
|
469
|
+
|
|
470
|
+
// filterRules is used to maintian the ui of custom filter
|
|
471
|
+
// customFilter is used to maintian the transformed filter object of custom filter
|
|
472
|
+
const [filterRules, setFilterRules] = useState<FilterRule[]>(initialState);
|
|
473
|
+
const [customFilter, setCustomFilter] = useState<any | null>(null);
|
|
474
|
+
|
|
475
|
+
const [fields, setFields] = useState<any[]>([]);
|
|
476
|
+
const [searchableFields, setSearchableFields] = useState<any[]>([]);
|
|
477
|
+
|
|
478
|
+
// used to show the list of predefined searches
|
|
479
|
+
const [predefinedSearches, setPredefinedSearches] = useState<PredefinedSearch[]>([]);
|
|
480
|
+
|
|
481
|
+
// used to open / close the custom fitler popup
|
|
482
|
+
const [showGlobalSearchElement, setShowGlobalSearchElement] = useState<boolean>(false);
|
|
483
|
+
|
|
484
|
+
// searchChips maintain the ui to display searched query
|
|
485
|
+
// searchFilter maintain the transformed filter of the searched query
|
|
486
|
+
const [searchChips, setSearchChips] = useState<{ columnName?: string; value: string }[]>([]);
|
|
487
|
+
const [searchFilter, setSearchFilter] = useState<any | null>(null);
|
|
488
|
+
|
|
489
|
+
// predefinedSearchChip maintain the ui to display predefined searches query
|
|
490
|
+
const [predefinedSearchChip, setPredefinedSearchChip] = useState<{ name: string; value: string } | null>(null);
|
|
491
|
+
|
|
492
|
+
// state to maintain the text typed in the search input box
|
|
493
|
+
const [inputValue, setInputValue] = useState<string | null>("");
|
|
494
|
+
|
|
495
|
+
// flag to prevent un necessary re renders
|
|
496
|
+
const [hasSearched, setHasSearched] = useState<boolean>(false);
|
|
497
|
+
|
|
498
|
+
// currentSavedFilterData is used to save the whole object of saved filter
|
|
499
|
+
const [currentSavedFilterData, setCurrentSavedFilterData] = useState<any>();
|
|
500
|
+
const [currentSavedFilterQuery, setCurrentSavedFilterQuery] = useState<any>();
|
|
501
|
+
const [currentSavedFilterRules, setCurrentSavedFilterRules] = useState<any>();
|
|
502
|
+
const [showSavedFilterComponent, setShowSavedFilterComponent] = useState<boolean>(false);
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
const [savedFilterTobeDeleted, setSavedFilterTobeDeleted] = useState<any>();
|
|
506
|
+
const [isDeleteSQDialogVisible, setIsDeleteSQDialogVisible] = useState<boolean>(false);
|
|
507
|
+
const [savedFilterQueryString, setSavedFilterQueryString] = useState<string>();
|
|
508
|
+
const [showOverlay, setShowOverlay] = useState(false);
|
|
509
|
+
const overlayRef = useRef<HTMLDivElement | null>(null);
|
|
510
|
+
const { user } = useSelector((state: any) => state.auth);
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
const [refreshKey, setRefreshKey] = useState(0);
|
|
515
|
+
|
|
516
|
+
const [predefinedSearchBaseFilter, setPredefinedSearchBaseFilter] = useState<any>(null);
|
|
517
|
+
|
|
518
|
+
const [savedFilters, setSavedFilters] = useState([]);
|
|
519
|
+
const [savedFiltersLoaded, setSavedFiltersLoaded] = useState(false);
|
|
520
|
+
|
|
521
|
+
const entityApi = createSolidEntityApi("savedFilters");
|
|
522
|
+
const {
|
|
523
|
+
useCreateSolidEntityMutation,
|
|
524
|
+
useDeleteSolidEntityMutation,
|
|
525
|
+
useGetSolidEntityByIdQuery,
|
|
526
|
+
useUpdateSolidEntityMutation,
|
|
527
|
+
useLazyGetSolidEntitiesQuery
|
|
528
|
+
} = entityApi;
|
|
529
|
+
|
|
530
|
+
const [
|
|
531
|
+
createEntity,
|
|
532
|
+
{ isSuccess: isEntityCreateSuccess, isError: isEntityCreateError, error: entityCreateError },
|
|
533
|
+
] = useCreateSolidEntityMutation();
|
|
534
|
+
|
|
535
|
+
const [
|
|
536
|
+
updateEntity,
|
|
537
|
+
{ isSuccess: isEntityUpdateSuceess, isError: isEntityUpdateError, error: entityUpdateError },
|
|
538
|
+
] = useUpdateSolidEntityMutation();
|
|
539
|
+
|
|
540
|
+
const [
|
|
541
|
+
deleteEntity,
|
|
542
|
+
{ isSuccess: isEntityDeleteSuceess, isError: isEntityDeleteError, error: entityDeleteError },
|
|
543
|
+
] = useDeleteSolidEntityMutation();
|
|
544
|
+
|
|
545
|
+
const [triggerGetSolidEntities, { data: solidEntityListViewData, isLoading: isSavedFilterLoading, error }] = useLazyGetSolidEntitiesQuery();
|
|
546
|
+
|
|
547
|
+
const [savedFilterFetchDataRefreshKey, setSavedFilterFetchDataRefreshKey] = useState(0);
|
|
548
|
+
|
|
549
|
+
useEffect(() => {
|
|
550
|
+
const fn = async () => {
|
|
551
|
+
setSavedFiltersLoaded(false)
|
|
552
|
+
const filters = {
|
|
553
|
+
$or: [
|
|
554
|
+
{
|
|
555
|
+
$and: [
|
|
556
|
+
{ model: { $in: [viewData?.data?.solidView?.model?.id] } },
|
|
557
|
+
{ view: { $in: [viewData?.solidView?.id] } },
|
|
558
|
+
{ user: { $in: [user?.user?.id] } },
|
|
559
|
+
{ isPrivate: { $eq: true } }
|
|
560
|
+
]
|
|
561
|
+
},
|
|
562
|
+
{
|
|
563
|
+
$and: [
|
|
564
|
+
{ model: { $in: [viewData?.data?.solidView?.model?.id] } },
|
|
565
|
+
{ view: { $in: [viewData?.solidView?.id] } },
|
|
566
|
+
{ isPrivate: { $eq: false } }
|
|
567
|
+
]
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
]
|
|
571
|
+
}
|
|
572
|
+
const queryData: any = {
|
|
573
|
+
offset: 0,
|
|
574
|
+
limit: 10,
|
|
575
|
+
filters: filters,
|
|
576
|
+
populate: ["model", "view", "user"],
|
|
577
|
+
sort: ["id:desc"],
|
|
578
|
+
};
|
|
579
|
+
const queryString = qs.stringify(queryData, { encodeValuesOnly: true });
|
|
580
|
+
setSavedFilterQueryString(queryString)
|
|
581
|
+
const savedFilter = await triggerGetSolidEntities(queryString).unwrap();
|
|
582
|
+
|
|
583
|
+
if (savedFilter) {
|
|
584
|
+
console.log("savedFilter", savedFilter);
|
|
585
|
+
setSavedFilters(savedFilter?.records)
|
|
586
|
+
setSavedFiltersLoaded(true);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
fn()
|
|
590
|
+
}, [activeSavedFilter, savedFilterFetchDataRefreshKey])
|
|
591
|
+
|
|
592
|
+
useImperativeHandle(ref, () => ({
|
|
593
|
+
clearFilter: () => {
|
|
594
|
+
setFilterRules(initialState);
|
|
595
|
+
}
|
|
596
|
+
}));
|
|
597
|
+
|
|
598
|
+
useEffect(() => {
|
|
599
|
+
const fn = async () => {
|
|
600
|
+
let searchChips: any;
|
|
601
|
+
let customChips: any;
|
|
602
|
+
let parsedSearchParams = searchParams;
|
|
603
|
+
if (savedFiltersLoaded) {
|
|
604
|
+
|
|
605
|
+
if (activeSavedFilter && savedFilters.length === 0) return;
|
|
606
|
+
|
|
607
|
+
const queryObject = queryStringToQueryObject();
|
|
608
|
+
// const savedQuery = parsedSearchParams?.get("savedQuery");
|
|
609
|
+
if (activeSavedFilter) {
|
|
610
|
+
const currentSavedFilterId = Number(activeSavedFilter);
|
|
611
|
+
const currentSavedFilterData: any = savedFilters.find((savedFilter: any) => savedFilter.id === currentSavedFilterId);
|
|
612
|
+
setCurrentSavedFilterData(currentSavedFilterData);
|
|
613
|
+
if (currentSavedFilterData) {
|
|
614
|
+
const filterJson = JSON.parse(currentSavedFilterData?.filterQueryJson);
|
|
615
|
+
if (filterJson) {
|
|
616
|
+
let finalSavedFilter = filterJson
|
|
617
|
+
setCurrentSavedFilterQuery(finalSavedFilter)
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
} else {
|
|
621
|
+
setCurrentSavedFilterData(null)
|
|
622
|
+
setCurrentSavedFilterQuery(null)
|
|
623
|
+
}
|
|
624
|
+
if (queryObject) {
|
|
625
|
+
if (queryObject) {
|
|
626
|
+
searchChips = queryObject?.search_predicate || null;
|
|
627
|
+
customChips = queryObject?.custom_filter_predicate || null;
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
if (searchChips) {
|
|
631
|
+
const formattedChips = searchChips?.$and.map((chip: any, key: any) => {
|
|
632
|
+
const chipKey = Object.keys(chip)[0]; // Get the key, e.g., "displayName"
|
|
633
|
+
const chipValue = chip[chipKey]?.$containsi; // Get the value of "$containsi"
|
|
634
|
+
const chipdata = {
|
|
635
|
+
columnName: chipKey,
|
|
636
|
+
value: chipValue
|
|
637
|
+
};
|
|
638
|
+
return chipdata
|
|
639
|
+
}
|
|
640
|
+
);
|
|
641
|
+
setSearchChips(formattedChips);
|
|
642
|
+
setSearchFilter(searchChips);
|
|
643
|
+
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
if (customChips && Object.keys(customChips).length !== 0) {
|
|
647
|
+
setCustomFilter(customChips);
|
|
648
|
+
const rules: FilterRule = transformFiltersToRules(customChips);
|
|
649
|
+
const hydratedRules = await hydrateRelationRules([rules], viewData);
|
|
650
|
+
setFilterRules(hydratedRules);
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
setHasSearched(true);
|
|
654
|
+
setRefreshKey((prev) => prev + 1)
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
fn()
|
|
658
|
+
}, [activeSavedFilter, savedFilters, savedFiltersLoaded])
|
|
659
|
+
|
|
660
|
+
|
|
661
|
+
|
|
662
|
+
|
|
663
|
+
useEffect(() => {
|
|
664
|
+
if (viewData?.data?.solidFieldsMetadata) {
|
|
665
|
+
let fieldsData = viewData?.data?.solidFieldsMetadata;
|
|
666
|
+
// console.log(`fiels data while rendering solid global search element: `);
|
|
667
|
+
// console.log(fieldsData);
|
|
668
|
+
|
|
669
|
+
const layoutChildren = viewData?.data?.solidView?.layout?.children ?? [];
|
|
670
|
+
const fieldElements = extractFields(layoutChildren);
|
|
671
|
+
|
|
672
|
+
|
|
673
|
+
const fieldsList = Object.entries(fieldsData ?? {}).map(([key, value]: any) => {
|
|
674
|
+
const viewFieldElement = fieldElements.find(
|
|
675
|
+
(f: any) => f?.attrs?.name === key
|
|
676
|
+
);
|
|
677
|
+
return {
|
|
678
|
+
name: value.displayName,
|
|
679
|
+
value: key,
|
|
680
|
+
type: value.type,
|
|
681
|
+
ormType: value.ormType,
|
|
682
|
+
matchMode: viewFieldElement?.attrs?.searchMatchMode,
|
|
683
|
+
searchField: viewFieldElement?.attrs?.searchField ?? null,
|
|
684
|
+
isSearchable: viewFieldElement?.attrs?.isSearchable ?? false,
|
|
685
|
+
};
|
|
686
|
+
});
|
|
687
|
+
|
|
688
|
+
setFields(fieldsList);
|
|
689
|
+
|
|
690
|
+
const searchableFieldsList = fieldsList.filter((field: any) => {
|
|
691
|
+
if (!field.isSearchable) return false;
|
|
692
|
+
|
|
693
|
+
switch (field.type) {
|
|
694
|
+
case "relation":
|
|
695
|
+
// Only include relation if searchField is present
|
|
696
|
+
return !!field.searchField;
|
|
697
|
+
case "longText":
|
|
698
|
+
case "shortText":
|
|
699
|
+
case "selectionStatic":
|
|
700
|
+
case "selectionDynamic":
|
|
701
|
+
return true;
|
|
702
|
+
// case "selectionStatic":
|
|
703
|
+
case "computed":
|
|
704
|
+
return field.ormType === "varchar";
|
|
705
|
+
default:
|
|
706
|
+
return false;
|
|
707
|
+
}
|
|
708
|
+
});
|
|
709
|
+
|
|
710
|
+
// console.log("searchableFieldsList", searchableFieldsList);
|
|
711
|
+
|
|
712
|
+
|
|
713
|
+
// Optionally map to a minimal structure if needed for UI
|
|
714
|
+
let finalSearchableFieldsList: any = searchableFieldsList.map((field: any) => ({
|
|
715
|
+
fieldName: field.value,
|
|
716
|
+
displayName: field.name,
|
|
717
|
+
searchField: field.searchField ?? "",
|
|
718
|
+
matchMode: field.matchMode
|
|
719
|
+
}));
|
|
720
|
+
|
|
721
|
+
// console.log("finalSearchableFieldsList", finalSearchableFieldsList);
|
|
722
|
+
|
|
723
|
+
setSearchableFields(finalSearchableFieldsList);
|
|
724
|
+
|
|
725
|
+
const predefinedSearchesList = viewData?.data?.solidView?.layout?.attrs?.predefinedSearches || [];
|
|
726
|
+
setPredefinedSearches(predefinedSearchesList);
|
|
727
|
+
}
|
|
728
|
+
// used to open the
|
|
729
|
+
}, [])
|
|
730
|
+
|
|
731
|
+
useEffect(() => {
|
|
732
|
+
if (chipsRef.current) {
|
|
733
|
+
const inputElement = chipsRef.current.querySelector("input");
|
|
734
|
+
if (inputElement) {
|
|
735
|
+
inputElement.addEventListener("input", (e: any) => {
|
|
736
|
+
setInputValue((e.target as HTMLInputElement).value);
|
|
737
|
+
});
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
}, []);
|
|
741
|
+
|
|
742
|
+
|
|
743
|
+
const handleAddChip = (columnName?: string) => {
|
|
744
|
+
if (inputValue?.trim()) {
|
|
745
|
+
const fallbackField = searchableFields[0]; // guaranteed object
|
|
746
|
+
if (!fallbackField) return;
|
|
747
|
+
// Support comma-separated values: split, trim and add as separate chips
|
|
748
|
+
const values = inputValue.split(",").map(v => v.trim()).filter(v => v !== "");
|
|
749
|
+
const fieldName = columnName || fallbackField.fieldName;
|
|
750
|
+
const chipsToAdd = values.map(v => ({
|
|
751
|
+
columnName: fieldName,
|
|
752
|
+
value: v,
|
|
753
|
+
columnDisplayName: fallbackField.displayName,
|
|
754
|
+
searchField: fallbackField.searchField,
|
|
755
|
+
matchMode: fallbackField.matchMode
|
|
756
|
+
}));
|
|
757
|
+
|
|
758
|
+
setSearchChips((prev) => [...prev, ...chipsToAdd]);
|
|
759
|
+
setInputValue("");
|
|
760
|
+
setHasSearched(true)
|
|
761
|
+
setRefreshKey((prev) => prev + 1)
|
|
762
|
+
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
};
|
|
766
|
+
|
|
767
|
+
const clearCustomFilter = () => {
|
|
768
|
+
// handleApplyCustomFilter(finalFilter)
|
|
769
|
+
setFilterRules(initialState);
|
|
770
|
+
setCustomFilter(null)
|
|
771
|
+
// setPredefinedSearchChip(null)
|
|
772
|
+
// setPredefinedSearchBaseFilter(null)
|
|
773
|
+
setHasSearched(true)
|
|
774
|
+
setRefreshKey((prev) => prev + 1)
|
|
775
|
+
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
|
|
779
|
+
const transformCustomFilterRules = (filterRules: any) => {
|
|
780
|
+
const transformedFilter = transformRulesToFilters(filterRules[0], viewData);
|
|
781
|
+
// If there's a predefined search, merge it with the new custom filter
|
|
782
|
+
let finalCustomFilter = transformedFilter;
|
|
783
|
+
// if (predefinedSearchChip && predefinedSearchBaseFilter) {
|
|
784
|
+
// // Combine predefined filter with new custom filter
|
|
785
|
+
// finalCustomFilter = {
|
|
786
|
+
// $and: [predefinedSearchBaseFilter, transformedFilter]
|
|
787
|
+
// };
|
|
788
|
+
// }
|
|
789
|
+
setCustomFilter(finalCustomFilter);
|
|
790
|
+
// handleApplyCustomFilter(finalFilter);
|
|
791
|
+
setShowGlobalSearchElement(false);
|
|
792
|
+
setHasSearched(true)
|
|
793
|
+
setRefreshKey((prev) => prev + 1)
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
const transformSavedFilterRules = (filterRules: any) => {
|
|
797
|
+
const transformedFilter = transformRulesToFilters(filterRules[0], viewData);
|
|
798
|
+
|
|
799
|
+
// If there's a predefined search, merge it with the new custom filter
|
|
800
|
+
let finalCustomFilter = transformedFilter;
|
|
801
|
+
// if (predefinedSearchChip && predefinedSearchBaseFilter) {
|
|
802
|
+
// // Combine predefined filter with new custom filter
|
|
803
|
+
// finalCustomFilter = {
|
|
804
|
+
// $and: [predefinedSearchBaseFilter, transformedFilter]
|
|
805
|
+
// };
|
|
806
|
+
// }
|
|
807
|
+
setCurrentSavedFilterQuery(finalCustomFilter);
|
|
808
|
+
// handleApplyCustomFilter(finalFilter);
|
|
809
|
+
setShowSavedFilterComponent(false);
|
|
810
|
+
setHasSearched(true)
|
|
811
|
+
setRefreshKey((prev) => prev + 1)
|
|
812
|
+
|
|
813
|
+
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
useEffect(() => {
|
|
817
|
+
if (refreshKey > 0) {
|
|
818
|
+
console.log("refres", refreshKey);
|
|
819
|
+
console.log("hasSearched", hasSearched);
|
|
820
|
+
|
|
821
|
+
const formattedChips = {
|
|
822
|
+
$and: searchChips.map((chip: any) => ({
|
|
823
|
+
fieldName: chip.columnName,
|
|
824
|
+
matchMode: chip.matchMode,
|
|
825
|
+
value: [chip.value],
|
|
826
|
+
searchField: chip.searchField ?? "",
|
|
827
|
+
}))
|
|
828
|
+
};
|
|
829
|
+
|
|
830
|
+
|
|
831
|
+
const finalSearchFilter = tranformSearchToFilters(formattedChips);
|
|
832
|
+
setSearchFilter(finalSearchFilter);
|
|
833
|
+
|
|
834
|
+
let finalSavedFilter: any = currentSavedFilterQuery
|
|
835
|
+
const finalPredefinedFilter = predefinedSearchBaseFilter
|
|
836
|
+
|
|
837
|
+
const finalCustomFilter = customFilter
|
|
838
|
+
|
|
839
|
+
console.log("finalCustomFilter", finalCustomFilter);
|
|
840
|
+
console.log("finalPredefinedFilter", finalPredefinedFilter);
|
|
841
|
+
console.log("finalSavedFilter", finalSavedFilter);
|
|
842
|
+
console.log("finalSearchFilter", finalSearchFilter);
|
|
843
|
+
|
|
844
|
+
const finalFilter = mergeAllDiffFilters(finalCustomFilter, finalSearchFilter, finalSavedFilter, finalPredefinedFilter)
|
|
845
|
+
handleApplyCustomFilter(finalFilter);
|
|
846
|
+
// }
|
|
847
|
+
}
|
|
848
|
+
}, [refreshKey]);
|
|
849
|
+
|
|
850
|
+
|
|
851
|
+
// Handle predefined search selection
|
|
852
|
+
|
|
853
|
+
const hasCustomFilterChanged = () => {
|
|
854
|
+
if (!predefinedSearchChip || !customFilter || !predefinedSearchBaseFilter) {
|
|
855
|
+
return false;
|
|
856
|
+
}
|
|
857
|
+
// Deep comparison to check if filter has changed
|
|
858
|
+
return JSON.stringify(customFilter) !== JSON.stringify(predefinedSearchBaseFilter);
|
|
859
|
+
};
|
|
860
|
+
|
|
861
|
+
const openSavedCustomFilter = async (savedfilter: any) => {
|
|
862
|
+
//Open custom filter popup
|
|
863
|
+
// router.push(`?savedQuery=${savedfilter.id}`);
|
|
864
|
+
// setShowGlobalSearchElement(true);
|
|
865
|
+
// // dont refetch the data yet
|
|
866
|
+
// const customFilter = JSON.parse(savedfilter.filterQueryJson);
|
|
867
|
+
// setCustomFilter(customFilter ? customFilter : null);
|
|
868
|
+
// if (customFilter) {
|
|
869
|
+
// const formatedCustomChips: FilterRule = transformFiltersToRules(customFilter ? customFilter : null);
|
|
870
|
+
// setFilterRules(formatedCustomChips ? [formatedCustomChips] : initialState);
|
|
871
|
+
// }
|
|
872
|
+
|
|
873
|
+
|
|
874
|
+
setSearchChips([]);
|
|
875
|
+
setSearchFilter(null);
|
|
876
|
+
setFilterRules(initialState);
|
|
877
|
+
setCustomFilter(null)
|
|
878
|
+
setPredefinedSearchChip(null);
|
|
879
|
+
setPredefinedSearchBaseFilter(null);
|
|
880
|
+
|
|
881
|
+
// push the savedQuery=1 in url
|
|
882
|
+
if (savedfilter?.id) {
|
|
883
|
+
const savedfilterId = savedfilter.id;
|
|
884
|
+
// router.push(`?savedQuery=${savedfilter.id}`);
|
|
885
|
+
setShowOverlay(false);
|
|
886
|
+
const currentSavedFilterData: any = savedFilters.find((savedFilter: any) => savedFilter.id === savedfilterId);
|
|
887
|
+
setCurrentSavedFilterData(currentSavedFilterData);
|
|
888
|
+
if (currentSavedFilterData) {
|
|
889
|
+
const filterJson = JSON.parse(currentSavedFilterData?.filterQueryJson);
|
|
890
|
+
if (filterJson) {
|
|
891
|
+
let finalSavedFilter = filterJson
|
|
892
|
+
setCurrentSavedFilterQuery(finalSavedFilter)
|
|
893
|
+
const rules: FilterRule = transformFiltersToRules(finalSavedFilter ? finalSavedFilter : null);
|
|
894
|
+
const hydratedRules = await hydrateRelationRules(
|
|
895
|
+
[rules],
|
|
896
|
+
viewData
|
|
897
|
+
);
|
|
898
|
+
setCurrentSavedFilterRules(hydratedRules ? hydratedRules : initialState);
|
|
899
|
+
setShowSavedFilterComponent(true)
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
} else {
|
|
903
|
+
console.error(ERROR_MESSAGES.SAVE_FILTER_UNDEFINED_NULL);
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
}
|
|
907
|
+
const deleteSavedFilter = async () => {
|
|
908
|
+
// delte the saved filter with id
|
|
909
|
+
await deleteEntity(savedFilterTobeDeleted);
|
|
910
|
+
// triggerGetSolidEntities(savedFilterQueryString);
|
|
911
|
+
let parsedSearchParams = searchParams;
|
|
912
|
+
const savedQuery = parsedSearchParams?.get("savedQuery");
|
|
913
|
+
if (savedFilterTobeDeleted == savedQuery) {
|
|
914
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
915
|
+
urlParams.delete("savedQuery");
|
|
916
|
+
router.push(`?${urlParams.toString()}`);
|
|
917
|
+
}
|
|
918
|
+
setIsDeleteSQDialogVisible(false);
|
|
919
|
+
setTimeout(() => {
|
|
920
|
+
setSavedFilterFetchDataRefreshKey(prev => prev + 1)
|
|
921
|
+
}, 500)
|
|
922
|
+
}
|
|
923
|
+
const handleSaveFilter = async (formValues: any) => {
|
|
924
|
+
setShowSaveFilterPopup(false)
|
|
925
|
+
|
|
926
|
+
try {
|
|
927
|
+
if (formValues.id) {
|
|
928
|
+
const filterJson = currentSavedFilterQuery;
|
|
929
|
+
const formData = new FormData();
|
|
930
|
+
formData.append("name", formValues.name);
|
|
931
|
+
formData.append("filterQueryJson", JSON.stringify(filterJson, null, 2));
|
|
932
|
+
formData.append("modelId", viewData?.data?.solidView?.model?.id);
|
|
933
|
+
formData.append("viewId", viewData?.data?.solidView?.id);
|
|
934
|
+
formData.append("isPrivate", formValues.isPrivate);
|
|
935
|
+
formData.append("userId", user?.user?.id);
|
|
936
|
+
|
|
937
|
+
await updateEntity({ id: +formValues.id, data: formData }).unwrap();
|
|
938
|
+
|
|
939
|
+
setSearchChips([]);
|
|
940
|
+
setSearchFilter(null);
|
|
941
|
+
setFilterRules(initialState);
|
|
942
|
+
setCustomFilter(null)
|
|
943
|
+
setPredefinedSearchChip(null);
|
|
944
|
+
const currentPageUrl = window.location.pathname; // Get the current page URL
|
|
945
|
+
localStorage.removeItem(currentPageUrl); // Store in local storage with the URL as the key
|
|
946
|
+
|
|
947
|
+
setPredefinedSearchBaseFilter(null);
|
|
948
|
+
setTimeout(() => {
|
|
949
|
+
router.push(`?savedQuery=${formValues.id}`);
|
|
950
|
+
}, 500)
|
|
951
|
+
} else {
|
|
952
|
+
|
|
953
|
+
const filterJson = customFilter;
|
|
954
|
+
const formData = new FormData();
|
|
955
|
+
formData.append("name", formValues.name);
|
|
956
|
+
formData.append("filterQueryJson", JSON.stringify(filterJson, null, 2));
|
|
957
|
+
formData.append("modelId", viewData?.data?.solidView?.model?.id);
|
|
958
|
+
formData.append("viewId", viewData?.data?.solidView?.id);
|
|
959
|
+
formData.append("isPrivate", formValues.isPrivate);
|
|
960
|
+
formData.append("userId", user?.user?.id);
|
|
961
|
+
const result = await createEntity(formData).unwrap();
|
|
962
|
+
|
|
963
|
+
setSearchChips([]);
|
|
964
|
+
setSearchFilter(null);
|
|
965
|
+
setFilterRules(initialState);
|
|
966
|
+
setCustomFilter(null)
|
|
967
|
+
setPredefinedSearchChip(null);
|
|
968
|
+
setPredefinedSearchBaseFilter(null);
|
|
969
|
+
|
|
970
|
+
const currentPageUrl = window.location.pathname; // Get the current page URL
|
|
971
|
+
localStorage.removeItem(currentPageUrl); // Store in local storage with the URL as the key
|
|
972
|
+
|
|
973
|
+
setTimeout(() => {
|
|
974
|
+
router.push(`?savedQuery=${result.data.id}`);
|
|
975
|
+
}, 500)
|
|
976
|
+
|
|
977
|
+
}
|
|
978
|
+
} catch (error) {
|
|
979
|
+
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
|
|
984
|
+
|
|
985
|
+
useEffect(() => {
|
|
986
|
+
// Explicitly type the event as a MouseEvent
|
|
987
|
+
function handleClickOutside(event: MouseEvent) {
|
|
988
|
+
if (overlayRef.current && !overlayRef.current.contains(event.target as Node)) {
|
|
989
|
+
setShowOverlay(false);
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
if (showOverlay) {
|
|
993
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
994
|
+
}
|
|
995
|
+
return () => {
|
|
996
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
997
|
+
};
|
|
998
|
+
}, [showOverlay]);
|
|
999
|
+
|
|
1000
|
+
const CustomChip = () => {
|
|
1001
|
+
console.log("customFilter", customFilter);
|
|
1002
|
+
const ruleCount =
|
|
1003
|
+
customFilter?.$or?.length ??
|
|
1004
|
+
customFilter?.$and?.length ??
|
|
1005
|
+
Object.keys(customFilter || {}).length;
|
|
1006
|
+
|
|
1007
|
+
return (
|
|
1008
|
+
<li>
|
|
1009
|
+
<div className="custom-filter-chip-type">
|
|
1010
|
+
<div className="flex align-items-center gap-2 text-base">
|
|
1011
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none"
|
|
1012
|
+
onClick={() => {
|
|
1013
|
+
setShowGlobalSearchElement(true)
|
|
1014
|
+
}
|
|
1015
|
+
}>
|
|
1016
|
+
<rect width="20" height="20" rx="4" fill="#722ED1" />
|
|
1017
|
+
<path d="M8.66667 15V13.3333H11.3333V15H8.66667ZM6 10.8333V9.16667H14V10.8333H6ZM4 6.66667V5H16V6.66667H4Z"
|
|
1018
|
+
fill="white" />
|
|
1019
|
+
</svg>
|
|
1020
|
+
<span><strong>{ruleCount}</strong> rules applied</span>
|
|
1021
|
+
</div>
|
|
1022
|
+
|
|
1023
|
+
{/* button to clear filter */}
|
|
1024
|
+
<a onClick={clearCustomFilter}
|
|
1025
|
+
style={{ cursor: "pointer" }}
|
|
1026
|
+
>
|
|
1027
|
+
<i className="pi pi-times ml-1">
|
|
1028
|
+
</i></a>
|
|
1029
|
+
</div>
|
|
1030
|
+
</li>
|
|
1031
|
+
)
|
|
1032
|
+
};
|
|
1033
|
+
|
|
1034
|
+
|
|
1035
|
+
//saved filter related code start
|
|
1036
|
+
|
|
1037
|
+
const applySavedFilter = (savedfilter: any) => {
|
|
1038
|
+
|
|
1039
|
+
setSearchChips([]);
|
|
1040
|
+
setSearchFilter(null);
|
|
1041
|
+
setFilterRules(initialState);
|
|
1042
|
+
setCustomFilter(null)
|
|
1043
|
+
setPredefinedSearchChip(null);
|
|
1044
|
+
setPredefinedSearchBaseFilter(null);
|
|
1045
|
+
const currentPageUrl = window.location.pathname; // Get the current page URL
|
|
1046
|
+
localStorage.removeItem(currentPageUrl); // Store in local storage with the URL as the key
|
|
1047
|
+
// push the savedQuery=1 in url
|
|
1048
|
+
if (savedfilter?.id) {
|
|
1049
|
+
router.push(`?savedQuery=${savedfilter.id}`);
|
|
1050
|
+
setShowOverlay(false);
|
|
1051
|
+
} else {
|
|
1052
|
+
console.error(ERROR_MESSAGES.SAVE_FILTER_UNDEFINED_NULL);
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
const removeSavedFilter = () => {
|
|
1057
|
+
const params = new URLSearchParams(searchParams.toString());
|
|
1058
|
+
setCurrentSavedFilterData(null);
|
|
1059
|
+
setCurrentSavedFilterQuery(null)
|
|
1060
|
+
if (params.has("savedQuery")) {
|
|
1061
|
+
params.delete("savedQuery");
|
|
1062
|
+
const newUrl = params.toString()
|
|
1063
|
+
? `${pathname}?${params.toString()}`
|
|
1064
|
+
: pathname;
|
|
1065
|
+
router.push(newUrl);
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
|
|
1070
|
+
const SavedFiltersChip = () => {
|
|
1071
|
+
|
|
1072
|
+
return (
|
|
1073
|
+
<li>
|
|
1074
|
+
<div className="custom-filter-chip-type">
|
|
1075
|
+
<div className="flex align-items-center gap-2 text-base">
|
|
1076
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none"
|
|
1077
|
+
onClick={() => {
|
|
1078
|
+
const fn = async () => {
|
|
1079
|
+
if (currentSavedFilterQuery) {
|
|
1080
|
+
const rules: FilterRule = transformFiltersToRules(currentSavedFilterQuery ? currentSavedFilterQuery : null);
|
|
1081
|
+
const hydratedRules = await hydrateRelationRules(
|
|
1082
|
+
[rules],
|
|
1083
|
+
viewData
|
|
1084
|
+
);
|
|
1085
|
+
setCurrentSavedFilterRules(hydratedRules ? hydratedRules : initialState);
|
|
1086
|
+
setShowSavedFilterComponent(true)
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
fn()
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
>
|
|
1093
|
+
<rect width="20" height="20" rx="4" fill="#722ED1" />
|
|
1094
|
+
<path d="M8.66667 15V13.3333H11.3333V15H8.66667ZM6 10.8333V9.16667H14V10.8333H6ZM4 6.66667V5H16V6.66667H4Z"
|
|
1095
|
+
fill="white" />
|
|
1096
|
+
</svg>
|
|
1097
|
+
<span><strong>{currentSavedFilterData?.name}</strong></span>
|
|
1098
|
+
</div>
|
|
1099
|
+
|
|
1100
|
+
{/* button to clear filter */}
|
|
1101
|
+
<a onClick={removeSavedFilter}
|
|
1102
|
+
style={{ cursor: "pointer" }}
|
|
1103
|
+
>
|
|
1104
|
+
<i className="pi pi-times ml-1">
|
|
1105
|
+
</i></a>
|
|
1106
|
+
</div>
|
|
1107
|
+
</li>
|
|
1108
|
+
)
|
|
1109
|
+
};
|
|
1110
|
+
|
|
1111
|
+
|
|
1112
|
+
|
|
1113
|
+
|
|
1114
|
+
//saved filter related code end
|
|
1115
|
+
|
|
1116
|
+
|
|
1117
|
+
// search related code start
|
|
1118
|
+
|
|
1119
|
+
const handleRemoveChipGroup = (columnName: string) => {
|
|
1120
|
+
const updatedChips = searchChips.filter(chip => chip.columnName !== columnName);
|
|
1121
|
+
setSearchChips(updatedChips);
|
|
1122
|
+
setHasSearched(true);
|
|
1123
|
+
setRefreshKey((prev) => prev + 1)
|
|
1124
|
+
|
|
1125
|
+
};
|
|
1126
|
+
|
|
1127
|
+
const groupedSearchChips = searchChips.reduce((acc: Record<string, string[]>, chip) => {
|
|
1128
|
+
const key = chip.columnName;
|
|
1129
|
+
if (!key) return acc; // skip if undefined
|
|
1130
|
+
|
|
1131
|
+
if (!acc[key]) {
|
|
1132
|
+
acc[key] = [];
|
|
1133
|
+
}
|
|
1134
|
+
acc[key].push(chip.value);
|
|
1135
|
+
return acc;
|
|
1136
|
+
}, {});
|
|
1137
|
+
|
|
1138
|
+
|
|
1139
|
+
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
|
1140
|
+
if (e.key === "Enter" && inputValue?.trim()) {
|
|
1141
|
+
handleAddChip();
|
|
1142
|
+
e.preventDefault();
|
|
1143
|
+
setShowOverlay(false);
|
|
1144
|
+
} else if (e.key === "Backspace" && inputValue === "") {
|
|
1145
|
+
|
|
1146
|
+
if (searchChips.length > 0) {
|
|
1147
|
+
setSearchChips((prev) => prev.slice(0, -1));
|
|
1148
|
+
} else if (customFilter) {
|
|
1149
|
+
setCustomFilter(null)
|
|
1150
|
+
setFilterRules(initialState);
|
|
1151
|
+
} else if (predefinedSearchChip) {
|
|
1152
|
+
setPredefinedSearchChip(null);
|
|
1153
|
+
setPredefinedSearchBaseFilter(null);
|
|
1154
|
+
} else if (activeSavedFilter) {
|
|
1155
|
+
removeSavedFilter()
|
|
1156
|
+
} else if (activeSavedFilter) {
|
|
1157
|
+
clearCustomFilter();
|
|
1158
|
+
}
|
|
1159
|
+
setHasSearched(true);
|
|
1160
|
+
setRefreshKey((prev) => prev + 1)
|
|
1161
|
+
}
|
|
1162
|
+
};
|
|
1163
|
+
|
|
1164
|
+
const SearchChip = () => (
|
|
1165
|
+
<>
|
|
1166
|
+
{Object.entries(groupedSearchChips).map(([column, values]) => {
|
|
1167
|
+
const fieldMeta = searchableFields.find(f => f.fieldName === column);
|
|
1168
|
+
const columnDisplayName = fieldMeta?.displayName || column;
|
|
1169
|
+
|
|
1170
|
+
return (
|
|
1171
|
+
<li key={column}>
|
|
1172
|
+
<div className="search-filter-chip-type">
|
|
1173
|
+
<div>{columnDisplayName}</div>
|
|
1174
|
+
{values.map((value, index) => (
|
|
1175
|
+
<React.Fragment>
|
|
1176
|
+
{/* displayname */}
|
|
1177
|
+
<span key={index} className="custom-chip-value">{value}
|
|
1178
|
+
</span>
|
|
1179
|
+
{index < values.length - 1 &&
|
|
1180
|
+
<span className="custom-chip-or">or</span>
|
|
1181
|
+
}
|
|
1182
|
+
</React.Fragment>
|
|
1183
|
+
))}
|
|
1184
|
+
{/* button to clear filter */}
|
|
1185
|
+
<i className="pi pi-times ml-1"
|
|
1186
|
+
style={{ cursor: "pointer" }}
|
|
1187
|
+
onClick={() => handleRemoveChipGroup(column)}
|
|
1188
|
+
>
|
|
1189
|
+
</i>
|
|
1190
|
+
</div>
|
|
1191
|
+
</li>
|
|
1192
|
+
)
|
|
1193
|
+
})}
|
|
1194
|
+
</>
|
|
1195
|
+
);
|
|
1196
|
+
|
|
1197
|
+
// search related code end
|
|
1198
|
+
|
|
1199
|
+
|
|
1200
|
+
// predefinedfilter related code start
|
|
1201
|
+
|
|
1202
|
+
const handlePredefinedSearch = (predefinedSearch: any) => {
|
|
1203
|
+
if (!inputValue?.trim()) return;
|
|
1204
|
+
|
|
1205
|
+
if (!predefinedSearch?.filters) {
|
|
1206
|
+
console.error('Invalid predefined search: missing filters', predefinedSearch);
|
|
1207
|
+
return;
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
try {
|
|
1211
|
+
// Replace {{search}} placeholders with actual search value
|
|
1212
|
+
const processedFilter = replacePlaceholders(predefinedSearch.filters, inputValue.trim());
|
|
1213
|
+
|
|
1214
|
+
// Clear all existing filters and searches
|
|
1215
|
+
// setSearchChips([]);
|
|
1216
|
+
// setSearchFilter(null);
|
|
1217
|
+
// setFilterRules(initialState);
|
|
1218
|
+
// setCustomFilter(null)
|
|
1219
|
+
// removeSavedFilter();
|
|
1220
|
+
// Set the predefined search chip
|
|
1221
|
+
setPredefinedSearchChip({
|
|
1222
|
+
name: predefinedSearch.name,
|
|
1223
|
+
value: inputValue.trim()
|
|
1224
|
+
});
|
|
1225
|
+
|
|
1226
|
+
setPredefinedSearchBaseFilter(processedFilter);
|
|
1227
|
+
|
|
1228
|
+
// Apply the predefined search filter as custom filter
|
|
1229
|
+
// setCustomFilter(processedFilter);
|
|
1230
|
+
|
|
1231
|
+
// Apply the filter
|
|
1232
|
+
// handleApplyCustomFilter(finalFilter);
|
|
1233
|
+
|
|
1234
|
+
// Clear input and close overlay
|
|
1235
|
+
setInputValue("");
|
|
1236
|
+
setShowOverlay(false);
|
|
1237
|
+
setHasSearched(true);
|
|
1238
|
+
setRefreshKey((prev) => prev + 1)
|
|
1239
|
+
} catch (error) {
|
|
1240
|
+
console.error('Error applying predefined search:', error);
|
|
1241
|
+
// Optionally show user-friendly error message
|
|
1242
|
+
}
|
|
1243
|
+
};
|
|
1244
|
+
|
|
1245
|
+
|
|
1246
|
+
const removePredefinedSearchChip = () => {
|
|
1247
|
+
setPredefinedSearchChip(null);
|
|
1248
|
+
setPredefinedSearchBaseFilter(null)
|
|
1249
|
+
setCustomFilter(null);
|
|
1250
|
+
// handleApplyCustomFilter(finalFilter);
|
|
1251
|
+
setHasSearched(true);
|
|
1252
|
+
setRefreshKey((prev) => prev + 1)
|
|
1253
|
+
};
|
|
1254
|
+
|
|
1255
|
+
const PredefinedSearchChip = () => (
|
|
1256
|
+
<li>
|
|
1257
|
+
<div className="search-filter-chip-type">
|
|
1258
|
+
<div className="flex align-items-center gap-2">
|
|
1259
|
+
<strong>{predefinedSearchChip?.name}:</strong>
|
|
1260
|
+
<span className="custom-chip-value">{predefinedSearchChip?.value}</span>
|
|
1261
|
+
</div>
|
|
1262
|
+
{/* button to clear filter */}
|
|
1263
|
+
<i className="pi pi-times ml-1"
|
|
1264
|
+
style={{ cursor: "pointer" }}
|
|
1265
|
+
onClick={removePredefinedSearchChip}
|
|
1266
|
+
>
|
|
1267
|
+
</i>
|
|
1268
|
+
</div>
|
|
1269
|
+
</li>
|
|
1270
|
+
);
|
|
1271
|
+
|
|
1272
|
+
// predefinedfilter related code end
|
|
1273
|
+
|
|
1274
|
+
return (
|
|
1275
|
+
<>
|
|
1276
|
+
<div className="flex justify-content-center solid-custom-filter-wrapper relative">
|
|
1277
|
+
<div className="solid-global-search-element">
|
|
1278
|
+
<ul className="">
|
|
1279
|
+
{currentSavedFilterData && <SavedFiltersChip />}
|
|
1280
|
+
{predefinedSearchChip && <PredefinedSearchChip />}
|
|
1281
|
+
{customFilter && <CustomChip />}
|
|
1282
|
+
<SearchChip />
|
|
1283
|
+
<li ref={chipsRef}>
|
|
1284
|
+
<div className="relative solid-global-search-element-wrapper">
|
|
1285
|
+
<InputText
|
|
1286
|
+
value={inputValue || ""}
|
|
1287
|
+
placeholder="Search..."
|
|
1288
|
+
onChange={(e) => {
|
|
1289
|
+
setInputValue(e.target.value);
|
|
1290
|
+
setShowOverlay(true);
|
|
1291
|
+
}}
|
|
1292
|
+
onFocus={() => {
|
|
1293
|
+
if (inputValue?.trim()) setShowOverlay(true);
|
|
1294
|
+
}}
|
|
1295
|
+
onBlur={() => {
|
|
1296
|
+
// Delay so you can click buttons inside overlay
|
|
1297
|
+
setTimeout(() => setShowOverlay(false), 150);
|
|
1298
|
+
}}
|
|
1299
|
+
|
|
1300
|
+
onKeyDown={handleKeyDown}
|
|
1301
|
+
/>
|
|
1302
|
+
<Button
|
|
1303
|
+
icon="pi pi-search"
|
|
1304
|
+
style={{ fontSize: 10 }}
|
|
1305
|
+
severity="secondary"
|
|
1306
|
+
outlined size="small"
|
|
1307
|
+
onClick={() => setShowOverlay(true)}
|
|
1308
|
+
className="custom-filter-button"
|
|
1309
|
+
/>
|
|
1310
|
+
</div>
|
|
1311
|
+
</li>
|
|
1312
|
+
</ul>
|
|
1313
|
+
</div>
|
|
1314
|
+
|
|
1315
|
+
{showOverlay && (
|
|
1316
|
+
<div ref={overlayRef} className="absolute w-full z-5 surface-0 border-round border-1 border-300 shadow-2 solid-search-overlay-pannel" style={{ top: 35 }}>
|
|
1317
|
+
{inputValue ? (
|
|
1318
|
+
<>
|
|
1319
|
+
<div className="custom-filter-search-options px-3 py-2 flex flex-column">
|
|
1320
|
+
<h6 className="my-1 font-bold">Search By Fields</h6>
|
|
1321
|
+
{
|
|
1322
|
+
searchableFields.map((value: any, index: any) => {
|
|
1323
|
+
// console.log("value", value);
|
|
1324
|
+
|
|
1325
|
+
return (
|
|
1326
|
+
<Button
|
|
1327
|
+
key={index}
|
|
1328
|
+
className="p-2 flex gap-1 text-color"
|
|
1329
|
+
// onClick={() => handleAddChip(value)}
|
|
1330
|
+
onMouseDown={(e) => {
|
|
1331
|
+
// Prevent focus loss from input
|
|
1332
|
+
e.preventDefault();
|
|
1333
|
+
const currentValue = inputValue?.trim();
|
|
1334
|
+
if (currentValue) {
|
|
1335
|
+
const values = currentValue.split(",").map((v) => v.trim()).filter((v) => v !== "");
|
|
1336
|
+
const chipsToAdd = values.map(v => ({
|
|
1337
|
+
columnName: value.fieldName,
|
|
1338
|
+
value: v,
|
|
1339
|
+
columnDisplayName: value.displayName,
|
|
1340
|
+
searchField: value.searchField,
|
|
1341
|
+
matchMode: value.matchMode
|
|
1342
|
+
}));
|
|
1343
|
+
setSearchChips((prev) => [...prev, ...chipsToAdd]);
|
|
1344
|
+
setInputValue("");
|
|
1345
|
+
setHasSearched(true);
|
|
1346
|
+
setRefreshKey((prev) => prev + 1)
|
|
1347
|
+
setShowOverlay(false);
|
|
1348
|
+
}
|
|
1349
|
+
}}
|
|
1350
|
+
text
|
|
1351
|
+
severity="secondary"
|
|
1352
|
+
size="small"
|
|
1353
|
+
>
|
|
1354
|
+
Search <strong>{value.displayName}</strong> for: <span className="font-bold text-color">{inputValue}</span>
|
|
1355
|
+
</Button>
|
|
1356
|
+
)
|
|
1357
|
+
})
|
|
1358
|
+
}
|
|
1359
|
+
</div>
|
|
1360
|
+
{predefinedSearches && predefinedSearches.length > 0 && (
|
|
1361
|
+
<>
|
|
1362
|
+
<Divider className="m-0" />
|
|
1363
|
+
<div className="custom-filter-search-options px-3 py-2 flex flex-column">
|
|
1364
|
+
<h6 className="my-1 font-bold">Predefined Searches</h6>
|
|
1365
|
+
{predefinedSearches.map((predefinedSearch: any, index: number) => (
|
|
1366
|
+
<Button
|
|
1367
|
+
key={index}
|
|
1368
|
+
className="p-2 flex flex-column align-items-start gap-1 text-color"
|
|
1369
|
+
onMouseDown={(e) => {
|
|
1370
|
+
e.preventDefault();
|
|
1371
|
+
handlePredefinedSearch(predefinedSearch);
|
|
1372
|
+
}}
|
|
1373
|
+
text
|
|
1374
|
+
severity="secondary"
|
|
1375
|
+
size="small"
|
|
1376
|
+
>
|
|
1377
|
+
<div className="flex gap-1 align-items-center">
|
|
1378
|
+
<strong>{predefinedSearch.name}:</strong>
|
|
1379
|
+
<span className="font-bold text-color">{inputValue}</span>
|
|
1380
|
+
</div>
|
|
1381
|
+
<div className="text-xs">{predefinedSearch.description}</div>
|
|
1382
|
+
</Button>
|
|
1383
|
+
))}
|
|
1384
|
+
</div>
|
|
1385
|
+
</>
|
|
1386
|
+
)}
|
|
1387
|
+
</>
|
|
1388
|
+
) :
|
|
1389
|
+
<>
|
|
1390
|
+
<div className="p-3 text-base">Search Here...</div>
|
|
1391
|
+
<Divider className="m-0" />
|
|
1392
|
+
</>
|
|
1393
|
+
}
|
|
1394
|
+
{savedFilters.length > 0 &&
|
|
1395
|
+
<>
|
|
1396
|
+
<div className="p-3">
|
|
1397
|
+
<p className="font-medium">Saved Filters</p>
|
|
1398
|
+
<div className="flex flex-column gap-2">
|
|
1399
|
+
{savedFilters.map((savedfilter: any) =>
|
|
1400
|
+
<SavedFilterList savedfilter={savedfilter} activeSavedFilter={activeSavedFilter} applySavedFilter={applySavedFilter} openSavedCustomFilter={openSavedCustomFilter} setSavedFilterTobeDeleted={setSavedFilterTobeDeleted} setIsDeleteSQDialogVisible={setIsDeleteSQDialogVisible}></SavedFilterList>
|
|
1401
|
+
)}
|
|
1402
|
+
</div>
|
|
1403
|
+
</div>
|
|
1404
|
+
<Divider className="m-0" />
|
|
1405
|
+
</>
|
|
1406
|
+
}
|
|
1407
|
+
<div className="px-2 py-1">
|
|
1408
|
+
<Button text size="small" label="Custom Filter" iconPos="left" icon='pi pi-plus' onClick={() => setShowGlobalSearchElement(true)} className="font-bold" />
|
|
1409
|
+
</div>
|
|
1410
|
+
</div>
|
|
1411
|
+
)
|
|
1412
|
+
}
|
|
1413
|
+
<Dialog header={false} className="solid-global-search-filter" showHeader={false} visible={showGlobalSearchElement} style={{ width: '65vw' }} breakpoints={{ '1024px': '75vw', '991px': '90vw', '767px': '94w', '250px': '96vw' }} onHide={() => { if (!showGlobalSearchElement) return; setShowGlobalSearchElement(false); }}>
|
|
1414
|
+
<div className="flex align-items-center justify-content-between px-3">
|
|
1415
|
+
<h5 className="solid-custom-title m-0">Add Custom Filter</h5>
|
|
1416
|
+
<Button icon="pi pi-times" rounded text aria-label="Cancel" type="reset" size="small" onClick={() => setShowGlobalSearchElement(false)} />
|
|
1417
|
+
</div>
|
|
1418
|
+
<Divider className="m-0" />
|
|
1419
|
+
<div className="p-3 lg:p-4">
|
|
1420
|
+
{fields.length > 0 &&
|
|
1421
|
+
<FilterComponent viewData={viewData} fields={fields} filterRules={filterRules} setFilterRules={setFilterRules} transformFilterRules={transformCustomFilterRules} closeDialog={() => setShowGlobalSearchElement(false)}></FilterComponent>
|
|
1422
|
+
}
|
|
1423
|
+
</div>
|
|
1424
|
+
</Dialog>
|
|
1425
|
+
<Dialog header={false} className="solid-global-search-filter" showHeader={false} visible={showSavedFilterComponent} style={{ width: '65vw' }} breakpoints={{ '1024px': '75vw', '991px': '90vw', '767px': '94w', '250px': '96vw' }} onHide={() => { if (!showSavedFilterComponent) return; setShowSavedFilterComponent(false); }}>
|
|
1426
|
+
<div className="flex align-items-center justify-content-between px-3">
|
|
1427
|
+
<h5 className="solid-custom-title m-0">Saved Filter</h5>
|
|
1428
|
+
<Button icon="pi pi-times" rounded text aria-label="Cancel" type="reset" size="small" onClick={() => setShowSavedFilterComponent(false)} />
|
|
1429
|
+
</div>
|
|
1430
|
+
<Divider className="m-0" />
|
|
1431
|
+
<div className="p-3 lg:p-4">
|
|
1432
|
+
{fields.length > 0 &&
|
|
1433
|
+
<FilterComponent viewData={viewData} fields={fields} filterRules={currentSavedFilterRules} setFilterRules={setCurrentSavedFilterRules} transformFilterRules={transformSavedFilterRules} closeDialog={() => setShowSavedFilterComponent(false)}></FilterComponent>
|
|
1434
|
+
}
|
|
1435
|
+
</div>
|
|
1436
|
+
</Dialog>
|
|
1437
|
+
<Dialog header="Save Custom Filter" className="solid-custom-filter-dialog" visible={showSaveFilterPopup} style={{ width: 500 }} onHide={() => { if (!showSaveFilterPopup) return; setShowSaveFilterPopup(false); }}>
|
|
1438
|
+
<SolidSaveCustomFilterForm currentSavedFilterData={currentSavedFilterData} handleSaveFilter={handleSaveFilter} closeDialog={setShowSaveFilterPopup}></SolidSaveCustomFilterForm>
|
|
1439
|
+
</Dialog>
|
|
1440
|
+
|
|
1441
|
+
<Dialog
|
|
1442
|
+
visible={isDeleteSQDialogVisible}
|
|
1443
|
+
header="Confirm Delete"
|
|
1444
|
+
modal
|
|
1445
|
+
className="solid-confirm-dialog"
|
|
1446
|
+
footer={() => (
|
|
1447
|
+
<div className="flex justify-content-center">
|
|
1448
|
+
<Button label="Yes" icon="pi pi-check" className='small-button' severity="danger" autoFocus onClick={deleteSavedFilter} />
|
|
1449
|
+
<Button label="No" icon="pi pi-times" className='small-button' onClick={() => setIsDeleteSQDialogVisible(false)} />
|
|
1450
|
+
</div>
|
|
1451
|
+
)}
|
|
1452
|
+
onHide={() => setIsDeleteSQDialogVisible(false)}
|
|
1453
|
+
>
|
|
1454
|
+
<p>Are you sure you want to delete the {currentSavedFilterData?.name} saved query?</p>
|
|
1455
|
+
</Dialog>
|
|
1456
|
+
</div>
|
|
1457
|
+
{/* <div>
|
|
1458
|
+
<Button
|
|
1459
|
+
icon="pi pi-save"
|
|
1460
|
+
style={{ fontSize: 10 }}
|
|
1461
|
+
severity="secondary"
|
|
1462
|
+
outlined size="small"
|
|
1463
|
+
onClick={() => {
|
|
1464
|
+
setShowSaveFilterPopup(true)
|
|
1465
|
+
}}
|
|
1466
|
+
/>
|
|
1467
|
+
</div> */}
|
|
1468
|
+
</>
|
|
1469
|
+
)
|
|
1470
|
+
});
|