@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.
Files changed (373) hide show
  1. package/dist/components/Svg/DevDocs.tsx +9 -0
  2. package/dist/components/Svg/DocsSvg.tsx +9 -0
  3. package/dist/components/Svg/ExcelSvg.tsx +15 -0
  4. package/dist/components/Svg/FieldSvg.tsx +9 -0
  5. package/dist/components/Svg/FileSvg.tsx +18 -0
  6. package/dist/components/Svg/HomePageModuleSvg.tsx +179 -0
  7. package/dist/components/Svg/ModelSvg.tsx +9 -0
  8. package/dist/components/Svg/ModuleSvg.tsx +9 -0
  9. package/dist/components/Svg/PDFSvg.tsx +15 -0
  10. package/dist/components/Svg/RightArrowSvg.tsx +9 -0
  11. package/dist/components/Svg/SettingsSvg.tsx +9 -0
  12. package/dist/components/auth/AuthLayout.tsx +223 -0
  13. package/dist/components/auth/ForgotPasswordThankYou.tsx +33 -0
  14. package/dist/components/auth/GoogleAuthChecking.tsx +63 -0
  15. package/dist/components/auth/SolidChangeForcePassword.tsx +222 -0
  16. package/dist/components/auth/SolidForgotPassword.tsx +127 -0
  17. package/dist/components/auth/SolidInitialLoginOtp.tsx +271 -0
  18. package/dist/components/auth/SolidInitiateRegisterOtp.tsx +218 -0
  19. package/dist/components/auth/SolidLogin.d.ts.map +1 -1
  20. package/dist/components/auth/SolidLogin.js +14 -8
  21. package/dist/components/auth/SolidLogin.js.map +1 -1
  22. package/dist/components/auth/SolidLogin.tsx +428 -0
  23. package/dist/components/auth/SolidOTPVerify.tsx +133 -0
  24. package/dist/components/auth/SolidRegister.tsx +454 -0
  25. package/dist/components/auth/SolidResetPassword.tsx +194 -0
  26. package/dist/components/common/AuthBanner.tsx +41 -0
  27. package/dist/components/common/AutoCompleteField.tsx +79 -0
  28. package/dist/components/common/BackButton.tsx +72 -0
  29. package/dist/components/common/CancelButton.tsx +61 -0
  30. package/dist/components/common/CodeEditor.tsx +38 -0
  31. package/dist/components/common/CreateButton.tsx +17 -0
  32. package/dist/components/common/DownloadProgressToast.tsx +55 -0
  33. package/dist/components/common/DropzonePlaceholder.tsx +31 -0
  34. package/dist/components/common/DropzoneUpload.tsx +11 -0
  35. package/dist/components/common/FileReaderExt.tsx +20 -0
  36. package/dist/components/common/GeneralSettings.tsx +1225 -0
  37. package/dist/components/common/HeaderDynamicTitles.tsx +13 -0
  38. package/dist/components/common/MarkdownViewer.tsx +84 -0
  39. package/dist/components/common/MultipleSelectAutoCompleteField.tsx +64 -0
  40. package/dist/components/common/NotFound.tsx +22 -0
  41. package/dist/components/common/SingleSelectAutoCompleteField.tsx +73 -0
  42. package/dist/components/common/SocialMediaLogin.tsx +53 -0
  43. package/dist/components/common/SolidAdmin.tsx +6 -0
  44. package/dist/components/common/SolidBreadcrumb.tsx +129 -0
  45. package/dist/components/common/SolidExport.tsx +563 -0
  46. package/dist/components/common/SolidExportStepper.tsx +135 -0
  47. package/dist/components/common/SolidFieldTooltip.tsx +23 -0
  48. package/dist/components/common/SolidFormHeader.tsx +25 -0
  49. package/dist/components/common/SolidFormStepper.tsx +350 -0
  50. package/dist/components/common/SolidModuleHome.tsx +128 -0
  51. package/dist/components/common/SolidPopupContainer.tsx +37 -0
  52. package/dist/components/common/SolidSettings/LlmSettings/AnthropicProviderComponent.tsx +45 -0
  53. package/dist/components/common/SolidSettings/LlmSettings/OpenAiProviderComponent.tsx +45 -0
  54. package/dist/components/common/SolidSettings/SettingDropzoneActivePlaceholder.tsx +20 -0
  55. package/dist/components/common/SolidSettings/SettingsImageRemoveButton.tsx +15 -0
  56. package/dist/components/common/SolidSettings/SolidUploadedImage.tsx +16 -0
  57. package/dist/components/common/SolidThemeLink.tsx +6 -0
  58. package/dist/components/common/SolidThemeProvider.tsx +44 -0
  59. package/dist/components/common/StepperArrows/ActiveArrowStep.tsx +18 -0
  60. package/dist/components/common/StepperArrows/ActiveBeforeStepArrow.tsx +18 -0
  61. package/dist/components/common/StepperArrows/InactiveStepArrow.tsx +19 -0
  62. package/dist/components/common/error.tsx +30 -0
  63. package/dist/components/common/useHandleFormCustomButtonClick.ts +40 -0
  64. package/dist/components/common/useHandleListCustomButtonClick.ts +42 -0
  65. package/dist/components/core/chatter/SolidChatter.tsx +248 -0
  66. package/dist/components/core/chatter/SolidChatterAuditMessage.tsx +35 -0
  67. package/dist/components/core/chatter/SolidChatterCustomMessage.tsx +46 -0
  68. package/dist/components/core/chatter/SolidChatterDateDivider.tsx +16 -0
  69. package/dist/components/core/chatter/SolidChatterHeader.tsx +218 -0
  70. package/dist/components/core/chatter/SolidChatterMessageBox.tsx +163 -0
  71. package/dist/components/core/chatter/SolidMessageComposer.tsx +146 -0
  72. package/dist/components/core/common/AvatarWidget.tsx +55 -0
  73. package/dist/components/core/common/DateFieldViewComponent.tsx +36 -0
  74. package/dist/components/core/common/FilterComponent.tsx +458 -0
  75. package/dist/components/core/common/LoadDynamicJsxComponent.tsx +70 -0
  76. package/dist/components/core/common/PDFViewer.tsx +117 -0
  77. package/dist/components/core/common/SolidAccountSettings/SolidAccountSettings.tsx +89 -0
  78. package/dist/components/core/common/SolidAccountSettings/SolidChangePassword.tsx +188 -0
  79. package/dist/components/core/common/SolidAccountSettings/SolidNotifications.tsx +139 -0
  80. package/dist/components/core/common/SolidAccountSettings/SolidPersonalInfo.tsx +311 -0
  81. package/dist/components/core/common/SolidCreateButton.tsx +48 -0
  82. package/dist/components/core/common/SolidGenericImport/DocumentSvg.tsx +15 -0
  83. package/dist/components/core/common/SolidGenericImport/SolidGenericImport.tsx +64 -0
  84. package/dist/components/core/common/SolidGenericImport/SolidImportDropzone.tsx +125 -0
  85. package/dist/components/core/common/SolidGenericImport/SolidImportInstructions.tsx +122 -0
  86. package/dist/components/core/common/SolidGenericImport/SolidImportStepper.tsx +217 -0
  87. package/dist/components/core/common/SolidGenericImport/SolidImportTransaction.tsx +205 -0
  88. package/dist/components/core/common/SolidGenericImport/SolidImportTransactionStatus.tsx +158 -0
  89. package/dist/components/core/common/SolidGenericImport/SolidImportWrapper.tsx +29 -0
  90. package/dist/components/core/common/SolidGlobalSearchElement.tsx +1470 -0
  91. package/dist/components/core/common/SolidLayoutViews.tsx +87 -0
  92. package/dist/components/core/common/SolidListViewOptions.tsx +31 -0
  93. package/dist/components/core/common/SolidLoaders/SolidCircularLoader.tsx +7 -0
  94. package/dist/components/core/common/SolidPasswordHelperText.tsx +34 -0
  95. package/dist/components/core/common/SolidSaveCustomFilterForm.tsx +75 -0
  96. package/dist/components/core/common/SolidSearchBox.tsx +17 -0
  97. package/dist/components/core/common/SolidViewLayoutManager.ts +421 -0
  98. package/dist/components/core/common/SolidXAiIframe.tsx +77 -0
  99. package/dist/components/core/dashboard/SolidDashboard.tsx +332 -0
  100. package/dist/components/core/dashboard/SolidDashboardBody.tsx +117 -0
  101. package/dist/components/core/dashboard/SolidDashboardFilterRequired.tsx +28 -0
  102. package/dist/components/core/dashboard/SolidDashboardHeader.tsx +10 -0
  103. package/dist/components/core/dashboard/SolidDashboardLoading.tsx +55 -0
  104. package/dist/components/core/dashboard/SolidDashboardNotAvailable.tsx +32 -0
  105. package/dist/components/core/dashboard/SolidDashboardRenderError.tsx +29 -0
  106. package/dist/components/core/dashboard/SolidDashboardVariable.tsx +256 -0
  107. package/dist/components/core/dashboard/SolidQuestionRenderer.tsx +78 -0
  108. package/dist/components/core/dashboard/chart-renderers/ChartJsRenderer.tsx +18 -0
  109. package/dist/components/core/dashboard/chart-renderers/PrimeReactDatatableRenderer.tsx +54 -0
  110. package/dist/components/core/dashboard/chart-renderers/init-chartjs.ts +25 -0
  111. package/dist/components/core/dashboard/dashboard-utils.ts +39 -0
  112. package/dist/components/core/extension/solid-core/CustomIcon/StatusIcon.tsx +17 -0
  113. package/dist/components/core/extension/solid-core/dashboardQuestion/ChartFormPreviewWidget.tsx +36 -0
  114. package/dist/components/core/extension/solid-core/emailTemplate/emailFormTypeChangeHandler.ts +18 -0
  115. package/dist/components/core/extension/solid-core/emailTemplate/emailFormTypeLoad.ts +18 -0
  116. package/dist/components/core/extension/solid-core/modelMetadata/list/DeleteModelRowAction.tsx +114 -0
  117. package/dist/components/core/extension/solid-core/modelMetadata/list/GenerateModelCodeRowAction.tsx +213 -0
  118. package/dist/components/core/extension/solid-core/moduleMetadata/list/DeleteModuleRowAction.tsx +138 -0
  119. package/dist/components/core/extension/solid-core/moduleMetadata/list/GenerateModuleCodeRowAction.tsx +209 -0
  120. package/dist/components/core/extension/solid-core/roleMetadata/RolePermissionsManyToManyFieldWidget.tsx +131 -0
  121. package/dist/components/core/field/FieldListViewData.tsx +313 -0
  122. package/dist/components/core/filter/SolidBooleanFilterElement.tsx +30 -0
  123. package/dist/components/core/filter/SolidFilterFields.tsx +131 -0
  124. package/dist/components/core/filter/SolidManyToManyFilterElement.tsx +64 -0
  125. package/dist/components/core/filter/SolidManyToOneFilterElement.tsx +61 -0
  126. package/dist/components/core/filter/SolidSelectionDynamicFilterElement.tsx +50 -0
  127. package/dist/components/core/filter/SolidSelectionStaticFilterElement.tsx +32 -0
  128. package/dist/components/core/filter/SolidVarInputsFilterElement.tsx +209 -0
  129. package/dist/components/core/filter/fields/SolidBigintField.tsx +9 -0
  130. package/dist/components/core/filter/fields/SolidBooleanField.tsx +68 -0
  131. package/dist/components/core/filter/fields/SolidComputedField.tsx +23 -0
  132. package/dist/components/core/filter/fields/SolidDateField.tsx +63 -0
  133. package/dist/components/core/filter/fields/SolidDatetimeField.tsx +54 -0
  134. package/dist/components/core/filter/fields/SolidDecimalField.tsx +9 -0
  135. package/dist/components/core/filter/fields/SolidExternalIdField.tsx +52 -0
  136. package/dist/components/core/filter/fields/SolidFloatField.tsx +9 -0
  137. package/dist/components/core/filter/fields/SolidIdField.tsx +46 -0
  138. package/dist/components/core/filter/fields/SolidIntField.tsx +61 -0
  139. package/dist/components/core/filter/fields/SolidLongTextField.tsx +9 -0
  140. package/dist/components/core/filter/fields/SolidMediaMultipleField.tsx +60 -0
  141. package/dist/components/core/filter/fields/SolidMediaSingleField.tsx +62 -0
  142. package/dist/components/core/filter/fields/SolidRelationField.tsx +17 -0
  143. package/dist/components/core/filter/fields/SolidRichTextField.tsx +9 -0
  144. package/dist/components/core/filter/fields/SolidSelectionDynamicField.tsx +52 -0
  145. package/dist/components/core/filter/fields/SolidSelectionStaticField.tsx +54 -0
  146. package/dist/components/core/filter/fields/SolidShortTextField.tsx +60 -0
  147. package/dist/components/core/filter/fields/SolidTimeField.tsx +48 -0
  148. package/dist/components/core/filter/fields/SolidUuidField.tsx +51 -0
  149. package/dist/components/core/filter/fields/relations/SolidRelationManyToManyField.tsx +62 -0
  150. package/dist/components/core/filter/fields/relations/SolidRelationManyToOneField.tsx +84 -0
  151. package/dist/components/core/form/SolidFormActionHeader.tsx +497 -0
  152. package/dist/components/core/form/SolidFormFieldRender.tsx +53 -0
  153. package/dist/components/core/form/SolidFormFieldRenderExtension.tsx +26 -0
  154. package/dist/components/core/form/SolidFormFooter.tsx +162 -0
  155. package/dist/components/core/form/SolidFormLayouts.tsx +104 -0
  156. package/dist/components/core/form/SolidFormUserViewLayout.tsx +84 -0
  157. package/dist/components/core/form/SolidFormView.tsx +1856 -0
  158. package/dist/components/core/form/SolidFormViewContextMenuHeaderButton.tsx +52 -0
  159. package/dist/components/core/form/SolidFormViewNormalHeaderButton.tsx +52 -0
  160. package/dist/components/core/form/SolidFormViewShimmerLoading.tsx +109 -0
  161. package/dist/components/core/form/fields/ISolidField.tsx +71 -0
  162. package/dist/components/core/form/fields/SolidBooleanField.tsx +434 -0
  163. package/dist/components/core/form/fields/SolidDateField.tsx +247 -0
  164. package/dist/components/core/form/fields/SolidDateTimeField.tsx +229 -0
  165. package/dist/components/core/form/fields/SolidDecimalField.tsx +171 -0
  166. package/dist/components/core/form/fields/SolidEmailField.tsx +176 -0
  167. package/dist/components/core/form/fields/SolidIntegerField.tsx +282 -0
  168. package/dist/components/core/form/fields/SolidJsonField.tsx +185 -0
  169. package/dist/components/core/form/fields/SolidLongTextField.tsx +618 -0
  170. package/dist/components/core/form/fields/SolidMediaMultipleField.tsx +663 -0
  171. package/dist/components/core/form/fields/SolidMediaSingleField.tsx +547 -0
  172. package/dist/components/core/form/fields/SolidPasswordField.tsx +390 -0
  173. package/dist/components/core/form/fields/SolidRelationField.tsx +56 -0
  174. package/dist/components/core/form/fields/SolidRichTextField.tsx +188 -0
  175. package/dist/components/core/form/fields/SolidSelectionDynamicField.tsx +340 -0
  176. package/dist/components/core/form/fields/SolidSelectionStaticField.tsx +462 -0
  177. package/dist/components/core/form/fields/SolidShortTextField.tsx +399 -0
  178. package/dist/components/core/form/fields/SolidTimeField.tsx +245 -0
  179. package/dist/components/core/form/fields/relations/SolidRelationManyToManyField.tsx +453 -0
  180. package/dist/components/core/form/fields/relations/SolidRelationManyToOneField.tsx +1036 -0
  181. package/dist/components/core/form/fields/relations/SolidRelationOneToManyField.tsx +627 -0
  182. package/dist/components/core/form/fields/relations/widgets/helpers/InlineRelationEntityDialog.tsx +38 -0
  183. package/dist/components/core/form/fields/relations/widgets/helpers/useRelationEntityHandler.ts +64 -0
  184. package/dist/components/core/form/fields/widgets/SolidAiInteractionMessageFieldFormWidget.tsx +135 -0
  185. package/dist/components/core/form/fields/widgets/SolidAiInteractionMetadataFieldFormWidget.tsx +144 -0
  186. package/dist/components/core/form/fields/widgets/SolidIconEditWidget.tsx +265 -0
  187. package/dist/components/core/form/fields/widgets/SolidIconViewWidget.tsx +32 -0
  188. package/dist/components/core/form/fields/widgets/SolidRelationFieldAvatarFormWidget.tsx +50 -0
  189. package/dist/components/core/form/fields/widgets/SolidS3FileViewerWidget.tsx +222 -0
  190. package/dist/components/core/form/fields/widgets/SolidShortTextFieldAvatarWidget.tsx +70 -0
  191. package/dist/components/core/form/widgets/CustomHtml.tsx +20 -0
  192. package/dist/components/core/kanban/KanbanBoard.tsx +150 -0
  193. package/dist/components/core/kanban/KanbanCard.tsx +279 -0
  194. package/dist/components/core/kanban/KanbanColumn.tsx +139 -0
  195. package/dist/components/core/kanban/KanbanUserViewLayout.tsx +84 -0
  196. package/dist/components/core/kanban/SolidKanbanView.tsx +894 -0
  197. package/dist/components/core/kanban/SolidKanbanViewConfigure.tsx +154 -0
  198. package/dist/components/core/kanban/SolidKanbanViewFields.tsx +164 -0
  199. package/dist/components/core/kanban/SolidManyToOneFilterElement.tsx +59 -0
  200. package/dist/components/core/kanban/SolidSelectionDynamicFilterElement.tsx +50 -0
  201. package/dist/components/core/kanban/SolidSelectionStaticFilterElement.tsx +32 -0
  202. package/dist/components/core/kanban/SolidVarInputsFilterElement.tsx +184 -0
  203. package/dist/components/core/kanban/kanban-fields/SolidBigintKanbanField.tsx +9 -0
  204. package/dist/components/core/kanban/kanban-fields/SolidBooleanKanbanField.tsx +16 -0
  205. package/dist/components/core/kanban/kanban-fields/SolidComputedKanbanField.tsx +23 -0
  206. package/dist/components/core/kanban/kanban-fields/SolidDateKanbanField.tsx +14 -0
  207. package/dist/components/core/kanban/kanban-fields/SolidDatetimeKanbanField.tsx +13 -0
  208. package/dist/components/core/kanban/kanban-fields/SolidDecimalKanbanField.tsx +9 -0
  209. package/dist/components/core/kanban/kanban-fields/SolidExternalIdKanbanField.tsx +12 -0
  210. package/dist/components/core/kanban/kanban-fields/SolidFloatKanbanField.tsx +9 -0
  211. package/dist/components/core/kanban/kanban-fields/SolidIdKanbanField.tsx +14 -0
  212. package/dist/components/core/kanban/kanban-fields/SolidIntKanbanField.tsx +20 -0
  213. package/dist/components/core/kanban/kanban-fields/SolidLongTextKanbanField.tsx +9 -0
  214. package/dist/components/core/kanban/kanban-fields/SolidMediaMultipleKanbanField.tsx +140 -0
  215. package/dist/components/core/kanban/kanban-fields/SolidMediaSingleKanbanField.tsx +164 -0
  216. package/dist/components/core/kanban/kanban-fields/SolidRelationKanbanField.tsx +13 -0
  217. package/dist/components/core/kanban/kanban-fields/SolidRichTextKanbanField.tsx +9 -0
  218. package/dist/components/core/kanban/kanban-fields/SolidSelectionDynamicKanbanField.tsx +14 -0
  219. package/dist/components/core/kanban/kanban-fields/SolidSelectionStaticKanbanField.tsx +14 -0
  220. package/dist/components/core/kanban/kanban-fields/SolidShortTextKanbanField.tsx +121 -0
  221. package/dist/components/core/kanban/kanban-fields/SolidTimeKanbanField.tsx +12 -0
  222. package/dist/components/core/kanban/kanban-fields/SolidUuidKanbanField.tsx +13 -0
  223. package/dist/components/core/kanban/kanban-fields/relations/SolidRelationManyToOneKanbanField.tsx +16 -0
  224. package/dist/components/core/list/ListViewRowActionPopup.tsx +41 -0
  225. package/dist/components/core/list/SolidColumnSelector/SolidListColumnSelector.tsx +242 -0
  226. package/dist/components/core/list/SolidEmptyListViewPlaceholder.tsx +111 -0
  227. package/dist/components/core/list/SolidListView.tsx +2007 -0
  228. package/dist/components/core/list/SolidListViewColumn.tsx +165 -0
  229. package/dist/components/core/list/SolidListViewConfigure.tsx +339 -0
  230. package/dist/components/core/list/SolidListViewHeaderButton.tsx +31 -0
  231. package/dist/components/core/list/SolidListViewHeaderContextMenuButton.tsx +30 -0
  232. package/dist/components/core/list/SolidListViewRowButtonContextMenu.tsx +41 -0
  233. package/dist/components/core/list/SolidListViewShimmerLoading.tsx +78 -0
  234. package/dist/components/core/list/SolidListingHeader.tsx +42 -0
  235. package/dist/components/core/list/SolidManyToOneFilterElement.tsx +60 -0
  236. package/dist/components/core/list/SolidSelectionDynamicFilterElement.tsx +50 -0
  237. package/dist/components/core/list/SolidSelectionStaticFilterElement.tsx +32 -0
  238. package/dist/components/core/list/SolidTableRowCell.tsx +35 -0
  239. package/dist/components/core/list/SolidVarInputsFilterElement.tsx +184 -0
  240. package/dist/components/core/list/columns/SolidBigintColumn.tsx +9 -0
  241. package/dist/components/core/list/columns/SolidBooleanColumn.tsx +90 -0
  242. package/dist/components/core/list/columns/SolidComputedColumn.tsx +27 -0
  243. package/dist/components/core/list/columns/SolidDateColumn.tsx +90 -0
  244. package/dist/components/core/list/columns/SolidDatetimeColumn.tsx +79 -0
  245. package/dist/components/core/list/columns/SolidDecimalColumn.tsx +9 -0
  246. package/dist/components/core/list/columns/SolidExternalIdColumn.tsx +80 -0
  247. package/dist/components/core/list/columns/SolidFloatColumn.tsx +9 -0
  248. package/dist/components/core/list/columns/SolidIdColumn.tsx +79 -0
  249. package/dist/components/core/list/columns/SolidIntColumn.tsx +87 -0
  250. package/dist/components/core/list/columns/SolidLongTextColumn.tsx +9 -0
  251. package/dist/components/core/list/columns/SolidMediaMultipleColumn.tsx +301 -0
  252. package/dist/components/core/list/columns/SolidMediaSingleColumn.tsx +170 -0
  253. package/dist/components/core/list/columns/SolidRelationColumn.tsx +21 -0
  254. package/dist/components/core/list/columns/SolidRichTextColumn.tsx +9 -0
  255. package/dist/components/core/list/columns/SolidSelectionDynamicColumn.tsx +80 -0
  256. package/dist/components/core/list/columns/SolidSelectionStaticColumn.tsx +81 -0
  257. package/dist/components/core/list/columns/SolidShortTextColumn.tsx +160 -0
  258. package/dist/components/core/list/columns/SolidTimeColumn.tsx +78 -0
  259. package/dist/components/core/list/columns/SolidUuidColumn.tsx +79 -0
  260. package/dist/components/core/list/columns/relations/SolidRelationManyToManyColumn.tsx +106 -0
  261. package/dist/components/core/list/columns/relations/SolidRelationManyToOneColumn.tsx +117 -0
  262. package/dist/components/core/list/columns/relations/SolidRelationOneToManyColumn.tsx +110 -0
  263. package/dist/components/core/list/widgets/SolidManyToManyRelationAvatarListWidget.tsx +30 -0
  264. package/dist/components/core/list/widgets/SolidManyToOneRelationAvatarListWidget.tsx +30 -0
  265. package/dist/components/core/list/widgets/SolidShortTextAvatarWidget.tsx +70 -0
  266. package/dist/components/core/list/widgets/SolidShortTextFieldImageRenderModeWidget.tsx +21 -0
  267. package/dist/components/core/locales/SolidChatterLocaleTabView.tsx +91 -0
  268. package/dist/components/core/locales/SolidLocale.tsx +127 -0
  269. package/dist/components/core/model/CreateModel.tsx +495 -0
  270. package/dist/components/core/model/FieldMetaData.tsx +263 -0
  271. package/dist/components/core/model/FieldMetaDataForm.tsx +3509 -0
  272. package/dist/components/core/model/FieldSelector.tsx +62 -0
  273. package/dist/components/core/model/ModelListViewData.tsx +384 -0
  274. package/dist/components/core/model/ModelMetaData.tsx +921 -0
  275. package/dist/components/core/module/CreateModule.tsx +617 -0
  276. package/dist/components/core/module/ModuleListViewData.tsx +431 -0
  277. package/dist/components/core/solid-ai/SolidAiMainWrapper.tsx +8 -0
  278. package/dist/components/core/solid-ai/SolidXAIIcon.tsx +37 -0
  279. package/dist/components/core/users/CreateUser.tsx +467 -0
  280. package/dist/components/core/users/CreateUserRole.tsx +212 -0
  281. package/dist/components/core/users/UserListView.tsx +376 -0
  282. package/dist/components/layout/AdminLayout.tsx +57 -0
  283. package/dist/components/layout/AdminSidebar.tsx +65 -0
  284. package/dist/components/layout/AppConfig.tsx +104 -0
  285. package/dist/components/layout/AppSidebar.tsx +232 -0
  286. package/dist/components/layout/ButtonLoader.tsx +7 -0
  287. package/dist/components/layout/CustomPagination.tsx +55 -0
  288. package/dist/components/layout/DashboardHeader.tsx +89 -0
  289. package/dist/components/layout/FilterMenu.tsx +122 -0
  290. package/dist/components/layout/Footer.tsx +13 -0
  291. package/dist/components/layout/GlobalSearch.tsx +37 -0
  292. package/dist/components/layout/Header.tsx +8 -0
  293. package/dist/components/layout/Layout.tsx +205 -0
  294. package/dist/components/layout/ListingHeader.tsx +204 -0
  295. package/dist/components/layout/Loader.tsx +16 -0
  296. package/dist/components/layout/UserSidebar.tsx +53 -0
  297. package/dist/components/layout/context/layoutcontext.tsx +52 -0
  298. package/dist/components/layout/navbar-one.tsx +258 -0
  299. package/dist/components/layout/navbar-two-menu.tsx +72 -0
  300. package/dist/components/layout/navbar-two.tsx +37 -0
  301. package/dist/components/layout/user-profile-menu.tsx +213 -0
  302. package/dist/components/layout/user-profile.tsx +7 -0
  303. package/dist/components/modelsComponents/filterIcon.tsx +9 -0
  304. package/dist/constants/error-messages.ts +238 -0
  305. package/dist/declarations.d.ts +22 -0
  306. package/dist/helpers/AppTitle.tsx +12 -0
  307. package/dist/helpers/ToastContainer.tsx +94 -0
  308. package/dist/helpers/autoCompleteVirtualScroll.ts +41 -0
  309. package/dist/helpers/countries.tsx +260 -0
  310. package/dist/helpers/downloadFileWithProgress.ts +91 -0
  311. package/dist/helpers/downloadMediaFile.tsx +21 -0
  312. package/dist/helpers/getAcceptedFileTypes.tsx +22 -0
  313. package/dist/helpers/getRandomColors.tsx +68 -0
  314. package/dist/helpers/helpers.ts +61 -0
  315. package/dist/helpers/hydrateRelationRules.ts +120 -0
  316. package/dist/helpers/permissions.ts +7 -0
  317. package/dist/helpers/registry.ts +337 -0
  318. package/dist/helpers/resendOtpHelper.tsx +5 -0
  319. package/dist/helpers/revalidate.ts +7 -0
  320. package/dist/helpers/rolesHelper.ts +17 -0
  321. package/dist/helpers/solidIcons.tsx +1831 -0
  322. package/dist/helpers/updatePasswordField.ts +41 -0
  323. package/dist/index.ts +421 -0
  324. package/dist/nextAuth/authProviders.d.ts.map +1 -1
  325. package/dist/nextAuth/authProviders.js +6 -5
  326. package/dist/nextAuth/authProviders.js.map +1 -1
  327. package/dist/nextAuth/authProviders.tsx +232 -0
  328. package/dist/nextAuth/handleLogout.tsx +39 -0
  329. package/dist/nextAuth/refreshAccessToken.tsx +28 -0
  330. package/dist/redux/api/aiInteractionApi.ts +59 -0
  331. package/dist/redux/api/authApi.ts +131 -0
  332. package/dist/redux/api/dashboardApi.ts +56 -0
  333. package/dist/redux/api/dashboardQuestionApi.ts +17 -0
  334. package/dist/redux/api/exportTemplateApi.tsx +59 -0
  335. package/dist/redux/api/fetchBaseQuery.tsx +118 -0
  336. package/dist/redux/api/fieldApi.ts +86 -0
  337. package/dist/redux/api/importTransactionApi.tsx +69 -0
  338. package/dist/redux/api/mediaApi.ts +55 -0
  339. package/dist/redux/api/mediaStorageProviderApi.ts +55 -0
  340. package/dist/redux/api/modelApi.ts +80 -0
  341. package/dist/redux/api/moduleApi.ts +72 -0
  342. package/dist/redux/api/permissionApi.ts +32 -0
  343. package/dist/redux/api/pincodeApi.tsx +56 -0
  344. package/dist/redux/api/roleApi.ts +58 -0
  345. package/dist/redux/api/solidActionApi.ts +66 -0
  346. package/dist/redux/api/solidChatterMessageApi.ts +25 -0
  347. package/dist/redux/api/solidEntityApi.tsx +164 -0
  348. package/dist/redux/api/solidMenuApi.ts +71 -0
  349. package/dist/redux/api/solidServiceApi.ts +31 -0
  350. package/dist/redux/api/solidSettingsApi.tsx +83 -0
  351. package/dist/redux/api/solidViewApi.ts +73 -0
  352. package/dist/redux/api/stateApi.tsx +56 -0
  353. package/dist/redux/api/testApi.ts +21 -0
  354. package/dist/redux/api/userApi.ts +135 -0
  355. package/dist/redux/features/authSlice.ts +19 -0
  356. package/dist/redux/features/dataViewSlice.ts +26 -0
  357. package/dist/redux/features/navbarSlice.ts +21 -0
  358. package/dist/redux/features/popupSlice.ts +37 -0
  359. package/dist/redux/features/settingsSlice.ts +60 -0
  360. package/dist/redux/features/themeSlice.ts +17 -0
  361. package/dist/redux/features/userSlice.ts +28 -0
  362. package/dist/redux/hooks/useSolidPopup.ts +20 -0
  363. package/dist/redux/store/defaultStoreConfig.ts +62 -0
  364. package/dist/styles.ts +4 -0
  365. package/dist/types/handlebars.d.ts +4 -0
  366. package/dist/types/index.d.ts +76 -0
  367. package/dist/types/layout.d.ts +94 -0
  368. package/dist/types/next-auth.d.ts +0 -0
  369. package/dist/types/next.d.ts +46 -0
  370. package/dist/types/solid-core.d.ts +320 -0
  371. package/package.json +1 -1
  372. package/src/components/auth/SolidLogin.tsx +26 -13
  373. 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
+ });