@dashadmin/dash-auto-admin 1.3.25 → 1.3.26

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 (176) hide show
  1. package/dist/DashAutoAdminComponentRegistry.js +64 -1
  2. package/dist/DashAutoAdminForm.js +137 -1
  3. package/dist/DashAutoAdminResizableDrawer.js +63 -1
  4. package/dist/DashAutoAdminSaveButton.js +57 -1
  5. package/dist/DashAutoCreate.js +102 -1
  6. package/dist/DashAutoDrawer.js +256 -1
  7. package/dist/DashAutoEdit.js +99 -1
  8. package/dist/DashAutoFiltersGenerator.js +193 -1
  9. package/dist/DashAutoFormGroups.js +118 -1
  10. package/dist/DashAutoFormLayout.js +68 -1
  11. package/dist/DashAutoFormMuiTabs.js +291 -1
  12. package/dist/DashAutoFormTabs.js +132 -1
  13. package/dist/DashAutoGroup.js +27 -1
  14. package/dist/DashAutoLayout.js +31 -1
  15. package/dist/DashAutoList.js +218 -1
  16. package/dist/DashAutoPostFilterForm.js +47 -1
  17. package/dist/DashAutoReferenceTab.js +10 -1
  18. package/dist/DashAutoResource.js +77 -1
  19. package/dist/DashAutoResourceLayout.js +16 -1
  20. package/dist/DashAutoShow.js +195 -1
  21. package/dist/DashAutoTabbedForm.js +244 -1
  22. package/dist/DashAutoTabbedForm.review.js +221 -1
  23. package/dist/DashAutoTabs.js +11 -1
  24. package/dist/DashFilterWrapper.js +62 -1
  25. package/dist/DashRedirect.js +56 -1
  26. package/dist/TabbedLayout.js +38 -1
  27. package/dist/common/DashAutoTitle.js +33 -1
  28. package/dist/common/components/FabButton.js +59 -1
  29. package/dist/common/components/TranslatedLabel.js +60 -1
  30. package/dist/common/settings/Settings.js +196 -1
  31. package/dist/common/settings/SettingsBarIcons.js +61 -1
  32. package/dist/context/DashAutoAdminFormContext.js +15 -1
  33. package/dist/hooks/useAutoAdminLoadingStateMediator.js +36 -1
  34. package/dist/hooks/useAutoAdminTranslate.js +61 -1
  35. package/dist/hooks/useHash.js +24 -1
  36. package/dist/hooks/useLogger.js +20 -1
  37. package/dist/hooks/useRoutePathPattern.js +20 -1
  38. package/dist/hooks/useVirtualHash.js +28 -1
  39. package/dist/index.js +77 -3406
  40. package/dist/list/DashAutoListActions.js +57 -1
  41. package/dist/list/DashAutoListDatagridWrapper.js +68 -1
  42. package/dist/list/DashAutoListDefaultActionsWrapper.js +14 -1
  43. package/dist/list/DashAutoListFilterFormWithButton.js +80 -1
  44. package/dist/list/DashAutoListTopToolbar.js +180 -1
  45. package/dist/mui/AttributeToField.js +576 -1
  46. package/dist/mui/AttributeToInput.js +630 -1
  47. package/dist/mui/AutoAdminResizableDrawer.js +63 -1
  48. package/dist/mui/AutoDataGrid.js +120 -1
  49. package/dist/mui/AutoReferenceFormTab.js +53 -1
  50. package/dist/mui/AutoReferenceTab.js +46 -1
  51. package/dist/mui/AutoTabs.js +19 -1
  52. package/dist/mui/components/ExtendedPagination.js +34 -1
  53. package/dist/mui/components/ListStringField.js +25 -1
  54. package/dist/providers/DashAuthProvider.js +215 -1
  55. package/dist/providers/DashDataProvider.js +310 -1
  56. package/dist/providers/index.js +10 -1
  57. package/dist/react-admin.d.js +0 -0
  58. package/dist/toolbar/buttons/BottomToolbarButtons.js +65 -1
  59. package/dist/toolbar/buttons/DashResourceButton.js +181 -1
  60. package/dist/toolbar/buttons/ListButtons.js +80 -1
  61. package/dist/toolbar/buttons/ToolbarButtons.js +135 -1
  62. package/dist/types/ActionCallback.d.js +0 -0
  63. package/dist/utils/SimpleLogger.js +52 -1
  64. package/dist/utils/enumToChoices.js +5 -1
  65. package/dist/utils/evalActionPermission.js +11 -1
  66. package/dist/utils/groupByTabs.js +21 -1
  67. package/dist/utils/hashedGroupByTabs.js +12 -1
  68. package/dist/utils/invertMap.js +12 -1
  69. package/dist/utils/isClassComponent.js +7 -1
  70. package/dist/utils/isComponent.js +29 -1
  71. package/dist/utils/isEnum.js +5 -1
  72. package/dist/utils/isFC.js +8 -1
  73. package/dist/utils/replaceParams.js +9 -1
  74. package/dist/utils/validate.js +19 -1
  75. package/dist/wrappers/UserAction.js +60 -1
  76. package/dist/wrappers/index.js +4 -1
  77. package/package.json +135 -120
  78. package/src/DashAutoAdminComponentRegistry.tsx +75 -0
  79. package/src/DashAutoAdminForm.tsx +155 -0
  80. package/src/DashAutoAdminResizableDrawer.tsx +69 -0
  81. package/src/DashAutoAdminSaveButton.tsx +116 -0
  82. package/src/DashAutoCreate.tsx +118 -0
  83. package/src/DashAutoDrawer.tsx +288 -0
  84. package/src/DashAutoEdit.tsx +109 -0
  85. package/src/DashAutoFiltersGenerator.tsx +208 -0
  86. package/src/DashAutoFormGroups.tsx +146 -0
  87. package/src/DashAutoFormLayout.tsx.review +113 -0
  88. package/src/DashAutoFormMuiTabs.tsx +368 -0
  89. package/src/DashAutoFormTabs.tsx +177 -0
  90. package/src/DashAutoGroup.tsx +42 -0
  91. package/src/DashAutoLayout.tsx +57 -0
  92. package/src/DashAutoList.tsx +237 -0
  93. package/src/DashAutoPostFilterForm.tsx +35 -0
  94. package/src/DashAutoReferenceTab.tsx +9 -0
  95. package/src/DashAutoResource.tsx +85 -0
  96. package/src/DashAutoResourceLayout.tsx +50 -0
  97. package/src/DashAutoShow.tsx +200 -0
  98. package/src/DashAutoTabbedForm.review.tsx +262 -0
  99. package/src/DashAutoTabbedForm.tsx +324 -0
  100. package/src/DashAutoTabs.tsx +19 -0
  101. package/src/DashFilterWrapper.tsx +43 -0
  102. package/src/DashRedirect.tsx +46 -0
  103. package/src/TabbedLayout.tsx +29 -0
  104. package/src/common/DashAutoTitle.tsx +24 -0
  105. package/src/common/components/FabButton.tsx +40 -0
  106. package/src/common/components/TranslatedLabel.tsx +81 -0
  107. package/src/common/settings/Settings.tsx +236 -0
  108. package/src/common/settings/SettingsBarIcons.tsx +72 -0
  109. package/src/context/DashAutoAdminFormContext.tsx +31 -0
  110. package/src/hooks/useAutoAdminLoadingStateMediator.tsx +42 -0
  111. package/src/hooks/useAutoAdminTranslate.tsx +106 -0
  112. package/src/hooks/useHash.tsx +27 -0
  113. package/src/hooks/useLogger.tsx +23 -0
  114. package/src/hooks/useRoutePathPattern.tsx +24 -0
  115. package/src/hooks/useVirtualHash.tsx +34 -0
  116. package/src/index.ts +85 -0
  117. package/src/interfaces/ICustomResourceSubComponent.ts +11 -0
  118. package/src/interfaces/IDashApplicationLayoutMainAction.ts +37 -0
  119. package/src/interfaces/IDashApplicationLayoutMenuItem.ts +24 -0
  120. package/src/interfaces/IDashAutoAdminAttribute.ts +104 -0
  121. package/src/interfaces/IDashAutoAdminCustomFieldComponent.ts +18 -0
  122. package/src/interfaces/IDashAutoAdminFormOptions.ts +22 -0
  123. package/src/interfaces/IDashAutoAdminListActions.ts +13 -0
  124. package/src/interfaces/IDashAutoAdminReference.ts +16 -0
  125. package/src/interfaces/IDashAutoAdminResourceConfig.ts +360 -0
  126. package/src/interfaces/IDashAutoForm.ts +24 -0
  127. package/src/interfaces/IDashAutoGridButton.ts +35 -0
  128. package/src/interfaces/IDashAutoShow.ts +12 -0
  129. package/src/interfaces/IGroupExtraData.ts +8 -0
  130. package/src/interfaces/IRecord.ts +7 -0
  131. package/src/interfaces/IReferenceFilter.ts +55 -0
  132. package/src/interfaces/IResourceComponent.ts +8 -0
  133. package/src/interfaces/IToolbarButton.ts +11 -0
  134. package/src/list/DashAutoListActions.tsx +88 -0
  135. package/src/list/DashAutoListDatagridWrapper.tsx +74 -0
  136. package/src/list/DashAutoListDefaultActionsWrapper.tsx +31 -0
  137. package/src/list/DashAutoListFilterFormWithButton.tsx +93 -0
  138. package/src/list/DashAutoListTopToolbar.tsx +240 -0
  139. package/src/mui/AttributeToField.tsx +657 -0
  140. package/src/mui/AttributeToInput.tsx +728 -0
  141. package/src/mui/AutoAdminResizableDrawer.tsx +69 -0
  142. package/src/mui/AutoDataGrid.tsx +127 -0
  143. package/src/mui/AutoReferenceFormTab.tsx +51 -0
  144. package/src/mui/AutoReferenceTab.tsx +45 -0
  145. package/src/mui/AutoTabs.tsx +32 -0
  146. package/src/mui/components/ExtendedPagination.tsx +23 -0
  147. package/src/mui/components/ListStringField.tsx +32 -0
  148. package/src/providers/DashAuthProvider.ts +341 -0
  149. package/src/providers/DashDataProvider.ts +466 -0
  150. package/src/providers/index.ts +17 -0
  151. package/src/toolbar/buttons/BottomToolbarButtons.tsx +59 -0
  152. package/src/toolbar/buttons/DashResourceButton.tsx +223 -0
  153. package/src/toolbar/buttons/ListButtons.tsx +137 -0
  154. package/src/toolbar/buttons/ToolbarButtons.tsx +186 -0
  155. package/src/utils/SimpleLogger.tsx +46 -0
  156. package/src/utils/enumToChoices.tsx +3 -0
  157. package/src/utils/evalActionPermission.tsx +14 -0
  158. package/src/utils/groupByTabs.tsx +23 -0
  159. package/src/utils/hashedGroupByTabs.tsx +16 -0
  160. package/src/utils/invertMap.tsx +10 -0
  161. package/src/utils/isClassComponent.tsx +9 -0
  162. package/src/utils/isComponent.tsx +45 -0
  163. package/src/utils/isEnum.tsx +3 -0
  164. package/src/utils/isFC.tsx +6 -0
  165. package/src/utils/replaceParams.tsx +6 -0
  166. package/src/utils/validate.tsx +24 -0
  167. package/src/wrappers/UserAction.tsx +67 -0
  168. package/src/wrappers/index.tsx +1 -0
  169. /package/{dist → src}/DashAutoAdminSaveButton.tsx.bkup +0 -0
  170. /package/{dist/DashAutoFormLayout.tsx.review → src/DashAutoFormLayout.tsx} +0 -0
  171. /package/{dist → src}/DashAutoFormTabs.review +0 -0
  172. /package/{dist → src}/DashAutoFormTabs.tsx.formcontext.wip +0 -0
  173. /package/{dist → src}/mui/AttributeToField.tsx.review +0 -0
  174. /package/{dist → src}/mui/AttributeToInput.tsx.review +0 -0
  175. /package/{dist → src}/react-admin.d.ts +0 -0
  176. /package/{dist → src}/types/ActionCallback.d.ts +0 -0
@@ -0,0 +1,728 @@
1
+ import {
2
+ ArrayInput,
3
+ ImageInput,
4
+ FileInput,
5
+ BooleanInput,
6
+ DateInput,
7
+ DateTimeInput,
8
+ NumberInput,
9
+ SelectArrayInput,
10
+ SelectInput,
11
+ ChipField,
12
+ ImageField,
13
+ PasswordInput,
14
+ ReferenceArrayInput,
15
+ ReferenceInput,
16
+ SimpleFormIterator,
17
+ SingleFieldList,
18
+ TextInput,
19
+ useRecordContext,
20
+ } from 'react-admin';
21
+ import { ErrorMessage } from "@hookform/error-message"
22
+
23
+ import { InputAdornment, InputLabel, TextField, Typography } from '@mui/material';
24
+ import Visibility from '@mui/icons-material/Visibility';
25
+
26
+ import IDashAutoAdminAttribute from '../interfaces/IDashAutoAdminAttribute';
27
+ import IDashAutoAdminFormOptions from '../interfaces/IDashAutoAdminFormOptions';
28
+
29
+ import { UserAction } from '../wrappers';
30
+ import { FunctionField } from 'react-admin';
31
+ import { FileField } from 'react-admin';
32
+
33
+ import React, { JSX, useEffect } from 'react';
34
+ import IDashAutoAdminResourceConfig from '../interfaces/IDashAutoAdminResourceConfig';
35
+ import IDashAutoAdminCustomFieldComponent from '../interfaces/IDashAutoAdminCustomFieldComponent';
36
+ import enumToChoices from '../utils/enumToChoices';
37
+ import isEnum from '../utils/isEnum';
38
+ import { useLocation, useParams } from 'react-router';
39
+ import replaceParams from '../utils/replaceParams';
40
+ import { useSelector } from 'react-redux';
41
+ //import { IDASHAppState } from 'dash-admin-state';
42
+ import { useEditContext } from 'react-admin';
43
+ import { useFormContext } from 'react-hook-form';
44
+ import { useComponentRegistry } from '../DashAutoAdminComponentRegistry';
45
+
46
+ export interface IGroupExtraData {
47
+ name: string;
48
+ icon?: JSX.Element;
49
+ }
50
+
51
+ export interface IFieldWrapper {
52
+ method: 'list' | 'view' | 'create' | 'edit';
53
+ index: React.Key;
54
+ input: IDashAutoAdminAttribute;
55
+ children: JSX.Element;
56
+ }
57
+
58
+
59
+ const FunctionFieldWrapper = ({
60
+ index,
61
+ method,
62
+ input,
63
+ children,
64
+ ..._props
65
+ }: IFieldWrapper): JSX.Element => {
66
+ const sortable = input?.sortable === true ? true : false;
67
+
68
+ const {
69
+ formState: { errors },
70
+ } = useFormContext()
71
+
72
+
73
+ if (method === 'edit') {
74
+ return (
75
+ <div
76
+ className={`auto-admin-field auto-admin-field-${method}`}
77
+ key={index}
78
+ >
79
+ <FunctionField
80
+ //key={index}
81
+ label={input?.label || input.attribute}
82
+ sortable={sortable}
83
+ {...(sortable && { sortBy: input.listAttribute || input.attribute })}
84
+ render={(record) => {
85
+ return React.cloneElement(children, { record: record });
86
+ }}
87
+ />
88
+
89
+ {!input?.hideErrorMessage || input?.custom && <ErrorMessage
90
+ errors={errors}
91
+ name={input.attribute}
92
+ render={(error) => {
93
+ return error ? <Typography className='dash-admin-field-error' color="error" >{typeof error.message === 'string' ? error.message : typeof (error as any).message?.message === 'string' ? (error as any).message?.message : JSON.stringify(error)}</Typography> : null;
94
+ }}
95
+ />}
96
+
97
+ </div>
98
+ );
99
+ }
100
+ return (
101
+ <div className={`auto-admin-field auto-admin-field-${method}`} key={index}>
102
+ {children}
103
+ </div>
104
+ );
105
+ };
106
+
107
+ /**
108
+ * The `AttributeToInput` function is a React component that renders an input field based on the provided `IDashAutoAdminAttribute` object.
109
+ * It handles various input types, including strings, numbers, booleans, dates, and enums. The function also supports custom components, reference inputs, and array inputs.
110
+ *
111
+ * The function takes the following parameters:
112
+ * - `method`: The current operation mode, such as 'list', 'view', 'create', or 'edit'.
113
+ * - `resourceConfig`: The configuration object for the current resource.
114
+ * - `input`: The `IDashAutoAdminAttribute` object that defines the input field.
115
+ * - `index`: An optional index value for the input field.
116
+ * - `options`: An optional object that provides additional configuration and field options.
117
+ *
118
+ * The function returns a JSX element that represents the input field, wrapped in a `FunctionFieldWrapper` component. The `FunctionFieldWrapper` component handles the rendering of the input field based on the current operation mode.
119
+ */
120
+
121
+ // Safe hook to get edit context only when available
122
+ const useSafeEditContext = () => {
123
+ try {
124
+ return useEditContext();
125
+ } catch (error) {
126
+ // EditContext is not available (e.g., in create mode)
127
+ return null;
128
+ }
129
+ };
130
+
131
+ // Safe hook to get record context
132
+ const useSafeRecordContext = () => {
133
+ try {
134
+ return useRecordContext();
135
+ } catch (error) {
136
+ // RecordContext is not available
137
+ return null;
138
+ }
139
+ };
140
+
141
+ // Custom hook to get the appropriate record context
142
+ const useRecordByMethod = (method: string, mode?: string) => {
143
+ // Always call both hooks, but handle when they're not available
144
+ const editContext = useSafeEditContext();
145
+ const recordContext = useSafeRecordContext();
146
+
147
+ // Return the appropriate context based on method
148
+ if (method === 'edit' || mode === 'edit') {
149
+ return editContext;
150
+ }
151
+ return recordContext;
152
+ };
153
+ const AttributeToInput = (
154
+ method: 'list' | 'view' | 'create' | 'edit',
155
+ resourceConfig: IDashAutoAdminResourceConfig,
156
+ input: IDashAutoAdminAttribute,
157
+ index?: number,
158
+ options?: IDashAutoAdminFormOptions,
159
+ ) => {
160
+
161
+ const DEBUG = false;
162
+ // Get the component registry
163
+ const { components } = useComponentRegistry();
164
+
165
+ // Move all hook calls to the top level, before any conditional logic
166
+ const mode = options?.mode || 'view';
167
+ const record = useRecordByMethod(method, options?.mode);
168
+ const location = useLocation();
169
+ const params = useParams();
170
+
171
+ const typeComponentMapper = (type: string) => {
172
+ const component = components[type];
173
+
174
+ if (component) {
175
+ return { custom: true, type: "component", component };
176
+ }
177
+ return { custom: true, type: "component", component: () => <>No component for {type}</> };
178
+ };
179
+
180
+ const ComponentWrapper =
181
+ resourceConfig?.fieldWrapper &&
182
+ typeof resourceConfig.fieldWrapper === 'function'
183
+ ? resourceConfig.fieldWrapper
184
+ : ({
185
+ _record,
186
+ _method,
187
+ _attribute,
188
+ _resourceConfig,
189
+ children,
190
+ }: IDashAutoAdminCustomFieldComponent) => children;
191
+
192
+ /*
193
+ input.type != 'custom'
194
+ input.type does not contains dots
195
+ input.type dies not represents an Enum or Array.
196
+ */
197
+
198
+ if (typeof input.type === "string" && !input.type.includes(".") && !Array.isArray(input.type)) {
199
+ switch (input.type) {
200
+ case 'string':
201
+ case 'text':
202
+ case 'String':
203
+ input.type = String;
204
+ input.slotProps = {
205
+ fullWidth: input?.fieldProps?.fullWidth ?? true,
206
+ };
207
+ break;
208
+ case 'textarea':
209
+ input.type = String;
210
+ input.multiple = true;
211
+
212
+ input.slotProps = {
213
+ fullWidth: input?.fieldProps?.fullWidth ?? true,
214
+ };
215
+
216
+ input.fieldProps = {
217
+ ...(input.fieldProps || {}),
218
+ multiline: input?.fieldProps?.multiline ?? true,
219
+ rows: input?.fieldProps?.rows ?? 4,
220
+ };
221
+ break;
222
+ case 'number':
223
+ case 'Number':
224
+ case 'integer':
225
+ input.type = Number;
226
+ break;
227
+ case 'boolean':
228
+ case 'Boolean':
229
+ input.type = Boolean;
230
+ break;
231
+ case 'date':
232
+ case 'Date':
233
+ input.type = Date;
234
+ break;
235
+ case 'custom':
236
+ default:
237
+ input.custom = true;
238
+ DEBUG && console.log('🔧 AttributeToInput - custom type detected, input.component:', input?.component);
239
+ DEBUG && console.log('🔧 AttributeToInput - components available:', Object.keys(components));
240
+
241
+ if(typeof input?.component === "string") {
242
+ const mappedResult = typeComponentMapper( input.component );
243
+ DEBUG && console.log('🔧 AttributeToInput - typeComponentMapper result:', mappedResult);
244
+ input = { ...input, ...mappedResult };
245
+ DEBUG && console.log('🔧 AttributeToInput - after merge, input.component:', input.component);
246
+ }
247
+
248
+ }
249
+ }
250
+
251
+ if (options && options.useReadOnlyInputAsTextField && input.readOnly) {
252
+ return (
253
+ <FunctionFieldWrapper index={index} method={mode} input={input}>
254
+ <ComponentWrapper
255
+ key={index}
256
+ label={input.label}
257
+ source={input.listAttribute || input.attribute}
258
+ {...(record && { record: record })}
259
+ method={method}
260
+ attribute={input}
261
+ resourceConfig={resourceConfig}
262
+ >
263
+ <TextInput
264
+ fullWidth
265
+ {...(record && { record: record })}
266
+ key={index}
267
+ label={input.label}
268
+ source={input.listAttribute || input.attribute}
269
+ {...{
270
+ ...input.fieldProps,
271
+ editable: false,
272
+ InputProps: {
273
+ readOnly: true,
274
+ endAdornment: (
275
+ <InputAdornment position='start'>
276
+ <Visibility />
277
+ </InputAdornment>
278
+ ),
279
+ },
280
+ }}
281
+ />
282
+ </ComponentWrapper>
283
+ </FunctionFieldWrapper>
284
+ );
285
+ } else if (options && options.readOnlyComponent && input.readOnly) {
286
+ return (
287
+ <FunctionFieldWrapper index={index} method={mode} input={input}>
288
+ <ComponentWrapper
289
+ {...(record && { record: record })}
290
+ method={method}
291
+ attribute={input}
292
+ key={index}
293
+ label={input.label}
294
+ source={input.listAttribute || input.attribute}
295
+ resourceConfig={resourceConfig}
296
+ >
297
+ <options.readOnlyComponent
298
+ fullWidth
299
+ key={index}
300
+ {...(record && { record: record })}
301
+ input={input}
302
+ label={input.label}
303
+ source={input.listAttribute || input.attribute}
304
+ {...{
305
+ ...input.fieldProps,
306
+ editable: false,
307
+ InputProps: { readOnly: true },
308
+ }}
309
+ />
310
+ </ComponentWrapper>
311
+ </FunctionFieldWrapper>
312
+ );
313
+ }
314
+
315
+ /* Force the attribute name to be the label, if not label provided */
316
+ if (!input.label) input.label = input.attribute;
317
+
318
+ if (
319
+ (input.custom && input.component) ||
320
+ (input.type === 'component' && input.component)
321
+ ) {
322
+
323
+ return (
324
+ <FunctionFieldWrapper index={index} method={mode} input={input}>
325
+ <UserAction
326
+ record={record}
327
+ key={index}
328
+ method={mode}
329
+ attribute={input}
330
+ resourceConfig={resourceConfig}
331
+ />
332
+ </FunctionFieldWrapper>
333
+ );
334
+ }
335
+
336
+ if (Array.isArray(input.type) && input.type.length > 0) {
337
+ const inputType: string | IDashAutoAdminAttribute = input.type[0];
338
+ /* Array of enum values – We use a SelectArrayInput */
339
+ if (isEnum(inputType)) {
340
+ return (
341
+ <FunctionFieldWrapper index={index} method={mode} input={input}>
342
+ <SelectArrayInput
343
+ key={index}
344
+ fullWidth
345
+ label={input.label}
346
+ source={input.attribute}
347
+ choices={enumToChoices(inputType)}
348
+ {...input?.fieldProps}
349
+ onChange={e => {
350
+ if (options?.handleChange) {
351
+ options.handleChange(e);
352
+ }
353
+ if (input.fieldProps?.onChange) {
354
+ input.fieldProps.onChange(e)
355
+ }
356
+ }}
357
+ />
358
+ </FunctionFieldWrapper>
359
+ );
360
+ }
361
+ /* Recurse */
362
+
363
+ if (typeof inputType === 'string') {
364
+ const _params = {
365
+ ...params, ...(location.hash.match(/\d+/g) || []).map(Number).reduce((acc, curr, currentIndex) => {
366
+ acc[currentIndex] = curr;
367
+ return acc;
368
+ }, {})
369
+ };
370
+
371
+ const _inputType = replaceParams(_params, inputType);
372
+ const [reference, sourceName] = _inputType.split('.');
373
+ const safeIfNull = (choice: any) =>
374
+ (choice ? choice[sourceName] : '?') || '??';
375
+
376
+ if (input && input.multiple === false && input.component) {
377
+ const CustomComponent = input.component;
378
+ return (
379
+ <FunctionFieldWrapper index={index} method={mode} input={input}>
380
+ <ReferenceInput
381
+ key={index}
382
+ fullWidth
383
+ allowEmpty
384
+ filter
385
+ pagination={false}
386
+ label={input.label}
387
+ reference={reference}
388
+ source={input.attribute}
389
+ {...input.componentProps}
390
+ >
391
+ <CustomComponent
392
+ optionText={safeIfNull}
393
+ method={method} // edit because its AttributeToInput we need to assure is edit or create
394
+ attribute={input}
395
+ onChange={e => {
396
+ if (options?.handleChange) {
397
+ options.handleChange(e);
398
+ }
399
+ if (input.fieldProps?.onChange) {
400
+ input.fieldProps.onChange(e)
401
+ }
402
+ }}
403
+ resourceConfig={resourceConfig}
404
+ />
405
+ </ReferenceInput>
406
+ </FunctionFieldWrapper>
407
+ );
408
+ }
409
+
410
+ return (
411
+ <FunctionFieldWrapper index={index} method={mode} input={input}>
412
+ <ReferenceArrayInput
413
+ key={index}
414
+ fullWidth
415
+ filter
416
+ pagination={false}
417
+ label={input.label}
418
+ reference={reference}
419
+ source={input.attribute}
420
+ {...input.componentProps}
421
+ >
422
+ <SingleFieldList {...input.fieldProps}>
423
+ <ChipField source={sourceName} />
424
+ </SingleFieldList>
425
+ </ReferenceArrayInput>
426
+ </FunctionFieldWrapper>
427
+ );
428
+ } else {
429
+ const inputTypeArray = input.type as IDashAutoAdminAttribute[];
430
+
431
+ return (
432
+ <FunctionFieldWrapper index={index} method={mode} input={input}>
433
+ <ArrayInput
434
+ key={index}
435
+ label={input.label}
436
+ source={input.attribute}
437
+ {...input.componentProps}
438
+ >
439
+ <SimpleFormIterator>
440
+ {inputTypeArray.map((attribute, idx) =>
441
+ AttributeToInput(method, resourceConfig, attribute, idx),
442
+ )}
443
+ </SimpleFormIterator>
444
+ </ArrayInput>
445
+ </FunctionFieldWrapper>
446
+ );
447
+ }
448
+ }
449
+
450
+ if (input && input.type === ImageInput) {
451
+ return (
452
+ <FunctionFieldWrapper index={index} method={mode} input={input}>
453
+ <ImageInput
454
+ key={index}
455
+ placeholder={'Arrástre una imágen o haga click aquí para seleccionar'}
456
+ source={input.attribute}
457
+ label={input.label}
458
+ accept='image/*'
459
+ {...input.fieldProps}
460
+ >
461
+ <ImageField source='src' title='title' />
462
+ </ImageInput>
463
+ </FunctionFieldWrapper>
464
+ );
465
+ }
466
+
467
+ if (input && input.type === FileInput) {
468
+ <FunctionFieldWrapper index={index} method={mode} input={input}>
469
+ <FileInput
470
+ key={index}
471
+ placeholder={'Arrástre un archivo o haga click aquí para seleccionar'}
472
+ source={input.attribute}
473
+ label={input.label}
474
+ {...input.fieldProps}
475
+ >
476
+ <FileField source='src' title='title' />
477
+ </FileInput>
478
+ </FunctionFieldWrapper>;
479
+ }
480
+
481
+ /* Special cases – Passing strings, passing enums */
482
+ if (typeof input.type === 'string') {
483
+ // Handle 'select' type with static options (no API call needed)
484
+ if (input.type === 'select' && Array.isArray(input.options) && input.options.length > 0) {
485
+ const choices = input.options.map((opt: { id: any; name: any }) => ({
486
+ id: opt.id,
487
+ name: opt.name,
488
+ }));
489
+
490
+ return (
491
+ <FunctionFieldWrapper index={index} method={mode} input={input}>
492
+ <SelectInput
493
+ key={index}
494
+ fullWidth
495
+ label={input.label}
496
+ source={input.listAttribute || input.attribute}
497
+ choices={choices}
498
+ {...input.fieldProps}
499
+ onChange={e => {
500
+ if (options?.handleChange) {
501
+ options.handleChange(e);
502
+ }
503
+ if (input.fieldProps?.onChange) {
504
+ input.fieldProps.onChange(e);
505
+ }
506
+ }}
507
+ {...input.componentProps}
508
+ />
509
+ </FunctionFieldWrapper>
510
+ );
511
+ }
512
+
513
+ // Handle 'select' type without options - skip rendering to avoid API errors
514
+ if (input.type === 'select' && (!input.options || input.options.length === 0)) {
515
+ console.warn(`Select field "${input.attribute}" has no options defined. Skipping render.`);
516
+ return null;
517
+ }
518
+
519
+ const _params = {
520
+ ...params, ...(location.pathname.match(/\d+/g) || []).map(Number).reduce((acc, curr, currentIndex) => {
521
+ acc[currentIndex] = curr;
522
+ return acc;
523
+ }, {})
524
+ };
525
+
526
+ const _inputType = replaceParams(_params, input.type);
527
+ const [reference, sourceName] = _inputType.split('.');
528
+ const CustomComponent = input.component || SelectInput;
529
+
530
+ if (input && input.multiple === false) {
531
+ return (
532
+ <FunctionFieldWrapper index={index} method={mode} input={input}>
533
+ <ReferenceInput
534
+ key={index}
535
+ allowEmpty
536
+ filters
537
+ label={input.label}
538
+ source={input.listAttribute || input.attribute}
539
+ reference={reference}
540
+ sort={{ field: sourceName, order: 'ASC' }}
541
+ {...input.componentProps}
542
+ >
543
+ <CustomComponent
544
+ optionText={sourceName}
545
+ method={method} // edit because its AttributeToInput
546
+ attribute={input}
547
+ label={input?.label || ''}
548
+ {...input.fieldProps}
549
+ onChange={e => {
550
+ if (options?.handleChange) {
551
+ options.handleChange(e);
552
+ }
553
+ if (input.fieldProps?.onChange) {
554
+ input.fieldProps.onChange(e)
555
+ }
556
+ }}
557
+ resourceConfig={resourceConfig}
558
+ />
559
+ </ReferenceInput>
560
+ </FunctionFieldWrapper>
561
+ );
562
+ }
563
+
564
+ return (
565
+ <FunctionFieldWrapper index={index} method={mode} input={input}>
566
+ <ReferenceArrayInput
567
+ key={index}
568
+ reference={reference}
569
+ source={input.listAttribute || input.attribute}
570
+ {...input.componentProps}
571
+ >
572
+ <SelectArrayInput
573
+ optionText={sourceName}
574
+ fullWidth
575
+ label={input?.label || ''}
576
+ {...input.fieldProps}
577
+ onChange={e => {
578
+ if (options?.handleChange) {
579
+ options.handleChange(e);
580
+ }
581
+ if (input.fieldProps?.onChange) {
582
+ input.fieldProps.onChange(e)
583
+ }
584
+ }}
585
+ />
586
+ </ReferenceArrayInput>
587
+ </FunctionFieldWrapper>
588
+ );
589
+ }
590
+
591
+ switch (input.type) {
592
+ case Number:
593
+ return (
594
+ <FunctionFieldWrapper index={index} method={mode} input={input}>
595
+ <NumberInput
596
+ key={index}
597
+ fullWidth
598
+ label={input.label}
599
+ source={input.attribute}
600
+ {...input.fieldProps}
601
+ onChange={e => {
602
+ if (options?.handleChange) {
603
+ options.handleChange(e);
604
+ }
605
+ if (input.fieldProps?.onChange) {
606
+ input.fieldProps.onChange(e)
607
+ }
608
+ }}
609
+ />
610
+ </FunctionFieldWrapper>
611
+ );
612
+
613
+ case Boolean:
614
+ return <FunctionFieldWrapper index={index} method={mode} input={input}>
615
+ <div>
616
+ {input?.showLabel !== false && (
617
+ <InputLabel htmlFor={input.listAttribute || input.attribute}>
618
+ {input.label}
619
+ </InputLabel>
620
+ )}
621
+ <BooleanInput
622
+ record={record}
623
+ key={index}
624
+ id={input.listAttribute || input.attribute}
625
+ label={input.label}
626
+ source={input.listAttribute || input.attribute}
627
+ {...input.fieldProps}
628
+ onChange={e => {
629
+ if (options?.handleChange) {
630
+ options.handleChange(e);
631
+ }
632
+ if (input.fieldProps?.onChange) {
633
+ input.fieldProps.onChange(e)
634
+ }
635
+ }}
636
+ />
637
+ </div>
638
+ </FunctionFieldWrapper>
639
+
640
+
641
+ case Date:
642
+ return input.fieldProps && input.fieldProps.showTime ? (
643
+ <FunctionFieldWrapper index={index} method={mode} input={input}>
644
+ <DateTimeInput
645
+ key={index}
646
+ label={input.label}
647
+ source={input.attribute}
648
+ {...input.fieldProps}
649
+ />
650
+ </FunctionFieldWrapper>
651
+ ) : (
652
+ <FunctionFieldWrapper index={index} method={mode} input={input}>
653
+ <DateInput
654
+ key={index}
655
+ label={input.label}
656
+ source={input.attribute}
657
+ {...input.fieldProps}
658
+ onChange={e => {
659
+ if (options?.handleChange) {
660
+ options.handleChange(e);
661
+ }
662
+ if (input.fieldProps?.onChange) {
663
+ input.fieldProps.onChange(e)
664
+ }
665
+ }}
666
+ />
667
+ </FunctionFieldWrapper>
668
+ );
669
+ }
670
+ if (isEnum(input.type)) {
671
+ return (
672
+ <FunctionFieldWrapper index={index} method={mode} input={input}>
673
+ <SelectInput
674
+ key={index}
675
+ label={input.label}
676
+ source={input.attribute}
677
+ choices={enumToChoices(input.type)}
678
+ InputProps={input.fieldOptions}
679
+ onChange={e => {
680
+ if (options?.handleChange) {
681
+ options.handleChange(e);
682
+ }
683
+ if (input.fieldProps?.onChange) {
684
+ input.fieldProps.onChange(e)
685
+ }
686
+ }}
687
+ />
688
+ </FunctionFieldWrapper>
689
+ );
690
+ }
691
+
692
+ if (input.isPassword) {
693
+ const passwordProps = {
694
+ key: index,
695
+ label: input.label,
696
+ source: input.attribute,
697
+ ...(input.slotProps ? { slotProps: input.slotProps } : {})
698
+ }
699
+
700
+ return (
701
+ <FunctionFieldWrapper index={index} method={mode} input={input}>
702
+ <PasswordInput {...passwordProps} />
703
+ </FunctionFieldWrapper>
704
+ );
705
+ }
706
+ const textFieldProps = {
707
+ label: input.label,
708
+ source: input.listAttribute || input.attribute,
709
+ ...input.fieldProps,
710
+ ...input.slotProps ? { slotProps: input.slotProps } : {},
711
+ onChange: (e) => {
712
+ if (options?.handleChange) {
713
+ options.handleChange(e);
714
+ }
715
+ if (input.fieldProps?.onChange) {
716
+ input.fieldProps.onChange(e)
717
+ }
718
+ }
719
+ }
720
+
721
+ return <FunctionFieldWrapper index={index} method={mode} input={input}>
722
+ <TextInput
723
+ {...textFieldProps}
724
+ />
725
+ </FunctionFieldWrapper>
726
+ };
727
+
728
+ export default AttributeToInput;