@firecms/core 3.0.0-canary.5 → 3.0.0-canary.50
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 -2
- package/dist/components/ClearFilterSortButton.d.ts +5 -0
- package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +11 -11
- package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +2 -2
- package/dist/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +5 -3
- package/dist/components/EntityCollectionTable/PropertyTableCell.d.ts +3 -2
- package/dist/components/EntityCollectionTable/column_utils.d.ts +1 -2
- package/dist/components/EntityCollectionTable/internal/CollectionTableToolbar.d.ts +1 -4
- package/dist/components/EntityCollectionTable/internal/popup_field/PopupFormField.d.ts +1 -1
- package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +12 -3
- package/dist/components/EntityCollectionView/EntityCollectionViewStartActions.d.ts +11 -0
- package/dist/components/EntityCollectionView/useSelectionController.d.ts +2 -0
- package/dist/components/EntityPreview.d.ts +25 -7
- package/dist/components/EntityView.d.ts +11 -0
- package/dist/components/FieldCaption.d.ts +5 -0
- package/dist/components/FireCMSAppBar.d.ts +3 -2
- package/dist/components/HomePage/NavigationCard.d.ts +8 -0
- package/dist/components/HomePage/{NavigationCollectionCard.d.ts → NavigationCardBinding.d.ts} +2 -2
- package/dist/components/HomePage/SmallNavigationCard.d.ts +6 -0
- package/dist/components/HomePage/index.d.ts +3 -1
- package/dist/components/SelectableTable/SelectableTable.d.ts +1 -1
- package/dist/components/VirtualTable/VirtualTableProps.d.ts +1 -1
- package/dist/components/common/types.d.ts +4 -6
- package/dist/components/common/useDataSourceEntityCollectionTableController.d.ts +3 -0
- package/dist/components/index.d.ts +4 -2
- package/dist/contexts/AuthControllerContext.d.ts +1 -1
- package/dist/core/{EntityView.d.ts → EntityEditView.d.ts} +2 -2
- package/dist/core/NavigationRoutes.d.ts +1 -1
- package/dist/core/Scaffold.d.ts +1 -1
- package/dist/form/EntityForm.d.ts +1 -1
- package/dist/form/components/ErrorFocus.d.ts +1 -1
- package/dist/form/components/StorageItemPreview.d.ts +3 -2
- package/dist/form/components/StorageUploadProgress.d.ts +1 -1
- package/dist/form/field_bindings/KeyValueFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +4 -3
- package/dist/form/field_bindings/TextFieldBinding.d.ts +2 -2
- package/dist/form/validation.d.ts +1 -1
- package/dist/hooks/data/delete.d.ts +2 -2
- package/dist/hooks/data/save.d.ts +2 -3
- package/dist/hooks/data/useDataSource.d.ts +2 -2
- package/dist/hooks/data/useEntityFetch.d.ts +3 -3
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/useBuildNavigationController.d.ts +6 -4
- package/dist/hooks/useProjectLog.d.ts +6 -2
- package/dist/hooks/useStorageSource.d.ts +2 -2
- package/dist/hooks/useValidateAuthenticator.d.ts +21 -0
- package/dist/index.es.js +10402 -9898
- 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/internal/useBuildDataSource.d.ts +1 -12
- package/dist/preview/PropertyPreview.d.ts +1 -1
- package/dist/preview/PropertyPreviewProps.d.ts +1 -4
- package/dist/preview/components/BooleanPreview.d.ts +5 -1
- package/dist/preview/components/EnumValuesChip.d.ts +1 -1
- package/dist/preview/components/ReferencePreview.d.ts +1 -7
- package/dist/types/analytics.d.ts +1 -1
- package/dist/types/auth.d.ts +37 -1
- package/dist/types/collections.d.ts +29 -5
- package/dist/types/datasource.d.ts +3 -6
- package/dist/types/entities.d.ts +5 -1
- package/dist/types/entity_actions.d.ts +14 -0
- package/dist/types/entity_callbacks.d.ts +2 -2
- package/dist/types/entity_overrides.d.ts +6 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/types/navigation.d.ts +14 -13
- package/dist/types/permissions.d.ts +5 -1
- package/dist/types/plugins.d.ts +20 -20
- package/dist/types/properties.d.ts +4 -4
- package/dist/types/property_config.d.ts +2 -2
- package/dist/types/roles.d.ts +31 -0
- package/dist/types/storage.d.ts +11 -3
- package/dist/types/user.d.ts +5 -0
- package/dist/util/collections.d.ts +9 -1
- package/dist/util/entities.d.ts +1 -1
- package/dist/util/icon_synonyms.d.ts +1 -4
- package/dist/util/icons.d.ts +8 -2
- package/dist/util/navigation_utils.d.ts +2 -2
- package/dist/util/permissions.d.ts +4 -4
- package/dist/util/references.d.ts +4 -2
- package/dist/util/resolutions.d.ts +9 -13
- package/dist/util/useTraceUpdate.d.ts +1 -0
- package/package.json +139 -119
- package/src/components/ClearFilterSortButton.tsx +41 -0
- package/src/components/DeleteEntityDialog.tsx +4 -4
- package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +2 -2
- package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +275 -278
- package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +9 -5
- package/src/components/EntityCollectionTable/PropertyTableCell.tsx +44 -44
- package/src/components/EntityCollectionTable/column_utils.tsx +3 -3
- package/src/components/EntityCollectionTable/fields/TableReferenceField.tsx +9 -16
- package/src/components/EntityCollectionTable/fields/TableStorageUpload.tsx +3 -3
- package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +27 -32
- package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +11 -6
- package/src/components/EntityCollectionTable/internal/default_entity_actions.tsx +9 -5
- package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +2 -4
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +69 -64
- package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +5 -6
- package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +68 -0
- package/src/components/EntityCollectionView/useSelectionController.tsx +30 -0
- package/src/components/EntityPreview.tsx +207 -70
- package/src/components/EntityView.tsx +84 -0
- package/src/components/FieldCaption.tsx +14 -0
- package/src/components/FireCMSAppBar.tsx +33 -11
- package/src/components/HomePage/DefaultHomePage.tsx +15 -11
- package/src/components/HomePage/NavigationCard.tsx +69 -0
- package/src/components/HomePage/NavigationCardBinding.tsx +116 -0
- package/src/components/HomePage/SmallNavigationCard.tsx +45 -0
- package/src/components/HomePage/index.tsx +3 -1
- package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +4 -4
- package/src/components/ReferenceWidget.tsx +4 -4
- package/src/components/SearchIconsView.tsx +4 -4
- package/src/components/SelectableTable/SelectableTable.tsx +1 -1
- package/src/components/SelectableTable/filters/BooleanFilterField.tsx +2 -3
- package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +23 -8
- package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +35 -24
- package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +35 -15
- package/src/components/VirtualTable/VirtualTable.tsx +28 -20
- package/src/components/VirtualTable/VirtualTableProps.tsx +1 -1
- package/src/components/VirtualTable/fields/VirtualTableDateField.tsx +1 -1
- package/src/components/common/types.tsx +4 -6
- package/src/components/common/useDataSourceEntityCollectionTableController.tsx +12 -1
- package/src/components/index.tsx +4 -2
- package/src/contexts/AuthControllerContext.tsx +1 -1
- package/src/core/Drawer.tsx +66 -39
- package/src/core/{EntityView.tsx → EntityEditView.tsx} +21 -40
- package/src/core/EntitySidePanel.tsx +2 -2
- package/src/core/FireCMS.tsx +18 -3
- package/src/core/NavigationRoutes.tsx +11 -4
- package/src/core/Scaffold.tsx +5 -4
- package/src/core/field_configs.tsx +1 -2
- package/src/form/EntityForm.tsx +40 -21
- package/src/form/PropertyFieldBinding.tsx +0 -2
- package/src/form/components/StorageItemPreview.tsx +5 -3
- package/src/form/components/StorageUploadProgress.tsx +7 -6
- package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +8 -12
- package/src/form/field_bindings/DateTimeFieldBinding.tsx +1 -1
- package/src/form/field_bindings/KeyValueFieldBinding.tsx +15 -15
- package/src/form/field_bindings/MapFieldBinding.tsx +15 -15
- package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +1 -1
- package/src/form/field_bindings/ReferenceFieldBinding.tsx +1 -0
- package/src/form/field_bindings/StorageUploadFieldBinding.tsx +14 -5
- package/src/form/field_bindings/TextFieldBinding.tsx +7 -5
- package/src/form/validation.ts +3 -4
- package/src/hooks/data/delete.ts +3 -3
- package/src/hooks/data/save.ts +2 -2
- package/src/hooks/data/useCollectionFetch.tsx +1 -1
- package/src/hooks/data/useDataSource.tsx +8 -3
- package/src/hooks/data/useEntityFetch.tsx +4 -4
- package/src/hooks/index.tsx +2 -0
- package/src/hooks/useBuildLocalConfigurationPersistence.tsx +9 -10
- package/src/hooks/useBuildModeController.tsx +11 -5
- package/src/hooks/useBuildNavigationController.tsx +199 -81
- package/src/hooks/useProjectLog.tsx +17 -7
- package/src/hooks/useReferenceDialog.tsx +2 -2
- package/src/hooks/useStorageSource.tsx +7 -2
- package/src/hooks/useValidateAuthenticator.tsx +115 -0
- package/src/internal/useBuildDataSource.ts +42 -44
- package/src/internal/useBuildSideEntityController.tsx +86 -20
- package/src/preview/PropertyPreview.tsx +3 -14
- package/src/preview/PropertyPreviewProps.tsx +1 -11
- package/src/preview/components/BooleanPreview.tsx +19 -4
- package/src/preview/components/EnumValuesChip.tsx +1 -1
- package/src/preview/components/ReferencePreview.tsx +55 -147
- package/src/preview/property_previews/ArrayOfMapsPreview.tsx +0 -1
- package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +0 -1
- package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +0 -1
- package/src/preview/property_previews/ArrayOfStringsPreview.tsx +0 -1
- package/src/preview/property_previews/ArrayOneOfPreview.tsx +0 -1
- package/src/preview/property_previews/ArrayPropertyPreview.tsx +0 -1
- package/src/preview/property_previews/StringPropertyPreview.tsx +8 -7
- package/src/types/analytics.ts +1 -0
- package/src/types/auth.tsx +50 -1
- package/src/types/collections.ts +33 -5
- package/src/types/datasource.ts +8 -5
- package/src/types/entities.ts +9 -1
- package/src/types/entity_actions.tsx +17 -0
- package/src/types/entity_callbacks.ts +2 -2
- package/src/types/entity_overrides.tsx +7 -0
- package/src/types/firecms.tsx +0 -1
- package/src/types/index.ts +2 -1
- package/src/types/navigation.ts +17 -16
- package/src/types/permissions.ts +6 -1
- package/src/types/plugins.tsx +26 -28
- package/src/types/properties.ts +8 -6
- package/src/types/property_config.tsx +2 -2
- package/src/types/roles.ts +41 -0
- package/src/types/side_entity_controller.tsx +1 -0
- package/src/types/storage.ts +12 -3
- package/src/types/user.ts +7 -0
- package/src/util/collections.ts +22 -0
- package/src/util/entities.ts +1 -1
- package/src/util/icon_list.ts +2 -2
- package/src/util/icon_synonyms.ts +1 -4
- package/src/util/icons.tsx +11 -3
- package/src/util/navigation_utils.ts +6 -6
- package/src/util/objects.ts +0 -14
- package/src/util/permissions.ts +11 -8
- package/src/util/references.ts +36 -5
- package/src/util/resolutions.ts +6 -24
- package/src/util/strings.ts +2 -2
- package/src/util/useTraceUpdate.tsx +2 -1
- package/dist/core/SideEntityView.d.ts +0 -7
- package/dist/internal/useLocaleConfig.d.ts +0 -1
- package/dist/types/appcheck.d.ts +0 -26
- package/src/components/HomePage/NavigationCollectionCard.tsx +0 -146
- package/src/core/SideEntityView.tsx +0 -38
- package/src/internal/useLocaleConfig.tsx +0 -18
- package/src/types/appcheck.ts +0 -29
package/src/form/EntityForm.tsx
CHANGED
|
@@ -19,8 +19,9 @@ import equal from "react-fast-compare"
|
|
|
19
19
|
import {
|
|
20
20
|
canCreateEntity,
|
|
21
21
|
canDeleteEntity,
|
|
22
|
-
fullPathToCollectionSegments,
|
|
23
22
|
getDefaultValuesFor,
|
|
23
|
+
getEntityTitlePropertyKey,
|
|
24
|
+
getValueInPath,
|
|
24
25
|
isHidden,
|
|
25
26
|
isReadOnly,
|
|
26
27
|
resolveCollection
|
|
@@ -134,12 +135,13 @@ export type EntityFormSaveParams<M extends Record<string, any>> = {
|
|
|
134
135
|
* @constructor
|
|
135
136
|
* @group Components
|
|
136
137
|
*/
|
|
137
|
-
export const EntityForm =
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
138
|
+
export const EntityForm = EntityFormInternal;
|
|
139
|
+
// export const EntityForm = React.memo<EntityFormProps<any>>(EntityFormInternal,
|
|
140
|
+
// (a: EntityFormProps<any>, b: EntityFormProps<any>) => {
|
|
141
|
+
// return a.status === b.status &&
|
|
142
|
+
// a.path === b.path &&
|
|
143
|
+
// equal(a.entity?.values, b.entity?.values);
|
|
144
|
+
// }) as typeof EntityFormInternal;
|
|
143
145
|
|
|
144
146
|
function getDataSourceEntityValues<M extends object>(initialResolvedCollection: ResolvedEntityCollection,
|
|
145
147
|
status: "new" | "existing" | "copy",
|
|
@@ -171,7 +173,7 @@ function EntityFormInternal<M extends Record<string, any>>({
|
|
|
171
173
|
onFormContextChange,
|
|
172
174
|
hideId,
|
|
173
175
|
autoSave,
|
|
174
|
-
onIdUpdateError
|
|
176
|
+
onIdUpdateError,
|
|
175
177
|
}: EntityFormProps<M>) {
|
|
176
178
|
|
|
177
179
|
const analyticsController = useAnalyticsController();
|
|
@@ -179,7 +181,7 @@ function EntityFormInternal<M extends Record<string, any>>({
|
|
|
179
181
|
const customizationController = useCustomizationController();
|
|
180
182
|
|
|
181
183
|
const context = useFireCMSContext();
|
|
182
|
-
const dataSource = useDataSource();
|
|
184
|
+
const dataSource = useDataSource(inputCollection);
|
|
183
185
|
const plugins = customizationController.plugins;
|
|
184
186
|
|
|
185
187
|
const initialResolvedCollection = useMemo(() => resolveCollection({
|
|
@@ -344,6 +346,9 @@ function EntityFormInternal<M extends Record<string, any>>({
|
|
|
344
346
|
fields: customizationController.propertyConfigs
|
|
345
347
|
});
|
|
346
348
|
|
|
349
|
+
const titlePropertyKey = getEntityTitlePropertyKey(resolvedCollection, customizationController.propertyConfigs);
|
|
350
|
+
const title = internalValues && titlePropertyKey ? getValueInPath(internalValues, titlePropertyKey) : undefined;
|
|
351
|
+
|
|
347
352
|
const onIdUpdate = inputCollection.callbacks?.onIdUpdate;
|
|
348
353
|
|
|
349
354
|
const doOnIdUpdate = useCallback(async () => {
|
|
@@ -389,12 +394,15 @@ function EntityFormInternal<M extends Record<string, any>>({
|
|
|
389
394
|
|
|
390
395
|
const authController = useAuthController();
|
|
391
396
|
|
|
392
|
-
const getActionsForEntity = useCallback(({
|
|
397
|
+
const getActionsForEntity = useCallback(({
|
|
398
|
+
entity,
|
|
399
|
+
customEntityActions
|
|
400
|
+
}: {
|
|
393
401
|
entity?: Entity<M>,
|
|
394
402
|
customEntityActions?: EntityAction[]
|
|
395
403
|
}): EntityAction[] => {
|
|
396
|
-
const createEnabled = canCreateEntity(inputCollection, authController,
|
|
397
|
-
const deleteEnabled = entity ? canDeleteEntity(inputCollection, authController,
|
|
404
|
+
const createEnabled = canCreateEntity(inputCollection, authController, path, null);
|
|
405
|
+
const deleteEnabled = entity ? canDeleteEntity(inputCollection, authController, path, entity) : true;
|
|
398
406
|
const actions: EntityAction[] = [];
|
|
399
407
|
if (createEnabled)
|
|
400
408
|
actions.push(copyEntityAction);
|
|
@@ -408,7 +416,8 @@ function EntityFormInternal<M extends Record<string, any>>({
|
|
|
408
416
|
const pluginActions: React.ReactNode[] = [];
|
|
409
417
|
|
|
410
418
|
const formContext: FormContext<M> = {
|
|
411
|
-
|
|
419
|
+
// @ts-ignore
|
|
420
|
+
setFieldValue: useCallback(formex.setFieldValue, []),
|
|
412
421
|
values: formex.values,
|
|
413
422
|
collection: resolvedCollection,
|
|
414
423
|
entityId,
|
|
@@ -416,12 +425,14 @@ function EntityFormInternal<M extends Record<string, any>>({
|
|
|
416
425
|
save
|
|
417
426
|
};
|
|
418
427
|
|
|
428
|
+
const submittedFormContext = useRef<FormContext<M> | null>(null);
|
|
419
429
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
420
430
|
useEffect(() => {
|
|
421
|
-
if (onFormContextChange) {
|
|
431
|
+
if (onFormContextChange && !formContextsEqual(submittedFormContext.current ?? undefined, formContext)) {
|
|
422
432
|
onFormContextChange(formContext);
|
|
433
|
+
submittedFormContext.current = formContext;
|
|
423
434
|
}
|
|
424
|
-
}, [
|
|
435
|
+
}, [formContext, onFormContextChange]);
|
|
425
436
|
|
|
426
437
|
if (plugins && inputCollection) {
|
|
427
438
|
const actionProps: PluginFormActionProps = {
|
|
@@ -436,7 +447,7 @@ function EntityFormInternal<M extends Record<string, any>>({
|
|
|
436
447
|
pluginActions.push(...plugins.map((plugin, i) => (
|
|
437
448
|
plugin.form?.Actions
|
|
438
449
|
? <plugin.form.Actions
|
|
439
|
-
key={`actions_${plugin.
|
|
450
|
+
key={`actions_${plugin.key}`} {...actionProps}/>
|
|
440
451
|
: null
|
|
441
452
|
)).filter(Boolean));
|
|
442
453
|
}
|
|
@@ -454,8 +465,8 @@ function EntityFormInternal<M extends Record<string, any>>({
|
|
|
454
465
|
className={`w-full py-2 flex flex-col items-start mt-${4 + (pluginActions ? 8 : 0)} lg:mt-${8 + (pluginActions ? 8 : 0)} mb-8`}>
|
|
455
466
|
|
|
456
467
|
<Typography
|
|
457
|
-
className={"mt-4 flex-grow " + inputCollection.hideIdFromForm ? "mb-2" : "mb-0"}
|
|
458
|
-
variant={"h4"}>{inputCollection.singularName ?? inputCollection.name}
|
|
468
|
+
className={"mt-4 flex-grow line-clamp-1 " + inputCollection.hideIdFromForm ? "mb-2" : "mb-0"}
|
|
469
|
+
variant={"h4"}>{title ?? inputCollection.singularName ?? inputCollection.name}
|
|
459
470
|
</Typography>
|
|
460
471
|
<Alert color={"base"} className={"w-full"} size={"small"}>
|
|
461
472
|
<code className={"text-xs select-all"}>{path}/{entityId}</code>
|
|
@@ -508,7 +519,7 @@ function InnerForm<M extends Record<string, any>>(props: FormexController<M> & {
|
|
|
508
519
|
savingError?: Error,
|
|
509
520
|
closeAfterSaveRef: MutableRefObject<boolean>,
|
|
510
521
|
autoSave?: boolean,
|
|
511
|
-
entityActions: EntityAction[]
|
|
522
|
+
entityActions: EntityAction[],
|
|
512
523
|
}) {
|
|
513
524
|
|
|
514
525
|
const {
|
|
@@ -530,7 +541,7 @@ function InnerForm<M extends Record<string, any>>(props: FormexController<M> & {
|
|
|
530
541
|
dirty,
|
|
531
542
|
closeAfterSaveRef,
|
|
532
543
|
autoSave,
|
|
533
|
-
entityActions
|
|
544
|
+
entityActions,
|
|
534
545
|
} = props;
|
|
535
546
|
|
|
536
547
|
const context = useFireCMSContext();
|
|
@@ -598,6 +609,7 @@ function InnerForm<M extends Record<string, any>>(props: FormexController<M> & {
|
|
|
598
609
|
<Tooltip title={<PropertyIdCopyTooltipContent propertyId={key}/>}
|
|
599
610
|
delayDuration={800}
|
|
600
611
|
side={"left"}
|
|
612
|
+
align={"start"}
|
|
601
613
|
sideOffset={16}>
|
|
602
614
|
<PropertyFieldBinding {...cmsFormFieldProps}/>
|
|
603
615
|
</Tooltip>
|
|
@@ -655,7 +667,7 @@ function InnerForm<M extends Record<string, any>>(props: FormexController<M> & {
|
|
|
655
667
|
fullPath: resolvedCollection.path,
|
|
656
668
|
collection: resolvedCollection,
|
|
657
669
|
context,
|
|
658
|
-
sideEntityController
|
|
670
|
+
sideEntityController,
|
|
659
671
|
});
|
|
660
672
|
}}>
|
|
661
673
|
{action.icon}
|
|
@@ -718,3 +730,10 @@ export function yupToFormErrors(yupError: ValidationError): Record<string, any>
|
|
|
718
730
|
}
|
|
719
731
|
return errors;
|
|
720
732
|
}
|
|
733
|
+
|
|
734
|
+
function formContextsEqual(a: FormContext<any> | undefined, b: FormContext<any> | undefined): boolean {
|
|
735
|
+
return a?.path === b?.path &&
|
|
736
|
+
a?.entityId === b?.entityId &&
|
|
737
|
+
equal(a?.values, b?.values) &&
|
|
738
|
+
equal(a?.collection, b?.collection);
|
|
739
|
+
}
|
|
@@ -92,7 +92,6 @@ function PropertyFieldBindingInternal<T extends CMSType = CMSType, M extends Rec
|
|
|
92
92
|
let Component: ComponentType<FieldProps<T>> | undefined;
|
|
93
93
|
const resolvedProperty: ResolvedProperty<T> | null = resolveProperty({
|
|
94
94
|
propertyKey,
|
|
95
|
-
propertyValue: fieldProps.field.value,
|
|
96
95
|
propertyOrBuilder: property,
|
|
97
96
|
values: fieldProps.form.values,
|
|
98
97
|
path: context.path,
|
|
@@ -116,7 +115,6 @@ function PropertyFieldBindingInternal<T extends CMSType = CMSType, M extends Rec
|
|
|
116
115
|
}
|
|
117
116
|
const configProperty = resolveProperty({
|
|
118
117
|
propertyOrBuilder: propertyConfig.property,
|
|
119
|
-
propertyValue: fieldProps.field.value,
|
|
120
118
|
values: fieldProps.form.values,
|
|
121
119
|
path: context.path,
|
|
122
120
|
entityId: context.entityId,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
|
|
3
|
-
import { Entity, ResolvedStringProperty } from "../../types";
|
|
3
|
+
import { Entity, EntityCollection, ResolvedStringProperty } from "../../types";
|
|
4
4
|
import { PreviewSize, PropertyPreview } from "../../preview";
|
|
5
5
|
|
|
6
6
|
import { cn, IconButton, paperMixin, RemoveIcon, Tooltip } from "@firecms/ui";
|
|
@@ -14,6 +14,7 @@ interface StorageItemPreviewProps {
|
|
|
14
14
|
onRemove: (value: string) => void;
|
|
15
15
|
size: PreviewSize;
|
|
16
16
|
disabled: boolean;
|
|
17
|
+
collection: EntityCollection;
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
export function StorageItemPreview({
|
|
@@ -23,7 +24,8 @@ export function StorageItemPreview({
|
|
|
23
24
|
entity,
|
|
24
25
|
onRemove,
|
|
25
26
|
disabled,
|
|
26
|
-
size
|
|
27
|
+
size,
|
|
28
|
+
collection
|
|
27
29
|
}: StorageItemPreviewProps) {
|
|
28
30
|
|
|
29
31
|
return (
|
|
@@ -54,7 +56,7 @@ export function StorageItemPreview({
|
|
|
54
56
|
<PropertyPreview propertyKey={name}
|
|
55
57
|
value={value}
|
|
56
58
|
property={property}
|
|
57
|
-
|
|
59
|
+
// entity={entity}
|
|
58
60
|
size={size}/>
|
|
59
61
|
</ErrorBoundary>
|
|
60
62
|
}
|
|
@@ -4,6 +4,7 @@ import { useSnackbarController, useStorageSource } from "../../hooks";
|
|
|
4
4
|
import { StorageFieldItem } from "../../util/useStorageUploadController";
|
|
5
5
|
import { ErrorView } from "../../components";
|
|
6
6
|
import { cn, paperMixin, Skeleton } from "@firecms/ui";
|
|
7
|
+
import { EntityCollection, StorageSource } from "../../types";
|
|
7
8
|
|
|
8
9
|
export interface StorageUploadItemProps {
|
|
9
10
|
storagePath: string;
|
|
@@ -22,10 +23,10 @@ export function StorageUploadProgress({
|
|
|
22
23
|
metadata,
|
|
23
24
|
onFileUploadComplete,
|
|
24
25
|
imageSize,
|
|
25
|
-
simple
|
|
26
|
+
simple,
|
|
26
27
|
}: StorageUploadItemProps) {
|
|
27
28
|
|
|
28
|
-
const
|
|
29
|
+
const storageSource = useStorageSource();
|
|
29
30
|
|
|
30
31
|
const snackbarController = useSnackbarController();
|
|
31
32
|
|
|
@@ -41,14 +42,14 @@ export function StorageUploadProgress({
|
|
|
41
42
|
setError(undefined);
|
|
42
43
|
setLoading(true);
|
|
43
44
|
|
|
44
|
-
|
|
45
|
+
storageSource.uploadFile({
|
|
45
46
|
file,
|
|
46
47
|
fileName,
|
|
47
48
|
path: storagePath,
|
|
48
49
|
metadata
|
|
49
50
|
})
|
|
50
51
|
.then(async ({ path }) => {
|
|
51
|
-
console.debug("Upload successful");
|
|
52
|
+
console.debug("Upload successful", path);
|
|
52
53
|
await onFileUploadComplete(path, entry, metadata);
|
|
53
54
|
if (mounted.current)
|
|
54
55
|
setLoading(false);
|
|
@@ -67,7 +68,7 @@ export function StorageUploadProgress({
|
|
|
67
68
|
.finally(() => {
|
|
68
69
|
uploading.current = false;
|
|
69
70
|
});
|
|
70
|
-
}, [entry, metadata, onFileUploadComplete,
|
|
71
|
+
}, [entry, metadata, onFileUploadComplete, storageSource, storagePath]);
|
|
71
72
|
|
|
72
73
|
React.useEffect(() => {
|
|
73
74
|
mounted.current = true;
|
|
@@ -89,7 +90,7 @@ export function StorageUploadProgress({
|
|
|
89
90
|
|
|
90
91
|
<div className={cn(paperMixin,
|
|
91
92
|
"relative m-4 border-box flex items-center justify-center",
|
|
92
|
-
|
|
93
|
+
`min-w-[${imageSize}px] min-h-[${imageSize}px]`)}>
|
|
93
94
|
|
|
94
95
|
{loading &&
|
|
95
96
|
<Skeleton className="w-full h-full"/>}
|
|
@@ -6,7 +6,7 @@ import { ErrorView } from "../../components";
|
|
|
6
6
|
import { getIconForProperty, getReferenceFrom } from "../../util";
|
|
7
7
|
|
|
8
8
|
import { useNavigationController, useReferenceDialog } from "../../hooks";
|
|
9
|
-
import { Button, ExpandablePanel } from "@firecms/ui";
|
|
9
|
+
import { Button, cn, ExpandablePanel, fieldBackgroundMixin } from "@firecms/ui";
|
|
10
10
|
import { useClearRestoreValue } from "../useClearRestoreValue";
|
|
11
11
|
|
|
12
12
|
type ArrayOfReferencesFieldProps = FieldProps<EntityReference[]>;
|
|
@@ -38,7 +38,6 @@ export function ArrayOfReferencesFieldBinding({
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
const expanded = property.expanded === undefined ? true : property.expanded;
|
|
41
|
-
const [onHover, setOnHover] = React.useState(false);
|
|
42
41
|
const selectedEntityIds = value && Array.isArray(value) ? value.map((ref) => ref.id) : [];
|
|
43
42
|
|
|
44
43
|
useClearRestoreValue({
|
|
@@ -81,21 +80,17 @@ export function ArrayOfReferencesFieldBinding({
|
|
|
81
80
|
if (!entryValue)
|
|
82
81
|
return <div>Internal ERROR</div>;
|
|
83
82
|
return (
|
|
84
|
-
<div
|
|
85
|
-
onMouseEnter={() => setOnHover(true)}
|
|
86
|
-
onMouseMove={() => setOnHover(true)}
|
|
87
|
-
onMouseLeave={() => setOnHover(false)}>
|
|
88
83
|
<ReferencePreview
|
|
84
|
+
key={internalId}
|
|
89
85
|
disabled={!ofProperty.path}
|
|
90
86
|
previewProperties={ofProperty.previewProperties}
|
|
91
87
|
size={"medium"}
|
|
92
88
|
onClick={onEntryClick}
|
|
89
|
+
hover={!disabled}
|
|
93
90
|
reference={entryValue}
|
|
94
|
-
onHover={onHover}
|
|
95
91
|
/>
|
|
96
|
-
</div>
|
|
97
92
|
);
|
|
98
|
-
}, [ofProperty.path, ofProperty.previewProperties,
|
|
93
|
+
}, [ofProperty.path, ofProperty.previewProperties, value]);
|
|
99
94
|
|
|
100
95
|
const title = (
|
|
101
96
|
<LabelWithIcon icon={getIconForProperty(property, "small")}
|
|
@@ -108,7 +103,7 @@ export function ArrayOfReferencesFieldBinding({
|
|
|
108
103
|
{!collection && <ErrorView
|
|
109
104
|
error={"The specified collection does not exist. Check console"}/>}
|
|
110
105
|
|
|
111
|
-
{collection &&
|
|
106
|
+
{collection && <div className={"group"}>
|
|
112
107
|
|
|
113
108
|
<FormikArrayContainer value={value}
|
|
114
109
|
addLabel={property.name ? "Add reference to " + property.name : "Add reference"}
|
|
@@ -126,7 +121,7 @@ export function ArrayOfReferencesFieldBinding({
|
|
|
126
121
|
onClick={onEntryClick}>
|
|
127
122
|
Edit {property.name}
|
|
128
123
|
</Button>
|
|
129
|
-
|
|
124
|
+
</div>}
|
|
130
125
|
</>;
|
|
131
126
|
|
|
132
127
|
return (
|
|
@@ -134,7 +129,8 @@ export function ArrayOfReferencesFieldBinding({
|
|
|
134
129
|
|
|
135
130
|
{!tableMode &&
|
|
136
131
|
<ExpandablePanel
|
|
137
|
-
|
|
132
|
+
titleClassName={fieldBackgroundMixin}
|
|
133
|
+
className={cn("px-2 md:px-4 pb-2 md:pb-4 pt-1 md:pt-2", fieldBackgroundMixin)}
|
|
138
134
|
initiallyExpanded={expanded}
|
|
139
135
|
title={title}>
|
|
140
136
|
{body}
|
|
@@ -43,7 +43,7 @@ export function DateTimeFieldBinding({
|
|
|
43
43
|
<>
|
|
44
44
|
<DateTimeField
|
|
45
45
|
value={internalValue}
|
|
46
|
-
onChange={(dateValue) => setValue(dateValue)}
|
|
46
|
+
onChange={(dateValue) => setValue(dateValue ?? null)}
|
|
47
47
|
size={"medium"}
|
|
48
48
|
mode={property.mode}
|
|
49
49
|
clearable={property.clearable}
|
|
@@ -32,20 +32,20 @@ type MapEditViewRowState = [number, {
|
|
|
32
32
|
*
|
|
33
33
|
* @group Form fields
|
|
34
34
|
*/
|
|
35
|
-
export function KeyValueFieldBinding
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
35
|
+
export function KeyValueFieldBinding({
|
|
36
|
+
propertyKey,
|
|
37
|
+
value,
|
|
38
|
+
showError,
|
|
39
|
+
error,
|
|
40
|
+
disabled,
|
|
41
|
+
property,
|
|
42
|
+
setValue,
|
|
43
|
+
tableMode,
|
|
44
|
+
includeDescription,
|
|
45
|
+
underlyingValueHasChanged,
|
|
46
|
+
autoFocus,
|
|
47
|
+
context
|
|
48
|
+
}: FieldProps<Record<string, any>>) {
|
|
49
49
|
|
|
50
50
|
const expanded = (property.expanded === undefined ? true : property.expanded) || autoFocus;
|
|
51
51
|
|
|
@@ -546,7 +546,7 @@ function getDataType(value: any): DataType | undefined {
|
|
|
546
546
|
return "array";
|
|
547
547
|
} else if (value instanceof Date) {
|
|
548
548
|
return "date";
|
|
549
|
-
} else if (value
|
|
549
|
+
} else if (value?.isEntityReference && value?.isEntityReference()) {
|
|
550
550
|
return "reference";
|
|
551
551
|
} else if (value instanceof GeoPoint) {
|
|
552
552
|
return "geopoint";
|
|
@@ -14,21 +14,21 @@ import { ExpandablePanel, InputLabel, Select, SelectItem } from "@firecms/ui";
|
|
|
14
14
|
* and tables to the specified properties.
|
|
15
15
|
* @group Form fields
|
|
16
16
|
*/
|
|
17
|
-
export function MapFieldBinding
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
17
|
+
export function MapFieldBinding({
|
|
18
|
+
propertyKey,
|
|
19
|
+
value,
|
|
20
|
+
showError,
|
|
21
|
+
error,
|
|
22
|
+
disabled,
|
|
23
|
+
property,
|
|
24
|
+
setValue,
|
|
25
|
+
partOfBlock,
|
|
26
|
+
tableMode,
|
|
27
|
+
includeDescription,
|
|
28
|
+
underlyingValueHasChanged,
|
|
29
|
+
autoFocus,
|
|
30
|
+
context
|
|
31
|
+
}: FieldProps<Record<string, any>>) {
|
|
32
32
|
|
|
33
33
|
const pickOnlySomeKeys = property.pickOnlySomeKeys || false;
|
|
34
34
|
const expanded = (property.expanded === undefined ? true : property.expanded) || autoFocus;
|
|
@@ -95,6 +95,7 @@ function ReferenceFieldBindingInternal<M extends Record<string, any>>({
|
|
|
95
95
|
{value && <ReferencePreview
|
|
96
96
|
disabled={!property.path}
|
|
97
97
|
previewProperties={property.previewProperties}
|
|
98
|
+
hover={!disabled}
|
|
98
99
|
size={"medium"}
|
|
99
100
|
onClick={disabled || isSubmitting ? undefined : onEntryClick}
|
|
100
101
|
reference={value}
|
|
@@ -3,6 +3,7 @@ import React, { useCallback } from "react";
|
|
|
3
3
|
import {
|
|
4
4
|
ArrayProperty,
|
|
5
5
|
Entity,
|
|
6
|
+
EntityCollection,
|
|
6
7
|
FieldProps,
|
|
7
8
|
ResolvedArrayProperty,
|
|
8
9
|
ResolvedStringProperty,
|
|
@@ -10,10 +11,10 @@ import {
|
|
|
10
11
|
} from "../../types";
|
|
11
12
|
import { useDropzone } from "react-dropzone";
|
|
12
13
|
import { PreviewSize } from "../../preview";
|
|
13
|
-
import { FieldHelperText,LabelWithIcon } from "../components";
|
|
14
|
+
import { FieldHelperText, LabelWithIcon } from "../components";
|
|
14
15
|
|
|
15
16
|
import { getIconForProperty, isReadOnly } from "../../util";
|
|
16
|
-
import {
|
|
17
|
+
import { useSnackbarController, useStorageSource } from "../../hooks";
|
|
17
18
|
import { DragDropContext, Draggable, Droppable } from "@hello-pangea/dnd";
|
|
18
19
|
import { StorageFieldItem, useStorageUploadController } from "../../util/useStorageUploadController";
|
|
19
20
|
import { StorageUploadProgress } from "../components/StorageUploadProgress";
|
|
@@ -55,13 +56,13 @@ export function StorageUploadFieldBinding({
|
|
|
55
56
|
property,
|
|
56
57
|
includeDescription,
|
|
57
58
|
context,
|
|
58
|
-
isSubmitting
|
|
59
|
+
isSubmitting,
|
|
59
60
|
}: StorageUploadFieldProps) {
|
|
60
61
|
|
|
61
62
|
if (!context.entityId)
|
|
62
63
|
throw new Error("StorageUploadFieldBinding: Entity id is null");
|
|
63
64
|
|
|
64
|
-
const storageSource = useStorageSource();
|
|
65
|
+
const storageSource = useStorageSource(context.collection);
|
|
65
66
|
const disabled = isReadOnly(property) || !!property.disabled || isSubmitting;
|
|
66
67
|
|
|
67
68
|
const {
|
|
@@ -108,6 +109,7 @@ export function StorageUploadFieldBinding({
|
|
|
108
109
|
|
|
109
110
|
<StorageUpload
|
|
110
111
|
value={internalValue}
|
|
112
|
+
collection={context.collection}
|
|
111
113
|
name={propertyKey}
|
|
112
114
|
disabled={disabled}
|
|
113
115
|
autoFocus={autoFocus}
|
|
@@ -133,6 +135,7 @@ export function StorageUploadFieldBinding({
|
|
|
133
135
|
|
|
134
136
|
function FileDropComponent({
|
|
135
137
|
storage,
|
|
138
|
+
collection,
|
|
136
139
|
disabled,
|
|
137
140
|
isDraggingOver,
|
|
138
141
|
onFilesAdded,
|
|
@@ -151,6 +154,7 @@ function FileDropComponent({
|
|
|
151
154
|
helpText
|
|
152
155
|
}: {
|
|
153
156
|
storage: StorageConfig,
|
|
157
|
+
collection: EntityCollection,
|
|
154
158
|
disabled: boolean,
|
|
155
159
|
isDraggingOver: boolean,
|
|
156
160
|
droppableProvided: any,
|
|
@@ -231,6 +235,7 @@ function FileDropComponent({
|
|
|
231
235
|
if (entry.storagePathOrDownloadUrl) {
|
|
232
236
|
child = (
|
|
233
237
|
<StorageItemPreview
|
|
238
|
+
collection={collection}
|
|
234
239
|
name={`storage_preview_${entry.storagePathOrDownloadUrl}`}
|
|
235
240
|
property={property}
|
|
236
241
|
disabled={disabled}
|
|
@@ -294,6 +299,7 @@ function FileDropComponent({
|
|
|
294
299
|
|
|
295
300
|
export interface StorageUploadProps {
|
|
296
301
|
value: StorageFieldItem[];
|
|
302
|
+
collection: EntityCollection;
|
|
297
303
|
setInternalValue: (v: StorageFieldItem[]) => void;
|
|
298
304
|
name: string;
|
|
299
305
|
property: ResolvedStringProperty | ResolvedArrayProperty<string[]>;
|
|
@@ -309,6 +315,7 @@ export interface StorageUploadProps {
|
|
|
309
315
|
}
|
|
310
316
|
|
|
311
317
|
export function StorageUpload({
|
|
318
|
+
collection,
|
|
312
319
|
property,
|
|
313
320
|
name,
|
|
314
321
|
value,
|
|
@@ -321,7 +328,7 @@ export function StorageUpload({
|
|
|
321
328
|
autoFocus,
|
|
322
329
|
storage,
|
|
323
330
|
entity,
|
|
324
|
-
storagePathBuilder
|
|
331
|
+
storagePathBuilder,
|
|
325
332
|
}: StorageUploadProps) {
|
|
326
333
|
|
|
327
334
|
if (multipleFilesSupported) {
|
|
@@ -401,6 +408,7 @@ export function StorageUpload({
|
|
|
401
408
|
className="rounded"
|
|
402
409
|
>
|
|
403
410
|
<StorageItemPreview
|
|
411
|
+
collection={collection}
|
|
404
412
|
name={`storage_preview_${entry.storagePathOrDownloadUrl}`}
|
|
405
413
|
property={renderProperty}
|
|
406
414
|
disabled={true}
|
|
@@ -414,6 +422,7 @@ export function StorageUpload({
|
|
|
414
422
|
>
|
|
415
423
|
{(provided, snapshot) => {
|
|
416
424
|
return <FileDropComponent storage={storage}
|
|
425
|
+
collection={collection}
|
|
417
426
|
disabled={disabled}
|
|
418
427
|
isDraggingOver={snapshot.isDraggingOver}
|
|
419
428
|
droppableProvided={provided}
|
|
@@ -7,7 +7,7 @@ import { getIconForProperty } from "../../util";
|
|
|
7
7
|
import { PropertyPreview } from "../../preview";
|
|
8
8
|
import { useClearRestoreValue } from "../useClearRestoreValue";
|
|
9
9
|
|
|
10
|
-
interface
|
|
10
|
+
interface TextFieldBindingProps<T extends string | number> extends FieldProps<T> {
|
|
11
11
|
allowInfinity?: boolean
|
|
12
12
|
}
|
|
13
13
|
|
|
@@ -18,6 +18,7 @@ interface TextFieldProps<T extends string | number> extends FieldProps<T> {
|
|
|
18
18
|
* @group Form fields
|
|
19
19
|
*/
|
|
20
20
|
export function TextFieldBinding<T extends string | number>({
|
|
21
|
+
context,
|
|
21
22
|
propertyKey,
|
|
22
23
|
value,
|
|
23
24
|
setValue,
|
|
@@ -27,7 +28,7 @@ export function TextFieldBinding<T extends string | number>({
|
|
|
27
28
|
autoFocus,
|
|
28
29
|
property,
|
|
29
30
|
includeDescription,
|
|
30
|
-
}:
|
|
31
|
+
}: TextFieldBindingProps<T>) {
|
|
31
32
|
|
|
32
33
|
let multiline: boolean | undefined;
|
|
33
34
|
let url: boolean | PreviewType | undefined;
|
|
@@ -96,9 +97,10 @@ export function TextFieldBinding<T extends string | number>({
|
|
|
96
97
|
{url && <Collapse
|
|
97
98
|
className="mt-1 ml-1"
|
|
98
99
|
in={Boolean(value)}>
|
|
99
|
-
<PropertyPreview
|
|
100
|
-
|
|
101
|
-
|
|
100
|
+
<PropertyPreview
|
|
101
|
+
value={value}
|
|
102
|
+
property={property}
|
|
103
|
+
size={"medium"}/>
|
|
102
104
|
</Collapse>}
|
|
103
105
|
|
|
104
106
|
</>
|
package/src/form/validation.ts
CHANGED
|
@@ -9,8 +9,7 @@ import {
|
|
|
9
9
|
} from "../types";
|
|
10
10
|
import * as yup from "yup";
|
|
11
11
|
import { AnySchema, ArraySchema, BooleanSchema, DateSchema, NumberSchema, ObjectSchema, StringSchema } from "yup";
|
|
12
|
-
import { enumToObjectEntries } from "../util
|
|
13
|
-
import { getValueInPath, hydrateRegExp, isPropertyBuilder } from "../util";
|
|
12
|
+
import { enumToObjectEntries, getValueInPath, hydrateRegExp, isPropertyBuilder } from "../util";
|
|
14
13
|
|
|
15
14
|
// Add custom unique function for array values
|
|
16
15
|
declare module "yup" {
|
|
@@ -90,12 +89,12 @@ export function mapPropertyToYup<T extends CMSType>(propertyContext: PropertyCon
|
|
|
90
89
|
throw Error("Unsupported data type in yup mapping");
|
|
91
90
|
}
|
|
92
91
|
|
|
93
|
-
export function getYupMapObjectSchema
|
|
92
|
+
export function getYupMapObjectSchema({
|
|
94
93
|
property,
|
|
95
94
|
entityId,
|
|
96
95
|
customFieldValidator,
|
|
97
96
|
name
|
|
98
|
-
}: PropertyContext<
|
|
97
|
+
}: PropertyContext<Record<string, any>>): ObjectSchema<any> {
|
|
99
98
|
const objectSchema: any = {};
|
|
100
99
|
const validation = property.validation;
|
|
101
100
|
if (property.properties)
|
package/src/hooks/data/delete.ts
CHANGED
|
@@ -12,10 +12,10 @@ import {
|
|
|
12
12
|
/**
|
|
13
13
|
* @group Hooks and utilities
|
|
14
14
|
*/
|
|
15
|
-
export type DeleteEntityWithCallbacksProps<M extends Record<string, any
|
|
15
|
+
export type DeleteEntityWithCallbacksProps<M extends Record<string, any>, UserType extends User = User> =
|
|
16
16
|
DeleteEntityProps<M>
|
|
17
17
|
& {
|
|
18
|
-
callbacks?: EntityCallbacks<M>;
|
|
18
|
+
callbacks?: EntityCallbacks<M, UserType>;
|
|
19
19
|
onDeleteSuccess?: (entity: Entity<M>) => void;
|
|
20
20
|
onDeleteFailure?: (entity: Entity<M>, e: Error) => void;
|
|
21
21
|
onPreDeleteHookError?: (entity: Entity<M>, e: Error) => void;
|
|
@@ -62,7 +62,7 @@ export async function deleteEntityWithCallbacks<M extends Record<string, any>, U
|
|
|
62
62
|
|
|
63
63
|
console.debug("Deleting entity", entity.path, entity.id);
|
|
64
64
|
|
|
65
|
-
const entityDeleteProps: EntityOnDeleteProps<M,
|
|
65
|
+
const entityDeleteProps: EntityOnDeleteProps<M, any> = {
|
|
66
66
|
entity,
|
|
67
67
|
collection,
|
|
68
68
|
entityId: entity.id,
|