@firecms/core 3.0.0-beta.2-pre.2 → 3.0.0-beta.2-pre.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -3
- package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +0 -3
- package/dist/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +1 -8
- package/dist/components/EntityCollectionTable/index.d.ts +2 -4
- package/dist/components/EntityCollectionTable/internal/popup_field/PopupFormField.d.ts +1 -1
- package/dist/components/{ReferenceSelectionInner.d.ts → ReferenceTable/ReferenceSelectionTable.d.ts} +2 -2
- package/dist/components/{EntityCollectionTable/SimpleTable.d.ts → SelectableTable/SelectableTable.d.ts} +3 -4
- package/dist/components/SelectableTable/SelectableTableContext.d.ts +4 -0
- package/dist/components/common/index.d.ts +5 -0
- package/dist/components/{EntityCollectionTable → common}/types.d.ts +7 -0
- package/dist/components/common/useTableSearchHelper.d.ts +12 -0
- package/dist/components/index.d.ts +5 -2
- package/dist/form/EntityForm.d.ts +2 -0
- package/dist/form/components/index.d.ts +0 -1
- package/dist/hooks/index.d.ts +1 -0
- package/dist/{internal → hooks}/useBuildNavigationController.d.ts +11 -4
- package/dist/hooks/useSnackbarController.d.ts +1 -0
- package/dist/index.es.js +4081 -4049
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +5 -5
- package/dist/index.umd.js.map +1 -1
- package/dist/types/fields.d.ts +0 -1
- package/dist/types/firecms.d.ts +6 -25
- package/dist/types/navigation.d.ts +2 -2
- package/dist/types/plugins.d.ts +0 -8
- package/package.json +4 -4
- package/src/components/ArrayContainer.tsx +11 -4
- package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +16 -22
- package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +1 -5
- package/src/components/EntityCollectionTable/PropertyTableCell.tsx +2 -2
- package/src/components/EntityCollectionTable/column_utils.tsx +1 -1
- package/src/components/EntityCollectionTable/index.tsx +1 -9
- package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +133 -136
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +20 -41
- package/src/components/{ReferenceSelectionInner.tsx → ReferenceTable/ReferenceSelectionTable.tsx} +31 -15
- package/src/components/{EntityCollectionTable/SimpleTable.tsx → SelectableTable/SelectableTable.tsx} +8 -9
- package/src/components/SelectableTable/SelectableTableContext.tsx +6 -0
- package/src/components/{EntityCollectionTable → SelectableTable}/filters/StringNumberFilterField.tsx +0 -1
- package/src/components/VirtualTable/VirtualTableHeader.tsx +10 -4
- package/src/components/common/index.ts +5 -0
- package/src/components/{EntityCollectionTable → common}/types.tsx +5 -0
- package/src/components/common/useTableSearchHelper.ts +47 -0
- package/src/components/index.tsx +6 -2
- package/src/core/EntitySidePanel.tsx +7 -5
- package/src/core/FireCMS.tsx +1 -16
- package/src/form/EntityForm.tsx +237 -196
- package/src/form/PropertyFieldBinding.tsx +7 -7
- package/src/form/components/CustomIdField.tsx +35 -34
- package/src/form/components/ErrorFocus.tsx +3 -3
- package/src/form/components/index.tsx +0 -1
- package/src/form/field_bindings/BlockFieldBinding.tsx +13 -12
- package/src/hooks/index.tsx +1 -0
- package/src/{internal → hooks}/useBuildNavigationController.tsx +23 -17
- package/src/hooks/useFireCMSContext.tsx +51 -3
- package/src/hooks/useReferenceDialog.tsx +2 -2
- package/src/hooks/useSnackbarController.tsx +1 -2
- package/src/internal/useBuildSideEntityController.tsx +1 -1
- package/src/types/fields.tsx +1 -1
- package/src/types/firecms.tsx +7 -28
- package/src/types/navigation.ts +2 -2
- package/src/types/plugins.tsx +0 -9
- package/src/util/resolutions.ts +1 -1
- package/dist/form/components/SubmitListener.d.ts +0 -1
- package/dist/form/components/SwitchControl.d.ts +0 -8
- package/src/form/components/SubmitListener.tsx +0 -32
- package/src/form/components/SwitchControl.tsx +0 -39
- /package/dist/components/{EntityCollectionTable → SelectableTable}/filters/BooleanFilterField.d.ts +0 -0
- /package/dist/components/{EntityCollectionTable → SelectableTable}/filters/DateTimeFilterField.d.ts +0 -0
- /package/dist/components/{EntityCollectionTable → SelectableTable}/filters/ReferenceFilterField.d.ts +0 -0
- /package/dist/components/{EntityCollectionTable → SelectableTable}/filters/StringNumberFilterField.d.ts +0 -0
- /package/dist/components/{EntityCollectionView → common}/useColumnsIds.d.ts +0 -0
- /package/dist/components/{EntityCollectionTable → common}/useDataSourceEntityCollectionTableController.d.ts +0 -0
- /package/dist/components/{EntityCollectionTable → common}/useDebouncedData.d.ts +0 -0
- /package/src/components/{EntityCollectionTable → SelectableTable}/filters/BooleanFilterField.tsx +0 -0
- /package/src/components/{EntityCollectionTable → SelectableTable}/filters/DateTimeFilterField.tsx +0 -0
- /package/src/components/{EntityCollectionTable → SelectableTable}/filters/ReferenceFilterField.tsx +0 -0
- /package/src/components/{EntityCollectionView → common}/useColumnsIds.tsx +0 -0
- /package/src/components/{EntityCollectionTable → common}/useDataSourceEntityCollectionTableController.tsx +0 -0
- /package/src/components/{EntityCollectionTable → common}/useDebouncedData.ts +0 -0
package/src/form/EntityForm.tsx
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
PropertyFieldBindingProps,
|
|
13
13
|
ResolvedEntityCollection
|
|
14
14
|
} from "../types";
|
|
15
|
-
import {
|
|
15
|
+
import { Formex, FormexController, getIn, setIn, useCreateFormex } from "@firecms/formex";
|
|
16
16
|
import { PropertyFieldBinding } from "./PropertyFieldBinding";
|
|
17
17
|
import { CustomFieldValidator, getYupEntitySchema } from "./validation";
|
|
18
18
|
import equal from "react-fast-compare"
|
|
@@ -41,6 +41,7 @@ import {
|
|
|
41
41
|
deleteEntityAction
|
|
42
42
|
} from "../components/EntityCollectionTable/internal/default_entity_actions";
|
|
43
43
|
import { useAnalyticsController } from "../hooks/useAnalyticsController";
|
|
44
|
+
import { ValidationError } from "yup";
|
|
44
45
|
|
|
45
46
|
/**
|
|
46
47
|
* @group Components
|
|
@@ -139,6 +140,23 @@ export const EntityForm = React.memo<EntityFormProps<any>>(EntityFormInternal,
|
|
|
139
140
|
equal(a.entity?.values, b.entity?.values);
|
|
140
141
|
}) as typeof EntityFormInternal;
|
|
141
142
|
|
|
143
|
+
function getDataSourceEntityValues<M extends object>(initialResolvedCollection: ResolvedEntityCollection,
|
|
144
|
+
status: "new" | "existing" | "copy",
|
|
145
|
+
entity: Entity<M> | undefined): Partial<EntityValues<M>> {
|
|
146
|
+
const properties = initialResolvedCollection.properties;
|
|
147
|
+
if ((status === "existing" || status === "copy") && entity) {
|
|
148
|
+
return entity.values ?? getDefaultValuesFor(properties);
|
|
149
|
+
} else if (status === "new") {
|
|
150
|
+
return getDefaultValuesFor(properties);
|
|
151
|
+
} else {
|
|
152
|
+
console.error({
|
|
153
|
+
status,
|
|
154
|
+
entity
|
|
155
|
+
});
|
|
156
|
+
throw new Error("Form has not been initialised with the correct parameters");
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
142
160
|
function EntityFormInternal<M extends Record<string, any>>({
|
|
143
161
|
status,
|
|
144
162
|
path,
|
|
@@ -187,20 +205,7 @@ function EntityFormInternal<M extends Record<string, any>>({
|
|
|
187
205
|
|
|
188
206
|
const closeAfterSaveRef = useRef(false);
|
|
189
207
|
|
|
190
|
-
const
|
|
191
|
-
const properties = initialResolvedCollection.properties;
|
|
192
|
-
if ((status === "existing" || status === "copy") && entity) {
|
|
193
|
-
return entity.values ?? getDefaultValuesFor(properties);
|
|
194
|
-
} else if (status === "new") {
|
|
195
|
-
return getDefaultValuesFor(properties);
|
|
196
|
-
} else {
|
|
197
|
-
console.error({
|
|
198
|
-
status,
|
|
199
|
-
entity
|
|
200
|
-
});
|
|
201
|
-
throw new Error("Form has not been initialised with the correct parameters");
|
|
202
|
-
}
|
|
203
|
-
}, [status, initialResolvedCollection, entity]);
|
|
208
|
+
const baseDataSourceValuesRef = useRef<Partial<EntityValues<M>>>(getDataSourceEntityValues(initialResolvedCollection, status, entity));
|
|
204
209
|
|
|
205
210
|
const [entityId, setEntityId] = React.useState<string | undefined>(initialEntityId);
|
|
206
211
|
const [entityIdError, setEntityIdError] = React.useState<boolean>(false);
|
|
@@ -208,11 +213,114 @@ function EntityFormInternal<M extends Record<string, any>>({
|
|
|
208
213
|
|
|
209
214
|
const [customIdLoading, setCustomIdLoading] = React.useState<boolean>(false);
|
|
210
215
|
|
|
211
|
-
const initialValuesRef = useRef<EntityValues<M>>(entity?.values ?? baseDataSourceValues as EntityValues<M>);
|
|
212
|
-
const
|
|
213
|
-
|
|
216
|
+
// const initialValuesRef = useRef<EntityValues<M>>(entity?.values ?? baseDataSourceValues as EntityValues<M>);
|
|
217
|
+
const [internalValues, setInternalValues] = useState<EntityValues<M> | undefined>(entity?.values ?? baseDataSourceValuesRef.current as EntityValues<M>);
|
|
218
|
+
|
|
219
|
+
const save = (values: EntityValues<M>): Promise<void> => {
|
|
220
|
+
return onEntitySaveRequested({
|
|
221
|
+
collection: resolvedCollection,
|
|
222
|
+
path,
|
|
223
|
+
entityId,
|
|
224
|
+
values,
|
|
225
|
+
previousValues: entity?.values,
|
|
226
|
+
closeAfterSave: closeAfterSaveRef.current,
|
|
227
|
+
autoSave: autoSave ?? false
|
|
228
|
+
}).then(_ => {
|
|
229
|
+
const eventName: CMSAnalyticsEvent = status === "new"
|
|
230
|
+
? "new_entity_saved"
|
|
231
|
+
: (status === "copy" ? "entity_copied" : (status === "existing" ? "entity_edited" : "unmapped_event"));
|
|
232
|
+
analyticsController.onAnalyticsEvent?.(eventName, { path });
|
|
233
|
+
}).catch(e => {
|
|
234
|
+
console.error(e);
|
|
235
|
+
setSavingError(e);
|
|
236
|
+
}).finally(() => {
|
|
237
|
+
closeAfterSaveRef.current = false;
|
|
238
|
+
});
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
const onSubmit = (values: EntityValues<M>, formexController: FormexController<EntityValues<M>>) => {
|
|
242
|
+
|
|
243
|
+
if (mustSetCustomId && !entityId) {
|
|
244
|
+
console.error("Missing custom Id");
|
|
245
|
+
setEntityIdError(true);
|
|
246
|
+
formexController.setSubmitting(false);
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
setSavingError(undefined);
|
|
251
|
+
setEntityIdError(false);
|
|
252
|
+
|
|
253
|
+
if (status === "existing") {
|
|
254
|
+
if (!entity?.id) throw Error("Form misconfiguration when saving, no id for existing entity");
|
|
255
|
+
} else if (status === "new" || status === "copy") {
|
|
256
|
+
if (inputCollection.customId) {
|
|
257
|
+
if (inputCollection.customId !== "optional" && !entityId) {
|
|
258
|
+
throw Error("Form misconfiguration when saving, entityId should be set");
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
} else {
|
|
262
|
+
throw Error("New FormType added, check EntityForm");
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return save(values)
|
|
266
|
+
?.then(_ => {
|
|
267
|
+
formexController.resetForm({
|
|
268
|
+
values,
|
|
269
|
+
submitCount: 0,
|
|
270
|
+
touched: {}
|
|
271
|
+
});
|
|
272
|
+
})
|
|
273
|
+
.finally(() => {
|
|
274
|
+
formexController.setSubmitting(false);
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
const formex: FormexController<M> = useCreateFormex<M>({
|
|
280
|
+
initialValues: baseDataSourceValuesRef.current as M,
|
|
281
|
+
onSubmit,
|
|
282
|
+
validation: (values) => {
|
|
283
|
+
return validationSchema?.validate(values, { abortEarly: false })
|
|
284
|
+
.then(() => {
|
|
285
|
+
return {};
|
|
286
|
+
})
|
|
287
|
+
.catch((e) => {
|
|
288
|
+
|
|
289
|
+
const errors: Record<string, string> = {};
|
|
290
|
+
e.inner.forEach((error: any) => {
|
|
291
|
+
errors[error.path] = error.message;
|
|
292
|
+
});
|
|
293
|
+
return yupToFormErrors(e);
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
useEffect(() => {
|
|
299
|
+
baseDataSourceValuesRef.current = getDataSourceEntityValues(initialResolvedCollection, status, entity);
|
|
300
|
+
const initialValues = formex.initialValues;
|
|
301
|
+
if (!formex.isSubmitting && initialValues && status === "existing") {
|
|
302
|
+
setUnderlyingChanges(
|
|
303
|
+
Object.entries(resolvedCollection.properties)
|
|
304
|
+
.map(([key, property]) => {
|
|
305
|
+
if (isHidden(property)) {
|
|
306
|
+
return {};
|
|
307
|
+
}
|
|
308
|
+
const initialValue = initialValues[key];
|
|
309
|
+
const latestValue = baseDataSourceValuesRef.current[key];
|
|
310
|
+
if (!equal(initialValue, latestValue)) {
|
|
311
|
+
return { [key]: latestValue };
|
|
312
|
+
}
|
|
313
|
+
return {};
|
|
314
|
+
})
|
|
315
|
+
.reduce((a, b) => ({ ...a, ...b }), {}) as Partial<EntityValues<M>>
|
|
316
|
+
);
|
|
317
|
+
} else {
|
|
318
|
+
setUnderlyingChanges({});
|
|
319
|
+
}
|
|
320
|
+
}, [entity, initialResolvedCollection, status]);
|
|
214
321
|
|
|
215
322
|
const doOnValuesChanges = (values?: EntityValues<M>) => {
|
|
323
|
+
const initialValues = formex.initialValues;
|
|
216
324
|
setInternalValues(values);
|
|
217
325
|
if (onValuesChanged)
|
|
218
326
|
onValuesChanged(values);
|
|
@@ -231,7 +339,7 @@ function EntityFormInternal<M extends Record<string, any>>({
|
|
|
231
339
|
path,
|
|
232
340
|
entityId,
|
|
233
341
|
values: internalValues,
|
|
234
|
-
previousValues: initialValues,
|
|
342
|
+
previousValues: formex.initialValues,
|
|
235
343
|
fields: customizationController.propertyConfigs
|
|
236
344
|
});
|
|
237
345
|
|
|
@@ -261,88 +369,7 @@ function EntityFormInternal<M extends Record<string, any>>({
|
|
|
261
369
|
doOnIdUpdate();
|
|
262
370
|
}, [doOnIdUpdate]);
|
|
263
371
|
|
|
264
|
-
const underlyingChanges
|
|
265
|
-
if (initialValues && status === "existing") {
|
|
266
|
-
return Object.entries(resolvedCollection.properties)
|
|
267
|
-
.map(([key, property]) => {
|
|
268
|
-
if (isHidden(property)) {
|
|
269
|
-
return {};
|
|
270
|
-
}
|
|
271
|
-
const initialValue = initialValues[key];
|
|
272
|
-
const latestValue = baseDataSourceValues[key];
|
|
273
|
-
if (!equal(initialValue, latestValue)) {
|
|
274
|
-
return { [key]: latestValue };
|
|
275
|
-
}
|
|
276
|
-
return {};
|
|
277
|
-
})
|
|
278
|
-
.reduce((a, b) => ({ ...a, ...b }), {}) as Partial<EntityValues<M>>;
|
|
279
|
-
} else {
|
|
280
|
-
return {};
|
|
281
|
-
}
|
|
282
|
-
}, [baseDataSourceValues, resolvedCollection.properties, initialValues, status]);
|
|
283
|
-
|
|
284
|
-
const save = (values: EntityValues<M>) => {
|
|
285
|
-
return onEntitySaveRequested({
|
|
286
|
-
collection: resolvedCollection,
|
|
287
|
-
path,
|
|
288
|
-
entityId,
|
|
289
|
-
values,
|
|
290
|
-
previousValues: entity?.values,
|
|
291
|
-
closeAfterSave: closeAfterSaveRef.current,
|
|
292
|
-
autoSave: autoSave ?? false
|
|
293
|
-
}).then(_ => {
|
|
294
|
-
const eventName: CMSAnalyticsEvent = status === "new"
|
|
295
|
-
? "new_entity_saved"
|
|
296
|
-
: (status === "copy" ? "entity_copied" : (status === "existing" ? "entity_edited" : "unmapped_event"));
|
|
297
|
-
analyticsController.onAnalyticsEvent?.(eventName, { path });
|
|
298
|
-
initialValuesRef.current = values;
|
|
299
|
-
})
|
|
300
|
-
.catch(e => {
|
|
301
|
-
console.error(e);
|
|
302
|
-
setSavingError(e);
|
|
303
|
-
})
|
|
304
|
-
.finally(() => {
|
|
305
|
-
closeAfterSaveRef.current = false;
|
|
306
|
-
});
|
|
307
|
-
};
|
|
308
|
-
|
|
309
|
-
const saveFormValues = (values: EntityValues<M>, formikActions: FormikHelpers<EntityValues<M>>) => {
|
|
310
|
-
|
|
311
|
-
if (mustSetCustomId && !entityId) {
|
|
312
|
-
console.error("Missing custom Id");
|
|
313
|
-
setEntityIdError(true);
|
|
314
|
-
formikActions.setSubmitting(false);
|
|
315
|
-
return;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
setSavingError(undefined);
|
|
319
|
-
setEntityIdError(false);
|
|
320
|
-
|
|
321
|
-
if (status === "existing") {
|
|
322
|
-
if (!entity?.id) throw Error("Form misconfiguration when saving, no id for existing entity");
|
|
323
|
-
} else if (status === "new" || status === "copy") {
|
|
324
|
-
if (inputCollection.customId) {
|
|
325
|
-
if (inputCollection.customId !== "optional" && !entityId) {
|
|
326
|
-
throw Error("Form misconfiguration when saving, entityId should be set");
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
} else {
|
|
330
|
-
throw Error("New FormType added, check EntityForm");
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
save(values)
|
|
334
|
-
?.then(_ => {
|
|
335
|
-
formikActions.resetForm({
|
|
336
|
-
values,
|
|
337
|
-
submitCount: 0,
|
|
338
|
-
touched: {}
|
|
339
|
-
});
|
|
340
|
-
})
|
|
341
|
-
.finally(() => {
|
|
342
|
-
formikActions.setSubmitting(false);
|
|
343
|
-
});
|
|
344
|
-
|
|
345
|
-
};
|
|
372
|
+
const [underlyingChanges, setUnderlyingChanges] = useState<Partial<EntityValues<M>>>({});
|
|
346
373
|
|
|
347
374
|
const uniqueFieldValidator: CustomFieldValidator = useCallback(({
|
|
348
375
|
name,
|
|
@@ -374,110 +401,102 @@ function EntityFormInternal<M extends Record<string, any>>({
|
|
|
374
401
|
return actions;
|
|
375
402
|
}, [authController, inputCollection, path]);
|
|
376
403
|
|
|
377
|
-
|
|
378
|
-
<Formik
|
|
379
|
-
initialValues={baseDataSourceValues as M}
|
|
380
|
-
onSubmit={saveFormValues}
|
|
381
|
-
validationSchema={validationSchema}
|
|
382
|
-
validate={(values) => console.debug("Validating", values)}
|
|
383
|
-
onReset={() => onDiscard && onDiscard()}
|
|
384
|
-
>
|
|
385
|
-
{(props) => {
|
|
386
|
-
|
|
387
|
-
const pluginActions: React.ReactNode[] = [];
|
|
388
|
-
|
|
389
|
-
const formContext: FormContext<M> = {
|
|
390
|
-
setFieldValue: props.setFieldValue,
|
|
391
|
-
values: props.values,
|
|
392
|
-
collection: resolvedCollection,
|
|
393
|
-
entityId,
|
|
394
|
-
path,
|
|
395
|
-
save
|
|
396
|
-
};
|
|
404
|
+
const pluginActions: React.ReactNode[] = [];
|
|
397
405
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
const actionProps: PluginFormActionProps = {
|
|
407
|
-
entityId,
|
|
408
|
-
path,
|
|
409
|
-
status,
|
|
410
|
-
collection: inputCollection,
|
|
411
|
-
context,
|
|
412
|
-
currentEntityId: entityId,
|
|
413
|
-
formContext
|
|
414
|
-
};
|
|
415
|
-
pluginActions.push(...plugins.map((plugin, i) => (
|
|
416
|
-
plugin.form?.Actions
|
|
417
|
-
? <plugin.form.Actions
|
|
418
|
-
key={`actions_${plugin.name}`} {...actionProps}/>
|
|
419
|
-
: null
|
|
420
|
-
)).filter(Boolean));
|
|
421
|
-
}
|
|
406
|
+
const formContext: FormContext<M> = {
|
|
407
|
+
setFieldValue: formex.setFieldValue,
|
|
408
|
+
values: formex.values,
|
|
409
|
+
collection: resolvedCollection,
|
|
410
|
+
entityId,
|
|
411
|
+
path,
|
|
412
|
+
save
|
|
413
|
+
};
|
|
422
414
|
|
|
423
|
-
|
|
415
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
416
|
+
useEffect(() => {
|
|
417
|
+
if (onFormContextChange) {
|
|
418
|
+
onFormContextChange(formContext);
|
|
419
|
+
}
|
|
420
|
+
}, [onFormContextChange, formContext]);
|
|
424
421
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
422
|
+
if (plugins && inputCollection) {
|
|
423
|
+
const actionProps: PluginFormActionProps = {
|
|
424
|
+
entityId,
|
|
425
|
+
path,
|
|
426
|
+
status,
|
|
427
|
+
collection: inputCollection,
|
|
428
|
+
context,
|
|
429
|
+
currentEntityId: entityId,
|
|
430
|
+
formContext
|
|
431
|
+
};
|
|
432
|
+
pluginActions.push(...plugins.map((plugin, i) => (
|
|
433
|
+
plugin.form?.Actions
|
|
434
|
+
? <plugin.form.Actions
|
|
435
|
+
key={`actions_${plugin.name}`} {...actionProps}/>
|
|
436
|
+
: null
|
|
437
|
+
)).filter(Boolean));
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
return <Formex value={formex}>
|
|
441
|
+
<div className="h-full overflow-auto">
|
|
442
|
+
|
|
443
|
+
{pluginActions.length > 0 && <div
|
|
444
|
+
className={cn("w-full flex justify-end items-center sticky top-0 right-0 left-0 z-10 bg-opacity-60 bg-slate-200 dark:bg-opacity-60 dark:bg-slate-800 backdrop-blur-md")}>
|
|
445
|
+
{pluginActions}
|
|
446
|
+
</div>}
|
|
447
|
+
|
|
448
|
+
<div className="pt-12 pb-16 pl-8 pr-8 md:pl-10 md:pr-10">
|
|
449
|
+
<div
|
|
450
|
+
className={`w-full py-2 flex flex-col items-start mt-${4 + (pluginActions ? 8 : 0)} lg:mt-${8 + (pluginActions ? 8 : 0)} mb-8`}>
|
|
451
|
+
|
|
452
|
+
<Typography
|
|
453
|
+
className={"mt-4 flex-grow " + inputCollection.hideIdFromForm ? "mb-2" : "mb-0"}
|
|
454
|
+
variant={"h4"}>{inputCollection.singularName ?? inputCollection.name}
|
|
455
|
+
</Typography>
|
|
456
|
+
<Alert color={"base"} className={"w-full"} size={"small"}>
|
|
457
|
+
<code className={"text-xs select-all"}>{path}/{entityId}</code>
|
|
458
|
+
</Alert>
|
|
459
|
+
</div>
|
|
429
460
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
461
|
+
{!hideId &&
|
|
462
|
+
<CustomIdField customId={inputCollection.customId}
|
|
463
|
+
entityId={entityId}
|
|
464
|
+
status={status}
|
|
465
|
+
onChange={setEntityId}
|
|
466
|
+
error={entityIdError}
|
|
467
|
+
loading={customIdLoading}
|
|
468
|
+
entity={entity}/>}
|
|
469
|
+
|
|
470
|
+
{entityId && <InnerForm
|
|
471
|
+
{...formex}
|
|
472
|
+
initialValues={formex.initialValues}
|
|
473
|
+
onModified={onModified}
|
|
474
|
+
onDiscard={onDiscard}
|
|
475
|
+
onValuesChanged={doOnValuesChanges}
|
|
476
|
+
underlyingChanges={underlyingChanges}
|
|
477
|
+
entity={entity}
|
|
478
|
+
resolvedCollection={resolvedCollection}
|
|
479
|
+
formContext={formContext}
|
|
480
|
+
status={status}
|
|
481
|
+
savingError={savingError}
|
|
482
|
+
closeAfterSaveRef={closeAfterSaveRef}
|
|
483
|
+
autoSave={autoSave}
|
|
484
|
+
entityActions={getActionsForEntity({ entity, customEntityActions: inputCollection.entityActions })}/>}
|
|
442
485
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
status={status}
|
|
447
|
-
onChange={setEntityId}
|
|
448
|
-
error={entityIdError}
|
|
449
|
-
loading={customIdLoading}
|
|
450
|
-
entity={entity}/>}
|
|
451
|
-
|
|
452
|
-
{entityId && <InnerForm
|
|
453
|
-
{...props}
|
|
454
|
-
initialValues={initialValues}
|
|
455
|
-
onModified={onModified}
|
|
456
|
-
onValuesChanged={doOnValuesChanges}
|
|
457
|
-
underlyingChanges={underlyingChanges}
|
|
458
|
-
entity={entity}
|
|
459
|
-
resolvedCollection={resolvedCollection}
|
|
460
|
-
formContext={formContext}
|
|
461
|
-
status={status}
|
|
462
|
-
savingError={savingError}
|
|
463
|
-
closeAfterSaveRef={closeAfterSaveRef}
|
|
464
|
-
autoSave={autoSave}
|
|
465
|
-
entityActions={getActionsForEntity({ entity, customEntityActions: inputCollection.entityActions })}/>}
|
|
466
|
-
|
|
467
|
-
</div>
|
|
468
|
-
</div>
|
|
469
|
-
}}
|
|
470
|
-
</Formik>
|
|
471
|
-
);
|
|
486
|
+
</div>
|
|
487
|
+
</div>
|
|
488
|
+
</Formex>
|
|
472
489
|
}
|
|
473
490
|
|
|
474
|
-
function InnerForm<M extends Record<string, any>>(props:
|
|
491
|
+
function InnerForm<M extends Record<string, any>>(props: FormexController<M> & {
|
|
492
|
+
initialValues: EntityValues<M>,
|
|
475
493
|
onModified: ((modified: boolean) => void) | undefined,
|
|
476
494
|
onValuesChanged?: (changedValues?: EntityValues<M>) => void,
|
|
477
495
|
underlyingChanges: Partial<M>,
|
|
478
496
|
entity: Entity<M> | undefined,
|
|
479
497
|
resolvedCollection: ResolvedEntityCollection<M>,
|
|
480
498
|
formContext: FormContext<M>,
|
|
499
|
+
onDiscard?: () => void,
|
|
481
500
|
status: "new" | "existing" | "copy",
|
|
482
501
|
savingError?: Error,
|
|
483
502
|
closeAfterSaveRef: MutableRefObject<boolean>,
|
|
@@ -487,6 +506,7 @@ function InnerForm<M extends Record<string, any>>(props: FormikProps<M> & {
|
|
|
487
506
|
|
|
488
507
|
const {
|
|
489
508
|
values,
|
|
509
|
+
onDiscard,
|
|
490
510
|
onModified,
|
|
491
511
|
onValuesChanged,
|
|
492
512
|
underlyingChanges,
|
|
@@ -498,6 +518,7 @@ function InnerForm<M extends Record<string, any>>(props: FormikProps<M> & {
|
|
|
498
518
|
isSubmitting,
|
|
499
519
|
status,
|
|
500
520
|
handleSubmit,
|
|
521
|
+
resetForm,
|
|
501
522
|
savingError,
|
|
502
523
|
dirty,
|
|
503
524
|
closeAfterSaveRef,
|
|
@@ -518,7 +539,7 @@ function InnerForm<M extends Record<string, any>>(props: FormikProps<M> & {
|
|
|
518
539
|
}, [modified, values]);
|
|
519
540
|
|
|
520
541
|
useEffect(() => {
|
|
521
|
-
if (!autoSave && underlyingChanges && entity) {
|
|
542
|
+
if (!autoSave && !isSubmitting && underlyingChanges && entity) {
|
|
522
543
|
// we update the form fields from the Firestore data
|
|
523
544
|
// if they were not touched
|
|
524
545
|
Object.entries(underlyingChanges).forEach(([key, value]) => {
|
|
@@ -529,7 +550,7 @@ function InnerForm<M extends Record<string, any>>(props: FormikProps<M> & {
|
|
|
529
550
|
}
|
|
530
551
|
});
|
|
531
552
|
}
|
|
532
|
-
}, [autoSave, underlyingChanges, entity, values, touched, setFieldValue]);
|
|
553
|
+
}, [isSubmitting, autoSave, underlyingChanges, entity, values, touched, setFieldValue]);
|
|
533
554
|
|
|
534
555
|
const formFields = (
|
|
535
556
|
<div className={"flex flex-col gap-8"}>
|
|
@@ -582,7 +603,12 @@ function InnerForm<M extends Record<string, any>>(props: FormikProps<M> & {
|
|
|
582
603
|
|
|
583
604
|
return (
|
|
584
605
|
|
|
585
|
-
<
|
|
606
|
+
<form onSubmit={handleSubmit}
|
|
607
|
+
onReset={() => {
|
|
608
|
+
console.debug("Resetting form")
|
|
609
|
+
resetForm();
|
|
610
|
+
return onDiscard && onDiscard();
|
|
611
|
+
}}
|
|
586
612
|
noValidate>
|
|
587
613
|
<div className="mt-12"
|
|
588
614
|
ref={formRef}>
|
|
@@ -662,6 +688,21 @@ function InnerForm<M extends Record<string, any>>(props: FormikProps<M> & {
|
|
|
662
688
|
</Button>
|
|
663
689
|
|
|
664
690
|
</DialogActions>}
|
|
665
|
-
</
|
|
691
|
+
</form>
|
|
666
692
|
);
|
|
667
693
|
}
|
|
694
|
+
|
|
695
|
+
export function yupToFormErrors(yupError: ValidationError): Record<string, any> {
|
|
696
|
+
let errors: Record<string, any> = {};
|
|
697
|
+
if (yupError.inner) {
|
|
698
|
+
if (yupError.inner.length === 0) {
|
|
699
|
+
return setIn(errors, yupError.path!, yupError.message);
|
|
700
|
+
}
|
|
701
|
+
for (const err of yupError.inner) {
|
|
702
|
+
if (!getIn(errors, err.path!)) {
|
|
703
|
+
errors = setIn(errors, err.path!, err.message);
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
return errors;
|
|
708
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { ComponentType, ReactElement, useCallback, useRef } from "react";
|
|
2
2
|
import equal from "react-fast-compare"
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { Field, FieldProps as FormexFieldProps, getIn } from "@firecms/formex";
|
|
5
5
|
|
|
6
6
|
import {
|
|
7
7
|
CMSType,
|
|
@@ -85,14 +85,14 @@ function PropertyFieldBindingInternal<T extends CMSType = CMSType, CustomProps =
|
|
|
85
85
|
|
|
86
86
|
const shouldAlwaysRerender = shouldPropertyReRender(property, customizationController.plugins);
|
|
87
87
|
// we use the standard Field for user defined fields, since it rebuilds
|
|
88
|
-
// when there are changes in other values, in contrast to
|
|
89
|
-
const FieldComponent =
|
|
88
|
+
// when there are changes in other values, in contrast to Field
|
|
89
|
+
const FieldComponent = Field;
|
|
90
90
|
|
|
91
91
|
return (
|
|
92
92
|
<FieldComponent
|
|
93
93
|
name={propertyKey}
|
|
94
94
|
>
|
|
95
|
-
{(fieldProps
|
|
95
|
+
{(fieldProps) => {
|
|
96
96
|
|
|
97
97
|
let Component: ComponentType<FieldProps<T>> | undefined;
|
|
98
98
|
const resolvedProperty: ResolvedProperty<T> | null = resolveProperty({
|
|
@@ -186,14 +186,14 @@ function FieldInternal<T extends CMSType, CustomProps, M extends Record<string,
|
|
|
186
186
|
{
|
|
187
187
|
Component: ComponentType<FieldProps<T, any, M>>,
|
|
188
188
|
componentProps: ResolvedPropertyFieldBindingProps<T, M>,
|
|
189
|
-
fieldProps:
|
|
189
|
+
fieldProps: FormexFieldProps<T, any>
|
|
190
190
|
}) {
|
|
191
191
|
|
|
192
192
|
const { plugins } = useCustomizationController();
|
|
193
193
|
|
|
194
194
|
const customFieldProps: any = property.customProps;
|
|
195
195
|
const value = fieldProps.field.value;
|
|
196
|
-
const initialValue = fieldProps.meta.initialValue;
|
|
196
|
+
// const initialValue = fieldProps.meta.initialValue;
|
|
197
197
|
const error = getIn(fieldProps.form.errors, propertyKey);
|
|
198
198
|
const touched = getIn(fieldProps.form.touched, propertyKey);
|
|
199
199
|
|
|
@@ -219,7 +219,7 @@ function FieldInternal<T extends CMSType, CustomProps, M extends Record<string,
|
|
|
219
219
|
const cmsFieldProps: FieldProps<T, CustomProps, M> = {
|
|
220
220
|
propertyKey,
|
|
221
221
|
value: value as T,
|
|
222
|
-
initialValue,
|
|
222
|
+
// initialValue,
|
|
223
223
|
setValue,
|
|
224
224
|
setFieldValue,
|
|
225
225
|
error,
|