@solidxai/core-ui 0.1.3 → 0.1.4-beta.1

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 (150) hide show
  1. package/dist/components/auth/SolidInitialLoginOtp.d.ts.map +1 -1
  2. package/dist/components/auth/SolidInitialLoginOtp.js +0 -5
  3. package/dist/components/auth/SolidInitialLoginOtp.js.map +1 -1
  4. package/dist/components/auth/SolidInitialLoginOtp.tsx +0 -5
  5. package/dist/components/auth/SolidLogin.d.ts.map +1 -1
  6. package/dist/components/auth/SolidLogin.js +7 -5
  7. package/dist/components/auth/SolidLogin.js.map +1 -1
  8. package/dist/components/auth/SolidLogin.tsx +10 -8
  9. package/dist/components/common/GeneralSettings.d.ts.map +1 -1
  10. package/dist/components/common/GeneralSettings.js +48 -47
  11. package/dist/components/common/GeneralSettings.js.map +1 -1
  12. package/dist/components/common/GeneralSettings.tsx +41 -10
  13. package/dist/components/core/common/FilterComponent.js.map +1 -1
  14. package/dist/components/core/common/FilterComponent.tsx +1 -1
  15. package/dist/components/core/common/GroupingComponent.d.ts +54 -0
  16. package/dist/components/core/common/GroupingComponent.d.ts.map +1 -0
  17. package/dist/components/core/common/GroupingComponent.js +196 -0
  18. package/dist/components/core/common/GroupingComponent.js.map +1 -0
  19. package/dist/components/core/common/GroupingComponent.tsx +452 -0
  20. package/dist/components/core/common/SolidGlobalSearchElement.d.ts +18 -1
  21. package/dist/components/core/common/SolidGlobalSearchElement.d.ts.map +1 -1
  22. package/dist/components/core/common/SolidGlobalSearchElement.js +152 -52
  23. package/dist/components/core/common/SolidGlobalSearchElement.js.map +1 -1
  24. package/dist/components/core/common/SolidGlobalSearchElement.tsx +212 -35
  25. package/dist/components/core/extension/solid-core/modelSequence/modelSequenceFormViewChangeHandler.d.ts +19 -0
  26. package/dist/components/core/extension/solid-core/modelSequence/modelSequenceFormViewChangeHandler.d.ts.map +1 -0
  27. package/dist/components/core/extension/solid-core/modelSequence/modelSequenceFormViewChangeHandler.js +90 -0
  28. package/dist/components/core/extension/solid-core/modelSequence/modelSequenceFormViewChangeHandler.js.map +1 -0
  29. package/dist/components/core/extension/solid-core/modelSequence/modelSequenceFormViewChangeHandler.tsx +59 -0
  30. package/dist/components/core/extension/solid-core/roleMetadata/RolePermissionsManyToManyFieldWidget.d.ts.map +1 -1
  31. package/dist/components/core/extension/solid-core/roleMetadata/RolePermissionsManyToManyFieldWidget.js +17 -28
  32. package/dist/components/core/extension/solid-core/roleMetadata/RolePermissionsManyToManyFieldWidget.js.map +1 -1
  33. package/dist/components/core/extension/solid-core/roleMetadata/RolePermissionsManyToManyFieldWidget.tsx +71 -56
  34. package/dist/components/core/filter/SolidOneToManyFilterElement.d.ts +2 -0
  35. package/dist/components/core/filter/SolidOneToManyFilterElement.d.ts.map +1 -0
  36. package/dist/components/core/filter/SolidOneToManyFilterElement.js +86 -0
  37. package/dist/components/core/filter/SolidOneToManyFilterElement.js.map +1 -0
  38. package/dist/components/core/filter/SolidOneToManyFilterElement.tsx +62 -0
  39. package/dist/components/core/filter/SolidVarInputsFilterElement.d.ts +1 -0
  40. package/dist/components/core/filter/SolidVarInputsFilterElement.d.ts.map +1 -1
  41. package/dist/components/core/filter/SolidVarInputsFilterElement.js +4 -1
  42. package/dist/components/core/filter/SolidVarInputsFilterElement.js.map +1 -1
  43. package/dist/components/core/filter/SolidVarInputsFilterElement.tsx +10 -0
  44. package/dist/components/core/filter/fields/SolidRelationField.d.ts.map +1 -1
  45. package/dist/components/core/filter/fields/SolidRelationField.js +4 -2
  46. package/dist/components/core/filter/fields/SolidRelationField.js.map +1 -1
  47. package/dist/components/core/filter/fields/SolidRelationField.tsx +4 -2
  48. package/dist/components/core/filter/fields/relations/SolidRelationOneToManyField.d.ts +4 -0
  49. package/dist/components/core/filter/fields/relations/SolidRelationOneToManyField.d.ts.map +1 -0
  50. package/dist/components/core/filter/fields/relations/SolidRelationOneToManyField.js +25 -0
  51. package/dist/components/core/filter/fields/relations/SolidRelationOneToManyField.js.map +1 -0
  52. package/dist/components/core/filter/fields/relations/SolidRelationOneToManyField.tsx +60 -0
  53. package/dist/components/core/form/SolidFormFooter.js +4 -4
  54. package/dist/components/core/form/SolidFormFooter.js.map +1 -1
  55. package/dist/components/core/form/SolidFormFooter.tsx +4 -4
  56. package/dist/components/core/form/fields/SolidBooleanField.d.ts.map +1 -1
  57. package/dist/components/core/form/fields/SolidBooleanField.js +11 -8
  58. package/dist/components/core/form/fields/SolidBooleanField.js.map +1 -1
  59. package/dist/components/core/form/fields/SolidBooleanField.tsx +20 -8
  60. package/dist/components/core/form/fields/relations/SolidRelationManyToManyField.d.ts +40 -0
  61. package/dist/components/core/form/fields/relations/SolidRelationManyToManyField.d.ts.map +1 -1
  62. package/dist/components/core/form/fields/relations/SolidRelationManyToManyField.js +317 -157
  63. package/dist/components/core/form/fields/relations/SolidRelationManyToManyField.js.map +1 -1
  64. package/dist/components/core/form/fields/relations/SolidRelationManyToManyField.tsx +463 -243
  65. package/dist/components/core/form/fields/relations/SolidRelationOneToManyField.d.ts.map +1 -1
  66. package/dist/components/core/form/fields/relations/SolidRelationOneToManyField.js +46 -95
  67. package/dist/components/core/form/fields/relations/SolidRelationOneToManyField.js.map +1 -1
  68. package/dist/components/core/form/fields/relations/SolidRelationOneToManyField.tsx +57 -113
  69. package/dist/components/core/form/fields/relations/widgets/helpers/useRelationEntityHandler.d.ts +15 -4
  70. package/dist/components/core/form/fields/relations/widgets/helpers/useRelationEntityHandler.d.ts.map +1 -1
  71. package/dist/components/core/form/fields/relations/widgets/helpers/useRelationEntityHandler.js +220 -33
  72. package/dist/components/core/form/fields/relations/widgets/helpers/useRelationEntityHandler.js.map +1 -1
  73. package/dist/components/core/form/fields/relations/widgets/helpers/useRelationEntityHandler.ts +167 -36
  74. package/dist/components/core/kanban/SolidKanbanView.d.ts.map +1 -1
  75. package/dist/components/core/kanban/SolidKanbanView.js +13 -12
  76. package/dist/components/core/kanban/SolidKanbanView.js.map +1 -1
  77. package/dist/components/core/kanban/SolidKanbanView.tsx +8 -7
  78. package/dist/components/core/list/SolidListView.d.ts +18 -10
  79. package/dist/components/core/list/SolidListView.d.ts.map +1 -1
  80. package/dist/components/core/list/SolidListView.js +176 -177
  81. package/dist/components/core/list/SolidListView.js.map +1 -1
  82. package/dist/components/core/list/SolidListView.tsx +130 -143
  83. package/dist/components/core/list/SolidListViewConfigure.d.ts +7 -0
  84. package/dist/components/core/list/SolidListViewConfigure.d.ts.map +1 -1
  85. package/dist/components/core/list/SolidListViewConfigure.js +6 -5
  86. package/dist/components/core/list/SolidListViewConfigure.js.map +1 -1
  87. package/dist/components/core/list/SolidListViewConfigure.tsx +21 -12
  88. package/dist/components/core/list/columns/SolidShortTextColumn.d.ts.map +1 -1
  89. package/dist/components/core/list/columns/SolidShortTextColumn.js +1 -37
  90. package/dist/components/core/list/columns/SolidShortTextColumn.js.map +1 -1
  91. package/dist/components/core/list/columns/SolidShortTextColumn.tsx +0 -41
  92. package/dist/components/core/list/columns/relations/SolidRelationManyToOneColumn.d.ts.map +1 -1
  93. package/dist/components/core/list/columns/relations/SolidRelationManyToOneColumn.js +9 -5
  94. package/dist/components/core/list/columns/relations/SolidRelationManyToOneColumn.js.map +1 -1
  95. package/dist/components/core/list/columns/relations/SolidRelationManyToOneColumn.tsx +14 -3
  96. package/dist/components/core/list/listViewRegistry.js.map +1 -1
  97. package/dist/components/core/list/listViewRegistry.ts +1 -2
  98. package/dist/components/core/tree/SolidTreeView.d.ts +38 -0
  99. package/dist/components/core/tree/SolidTreeView.d.ts.map +1 -0
  100. package/dist/components/core/tree/SolidTreeView.js +1179 -0
  101. package/dist/components/core/tree/SolidTreeView.js.map +1 -0
  102. package/dist/components/core/tree/SolidTreeView.tsx +1637 -0
  103. package/dist/components/core/tree/treeViewRegistry.d.ts +7 -0
  104. package/dist/components/core/tree/treeViewRegistry.d.ts.map +1 -0
  105. package/dist/components/core/tree/treeViewRegistry.js +17 -0
  106. package/dist/components/core/tree/treeViewRegistry.js.map +1 -0
  107. package/dist/components/core/tree/treeViewRegistry.ts +23 -0
  108. package/dist/components/core/users/CreateUser.d.ts.map +1 -1
  109. package/dist/components/core/users/CreateUser.js +19 -6
  110. package/dist/components/core/users/CreateUser.js.map +1 -1
  111. package/dist/components/core/users/CreateUser.tsx +39 -0
  112. package/dist/helpers/helpers.d.ts +2 -0
  113. package/dist/helpers/helpers.d.ts.map +1 -1
  114. package/dist/helpers/helpers.js +3 -1
  115. package/dist/helpers/helpers.js.map +1 -1
  116. package/dist/helpers/helpers.ts +4 -1
  117. package/dist/helpers/registry.d.ts.map +1 -1
  118. package/dist/helpers/registry.js +5 -1
  119. package/dist/helpers/registry.js.map +1 -1
  120. package/dist/helpers/registry.ts +7 -2
  121. package/dist/index.d.ts +3 -1
  122. package/dist/index.d.ts.map +1 -1
  123. package/dist/index.js +2 -0
  124. package/dist/index.js.map +1 -1
  125. package/dist/index.ts +6 -1
  126. package/dist/resources/globals.css +32 -4
  127. package/dist/routes/pages/admin/core/ListPage.d.ts.map +1 -1
  128. package/dist/routes/pages/admin/core/ListPage.js +2 -2
  129. package/dist/routes/pages/admin/core/ListPage.js.map +1 -1
  130. package/dist/routes/pages/admin/core/ListPage.tsx +3 -2
  131. package/dist/routes/pages/admin/core/ModuleHomePage.d.ts.map +1 -1
  132. package/dist/routes/pages/admin/core/ModuleHomePage.js +4 -15
  133. package/dist/routes/pages/admin/core/ModuleHomePage.js.map +1 -1
  134. package/dist/routes/pages/admin/core/ModuleHomePage.tsx +4 -3
  135. package/dist/routes/pages/admin/core/TreePage.d.ts +2 -0
  136. package/dist/routes/pages/admin/core/TreePage.d.ts.map +1 -0
  137. package/dist/routes/pages/admin/core/TreePage.js +37 -0
  138. package/dist/routes/pages/admin/core/TreePage.js.map +1 -0
  139. package/dist/routes/pages/admin/core/TreePage.tsx +30 -0
  140. package/dist/routes/solidRoutes.d.ts.map +1 -1
  141. package/dist/routes/solidRoutes.js +2 -0
  142. package/dist/routes/solidRoutes.js.map +1 -1
  143. package/dist/routes/solidRoutes.tsx +3 -1
  144. package/dist/routes/types.d.ts +1 -1
  145. package/dist/routes/types.d.ts.map +1 -1
  146. package/dist/routes/types.js.map +1 -1
  147. package/dist/routes/types.ts +1 -0
  148. package/dist/types/index.d.ts +8 -2
  149. package/dist/types/solid-core.d.ts +40 -0
  150. package/package.json +1 -1
@@ -1,4 +1,3 @@
1
-
2
1
  import { Message } from "primereact/message";
3
2
  import { useEffect, useState } from "react";
4
3
  import * as Yup from 'yup';
@@ -9,16 +8,33 @@ import { Button } from "primereact/button";
9
8
  import { SolidFormFieldWidgetProps } from "../../../../../types/solid-core";
10
9
  import { useRelationEntityHandler } from "./widgets/helpers/useRelationEntityHandler";
11
10
  import { InlineRelationEntityDialog } from "./widgets/helpers/InlineRelationEntityDialog";
12
- import { capitalize } from "lodash";
13
11
  import { Checkbox } from "primereact/checkbox";
14
12
  import { Panel } from "primereact/panel";
15
13
  import { SolidFieldTooltip } from "../../../../../components/common/SolidFieldTooltip";
16
14
  import qs from 'qs';
17
- // import Handlebars from "handlebars/dist/handlebars";
18
15
  import * as Handlebars from "handlebars";
19
16
  import { ERROR_MESSAGES } from "../../../../../constants/error-messages";
20
-
21
-
17
+ import { useRouter } from "../../../../../hooks/useRouter";
18
+ import { usePathname } from "../../../../../hooks/usePathname";
19
+ import { camelCase, capitalize } from "lodash";
20
+ import { SolidListView } from "../../../../core/list/SolidListView";
21
+ import { RenderSolidFormEmbededView } from "./SolidRelationManyToOneField";
22
+ import { Dialog } from "primereact/dialog";
23
+
24
+ export type FormViewParams = {
25
+ moduleName: any;
26
+ id: any;
27
+ embeded: any;
28
+ isCustomCreate: any;
29
+ customLayout: any;
30
+ modelName: any;
31
+ parentFieldName?: any;
32
+ parentData: any;
33
+ onEmbeddedFormSave: any;
34
+ inlineCreateAutoSave: any;
35
+ customCreateHandler?: any;
36
+ handlePopupClose?: any;
37
+ };
22
38
 
23
39
 
24
40
 
@@ -31,63 +47,20 @@ export class SolidRelationManyToManyField implements ISolidField {
31
47
  }
32
48
 
33
49
  initialValue(): any {
34
-
35
- const manyToManyFieldData = this.fieldContext.data[this.fieldContext.field.attrs.name];
36
- const fieldMetadata = this.fieldContext.fieldMetadata;
37
- const userKeyField = fieldMetadata?.relationModel?.userKeyField?.name;
38
- if (manyToManyFieldData) {
39
- return manyToManyFieldData.map((e: any) => {
40
- const manyToManyColVal = e[userKeyField] || '';
41
- return {
42
- label: manyToManyColVal,
43
- value: e?.id || '',
44
- original: e
45
- };
46
- });
47
- }
48
50
  return [];
49
51
  }
50
52
 
51
53
  updateFormData(value: any, formData: FormData): any {
52
- const fieldLayoutInfo = this.fieldContext.field;
53
- //if empty then clear the field
54
- if(value && value.length === 0) {
55
- formData.append(`${fieldLayoutInfo.attrs.name}Command`, "clear");
56
- }
57
- if (value && value.length > 0) {
58
- const shouldUseOriginal = value.every((item: any) => item.original && item.original.id);
59
-
60
- value.forEach((item: any, index: number) => {
61
- if (shouldUseOriginal) {
62
- formData.append(
63
- `${fieldLayoutInfo.attrs.name}Ids[${index}]`,
64
- item.value
65
- );
66
- } else {
67
- formData.append(
68
- `${fieldLayoutInfo.attrs.name}[${index}]`,
69
- JSON.stringify(item.original)
70
- );
71
- }
72
- });
73
- if (shouldUseOriginal) {
74
- formData.append(`${fieldLayoutInfo.attrs.name}Command`, "set")
75
- } else {
76
- formData.append(`${fieldLayoutInfo.attrs.name}Command`, "update")
77
-
78
- }
79
-
80
- }
54
+ // Link/unlink is handled per-interaction in each widget.
55
+ // No bulk update needed on form submit for many-to-many.
81
56
  }
82
57
 
83
58
  validationSchema(): Yup.Schema {
84
59
  let schema = Yup.array();
85
-
86
60
  const fieldMetadata = this.fieldContext.fieldMetadata;
87
61
  const fieldLayoutInfo = this.fieldContext.field;
88
62
  const fieldLabel = fieldLayoutInfo.attrs.label ?? fieldMetadata.displayName;
89
63
 
90
- // 1. required
91
64
  if (fieldMetadata.required) {
92
65
  schema = schema
93
66
  .min(1, ERROR_MESSAGES.SELECT_ATLEAST_ONE(fieldLabel))
@@ -98,75 +71,73 @@ export class SolidRelationManyToManyField implements ISolidField {
98
71
  }
99
72
 
100
73
  render(formik: FormikObject) {
101
- const fieldMetadata = this.fieldContext.fieldMetadata;
102
74
  const fieldLayoutInfo = this.fieldContext.field;
103
75
  const className = fieldLayoutInfo.attrs?.className || 'field col-12';
104
76
 
105
- const isFormFieldValid = (formik: any, fieldName: string) => formik.touched[fieldName] && formik.errors[fieldName];
106
- const fieldLabel = fieldLayoutInfo.attrs.label ?? fieldMetadata.displayName;
107
-
108
77
  let viewWidget = fieldLayoutInfo.attrs.viewWidget;
109
78
  let editWidget = fieldLayoutInfo.attrs.editWidget;
110
- if (!editWidget) {
111
- editWidget = 'DefaultRelationManyToManyAutoCompleteFormEditWidget';
112
- }
113
- if (!viewWidget) {
114
- viewWidget = 'DefaultRelationOneToManyFormViewWidget';
115
- }
79
+ if (!editWidget) editWidget = 'DefaultRelationManyToManyAutoCompleteFormEditWidget';
80
+ if (!viewWidget) viewWidget = 'DefaultRelationManyToManyListFormEditWidget';
81
+
116
82
  const viewMode: string = this.fieldContext.viewMode;
117
83
  return (
118
- <>
119
- <div className={className}>
120
- {viewMode === "view" &&
121
- this.renderExtensionRenderMode(viewWidget, formik)
122
- }
123
- {viewMode === "edit" && (
124
- <>
125
- {editWidget &&
126
- this.renderExtensionRenderMode(editWidget, formik)
127
- }
128
- </>
129
- )
130
- }
131
- </div>
132
- </>
84
+ <div className={className}>
85
+ {viewMode === "view" && this.renderExtensionRenderMode(viewWidget, formik)}
86
+ {viewMode === "edit" && editWidget && this.renderExtensionRenderMode(editWidget, formik)}
87
+ </div>
133
88
  );
134
89
  }
135
90
 
136
91
  renderExtensionRenderMode(widget: string, formik: FormikObject) {
137
- let DynamicWidget = getExtensionComponent(widget);
138
- const widgetProps: SolidFormFieldWidgetProps = {
139
- formik: formik,
140
- fieldContext: this.fieldContext,
141
- }
142
- return (
143
- <>
144
- {DynamicWidget && <DynamicWidget {...widgetProps} />}
145
- </>
146
- )
92
+ const DynamicWidget = getExtensionComponent(widget);
93
+ const widgetProps: SolidFormFieldWidgetProps = { formik, fieldContext: this.fieldContext };
94
+ return <>{DynamicWidget && <DynamicWidget {...widgetProps} />}</>;
147
95
  }
148
96
  }
149
97
 
150
98
 
151
99
 
100
+ /**
101
+ * AUTOCOMPLETE WIDGET
102
+ *
103
+ * State:
104
+ * currentValues — chips shown in the input (currently linked items)
105
+ * suggestions — dropdown options populated on each keystroke
106
+ *
107
+ * Flow:
108
+ * mount → fetchCurrentValues()
109
+ * user types → fetchSuggestions() via completeMethod
110
+ * user selects → linkItem() → on success, adds to currentValues
111
+ * user removes chip→ unlinkItem() → on success, removes from currentValues
112
+ */
152
113
  export const DefaultRelationManyToManyAutoCompleteFormEditWidget = ({ formik, fieldContext }: SolidFormFieldWidgetProps) => {
153
114
  const fieldMetadata = fieldContext.fieldMetadata;
154
115
  const fieldLayoutInfo = fieldContext.field;
155
- const className = fieldLayoutInfo.attrs?.className || 'field col-12';
156
116
  const fieldLabel = fieldLayoutInfo.attrs.label ?? fieldMetadata.displayName;
157
117
  const showFieldLabel = fieldLayoutInfo?.attrs?.showLabel;
158
118
  const readOnlyPermission = fieldContext.readOnly;
159
119
  const disabled = fieldLayoutInfo.attrs?.disabled;
160
120
  const readOnly = fieldLayoutInfo.attrs?.readOnly;
161
- const whereClause = fieldLayoutInfo.attrs.whereClause;
162
121
 
163
122
  const [visibleCreateDialog, setVisibleCreateDialog] = useState(false);
164
- const { autoCompleteItems, fetchRelationEntities, addNewRelation } = useRelationEntityHandler({ fieldContext, formik });
165
- const isFormFieldValid = (formik: any, fieldName: string) => formik.touched[fieldName] && formik.errors[fieldName];
166
123
 
167
- // const onChange = (e: any) => {
168
- // formik.setFieldValue(fieldContext.field.attrs.name, e.value);
169
- // };
124
+ const {
125
+ currentValues,
126
+ suggestions,
127
+ fetchCurrentValues,
128
+ fetchSuggestions,
129
+ linkItem,
130
+ unlinkItem,
131
+ addNewRelation,
132
+ } = useRelationEntityHandler({ fieldContext });
133
+
134
+ const isFormFieldValid = (formik: any, fieldName: string) =>
135
+ formik.touched[fieldName] && formik.errors[fieldName];
136
+
137
+ // On mount: load already-linked items into currentValues
138
+ useEffect(() => {
139
+ fetchCurrentValues();
140
+ }, [fieldContext.data?.id]);
170
141
 
171
142
  const autoCompleteSearch = async (event: AutoCompleteCompleteEvent) => {
172
143
  const queryData: any = {
@@ -176,93 +147,72 @@ export const DefaultRelationManyToManyAutoCompleteFormEditWidget = ({ formik, fi
176
147
  $and: [
177
148
  {
178
149
  [fieldMetadata?.relationModel?.userKeyField?.name]: {
179
- [fieldLayoutInfo?.attrs?.autocompleteMatchMode || '$containsi']: event.query
180
- }
181
- }
182
- ]
183
- }
150
+ [fieldLayoutInfo?.attrs?.autocompleteMatchMode || '$containsi']: event.query,
151
+ },
152
+ },
153
+ ],
154
+ },
184
155
  };
156
+
185
157
  let fixedFilterToBeApplied = false;
186
158
  let fixedFilterParsed = false;
187
159
 
188
160
  if (fieldMetadata?.relationFieldFixedFilter || fieldLayoutInfo?.attrs?.whereClause) {
189
- const convertedFixedFilter = fieldLayoutInfo?.attrs?.whereClause ? fieldLayoutInfo?.attrs?.whereClause : fieldMetadata?.relationFieldFixedFilter;
161
+ const rawFilter = fieldLayoutInfo?.attrs?.whereClause ?? fieldMetadata?.relationFieldFixedFilter;
190
162
  fixedFilterToBeApplied = true;
191
- const fixedFilterTemplate = Handlebars.compile(convertedFixedFilter);
192
- const renderedFilter = fixedFilterTemplate(formik.values);
163
+ const rendered = Handlebars.compile(rawFilter)(formik.values);
193
164
 
194
- let parsedFilter: any;
195
165
  try {
196
- parsedFilter = JSON.parse(renderedFilter);
197
- const isValid = (obj: any): boolean => {
198
- if (!obj || typeof obj !== 'object') return false;
199
-
200
- const hasValidValue = (val: any): boolean => {
201
- if (val === null || val === undefined || val === '') return false;
202
- if (typeof val === 'object') {
203
- return Object.values(val).some(hasValidValue);
204
- }
205
- return true;
206
- };
207
-
208
- return hasValidValue(parsedFilter);
166
+ const parsed = JSON.parse(rendered);
167
+ const hasValue = (val: any): boolean => {
168
+ if (val === null || val === undefined || val === '') return false;
169
+ if (typeof val === 'object') return Object.values(val).some(hasValue);
170
+ return true;
209
171
  };
210
-
211
- if (isValid(parsedFilter)) {
212
- queryData.filters.$and.push(parsedFilter);
172
+ if (hasValue(parsed)) {
173
+ queryData.filters.$and.push(parsed);
213
174
  fixedFilterParsed = true;
214
175
  } else {
215
- console.warn(ERROR_MESSAGES.SKIPPING_EMPTY_FIXED_FILTER, parsedFilter);
176
+ console.warn(ERROR_MESSAGES.SKIPPING_EMPTY_FIXED_FILTER, parsed);
216
177
  }
217
178
  } catch (e) {
218
- console.error(ERROR_MESSAGES.INVALID_JSON_WHERECLAUSE, renderedFilter);
219
- parsedFilter = {};
179
+ console.error(ERROR_MESSAGES.INVALID_JSON_WHERECLAUSE, rendered);
220
180
  }
221
-
222
181
  }
223
182
 
224
- let autocompleteQs = qs.stringify(queryData, {
225
- encodeValuesOnly: true,
226
- });
227
- // if (whereClause) {
228
- // autocompleteQs = `${autocompleteQs}&${whereClause}`;
229
- // }
230
-
231
183
  if (fixedFilterToBeApplied && !fixedFilterParsed) {
232
184
  console.error(ERROR_MESSAGES.FIXED_FILTER_NOT_APPLIED);
233
-
234
185
  } else {
235
- // const autocompleteQs = qs.stringify(queryData, {
236
- // encodeValuesOnly: true,
237
- // });
238
- fetchRelationEntities(autocompleteQs);
186
+ fetchSuggestions(qs.stringify(queryData, { encodeValuesOnly: true }));
239
187
  }
240
188
  };
241
189
 
242
190
  return (
243
-
244
191
  <div className="relative">
245
192
  <div className="flex flex-column gap-2 mt-1 sm:mt-2 md:mt-3 lg:mt-4">
246
- {showFieldLabel != false &&
193
+ {showFieldLabel !== false && (
247
194
  <label htmlFor={fieldLayoutInfo.attrs.name} className="form-field-label">
248
195
  {fieldLabel}
249
196
  {fieldMetadata.required && <span className="text-red-500"> *</span>}
250
197
  <SolidFieldTooltip fieldContext={fieldContext} />
251
198
  </label>
252
- }
199
+ )}
253
200
  <div className="flex align-items-center gap-3">
254
201
  <AutoComplete
255
202
  readOnly={readOnly || readOnlyPermission}
256
203
  disabled={disabled || readOnlyPermission}
257
204
  multiple
258
- {...formik.getFieldProps(fieldLayoutInfo.attrs.name)}
259
205
  id={fieldLayoutInfo.attrs.name}
260
206
  field="label"
261
- value={formik.values[fieldLayoutInfo.attrs.name] || ''}
207
+ value={currentValues}
262
208
  dropdown={!readOnlyPermission}
263
- suggestions={autoCompleteItems}
209
+ suggestions={suggestions}
264
210
  completeMethod={autoCompleteSearch}
265
- onChange={(e) => fieldContext.onChange(e, 'onFieldChange')}
211
+ onChange={() => {
212
+ // Intentionally empty — currentValues is managed via onSelect/onUnselect
213
+ }}
214
+ onSelect={(e) => linkItem(e.value)}
215
+ onUnselect={(e) => unlinkItem(e.value)}
266
216
  className="solid-standard-autocomplete w-full"
267
217
  />
268
218
  {fieldContext.field.attrs.inlineCreate && (
@@ -296,158 +246,428 @@ export const DefaultRelationManyToManyAutoCompleteFormEditWidget = ({ formik, fi
296
246
  )}
297
247
  </div>
298
248
  );
299
- }
300
-
301
-
302
-
249
+ };
250
+
251
+
252
+
253
+ /**
254
+ * CHECKBOX WIDGET
255
+ *
256
+ * State:
257
+ * allOptions — every possible item to render as a checkbox row
258
+ * currentValues — the subset that is currently linked (drives checked state)
259
+ *
260
+ * Flow:
261
+ * mount → fetchCurrentValues() + fetchAllOptions()
262
+ * user checks → linkItem() → on success, adds to currentValues
263
+ * user unchecks → unlinkItem() → on success, removes from currentValues
264
+ */
303
265
  export const DefaultRelationManyToManyCheckBoxFormEditWidget = ({ formik, fieldContext }: SolidFormFieldWidgetProps) => {
304
266
  const fieldMetadata = fieldContext.fieldMetadata;
305
267
  const fieldLayoutInfo = fieldContext.field;
306
268
  const showFieldLabel = fieldLayoutInfo?.attrs?.showLabel;
307
-
308
269
  const readOnlyPermission = fieldContext.readOnly;
270
+
309
271
  const [visibleCreateDialog, setVisibleCreateDialog] = useState(false);
310
- const { autoCompleteItems, fetchRelationEntities, addNewRelation } = useRelationEntityHandler({ fieldContext, formik });
272
+
273
+ const {
274
+ currentValues,
275
+ allOptions,
276
+ fetchCurrentValues,
277
+ fetchAllOptions,
278
+ linkItem,
279
+ unlinkItem,
280
+ addNewRelation,
281
+ } = useRelationEntityHandler({ fieldContext });
282
+
283
+ // On mount: load already-linked items + all possible options
284
+ useEffect(() => {
285
+ fetchCurrentValues();
286
+ }, [fieldContext.data?.id]);
311
287
 
312
288
  useEffect(() => {
313
- const fieldMetadata = fieldContext.fieldMetadata;
314
- const fieldLayoutInfo = fieldContext.field;
315
289
  const queryData: any = {
316
290
  offset: 0,
317
291
  limit: 1000,
318
- filters: {
319
- $and: []
320
- }
292
+ filters: { $and: [] },
321
293
  };
322
294
 
323
295
  let fixedFilterToBeApplied = false;
324
296
  let fixedFilterParsed = false;
325
297
 
326
298
  if (fieldMetadata?.relationFieldFixedFilter || fieldLayoutInfo?.attrs?.whereClause) {
327
- const convertedFixedFilter = fieldLayoutInfo?.attrs?.whereClause ? fieldLayoutInfo?.attrs?.whereClause : fieldMetadata?.relationFieldFixedFilter;
299
+ const rawFilter = fieldLayoutInfo?.attrs?.whereClause ?? fieldMetadata?.relationFieldFixedFilter;
328
300
  fixedFilterToBeApplied = true;
329
- const fixedFilterTemplate = Handlebars.compile(convertedFixedFilter);
330
- const renderedFilter = fixedFilterTemplate(formik.values);
301
+ const rendered = Handlebars.compile(rawFilter)(formik.values);
331
302
 
332
- let parsedFilter: any;
333
303
  try {
334
- parsedFilter = JSON.parse(renderedFilter);
335
- const isValid = (obj: any): boolean => {
336
- if (!obj || typeof obj !== 'object') return false;
337
-
338
- const hasValidValue = (val: any): boolean => {
339
- if (val === null || val === undefined || val === '') return false;
340
- if (typeof val === 'object') {
341
- return Object.values(val).some(hasValidValue);
342
- }
343
- return true;
344
- };
345
-
346
- return hasValidValue(parsedFilter);
304
+ const parsed = JSON.parse(rendered);
305
+ const hasValue = (val: any): boolean => {
306
+ if (val === null || val === undefined || val === '') return false;
307
+ if (typeof val === 'object') return Object.values(val).some(hasValue);
308
+ return true;
347
309
  };
348
-
349
- if (isValid(parsedFilter)) {
350
- queryData.filters.$and.push(parsedFilter);
310
+ if (hasValue(parsed)) {
311
+ queryData.filters.$and.push(parsed);
351
312
  fixedFilterParsed = true;
352
313
  } else {
353
- console.warn(ERROR_MESSAGES.SKIPPING_EMPTY_FIXED_FILTER, parsedFilter);
314
+ console.warn(ERROR_MESSAGES.SKIPPING_EMPTY_FIXED_FILTER, parsed);
354
315
  }
355
316
  } catch (e) {
356
- console.error(ERROR_MESSAGES.INVALID_JSON_WHERECLAUSE, renderedFilter);
357
- parsedFilter = {};
317
+ console.error(ERROR_MESSAGES.INVALID_JSON_WHERECLAUSE, rendered);
358
318
  }
359
-
360
319
  }
361
320
 
362
321
  if (fixedFilterToBeApplied && !fixedFilterParsed) {
363
322
  console.error(ERROR_MESSAGES.FIXED_FILTER_NOT_APPLIED);
364
-
365
323
  } else {
366
- const autocompleteQs = qs.stringify(queryData, {
367
- encodeValuesOnly: true,
368
- });
369
- fetchRelationEntities(autocompleteQs);
324
+ fetchAllOptions(qs.stringify(queryData, { encodeValuesOnly: true }));
370
325
  }
371
-
372
326
  }, [fieldContext, formik.values]);
373
327
 
374
- const handleCheckboxChange = (e: any) => {
375
- if (formik.values[fieldLayoutInfo.attrs.name].some((item: any) => item.value === e.value)) {
376
- formik.setFieldValue(fieldLayoutInfo.attrs.name, formik.values[fieldLayoutInfo.attrs.name].filter((s: any) => s.value !== e.value));
328
+ const handleCheckboxChange = (item: any) => {
329
+ const isCurrentlyLinked = currentValues.some((s) => s.value === item.value);
330
+ if (isCurrentlyLinked) {
331
+ unlinkItem(item);
377
332
  } else {
378
- formik.setFieldValue(fieldLayoutInfo.attrs.name, [...formik.values[fieldLayoutInfo.attrs.name], e]);
333
+ linkItem(item);
379
334
  }
380
335
  };
381
336
 
382
- const headerTemplate = (options: any) => {
383
- const className = `${options.className} justify-content-space-between`;
384
-
385
- return (
386
- <div className={className}>
387
- <div className="flex align-items-center gap-3">
388
- {showFieldLabel != false &&
389
- <label className="form-field-label">
390
- {capitalize(fieldLayoutInfo.attrs.name)}
391
- {fieldMetadata.required && <span className="text-red-500"> *</span>}
392
- <SolidFieldTooltip fieldContext={fieldContext} />
393
- </label>
394
- }
395
- {fieldContext.field.attrs.inlineCreate && (
396
- <>
397
- <Button
398
- icon="pi pi-plus"
399
- rounded
400
- outlined
401
- aria-label="Filter"
402
- type="button"
403
- size="small"
404
- onClick={() => setVisibleCreateDialog(true)}
405
- className="custom-add-button"
406
- />
407
- <InlineRelationEntityDialog
408
- visible={visibleCreateDialog}
409
- setVisible={setVisibleCreateDialog}
410
- fieldContext={fieldContext}
411
- onCreate={addNewRelation}
412
- />
413
- </>
414
- )}
415
- {/* <div className="many-to-many-add" >
416
- <Button icon="pi pi-plus"
337
+ const headerTemplate = (options: any) => (
338
+ <div className={`${options.className} justify-content-space-between`}>
339
+ <div className="flex align-items-center gap-3">
340
+ {showFieldLabel !== false && (
341
+ <label className="form-field-label">
342
+ {capitalize(fieldLayoutInfo.attrs.name)}
343
+ {fieldMetadata.required && <span className="text-red-500"> *</span>}
344
+ <SolidFieldTooltip fieldContext={fieldContext} />
345
+ </label>
346
+ )}
347
+ {fieldContext.field.attrs.inlineCreate && (
348
+ <>
349
+ <Button
350
+ icon="pi pi-plus"
417
351
  rounded
418
352
  outlined
419
353
  aria-label="Filter"
420
354
  type="button"
421
- onClick={() => autoCompleteSearch()}
355
+ size="small"
356
+ onClick={() => setVisibleCreateDialog(true)}
357
+ className="custom-add-button"
422
358
  />
423
- </div> */}
424
- </div>
425
- <div>
426
- {options.togglerElement}
427
- </div>
359
+ <InlineRelationEntityDialog
360
+ visible={visibleCreateDialog}
361
+ setVisible={setVisibleCreateDialog}
362
+ fieldContext={fieldContext}
363
+ onCreate={addNewRelation}
364
+ />
365
+ </>
366
+ )}
428
367
  </div>
429
- );
430
- };
368
+ <div>{options.togglerElement}</div>
369
+ </div>
370
+ );
371
+
431
372
  return (
432
373
  <div>
433
374
  <Panel toggleable headerTemplate={headerTemplate}>
434
375
  <div className="formgrid grid">
435
- {autoCompleteItems && autoCompleteItems.map((a: any, i: number) => {
436
- return (
437
- <div key={a.label} className={`field col-6 flex gap-2 ${i >= 2 ? 'mt-3' : ''}`}>
438
- <Checkbox
439
- readOnly={readOnlyPermission}
440
- inputId={a.label}
441
- checked={formik.values[fieldLayoutInfo.attrs.name].some((item: any) => item.label === a.label)}
442
- onChange={() => handleCheckboxChange(a)}
443
- />
444
- <label htmlFor={a.label} className="form-field-label m-0"> {a.label}</label>
445
- </div>
446
- )
447
- })}
376
+ {allOptions.map((item: any, i: number) => (
377
+ <div key={item.value} className={`field col-6 flex gap-2 ${i >= 2 ? 'mt-3' : ''}`}>
378
+ <Checkbox
379
+ readOnly={readOnlyPermission}
380
+ inputId={item.label}
381
+ checked={currentValues.some((s) => s.value === item.value)}
382
+ onChange={() => handleCheckboxChange(item)}
383
+ />
384
+ <label htmlFor={item.label} className="form-field-label m-0">
385
+ {item.label}
386
+ </label>
387
+ </div>
388
+ ))}
448
389
  </div>
449
390
  </Panel>
450
391
  </div>
451
- )
392
+ );
393
+ };
452
394
 
453
- }
395
+
396
+
397
+ const buildRelationCustomFilter = ({
398
+ fieldContext,
399
+ fieldLayoutInfo,
400
+ }: {
401
+ fieldContext: any;
402
+ fieldLayoutInfo?: any;
403
+ }) => {
404
+ if (!fieldContext) return { id: { $eq: -1 } };
405
+
406
+ const relationFieldName =
407
+ fieldContext.fieldMetadata?.relationCoModelFieldName ?? fieldContext.modelName;
408
+ const parentId = fieldContext.data?.id ?? -1;
409
+ const baseFilter = { [relationFieldName]: { id: { $eq: parentId } } };
410
+ const whereClause = fieldLayoutInfo?.attrs?.whereClause;
411
+
412
+ if (!whereClause) return { $and: [baseFilter] };
413
+
414
+ try {
415
+ return { $and: [baseFilter, JSON.parse(whereClause)] };
416
+ } catch (error) {
417
+ console.error("Failed to parse whereClause:", error);
418
+ return { $and: [baseFilter] };
419
+ }
420
+ };
421
+
422
+ export const DefaultRelationManyToManyListFormEditWidget = ({ formik, fieldContext }: SolidFormFieldWidgetProps) => {
423
+ const fieldMetadata = fieldContext.fieldMetadata;
424
+ const router = useRouter();
425
+ const fieldLayoutInfo = fieldContext.field;
426
+ const fieldLabel = fieldLayoutInfo.attrs.label ?? fieldMetadata.displayName;
427
+ const solidFormViewMetaData = fieldContext.solidFormViewMetaData;
428
+ const [visibleCreateRelationEntity, setvisibleCreateRelationEntity] = useState(false);
429
+ const [listViewParams, setListViewParams] = useState<any>();
430
+ const [formViewParams, setformViewParams] = useState<FormViewParams>();
431
+ const [refreshList, setRefreshList] = useState(false);
432
+ const showFieldLabel = fieldLayoutInfo?.attrs?.showLabel;
433
+ const readOnlyPermission = fieldContext.readOnly;
434
+ const pathname = usePathname();
435
+ const lastPathSegment = pathname.split('/').pop();
436
+ const userKeyField: any = Object.entries(
437
+ fieldContext.solidFormViewMetaData.data.solidFieldsMetadata
438
+ ).find(([_, value]: any) => value.isUserKey)?.[0];
439
+ const [showSaveParentEntityConfirmationPopup, setShowSaveParentEntityConfirmationPopup] = useState(false);
440
+
441
+
442
+
443
+ const [visibleLinkDialog, setVisibleLinkDialog] = useState(false);
444
+ const [linkSearchResults, setLinkSearchResults] = useState<any[]>([]);
445
+ const [selectedLinkItem, setSelectedLinkItem] = useState<any>(null);
446
+ const [isLinking, setIsLinking] = useState(false);
447
+
448
+ const { fetchSuggestions, linkItem, unlinkItem, suggestions } = useRelationEntityHandler({ fieldContext });
449
+
450
+ const handleAddClickForEmbeddedView = () => {
451
+ if (lastPathSegment === "new") {
452
+ setShowSaveParentEntityConfirmationPopup(true);
453
+ } else {
454
+ setSelectedLinkItem(null);
455
+ setLinkSearchResults([]);
456
+ setVisibleLinkDialog(true);
457
+ }
458
+ };
459
+
460
+ const handleLinkSearch = async (event: AutoCompleteCompleteEvent) => {
461
+ const queryData: any = {
462
+ offset: 0,
463
+ limit: 1000,
464
+ filters: {
465
+ $and: [
466
+ {
467
+ [fieldMetadata?.relationModel?.userKeyField?.name]: {
468
+ [fieldLayoutInfo?.attrs?.autocompleteMatchMode || '$containsi']: event.query,
469
+ },
470
+ },
471
+ ],
472
+ },
473
+ };
474
+ await fetchSuggestions(qs.stringify(queryData, { encodeValuesOnly: true }));
475
+ };
476
+
477
+ const handleLinkConfirm = async () => {
478
+ if (!selectedLinkItem) return;
479
+ setIsLinking(true);
480
+ try {
481
+ await linkItem(selectedLinkItem);
482
+ setVisibleLinkDialog(false);
483
+ setSelectedLinkItem(null);
484
+ setRefreshList((prev) => !prev);
485
+ } finally {
486
+ setIsLinking(false);
487
+ }
488
+ };
489
+
490
+ const handleDeleteClick = async (id: any) => {
491
+ await unlinkItem({ value: id, label: '' });
492
+ setRefreshList((prev) => !prev);
493
+ };
494
+
495
+ const handleEditClickForEmbeddedView = (id: any) => {
496
+ if (id === "new") {
497
+ setShowSaveParentEntityConfirmationPopup(true);
498
+ } else {
499
+ setformViewParams({
500
+ moduleName: fieldContext.fieldMetadata.relationModelModuleName,
501
+ id,
502
+ embeded: true,
503
+ isCustomCreate: false,
504
+ customLayout: fieldLayoutInfo?.attrs?.inlineCreateLayout,
505
+ modelName: camelCase(fieldContext.fieldMetadata.relationCoModelSingularName),
506
+ parentFieldName: fieldContext.fieldMetadata.relationCoModelFieldName,
507
+ parentData: userKeyField
508
+ ? { [userKeyField]: { solidManyToOneLabel: fieldContext.data[userKeyField], solidManyToOneValue: fieldContext.data['id'] } }
509
+ : {},
510
+ onEmbeddedFormSave: fieldContext.onEmbeddedFormSave,
511
+ inlineCreateAutoSave: fieldLayoutInfo?.attrs?.inlineCreateAutoSave,
512
+ });
513
+ setvisibleCreateRelationEntity(true);
514
+ }
515
+ };
516
+
517
+ const handlePopupClose = () => {
518
+ setvisibleCreateRelationEntity(false);
519
+ const currentUrl = new URL(window.location.href);
520
+ currentUrl.searchParams.delete('childEntity');
521
+ router.push(currentUrl.toString());
522
+ setRefreshList((prev) => !prev);
523
+ setListViewParams({
524
+ moduleName: fieldContext.fieldMetadata.relationModelModuleName,
525
+ modelName: camelCase(fieldContext.fieldMetadata.relationCoModelSingularName),
526
+ inlineCreate: readOnlyPermission === false,
527
+ customLayout: fieldLayoutInfo?.attrs?.inlineListLayout,
528
+ embeded: true,
529
+ id: fieldContext.data?.id ?? 'new',
530
+ customFilter: buildRelationCustomFilter({ fieldContext, fieldLayoutInfo }),
531
+ });
532
+ };
533
+
534
+ useEffect(() => {
535
+ setListViewParams({
536
+ moduleName: fieldContext.fieldMetadata.relationModelModuleName,
537
+ modelName: camelCase(fieldContext.fieldMetadata.relationCoModelSingularName),
538
+ inlineCreate: readOnlyPermission === false,
539
+ customLayout: fieldLayoutInfo?.attrs?.inlineListLayout,
540
+ embeded: true,
541
+ id: fieldContext.data?.id ?? 'new',
542
+ customFilter: buildRelationCustomFilter({ fieldContext, fieldLayoutInfo }),
543
+ });
544
+
545
+ setformViewParams({
546
+ moduleName: fieldContext.fieldMetadata.relationModelModuleName,
547
+ modelName: camelCase(fieldContext.fieldMetadata.relationCoModelSingularName),
548
+ parentFieldName: fieldContext.fieldMetadata.relationCoModelFieldName,
549
+ id: "new",
550
+ embeded: true,
551
+ isCustomCreate: false,
552
+ customLayout: fieldLayoutInfo?.attrs?.inlineCreateLayout,
553
+ parentData: userKeyField
554
+ ? { [userKeyField]: { solidManyToOneLabel: fieldContext.data[userKeyField], solidManyToOneValue: fieldContext.data['id'] } }
555
+ : {},
556
+ onEmbeddedFormSave: fieldContext.onEmbeddedFormSave,
557
+ inlineCreateAutoSave: fieldLayoutInfo?.attrs?.inlineCreateAutoSave,
558
+ });
559
+ }, [readOnlyPermission]);
560
+
561
+ const saveParentEntity = async () => {
562
+ const currentUrl = new URL(window.location.href);
563
+ currentUrl.searchParams.set('childEntity', fieldLayoutInfo.attrs.name);
564
+ currentUrl.searchParams.set('viewMode', 'edit');
565
+ try {
566
+ router.push(currentUrl.toString());
567
+ await formik.handleSubmit();
568
+ } catch { }
569
+ setShowSaveParentEntityConfirmationPopup(false);
570
+ };
571
+
572
+ return (
573
+ <div>
574
+ {showFieldLabel !== false && (
575
+ <label htmlFor={fieldLayoutInfo.attrs.name} className="form-field-label">
576
+ {fieldLabel}
577
+ {fieldMetadata.required && <span className="text-red-500"> *</span>}
578
+ <SolidFieldTooltip fieldContext={fieldContext} />
579
+ </label>
580
+ )}
581
+ {listViewParams && (
582
+ <SolidListView key={refreshList.toString()} {...listViewParams} embededFieldRelationType="many-to-many" handleAddClickForEmbeddedView={handleAddClickForEmbeddedView} handleEditClickForEmbeddedView={handleEditClickForEmbeddedView} handleDeleteClick={handleDeleteClick} />
583
+ )}
584
+ {readOnlyPermission !== true && formViewParams && (
585
+ <RenderSolidFormEmbededView
586
+ formik={formik}
587
+ fieldContext={fieldContext}
588
+ visibleCreateRelationEntity={visibleCreateRelationEntity}
589
+ setvisibleCreateRelationEntity={setvisibleCreateRelationEntity}
590
+ formViewParams={formViewParams}
591
+ handlePopupClose={handlePopupClose}
592
+ />
593
+ )}
594
+
595
+ <Dialog
596
+ header={`Link existing ${fieldLabel}`}
597
+ visible={visibleLinkDialog}
598
+ style={{ width: '30vw', minWidth: 320 }}
599
+ onHide={() => setVisibleLinkDialog(false)}
600
+ footer={
601
+ <div className="flex gap-2 justify-content-end">
602
+ <Button
603
+ label="Link"
604
+ size="small"
605
+ disabled={!selectedLinkItem || isLinking}
606
+ loading={isLinking}
607
+ onClick={handleLinkConfirm}
608
+ />
609
+ <Button
610
+ label="Cancel"
611
+ size="small"
612
+ outlined
613
+ className="bg-primary-reverse"
614
+ onClick={() => setVisibleLinkDialog(false)}
615
+ />
616
+ </div>
617
+ }
618
+ >
619
+ <div className="flex flex-column gap-2 pt-2">
620
+ <label className="form-field-label">
621
+ Search {fieldLabel}
622
+ </label>
623
+ <AutoComplete
624
+ field="label"
625
+ value={selectedLinkItem}
626
+ suggestions={suggestions}
627
+ completeMethod={handleLinkSearch}
628
+ onChange={(e) => setSelectedLinkItem(e.value)}
629
+ onSelect={(e) => setSelectedLinkItem(e.value)}
630
+ placeholder={`Type to search...`}
631
+ className="w-full"
632
+ dropdown
633
+ />
634
+ </div>
635
+ </Dialog>
636
+
637
+
638
+ <Dialog
639
+ showHeader={false}
640
+ headerClassName="py-2"
641
+ contentClassName="px-0 pb-0"
642
+ className="solid-confirm-dialog"
643
+ contentStyle={{ borderRadius: 6 }}
644
+ visible={showSaveParentEntityConfirmationPopup}
645
+ style={{ width: '20vw' }}
646
+ onHide={() => {
647
+ if (!showSaveParentEntityConfirmationPopup) return;
648
+ setShowSaveParentEntityConfirmationPopup(false);
649
+ }}
650
+ >
651
+ <div className="p-4">
652
+ <p className="m-0 solid-primary-title" style={{ fontSize: 16 }}>
653
+ Before Creating {fieldLabel} you need to save{' '}
654
+ {solidFormViewMetaData?.data?.solidView?.model?.displayName
655
+ ? solidFormViewMetaData?.data?.solidView?.model?.displayName
656
+ : capitalize(fieldContext.modelName)}
657
+ . Please click save if you wish to proceed?
658
+ </p>
659
+ <div className="flex align-items-center justify-content-start gap-2 mt-3">
660
+ <Button label="Save" size="small" onClick={saveParentEntity} />
661
+ <Button
662
+ label="Cancel"
663
+ size="small"
664
+ onClick={() => setShowSaveParentEntityConfirmationPopup(false)}
665
+ outlined
666
+ className="bg-primary-reverse"
667
+ />
668
+ </div>
669
+ </div>
670
+ </Dialog>
671
+ </div>
672
+ );
673
+ };