@firecms/core 3.0.0-canary.16 → 3.0.0-canary.160
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 +3 -3
- package/dist/app/AppBar.d.ts +12 -0
- package/dist/app/Drawer.d.ts +16 -0
- package/dist/app/Scaffold.d.ts +30 -0
- package/dist/app/index.d.ts +4 -0
- package/dist/app/useApp.d.ts +16 -0
- package/dist/components/ArrayContainer.d.ts +19 -6
- package/dist/components/CircularProgressCenter.d.ts +1 -1
- package/dist/components/ClearFilterSortButton.d.ts +5 -0
- package/dist/components/{DeleteConfirmationDialog.d.ts → ConfirmationDialog.d.ts} +1 -1
- package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +11 -12
- package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +1 -1
- package/dist/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +7 -5
- package/dist/components/EntityCollectionTable/PropertyTableCell.d.ts +1 -0
- package/dist/components/EntityCollectionTable/column_utils.d.ts +1 -2
- package/dist/components/EntityCollectionTable/fields/TableReferenceField.d.ts +3 -1
- package/dist/components/EntityCollectionTable/internal/CollectionTableToolbar.d.ts +1 -4
- package/dist/components/EntityCollectionTable/internal/EntityTableCell.d.ts +2 -2
- package/dist/components/EntityCollectionTable/internal/popup_field/PopupFormField.d.ts +7 -4
- package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +12 -2
- package/dist/components/EntityCollectionView/EntityCollectionViewStartActions.d.ts +11 -0
- package/dist/components/EntityCollectionView/utils.d.ts +3 -0
- package/dist/components/EntityPreview.d.ts +7 -6
- package/dist/components/ErrorView.d.ts +1 -1
- package/dist/components/HomePage/DefaultHomePage.d.ts +1 -1
- package/dist/components/HomePage/NavigationCardBinding.d.ts +1 -1
- package/dist/components/PropertyConfigBadge.d.ts +2 -1
- package/dist/components/PropertyIdCopyTooltip.d.ts +8 -0
- package/dist/components/ReferenceWidget.d.ts +3 -1
- package/dist/components/SelectableTable/SelectableTable.d.ts +1 -1
- package/dist/components/SelectableTable/filters/ReferenceFilterField.d.ts +2 -1
- package/dist/components/VirtualTable/VirtualTableProps.d.ts +15 -12
- package/dist/components/VirtualTable/types.d.ts +3 -3
- package/dist/components/{EntityCollectionTable/internal → common}/default_entity_actions.d.ts +1 -1
- package/dist/components/common/index.d.ts +1 -0
- package/dist/components/common/table_height.d.ts +5 -0
- package/dist/components/common/types.d.ts +4 -6
- package/dist/components/common/useColumnsIds.d.ts +2 -1
- package/dist/components/common/useDataSourceEntityCollectionTableController.d.ts +4 -1
- package/dist/components/index.d.ts +4 -2
- package/dist/{components/FireCMSAppBar.d.ts → core/DefaultAppBar.d.ts} +6 -9
- package/dist/core/DefaultDrawer.d.ts +19 -0
- package/dist/core/DrawerNavigationItem.d.ts +10 -0
- package/dist/core/EntityEditView.d.ts +18 -4
- package/dist/core/FireCMS.d.ts +2 -2
- package/dist/core/NavigationRoutes.d.ts +3 -3
- package/dist/core/index.d.ts +3 -4
- package/dist/form/PropertyFieldBinding.d.ts +1 -1
- package/dist/form/components/ErrorFocus.d.ts +1 -1
- package/dist/form/components/FieldHelperText.d.ts +3 -3
- package/dist/form/components/LabelWithIcon.d.ts +1 -1
- package/dist/form/components/LabelWithIconAndTooltip.d.ts +15 -0
- package/dist/form/components/StorageItemPreview.d.ts +4 -4
- package/dist/form/components/index.d.ts +1 -1
- package/dist/form/field_bindings/ArrayCustomShapedFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/ArrayOfReferencesFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/BlockFieldBinding.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/MarkdownEditorFieldBinding.d.ts +11 -0
- package/dist/form/field_bindings/{MultiSelectBinding.d.ts → MultiSelectFieldBinding.d.ts} +1 -1
- package/dist/form/field_bindings/ReadOnlyFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/ReferenceFieldBinding.d.ts +2 -2
- package/dist/form/field_bindings/RepeatFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/SelectFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +3 -5
- package/dist/form/field_bindings/SwitchFieldBinding.d.ts +1 -2
- package/dist/form/field_bindings/TextFieldBinding.d.ts +1 -1
- package/dist/form/index.d.ts +3 -5
- package/dist/form/useClearRestoreValue.d.ts +2 -2
- package/dist/hooks/data/delete.d.ts +4 -4
- package/dist/hooks/data/save.d.ts +4 -5
- package/dist/hooks/data/useCollectionFetch.d.ts +1 -1
- package/dist/hooks/data/useEntityFetch.d.ts +3 -3
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/useAuthController.d.ts +1 -1
- package/dist/hooks/useBuildNavigationController.d.ts +3 -4
- package/dist/hooks/useFireCMSContext.d.ts +1 -1
- package/dist/hooks/useProjectLog.d.ts +8 -2
- package/dist/hooks/useResolvedNavigationFrom.d.ts +3 -3
- package/dist/hooks/useValidateAuthenticator.d.ts +5 -9
- package/dist/index.d.ts +1 -0
- package/dist/index.es.js +20202 -14110
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +22773 -588
- package/dist/index.umd.js.map +1 -1
- package/dist/internal/useBuildDataSource.d.ts +1 -16
- package/dist/preview/PropertyPreviewProps.d.ts +6 -1
- package/dist/preview/components/EnumValuesChip.d.ts +1 -1
- package/dist/preview/components/ReferencePreview.d.ts +3 -2
- package/dist/preview/components/StorageThumbnail.d.ts +2 -1
- package/dist/preview/components/UrlComponentPreview.d.ts +2 -1
- package/dist/preview/util.d.ts +3 -3
- package/dist/types/auth.d.ts +8 -10
- package/dist/types/collections.d.ts +53 -18
- package/dist/types/datasource.d.ts +51 -35
- package/dist/types/entities.d.ts +6 -1
- package/dist/types/entity_actions.d.ts +18 -4
- package/dist/types/entity_callbacks.d.ts +16 -16
- package/dist/types/entity_overrides.d.ts +2 -2
- package/dist/types/export_import.d.ts +4 -4
- package/dist/types/fields.d.ts +63 -41
- package/dist/types/firecms.d.ts +6 -2
- package/dist/types/firecms_context.d.ts +1 -1
- package/dist/types/index.d.ts +0 -1
- package/dist/types/navigation.d.ts +6 -5
- package/dist/types/permissions.d.ts +4 -4
- package/dist/types/plugins.d.ts +22 -12
- package/dist/types/properties.d.ts +34 -21
- package/dist/types/property_config.d.ts +0 -2
- package/dist/types/side_dialogs_controller.d.ts +10 -0
- package/dist/types/storage.d.ts +86 -3
- package/dist/types/user.d.ts +1 -0
- package/dist/util/builders.d.ts +2 -2
- package/dist/util/entities.d.ts +2 -2
- package/dist/util/icon_list.d.ts +5 -1
- package/dist/util/icon_synonyms.d.ts +1 -97
- package/dist/util/icons.d.ts +6 -3
- package/dist/util/index.d.ts +1 -0
- package/dist/util/navigation_utils.d.ts +2 -2
- package/dist/util/objects.d.ts +2 -1
- package/dist/util/permissions.d.ts +4 -4
- package/dist/util/plurals.d.ts +0 -2
- package/dist/util/property_utils.d.ts +3 -3
- package/dist/util/resolutions.d.ts +30 -16
- package/dist/util/storage.d.ts +23 -2
- package/dist/util/useStorageUploadController.d.ts +3 -3
- package/package.json +59 -44
- package/src/app/AppBar.tsx +18 -0
- package/src/app/Drawer.tsx +24 -0
- package/src/app/Scaffold.tsx +243 -0
- package/src/app/index.ts +4 -0
- package/src/app/useApp.tsx +32 -0
- package/src/components/ArrayContainer.tsx +92 -25
- package/src/components/CircularProgressCenter.tsx +2 -2
- package/src/components/ClearFilterSortButton.tsx +41 -0
- package/src/components/{DeleteConfirmationDialog.tsx → ConfirmationDialog.tsx} +3 -3
- package/src/components/DeleteEntityDialog.tsx +9 -18
- package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +13 -20
- package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +28 -25
- package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +12 -8
- package/src/components/EntityCollectionTable/PropertyTableCell.tsx +47 -39
- package/src/components/EntityCollectionTable/column_utils.tsx +3 -3
- package/src/components/EntityCollectionTable/fields/TableReferenceField.tsx +31 -17
- package/src/components/EntityCollectionTable/fields/TableStorageUpload.tsx +16 -8
- package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +30 -35
- package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +36 -34
- package/src/components/EntityCollectionTable/internal/EntityTableCellActions.tsx +19 -7
- package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +82 -75
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +139 -87
- package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +68 -0
- package/src/components/EntityCollectionView/useSelectionController.tsx +19 -7
- package/src/components/EntityCollectionView/utils.ts +19 -0
- package/src/components/EntityPreview.tsx +55 -51
- package/src/components/EntityView.tsx +10 -10
- package/src/components/ErrorView.tsx +4 -4
- package/src/components/HomePage/DefaultHomePage.tsx +26 -19
- package/src/components/HomePage/FavouritesView.tsx +1 -1
- package/src/components/HomePage/NavigationCard.tsx +4 -4
- package/src/components/HomePage/NavigationCardBinding.tsx +2 -2
- package/src/components/HomePage/NavigationGroup.tsx +2 -2
- package/src/components/HomePage/SmallNavigationCard.tsx +5 -6
- package/src/components/PropertyConfigBadge.tsx +9 -3
- package/src/components/PropertyIdCopyTooltip.tsx +48 -0
- package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +8 -7
- package/src/components/ReferenceWidget.tsx +22 -12
- package/src/components/SearchIconsView.tsx +10 -7
- package/src/components/SelectableTable/SelectableTable.tsx +9 -9
- package/src/components/SelectableTable/filters/BooleanFilterField.tsx +2 -3
- package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +25 -8
- package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +30 -6
- package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +90 -21
- package/src/components/VirtualTable/VirtualTable.tsx +77 -46
- package/src/components/VirtualTable/VirtualTableCell.tsx +1 -9
- package/src/components/VirtualTable/VirtualTableHeader.tsx +10 -10
- package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +2 -2
- package/src/components/VirtualTable/VirtualTableProps.tsx +18 -14
- package/src/components/VirtualTable/VirtualTableRow.tsx +5 -6
- package/src/components/VirtualTable/fields/VirtualTableDateField.tsx +5 -5
- package/src/components/VirtualTable/fields/VirtualTableInput.tsx +2 -1
- package/src/components/VirtualTable/fields/VirtualTableNumberInput.tsx +2 -1
- package/src/components/VirtualTable/fields/VirtualTableSelect.tsx +16 -28
- package/src/components/VirtualTable/types.tsx +2 -3
- package/src/components/{EntityCollectionTable/internal → common}/default_entity_actions.tsx +8 -4
- package/src/components/common/index.ts +1 -0
- package/src/components/{VirtualTable/common.tsx → common/table_height.tsx} +5 -2
- package/src/components/common/types.tsx +4 -6
- package/src/components/common/useColumnsIds.tsx +23 -2
- package/src/components/common/useDataSourceEntityCollectionTableController.tsx +25 -14
- package/src/components/common/useTableSearchHelper.ts +53 -12
- package/src/components/index.tsx +4 -2
- package/src/contexts/DialogsProvider.tsx +2 -2
- package/src/contexts/SnackbarProvider.tsx +2 -0
- package/src/core/DefaultAppBar.tsx +178 -0
- package/src/core/DefaultDrawer.tsx +183 -0
- package/src/core/DrawerNavigationItem.tsx +66 -0
- package/src/core/EntityEditView.tsx +721 -156
- package/src/core/EntitySidePanel.tsx +1 -2
- package/src/core/FireCMS.tsx +57 -53
- package/src/core/NavigationRoutes.tsx +7 -8
- package/src/core/SideDialogs.tsx +2 -1
- package/src/core/field_configs.tsx +9 -10
- package/src/core/index.tsx +3 -4
- package/src/form/PropertyFieldBinding.tsx +74 -35
- package/src/form/components/CustomIdField.tsx +6 -2
- package/src/form/components/FieldHelperText.tsx +4 -4
- package/src/form/components/LabelWithIcon.tsx +27 -19
- package/src/form/components/LabelWithIconAndTooltip.tsx +28 -0
- package/src/form/components/StorageItemPreview.tsx +22 -12
- package/src/form/components/StorageUploadProgress.tsx +3 -4
- package/src/form/components/index.tsx +1 -1
- package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +29 -17
- package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +45 -35
- package/src/form/field_bindings/BlockFieldBinding.tsx +53 -33
- package/src/form/field_bindings/DateTimeFieldBinding.tsx +17 -14
- package/src/form/field_bindings/KeyValueFieldBinding.tsx +60 -51
- package/src/form/field_bindings/MapFieldBinding.tsx +67 -48
- package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +150 -0
- package/src/form/field_bindings/{MultiSelectBinding.tsx → MultiSelectFieldBinding.tsx} +25 -20
- package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +11 -16
- package/src/form/field_bindings/ReferenceFieldBinding.tsx +42 -31
- package/src/form/field_bindings/RepeatFieldBinding.tsx +52 -34
- package/src/form/field_bindings/SelectFieldBinding.tsx +21 -13
- package/src/form/field_bindings/StorageUploadFieldBinding.tsx +37 -47
- package/src/form/field_bindings/SwitchFieldBinding.tsx +28 -24
- package/src/form/field_bindings/TextFieldBinding.tsx +26 -23
- package/src/form/index.tsx +4 -9
- package/src/form/useClearRestoreValue.tsx +2 -2
- package/src/form/validation.ts +1 -17
- package/src/hooks/data/delete.ts +6 -5
- package/src/hooks/data/save.ts +12 -8
- package/src/hooks/data/useCollectionFetch.tsx +2 -2
- package/src/hooks/data/useDataSource.tsx +11 -3
- package/src/hooks/data/useEntityFetch.tsx +5 -5
- package/src/hooks/index.tsx +1 -0
- package/src/hooks/useAuthController.tsx +1 -1
- package/src/hooks/useBuildLocalConfigurationPersistence.tsx +8 -10
- package/src/hooks/useBuildModeController.tsx +11 -5
- package/src/hooks/useBuildNavigationController.tsx +92 -34
- package/src/hooks/useFireCMSContext.tsx +5 -5
- package/src/hooks/useProjectLog.tsx +32 -10
- package/src/hooks/useResolvedNavigationFrom.tsx +6 -6
- package/src/hooks/useValidateAuthenticator.tsx +21 -41
- package/src/index.ts +1 -0
- package/src/internal/useBuildDataSource.ts +72 -82
- package/src/internal/useBuildSideDialogsController.tsx +1 -0
- package/src/internal/useBuildSideEntityController.tsx +102 -22
- package/src/internal/useUnsavedChangesDialog.tsx +5 -3
- package/src/preview/PropertyPreview.tsx +11 -18
- package/src/preview/PropertyPreviewProps.tsx +7 -1
- package/src/preview/components/BooleanPreview.tsx +2 -2
- package/src/preview/components/EmptyValue.tsx +1 -1
- package/src/preview/components/EnumValuesChip.tsx +2 -2
- package/src/preview/components/ImagePreview.tsx +25 -35
- package/src/preview/components/ReferencePreview.tsx +23 -34
- package/src/preview/components/StorageThumbnail.tsx +5 -1
- package/src/preview/components/UrlComponentPreview.tsx +44 -11
- package/src/preview/property_previews/ArrayOfMapsPreview.tsx +2 -3
- package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +4 -3
- package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +2 -3
- package/src/preview/property_previews/ArrayOfStringsPreview.tsx +1 -2
- package/src/preview/property_previews/ArrayOneOfPreview.tsx +4 -5
- package/src/preview/property_previews/ArrayPropertyPreview.tsx +4 -5
- package/src/preview/property_previews/MapPropertyPreview.tsx +9 -9
- package/src/preview/property_previews/SkeletonPropertyComponent.tsx +12 -12
- package/src/preview/property_previews/StringPropertyPreview.tsx +3 -3
- package/src/preview/util.ts +10 -10
- package/src/types/auth.tsx +9 -13
- package/src/types/collections.ts +62 -20
- package/src/types/customization_controller.tsx +0 -1
- package/src/types/datasource.ts +60 -43
- package/src/types/entities.ts +11 -1
- package/src/types/entity_actions.tsx +20 -7
- package/src/types/entity_callbacks.ts +18 -18
- package/src/types/entity_overrides.tsx +2 -2
- package/src/types/export_import.ts +4 -4
- package/src/types/fields.tsx +69 -45
- package/src/types/firecms.tsx +7 -2
- package/src/types/firecms_context.tsx +1 -1
- package/src/types/index.ts +0 -1
- package/src/types/navigation.ts +7 -7
- package/src/types/permissions.ts +5 -5
- package/src/types/plugins.tsx +24 -14
- package/src/types/properties.ts +39 -22
- package/src/types/property_config.tsx +0 -2
- package/src/types/side_dialogs_controller.tsx +13 -0
- package/src/types/storage.ts +94 -3
- package/src/types/user.ts +2 -0
- package/src/util/builders.ts +6 -6
- package/src/util/entities.ts +6 -5
- package/src/util/enums.ts +1 -1
- package/src/util/icon_list.ts +15 -10
- package/src/util/icon_synonyms.ts +3 -99
- package/src/util/icons.tsx +17 -7
- package/src/util/index.ts +1 -0
- package/src/util/make_properties_editable.ts +13 -5
- package/src/util/navigation_utils.ts +6 -6
- package/src/util/objects.ts +45 -28
- package/src/util/permissions.ts +9 -8
- package/src/util/plurals.ts +0 -2
- package/src/util/property_utils.tsx +11 -4
- package/src/util/references.ts +3 -0
- package/src/util/resolutions.ts +79 -46
- package/src/util/storage.ts +79 -21
- package/src/util/strings.ts +2 -2
- package/src/util/useStorageUploadController.tsx +34 -8
- package/src/util/useTraceUpdate.tsx +1 -0
- package/dist/components/PropertyIdCopyTooltipContent.d.ts +0 -3
- package/dist/components/VirtualTable/common.d.ts +0 -2
- package/dist/core/Drawer.d.ts +0 -23
- package/dist/core/Scaffold.d.ts +0 -55
- package/dist/core/SideEntityView.d.ts +0 -7
- package/dist/form/EntityForm.d.ts +0 -77
- package/dist/form/components/FormikArrayContainer.d.ts +0 -18
- package/dist/form/field_bindings/MarkdownFieldBinding.d.ts +0 -9
- package/dist/internal/useBuildCustomizationController.d.ts +0 -2
- package/dist/internal/useLocaleConfig.d.ts +0 -1
- package/dist/types/appcheck.d.ts +0 -26
- package/src/components/FireCMSAppBar.tsx +0 -165
- package/src/components/PropertyIdCopyTooltipContent.tsx +0 -28
- package/src/core/Drawer.tsx +0 -191
- package/src/core/Scaffold.tsx +0 -281
- package/src/core/SideEntityView.tsx +0 -38
- package/src/form/EntityForm.tsx +0 -728
- package/src/form/components/FormikArrayContainer.tsx +0 -44
- package/src/form/field_bindings/MarkdownFieldBinding.tsx +0 -695
- package/src/internal/useBuildCustomizationController.tsx +0 -5
- package/src/internal/useLocaleConfig.tsx +0 -18
- package/src/types/appcheck.ts +0 -29
|
@@ -1,18 +1,41 @@
|
|
|
1
|
-
import React, { useCallback, useEffect, useRef, useState } from "react";
|
|
1
|
+
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
2
2
|
import {
|
|
3
|
+
CMSAnalyticsEvent,
|
|
3
4
|
Entity,
|
|
5
|
+
EntityAction,
|
|
4
6
|
EntityCollection,
|
|
5
7
|
EntityCustomView,
|
|
6
8
|
EntityStatus,
|
|
7
9
|
EntityValues,
|
|
8
10
|
FireCMSPlugin,
|
|
9
11
|
FormContext,
|
|
12
|
+
PluginFormActionProps,
|
|
13
|
+
PropertyFieldBindingProps,
|
|
14
|
+
ResolvedEntityCollection,
|
|
10
15
|
User
|
|
11
16
|
} from "../types";
|
|
12
|
-
import
|
|
17
|
+
import equal from "react-fast-compare"
|
|
18
|
+
|
|
19
|
+
import {
|
|
20
|
+
CircularProgressCenter,
|
|
21
|
+
copyEntityAction,
|
|
22
|
+
deleteEntityAction,
|
|
23
|
+
EntityCollectionView,
|
|
24
|
+
EntityView,
|
|
25
|
+
ErrorBoundary,
|
|
26
|
+
getFormFieldKeys,
|
|
27
|
+
} from "../components";
|
|
13
28
|
import {
|
|
29
|
+
canCreateEntity,
|
|
30
|
+
canDeleteEntity,
|
|
14
31
|
canEditEntity,
|
|
32
|
+
getDefaultValuesFor,
|
|
33
|
+
getEntityTitlePropertyKey,
|
|
34
|
+
getValueInPath,
|
|
35
|
+
isHidden,
|
|
36
|
+
isReadOnly,
|
|
15
37
|
removeInitialAndTrailingSlashes,
|
|
38
|
+
resolveCollection,
|
|
16
39
|
resolveDefaultSelectedView,
|
|
17
40
|
resolveEntityView,
|
|
18
41
|
useDebouncedCallback
|
|
@@ -28,11 +51,29 @@ import {
|
|
|
28
51
|
useSideEntityController,
|
|
29
52
|
useSnackbarController
|
|
30
53
|
} from "../hooks";
|
|
31
|
-
import {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
54
|
+
import {
|
|
55
|
+
Alert,
|
|
56
|
+
Button,
|
|
57
|
+
CircularProgress,
|
|
58
|
+
CloseIcon,
|
|
59
|
+
cls,
|
|
60
|
+
defaultBorderMixin,
|
|
61
|
+
DialogActions,
|
|
62
|
+
IconButton,
|
|
63
|
+
NotesIcon,
|
|
64
|
+
paperMixin,
|
|
65
|
+
Tab,
|
|
66
|
+
Tabs,
|
|
67
|
+
Typography
|
|
68
|
+
} from "@firecms/ui";
|
|
35
69
|
import { useSideDialogContext } from "./index";
|
|
70
|
+
import { Formex, FormexController, getIn, setIn, useCreateFormex } from "@firecms/formex";
|
|
71
|
+
import { useAnalyticsController } from "../hooks/useAnalyticsController";
|
|
72
|
+
import { CustomIdField } from "../form/components/CustomIdField";
|
|
73
|
+
import { CustomFieldValidator, getYupEntitySchema } from "../form/validation";
|
|
74
|
+
import { ErrorFocus } from "../form/components/ErrorFocus";
|
|
75
|
+
import { LabelWithIconAndTooltip, PropertyFieldBinding } from "../form";
|
|
76
|
+
import { ValidationError } from "yup";
|
|
36
77
|
|
|
37
78
|
const MAIN_TAB_VALUE = "main_##Q$SC^#S6";
|
|
38
79
|
|
|
@@ -43,7 +84,6 @@ export interface EntityEditViewProps<M extends Record<string, any>> {
|
|
|
43
84
|
copy?: boolean;
|
|
44
85
|
selectedSubPath?: string;
|
|
45
86
|
parentCollectionIds: string[];
|
|
46
|
-
formWidth?: number | string;
|
|
47
87
|
onValuesAreModified: (modified: boolean) => void;
|
|
48
88
|
onUpdate?: (params: { entity: Entity<any> }) => void;
|
|
49
89
|
onClose?: () => void;
|
|
@@ -53,20 +93,54 @@ export interface EntityEditViewProps<M extends Record<string, any>> {
|
|
|
53
93
|
* This is the default view that is used as the content of a side panel when
|
|
54
94
|
* an entity is opened.
|
|
55
95
|
* You probably don't want to use this view directly since it is bound to the
|
|
56
|
-
* side panel.
|
|
96
|
+
* side panel.
|
|
57
97
|
*/
|
|
58
|
-
export function EntityEditView<M extends Record<string, any>,
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
98
|
+
export function EntityEditView<M extends Record<string, any>, USER extends User>({
|
|
99
|
+
entityId,
|
|
100
|
+
...props
|
|
101
|
+
}: EntityEditViewProps<M>) {
|
|
102
|
+
const {
|
|
103
|
+
entity,
|
|
104
|
+
dataLoading,
|
|
105
|
+
// eslint-disable-next-line no-unused-vars
|
|
106
|
+
dataLoadingError
|
|
107
|
+
} = useEntityFetch<M, USER>({
|
|
108
|
+
path: props.path,
|
|
109
|
+
entityId: entityId,
|
|
110
|
+
collection: props.collection,
|
|
111
|
+
useCache: false
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
if (dataLoading) {
|
|
115
|
+
return <CircularProgressCenter/>
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (entityId && !entity) {
|
|
119
|
+
console.error(`Entity with id ${entityId} not found in collection ${props.collection.path}`);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return <EntityEditViewInner<M> {...props}
|
|
123
|
+
entityId={entityId}
|
|
124
|
+
entity={entity}
|
|
125
|
+
dataLoading={dataLoading}/>;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function EntityEditViewInner<M extends Record<string, any>>({
|
|
129
|
+
path,
|
|
130
|
+
entityId: entityIdProp,
|
|
131
|
+
selectedSubPath: selectedSubPathProp,
|
|
132
|
+
copy,
|
|
133
|
+
collection,
|
|
134
|
+
parentCollectionIds,
|
|
135
|
+
onValuesAreModified,
|
|
136
|
+
onUpdate,
|
|
137
|
+
onClose,
|
|
138
|
+
entity,
|
|
139
|
+
dataLoading
|
|
140
|
+
}: EntityEditViewProps<M> & {
|
|
141
|
+
entity?: Entity<M>,
|
|
142
|
+
dataLoading: boolean
|
|
143
|
+
}) {
|
|
70
144
|
|
|
71
145
|
if (collection.customId && collection.formAutoSave) {
|
|
72
146
|
console.warn(`The collection ${collection.path} has customId and formAutoSave enabled. This is not supported and formAutoSave will be ignored`);
|
|
@@ -91,33 +165,65 @@ export function EntityEditView<M extends Record<string, any>, UserType extends U
|
|
|
91
165
|
|
|
92
166
|
// const largeLayout = useLargeLayout();
|
|
93
167
|
// const largeLayoutTabSelected = useRef(!largeLayout);
|
|
168
|
+
// const resolvedFormWidth: string = typeof formWidth === "number" ? `${formWidth}px` : formWidth ?? FORM_CONTAINER_WIDTH;
|
|
94
169
|
|
|
95
|
-
const
|
|
170
|
+
const inputCollection = collection;
|
|
96
171
|
|
|
172
|
+
const authController = useAuthController();
|
|
97
173
|
const dataSource = useDataSource(collection);
|
|
98
174
|
const sideDialogContext = useSideDialogContext();
|
|
99
175
|
const sideEntityController = useSideEntityController();
|
|
100
176
|
const snackbarController = useSnackbarController();
|
|
101
177
|
const customizationController = useCustomizationController();
|
|
102
178
|
const context = useFireCMSContext();
|
|
103
|
-
const authController = useAuthController<UserType>();
|
|
104
179
|
|
|
105
|
-
const
|
|
180
|
+
const closeAfterSaveRef = useRef(false);
|
|
106
181
|
|
|
107
|
-
const
|
|
182
|
+
const analyticsController = useAnalyticsController();
|
|
108
183
|
|
|
109
|
-
const
|
|
110
|
-
|
|
184
|
+
const initialResolvedCollection = useMemo(() => resolveCollection({
|
|
185
|
+
collection: inputCollection,
|
|
186
|
+
path,
|
|
187
|
+
values: entity?.values,
|
|
188
|
+
propertyConfigs: customizationController.propertyConfigs
|
|
189
|
+
}), [entity?.values, path, customizationController.propertyConfigs]);
|
|
190
|
+
|
|
191
|
+
const initialStatus = copy ? "copy" : (entityIdProp ? "existing" : "new");
|
|
192
|
+
const [status, setStatus] = useState<EntityStatus>(initialStatus);
|
|
193
|
+
|
|
194
|
+
const mustSetCustomId: boolean = (status === "new" || status === "copy") &&
|
|
195
|
+
(Boolean(initialResolvedCollection.customId) && initialResolvedCollection.customId !== "optional");
|
|
196
|
+
|
|
197
|
+
const initialEntityId: string | undefined = useMemo((): string | undefined => {
|
|
198
|
+
if (status === "new" || status === "copy") {
|
|
199
|
+
if (mustSetCustomId) {
|
|
200
|
+
return undefined;
|
|
201
|
+
} else {
|
|
202
|
+
return dataSource.generateEntityId(path, collection);
|
|
203
|
+
}
|
|
204
|
+
} else {
|
|
205
|
+
return entityIdProp;
|
|
206
|
+
}
|
|
207
|
+
}, [entityIdProp, status]);
|
|
111
208
|
|
|
112
|
-
const
|
|
113
|
-
const subcollectionsCount = subcollections?.length ?? 0;
|
|
114
|
-
const customViews = collection.entityViews;
|
|
115
|
-
const customViewsCount = customViews?.length ?? 0;
|
|
116
|
-
const autoSave = collection.formAutoSave && !collection.customId;
|
|
209
|
+
const [entityId, setEntityId] = React.useState<string | undefined>(initialEntityId);
|
|
117
210
|
|
|
118
|
-
const
|
|
211
|
+
// const doOnValuesChanges = (values?: EntityValues<M>) => {
|
|
212
|
+
// const initialValues = formex.initialValues;
|
|
213
|
+
// setInternalValues(values);
|
|
214
|
+
// if (onValuesChanged)
|
|
215
|
+
// onValuesChanged(values);
|
|
216
|
+
// if (autoSave && values && !equal(values, initialValues)) {
|
|
217
|
+
// save(values);
|
|
218
|
+
// }
|
|
219
|
+
// };
|
|
220
|
+
|
|
221
|
+
const [entityIdError, setEntityIdError] = React.useState<boolean>(false);
|
|
222
|
+
const [savingError, setSavingError] = React.useState<Error | undefined>();
|
|
119
223
|
|
|
120
|
-
const
|
|
224
|
+
const [customIdLoading, setCustomIdLoading] = React.useState<boolean>(false);
|
|
225
|
+
|
|
226
|
+
const defaultSelectedView = selectedSubPathProp ?? resolveDefaultSelectedView(
|
|
121
227
|
collection ? collection.defaultSelectedView : undefined,
|
|
122
228
|
{
|
|
123
229
|
status,
|
|
@@ -125,25 +231,23 @@ export function EntityEditView<M extends Record<string, any>, UserType extends U
|
|
|
125
231
|
}
|
|
126
232
|
);
|
|
127
233
|
|
|
128
|
-
const
|
|
234
|
+
const [selectedTab, setSelectedTab] = useState<string>(defaultSelectedView ?? MAIN_TAB_VALUE);
|
|
129
235
|
|
|
130
|
-
const mainViewVisible =
|
|
236
|
+
const mainViewVisible = selectedTab === MAIN_TAB_VALUE;
|
|
131
237
|
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
entityId,
|
|
140
|
-
collection,
|
|
141
|
-
useCache: false
|
|
142
|
-
});
|
|
238
|
+
const subcollections = (collection.subcollections ?? []).filter(c => !c.hideFromNavigation);
|
|
239
|
+
const subcollectionsCount = subcollections?.length ?? 0;
|
|
240
|
+
const customViews = collection.entityViews;
|
|
241
|
+
const customViewsCount = customViews?.length ?? 0;
|
|
242
|
+
const autoSave = collection.formAutoSave && !collection.customId;
|
|
243
|
+
|
|
244
|
+
const hasAdditionalViews = customViewsCount > 0 || subcollectionsCount > 0;
|
|
143
245
|
|
|
144
246
|
const [usedEntity, setUsedEntity] = useState<Entity<M> | undefined>(entity);
|
|
145
247
|
const [readOnly, setReadOnly] = useState<boolean | undefined>(undefined);
|
|
146
248
|
|
|
249
|
+
const baseDataSourceValuesRef = useRef<Partial<EntityValues<M>>>(getDataSourceEntityValues(initialResolvedCollection, status, usedEntity));
|
|
250
|
+
|
|
147
251
|
useEffect(() => {
|
|
148
252
|
if (entity)
|
|
149
253
|
setUsedEntity(entity);
|
|
@@ -202,7 +306,7 @@ export function EntityEditView<M extends Record<string, any>, UserType extends U
|
|
|
202
306
|
sideEntityController.replace({
|
|
203
307
|
path,
|
|
204
308
|
entityId: updatedEntity.id,
|
|
205
|
-
selectedSubPath:
|
|
309
|
+
selectedSubPath: MAIN_TAB_VALUE === selectedTab ? undefined : selectedTab,
|
|
206
310
|
updateUrl: true,
|
|
207
311
|
collection,
|
|
208
312
|
});
|
|
@@ -238,7 +342,7 @@ export function EntityEditView<M extends Record<string, any>, UserType extends U
|
|
|
238
342
|
closeAfterSave: boolean,
|
|
239
343
|
}) => {
|
|
240
344
|
setSaving(true);
|
|
241
|
-
saveEntityWithCallbacks({
|
|
345
|
+
return saveEntityWithCallbacks({
|
|
242
346
|
path,
|
|
243
347
|
entityId,
|
|
244
348
|
values,
|
|
@@ -269,7 +373,7 @@ export function EntityEditView<M extends Record<string, any>, UserType extends U
|
|
|
269
373
|
if (autoSave) {
|
|
270
374
|
setValuesToBeSaved(values);
|
|
271
375
|
} else {
|
|
272
|
-
saveEntity({
|
|
376
|
+
return saveEntity({
|
|
273
377
|
collection,
|
|
274
378
|
path,
|
|
275
379
|
entityId,
|
|
@@ -280,17 +384,121 @@ export function EntityEditView<M extends Record<string, any>, UserType extends U
|
|
|
280
384
|
}
|
|
281
385
|
};
|
|
282
386
|
|
|
387
|
+
const onSubmit = (values: EntityValues<M>, formexController: FormexController<EntityValues<M>>) => {
|
|
388
|
+
|
|
389
|
+
if (mustSetCustomId && !entityId) {
|
|
390
|
+
console.error("Missing custom Id");
|
|
391
|
+
setEntityIdError(true);
|
|
392
|
+
formexController.setSubmitting(false);
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
setSavingError(undefined);
|
|
397
|
+
setEntityIdError(false);
|
|
398
|
+
|
|
399
|
+
if (status === "existing") {
|
|
400
|
+
if (!entity?.id) throw Error("Form misconfiguration when saving, no id for existing entity");
|
|
401
|
+
} else if (status === "new" || status === "copy") {
|
|
402
|
+
if (inputCollection.customId) {
|
|
403
|
+
if (inputCollection.customId !== "optional" && !entityId) {
|
|
404
|
+
throw Error("Form misconfiguration when saving, entityId should be set");
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
} else {
|
|
408
|
+
throw Error("New FormType added, check EntityForm");
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
return save(values)
|
|
412
|
+
?.then(_ => {
|
|
413
|
+
formexController.resetForm({
|
|
414
|
+
values,
|
|
415
|
+
submitCount: 0,
|
|
416
|
+
touched: {}
|
|
417
|
+
});
|
|
418
|
+
})
|
|
419
|
+
.finally(() => {
|
|
420
|
+
formexController.setSubmitting(false);
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
const formex: FormexController<M> = useCreateFormex<M>({
|
|
426
|
+
initialValues: baseDataSourceValuesRef.current as M,
|
|
427
|
+
onSubmit,
|
|
428
|
+
validation: (values) => {
|
|
429
|
+
return validationSchema?.validate(values, { abortEarly: false })
|
|
430
|
+
.then(() => {
|
|
431
|
+
return {};
|
|
432
|
+
})
|
|
433
|
+
.catch((e: any) => {
|
|
434
|
+
// const errors: Record<string, string> = {};
|
|
435
|
+
// e.inner.forEach((error: any) => {
|
|
436
|
+
// errors[error.path] = error.message;
|
|
437
|
+
// });
|
|
438
|
+
return yupToFormErrors(e);
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
const resolvedCollection = resolveCollection<M>({
|
|
444
|
+
collection: inputCollection,
|
|
445
|
+
path,
|
|
446
|
+
entityId,
|
|
447
|
+
values: formex.values,
|
|
448
|
+
previousValues: formex.initialValues,
|
|
449
|
+
propertyConfigs: customizationController.propertyConfigs
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
const lastSavedValues = useRef<EntityValues<M> | undefined>(entity?.values);
|
|
453
|
+
|
|
454
|
+
const save = (values: EntityValues<M>): Promise<void> => {
|
|
455
|
+
lastSavedValues.current = values;
|
|
456
|
+
return onSaveEntityRequest({
|
|
457
|
+
collection: resolvedCollection,
|
|
458
|
+
path,
|
|
459
|
+
entityId,
|
|
460
|
+
values,
|
|
461
|
+
previousValues: entity?.values,
|
|
462
|
+
closeAfterSave: closeAfterSaveRef.current,
|
|
463
|
+
autoSave: autoSave ?? false
|
|
464
|
+
}).then(_ => {
|
|
465
|
+
const eventName: CMSAnalyticsEvent = status === "new"
|
|
466
|
+
? "new_entity_saved"
|
|
467
|
+
: (status === "copy" ? "entity_copied" : (status === "existing" ? "entity_edited" : "unmapped_event"));
|
|
468
|
+
analyticsController.onAnalyticsEvent?.(eventName, { path });
|
|
469
|
+
}).catch(e => {
|
|
470
|
+
console.error(e);
|
|
471
|
+
setSavingError(e);
|
|
472
|
+
}).finally(() => {
|
|
473
|
+
closeAfterSaveRef.current = false;
|
|
474
|
+
});
|
|
475
|
+
};
|
|
476
|
+
|
|
477
|
+
const formContext: FormContext<M> = {
|
|
478
|
+
// @ts-ignore
|
|
479
|
+
setFieldValue: useCallback(formex.setFieldValue, []),
|
|
480
|
+
values: formex.values,
|
|
481
|
+
collection: resolvedCollection,
|
|
482
|
+
entityId: entityId as string,
|
|
483
|
+
path,
|
|
484
|
+
save,
|
|
485
|
+
formex
|
|
486
|
+
};
|
|
487
|
+
|
|
283
488
|
const resolvedEntityViews = customViews ? customViews
|
|
284
489
|
.map(e => resolveEntityView(e, customizationController.entityViews))
|
|
285
490
|
.filter(Boolean) as EntityCustomView[]
|
|
286
491
|
: [];
|
|
287
492
|
|
|
493
|
+
const selectedEntityView = resolvedEntityViews.find(e => e.key === selectedTab);
|
|
494
|
+
const shouldShowEntityActions = !autoSave && (selectedTab === MAIN_TAB_VALUE || selectedEntityView?.includeActions);
|
|
495
|
+
|
|
288
496
|
const customViewsView: React.ReactNode[] | undefined = customViews && resolvedEntityViews
|
|
289
497
|
.map(
|
|
290
498
|
(customView, colIndex) => {
|
|
291
499
|
if (!customView)
|
|
292
500
|
return null;
|
|
293
|
-
if (
|
|
501
|
+
if (selectedTab !== customView.key)
|
|
294
502
|
return null;
|
|
295
503
|
const Builder = customView.Builder;
|
|
296
504
|
if (!Builder) {
|
|
@@ -298,7 +506,7 @@ export function EntityEditView<M extends Record<string, any>, UserType extends U
|
|
|
298
506
|
return null;
|
|
299
507
|
}
|
|
300
508
|
return <div
|
|
301
|
-
className={
|
|
509
|
+
className={cls(defaultBorderMixin,
|
|
302
510
|
"relative flex-grow w-full h-full overflow-auto ")}
|
|
303
511
|
key={`custom_view_${customView.key}`}
|
|
304
512
|
role="tabpanel">
|
|
@@ -306,7 +514,7 @@ export function EntityEditView<M extends Record<string, any>, UserType extends U
|
|
|
306
514
|
{formContext && <Builder
|
|
307
515
|
collection={collection}
|
|
308
516
|
entity={usedEntity}
|
|
309
|
-
modifiedValues={
|
|
517
|
+
modifiedValues={formex.values ?? usedEntity?.values}
|
|
310
518
|
formContext={formContext}
|
|
311
519
|
/>}
|
|
312
520
|
</ErrorBoundary>
|
|
@@ -323,7 +531,7 @@ export function EntityEditView<M extends Record<string, any>, UserType extends U
|
|
|
323
531
|
(subcollection, colIndex) => {
|
|
324
532
|
const subcollectionId = subcollection.id ?? subcollection.path;
|
|
325
533
|
const fullPath = usedEntity ? `${path}/${usedEntity?.id}/${removeInitialAndTrailingSlashes(subcollectionId)}` : undefined;
|
|
326
|
-
if (
|
|
534
|
+
if (selectedTab !== subcollectionId)
|
|
327
535
|
return null;
|
|
328
536
|
return (
|
|
329
537
|
<div
|
|
@@ -359,21 +567,18 @@ export function EntityEditView<M extends Record<string, any>, UserType extends U
|
|
|
359
567
|
}, []);
|
|
360
568
|
|
|
361
569
|
const onSideTabClick = (value: string) => {
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
570
|
+
setSelectedTab(value);
|
|
571
|
+
if (status === "existing") {
|
|
572
|
+
sideEntityController.replace({
|
|
573
|
+
path,
|
|
574
|
+
entityId,
|
|
575
|
+
selectedSubPath: value === MAIN_TAB_VALUE ? undefined : value,
|
|
576
|
+
updateUrl: true,
|
|
577
|
+
collection,
|
|
578
|
+
});
|
|
579
|
+
}
|
|
370
580
|
};
|
|
371
581
|
|
|
372
|
-
const onValuesChanged = useCallback((values?: EntityValues<M>) => {
|
|
373
|
-
modifiedValuesRef.current = values;
|
|
374
|
-
}, []);
|
|
375
|
-
|
|
376
|
-
// eslint-disable-next-line n/handle-callback-err
|
|
377
582
|
const onIdUpdateError = useCallback((error: any) => {
|
|
378
583
|
snackbarController.open({
|
|
379
584
|
type: "error",
|
|
@@ -390,28 +595,344 @@ export function EntityEditView<M extends Record<string, any>, UserType extends U
|
|
|
390
595
|
: undefined);
|
|
391
596
|
}, []);
|
|
392
597
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
598
|
+
// useEffect(() => {
|
|
599
|
+
// baseDataSourceValuesRef.current = getDataSourceEntityValues(initialResolvedCollection, status, entity);
|
|
600
|
+
// const initialValues = formex.initialValues;
|
|
601
|
+
// if (!formex.isSubmitting && initialValues && status === "existing") {
|
|
602
|
+
// setUnderlyingChanges(
|
|
603
|
+
// Object.entries(resolvedCollection.properties)
|
|
604
|
+
// .map(([key, property]) => {
|
|
605
|
+
// if (isHidden(property)) {
|
|
606
|
+
// return {};
|
|
607
|
+
// }
|
|
608
|
+
// const initialValue = initialValues[key];
|
|
609
|
+
// const latestValue = baseDataSourceValuesRef.current[key];
|
|
610
|
+
// if (!equal(initialValue, latestValue)) {
|
|
611
|
+
// return { [key]: latestValue };
|
|
612
|
+
// }
|
|
613
|
+
// return {};
|
|
614
|
+
// })
|
|
615
|
+
// .reduce((a, b) => ({ ...a, ...b }), {}) as Partial<EntityValues<M>>
|
|
616
|
+
// );
|
|
617
|
+
// } else {
|
|
618
|
+
// setUnderlyingChanges({});
|
|
619
|
+
// }
|
|
620
|
+
// }, [entity, initialResolvedCollection, status]);
|
|
621
|
+
|
|
622
|
+
const pluginActions: React.ReactNode[] = [];
|
|
623
|
+
|
|
624
|
+
const plugins = customizationController.plugins;
|
|
625
|
+
|
|
626
|
+
if (plugins && inputCollection) {
|
|
627
|
+
const actionProps: PluginFormActionProps = {
|
|
628
|
+
entityId,
|
|
629
|
+
path,
|
|
630
|
+
status,
|
|
631
|
+
collection: inputCollection,
|
|
632
|
+
context,
|
|
633
|
+
currentEntityId: entityId,
|
|
634
|
+
formContext
|
|
635
|
+
};
|
|
636
|
+
pluginActions.push(...plugins.map((plugin, i) => (
|
|
637
|
+
plugin.form?.Actions
|
|
638
|
+
? <plugin.form.Actions
|
|
639
|
+
key={`actions_${plugin.key}`} {...actionProps}/>
|
|
640
|
+
: null
|
|
641
|
+
)).filter(Boolean));
|
|
396
642
|
}
|
|
397
643
|
|
|
644
|
+
const titlePropertyKey = getEntityTitlePropertyKey(resolvedCollection, customizationController.propertyConfigs);
|
|
645
|
+
const title = formex.values && titlePropertyKey ? getValueInPath(formex.values, titlePropertyKey) : undefined;
|
|
646
|
+
|
|
647
|
+
const onIdUpdate = inputCollection.callbacks?.onIdUpdate;
|
|
648
|
+
|
|
649
|
+
const doOnIdUpdate = useCallback(async () => {
|
|
650
|
+
if (onIdUpdate && formex.values && (status === "new" || status === "copy")) {
|
|
651
|
+
setCustomIdLoading(true);
|
|
652
|
+
try {
|
|
653
|
+
const updatedId = await onIdUpdate({
|
|
654
|
+
collection: resolvedCollection,
|
|
655
|
+
path,
|
|
656
|
+
entityId,
|
|
657
|
+
values: formex.values,
|
|
658
|
+
context
|
|
659
|
+
});
|
|
660
|
+
setEntityId(updatedId);
|
|
661
|
+
} catch (e) {
|
|
662
|
+
onIdUpdateError?.(e);
|
|
663
|
+
console.error(e);
|
|
664
|
+
}
|
|
665
|
+
setCustomIdLoading(false);
|
|
666
|
+
}
|
|
667
|
+
}, [entityId, formex.values, status]);
|
|
668
|
+
|
|
669
|
+
useEffect(() => {
|
|
670
|
+
doOnIdUpdate();
|
|
671
|
+
}, [doOnIdUpdate]);
|
|
672
|
+
|
|
673
|
+
const [underlyingChanges, setUnderlyingChanges] = useState<Partial<EntityValues<M>>>({});
|
|
674
|
+
|
|
675
|
+
const uniqueFieldValidator: CustomFieldValidator = useCallback(({
|
|
676
|
+
name,
|
|
677
|
+
value,
|
|
678
|
+
property
|
|
679
|
+
}) => dataSource.checkUniqueField(path, name, value, entityId, collection),
|
|
680
|
+
[dataSource, path, entityId]);
|
|
681
|
+
|
|
682
|
+
const validationSchema = useMemo(() => entityId
|
|
683
|
+
? getYupEntitySchema(
|
|
684
|
+
entityId,
|
|
685
|
+
resolvedCollection.properties,
|
|
686
|
+
uniqueFieldValidator)
|
|
687
|
+
: undefined,
|
|
688
|
+
[entityId, resolvedCollection.properties, uniqueFieldValidator]);
|
|
689
|
+
|
|
690
|
+
const getActionsForEntity = useCallback(({
|
|
691
|
+
entity,
|
|
692
|
+
customEntityActions
|
|
693
|
+
}: {
|
|
694
|
+
entity?: Entity<M>,
|
|
695
|
+
customEntityActions?: EntityAction[]
|
|
696
|
+
}): EntityAction[] => {
|
|
697
|
+
const createEnabled = canCreateEntity(inputCollection, authController, path, null);
|
|
698
|
+
const deleteEnabled = entity ? canDeleteEntity(inputCollection, authController, path, entity) : true;
|
|
699
|
+
const actions: EntityAction[] = [];
|
|
700
|
+
if (createEnabled)
|
|
701
|
+
actions.push(copyEntityAction);
|
|
702
|
+
if (deleteEnabled)
|
|
703
|
+
actions.push(deleteEntityAction);
|
|
704
|
+
if (customEntityActions)
|
|
705
|
+
actions.push(...customEntityActions);
|
|
706
|
+
return actions;
|
|
707
|
+
}, [authController, inputCollection, path]);
|
|
708
|
+
|
|
709
|
+
const modified = formex.dirty;
|
|
710
|
+
useEffect(() => {
|
|
711
|
+
if (!autoSave) {
|
|
712
|
+
onValuesAreModified(modified);
|
|
713
|
+
} else {
|
|
714
|
+
if (formex.values && !equal(formex.values, lastSavedValues.current)) {
|
|
715
|
+
save(formex.values);
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
}, [modified, formex.values]);
|
|
719
|
+
|
|
720
|
+
useEffect(() => {
|
|
721
|
+
if (!autoSave && !formex.isSubmitting && underlyingChanges && entity) {
|
|
722
|
+
// we update the form fields from the Firestore data
|
|
723
|
+
// if they were not touched
|
|
724
|
+
Object.entries(underlyingChanges).forEach(([key, value]) => {
|
|
725
|
+
const formValue = formex.values[key];
|
|
726
|
+
if (!equal(value, formValue) && !formex.touched[key]) {
|
|
727
|
+
console.debug("Updated value from the datasource:", key, value);
|
|
728
|
+
formex.setFieldValue(key, value !== undefined ? value : null);
|
|
729
|
+
}
|
|
730
|
+
});
|
|
731
|
+
}
|
|
732
|
+
}, [formex.isSubmitting, autoSave, underlyingChanges, entity, formex.values, formex.touched, formex.setFieldValue]);
|
|
733
|
+
|
|
734
|
+
const formFields = (
|
|
735
|
+
<>
|
|
736
|
+
{(getFormFieldKeys(resolvedCollection))
|
|
737
|
+
.map((key) => {
|
|
738
|
+
|
|
739
|
+
const property = resolvedCollection.properties[key];
|
|
740
|
+
if (property) {
|
|
741
|
+
|
|
742
|
+
const underlyingValueHasChanged: boolean =
|
|
743
|
+
!!underlyingChanges &&
|
|
744
|
+
Object.keys(underlyingChanges).includes(key) &&
|
|
745
|
+
formex.touched[key];
|
|
746
|
+
|
|
747
|
+
const disabled = (!autoSave && formex.isSubmitting) || isReadOnly(property) || Boolean(property.disabled);
|
|
748
|
+
const hidden = isHidden(property);
|
|
749
|
+
if (hidden) return null;
|
|
750
|
+
const cmsFormFieldProps: PropertyFieldBindingProps<any, M> = {
|
|
751
|
+
propertyKey: key,
|
|
752
|
+
disabled,
|
|
753
|
+
property,
|
|
754
|
+
includeDescription: property.description || property.longDescription,
|
|
755
|
+
underlyingValueHasChanged: underlyingValueHasChanged && !autoSave,
|
|
756
|
+
context: formContext,
|
|
757
|
+
partOfArray: false,
|
|
758
|
+
minimalistView: false,
|
|
759
|
+
autoFocus: false
|
|
760
|
+
};
|
|
761
|
+
|
|
762
|
+
return (
|
|
763
|
+
<div id={`form_field_${key}`}
|
|
764
|
+
key={`field_${resolvedCollection.name}_${key}`}>
|
|
765
|
+
<ErrorBoundary>
|
|
766
|
+
<PropertyFieldBinding {...cmsFormFieldProps}/>
|
|
767
|
+
</ErrorBoundary>
|
|
768
|
+
</div>
|
|
769
|
+
);
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
const additionalField = resolvedCollection.additionalFields?.find(f => f.key === key);
|
|
773
|
+
if (additionalField && entity) {
|
|
774
|
+
const Builder = additionalField.Builder;
|
|
775
|
+
if (!Builder && !additionalField.value) {
|
|
776
|
+
throw new Error("When using additional fields you need to provide a Builder or a value");
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
const child = Builder
|
|
780
|
+
? <Builder entity={entity} context={context}/>
|
|
781
|
+
: <>
|
|
782
|
+
{additionalField.value?.({
|
|
783
|
+
entity,
|
|
784
|
+
context
|
|
785
|
+
})?.toString()}
|
|
786
|
+
</>;
|
|
787
|
+
return (
|
|
788
|
+
<div>
|
|
789
|
+
<LabelWithIconAndTooltip
|
|
790
|
+
propertyKey={key}
|
|
791
|
+
icon={<NotesIcon size={"small"}/>}
|
|
792
|
+
title={additionalField.name}
|
|
793
|
+
className={"text-text-secondary dark:text-text-secondary-dark ml-3.5"}/>
|
|
794
|
+
<div
|
|
795
|
+
className={cls(paperMixin, "min-h-14 p-4 md:p-6 overflow-x-scroll no-scrollbar")}>
|
|
796
|
+
|
|
797
|
+
<ErrorBoundary>
|
|
798
|
+
{child}
|
|
799
|
+
</ErrorBoundary>
|
|
800
|
+
|
|
801
|
+
</div>
|
|
802
|
+
</div>
|
|
803
|
+
);
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
console.warn(`Property ${key} not found in collection ${resolvedCollection.name} in properties or additional fields. Skipping.`);
|
|
807
|
+
return null;
|
|
808
|
+
})
|
|
809
|
+
.filter(Boolean)}
|
|
810
|
+
|
|
811
|
+
</>
|
|
812
|
+
);
|
|
813
|
+
|
|
814
|
+
const disabled = formex.isSubmitting || (!modified && status === "existing");
|
|
815
|
+
const formRef = React.useRef<HTMLDivElement>(null);
|
|
816
|
+
|
|
817
|
+
const entityActions = getActionsForEntity({
|
|
818
|
+
entity,
|
|
819
|
+
customEntityActions: inputCollection.entityActions
|
|
820
|
+
});
|
|
821
|
+
const formActions = entityActions.filter(a => a.includeInForm === undefined || a.includeInForm);
|
|
822
|
+
|
|
823
|
+
const dialogActions = <DialogActions position={"absolute"}>
|
|
824
|
+
|
|
825
|
+
{savingError &&
|
|
826
|
+
<div className="text-right">
|
|
827
|
+
<Typography color={"error"}>
|
|
828
|
+
{savingError.message}
|
|
829
|
+
</Typography>
|
|
830
|
+
</div>}
|
|
831
|
+
|
|
832
|
+
{entity && formActions.length > 0 && <div className="flex-grow flex overflow-auto no-scrollbar">
|
|
833
|
+
{formActions.map(action => (
|
|
834
|
+
<IconButton
|
|
835
|
+
key={action.name}
|
|
836
|
+
color="primary"
|
|
837
|
+
onClick={(event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
|
838
|
+
event.stopPropagation();
|
|
839
|
+
if (entity)
|
|
840
|
+
action.onClick({
|
|
841
|
+
entity,
|
|
842
|
+
fullPath: resolvedCollection.path,
|
|
843
|
+
collection: resolvedCollection,
|
|
844
|
+
context,
|
|
845
|
+
sideEntityController
|
|
846
|
+
});
|
|
847
|
+
}}>
|
|
848
|
+
{action.icon}
|
|
849
|
+
</IconButton>
|
|
850
|
+
))}
|
|
851
|
+
</div>}
|
|
852
|
+
{formex.isSubmitting && <CircularProgress size={"small"}/>}
|
|
853
|
+
<Button
|
|
854
|
+
variant="text"
|
|
855
|
+
disabled={disabled || formex.isSubmitting}
|
|
856
|
+
type="reset">
|
|
857
|
+
{status === "existing" ? "Discard" : "Clear"}
|
|
858
|
+
</Button>
|
|
859
|
+
|
|
860
|
+
<Button
|
|
861
|
+
variant="text"
|
|
862
|
+
color="primary"
|
|
863
|
+
type="submit"
|
|
864
|
+
disabled={disabled || formex.isSubmitting}
|
|
865
|
+
onClick={() => {
|
|
866
|
+
closeAfterSaveRef.current = false;
|
|
867
|
+
}}>
|
|
868
|
+
{status === "existing" && "Save"}
|
|
869
|
+
{status === "copy" && "Create copy"}
|
|
870
|
+
{status === "new" && "Create"}
|
|
871
|
+
</Button>
|
|
872
|
+
|
|
873
|
+
<Button
|
|
874
|
+
variant="filled"
|
|
875
|
+
color="primary"
|
|
876
|
+
type="submit"
|
|
877
|
+
disabled={disabled || formex.isSubmitting}
|
|
878
|
+
onClick={() => {
|
|
879
|
+
closeAfterSaveRef.current = true;
|
|
880
|
+
}}>
|
|
881
|
+
{status === "existing" && "Save and close"}
|
|
882
|
+
{status === "copy" && "Create copy and close"}
|
|
883
|
+
{status === "new" && "Create and close"}
|
|
884
|
+
</Button>
|
|
885
|
+
|
|
886
|
+
</DialogActions>;
|
|
887
|
+
|
|
398
888
|
function buildForm() {
|
|
399
|
-
|
|
400
|
-
let form =
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
889
|
+
|
|
890
|
+
let form = <>
|
|
891
|
+
|
|
892
|
+
{pluginActions.length > 0 && <div
|
|
893
|
+
className={cls("w-full flex justify-end items-center sticky top-0 right-0 left-0 z-10 bg-opacity-60 bg-surface-accent-200 dark:bg-opacity-60 dark:bg-surface-accent-800 backdrop-blur-md")}>
|
|
894
|
+
{pluginActions}
|
|
895
|
+
</div>}
|
|
896
|
+
|
|
897
|
+
<div className="pt-12 pb-16 pl-4 sm:px-8 md:px-10">
|
|
898
|
+
<div
|
|
899
|
+
className={`w-full py-2 flex flex-col items-start mt-${4 + (pluginActions ? 8 : 0)} lg:mt-${8 + (pluginActions ? 8 : 0)} mb-8`}>
|
|
900
|
+
|
|
901
|
+
<Typography
|
|
902
|
+
className={"mt-4 flex-grow line-clamp-1 " + inputCollection.hideIdFromForm ? "mb-2" : "mb-0"}
|
|
903
|
+
variant={"h4"}>{title ?? inputCollection.singularName ?? inputCollection.name}
|
|
904
|
+
</Typography>
|
|
905
|
+
<Alert color={"base"} className={"w-full"} size={"small"}>
|
|
906
|
+
<code className={"text-xs select-all"}>{path}/{entityId}</code>
|
|
907
|
+
</Alert>
|
|
908
|
+
</div>
|
|
909
|
+
|
|
910
|
+
{!collection.hideIdFromForm &&
|
|
911
|
+
<CustomIdField customId={inputCollection.customId}
|
|
912
|
+
entityId={entityId}
|
|
913
|
+
status={status}
|
|
914
|
+
onChange={setEntityId}
|
|
915
|
+
error={entityIdError}
|
|
916
|
+
loading={customIdLoading}
|
|
917
|
+
entity={entity}/>}
|
|
918
|
+
|
|
919
|
+
{entityId && formContext && <>
|
|
920
|
+
<div className="mt-12 flex flex-col gap-8"
|
|
921
|
+
ref={formRef}>
|
|
922
|
+
|
|
923
|
+
{formFields}
|
|
924
|
+
|
|
925
|
+
<ErrorFocus containerRef={formRef}/>
|
|
926
|
+
|
|
927
|
+
</div>
|
|
928
|
+
|
|
929
|
+
<div className="h-14"/>
|
|
930
|
+
|
|
931
|
+
</>}
|
|
932
|
+
|
|
933
|
+
</div>
|
|
934
|
+
</>;
|
|
935
|
+
|
|
415
936
|
if (plugins) {
|
|
416
937
|
plugins.forEach((plugin: FireCMSPlugin) => {
|
|
417
938
|
if (plugin.form?.provider) {
|
|
@@ -421,8 +942,6 @@ export function EntityEditView<M extends Record<string, any>, UserType extends U
|
|
|
421
942
|
path={path}
|
|
422
943
|
collection={collection}
|
|
423
944
|
onDiscard={onDiscard}
|
|
424
|
-
onValuesChanged={onValuesChanged}
|
|
425
|
-
onModified={onModified}
|
|
426
945
|
entity={usedEntity}
|
|
427
946
|
context={context}
|
|
428
947
|
formContext={formContext}
|
|
@@ -436,7 +955,7 @@ export function EntityEditView<M extends Record<string, any>, UserType extends U
|
|
|
436
955
|
return <ErrorBoundary>{form}</ErrorBoundary>;
|
|
437
956
|
}
|
|
438
957
|
|
|
439
|
-
const
|
|
958
|
+
const entityView = (readOnly === undefined)
|
|
440
959
|
? <></>
|
|
441
960
|
: (!readOnly
|
|
442
961
|
? buildForm()
|
|
@@ -451,6 +970,7 @@ export function EntityEditView<M extends Record<string, any>, UserType extends U
|
|
|
451
970
|
entity={usedEntity as Entity<M>}
|
|
452
971
|
path={path}
|
|
453
972
|
collection={collection}/>
|
|
973
|
+
|
|
454
974
|
</>
|
|
455
975
|
));
|
|
456
976
|
|
|
@@ -475,87 +995,132 @@ export function EntityEditView<M extends Record<string, any>, UserType extends U
|
|
|
475
995
|
</Tab>
|
|
476
996
|
);
|
|
477
997
|
|
|
998
|
+
useEffect(() => {
|
|
999
|
+
if (entityId && onIdChange)
|
|
1000
|
+
onIdChange(entityId);
|
|
1001
|
+
}, [entityId, onIdChange]);
|
|
1002
|
+
|
|
478
1003
|
return (
|
|
479
|
-
<
|
|
480
|
-
className="flex flex-col h-full w-full transition-width duration-250 ease-in-out">
|
|
481
|
-
{
|
|
482
|
-
<>
|
|
1004
|
+
<Formex value={formex}>
|
|
483
1005
|
|
|
484
|
-
|
|
485
|
-
className={cn(defaultBorderMixin, "no-scrollbar border-b pl-2 pr-2 pt-1 flex items-end overflow-scroll bg-gray-50 dark:bg-gray-950")}>
|
|
486
|
-
|
|
487
|
-
<div
|
|
488
|
-
className="pb-1 self-center">
|
|
489
|
-
<IconButton
|
|
490
|
-
onClick={() => {
|
|
491
|
-
onClose?.();
|
|
492
|
-
return sideDialogContext.close(false);
|
|
493
|
-
}}
|
|
494
|
-
size="large">
|
|
495
|
-
<CloseIcon/>
|
|
496
|
-
</IconButton>
|
|
497
|
-
</div>
|
|
498
|
-
|
|
499
|
-
<div className={"flex-grow"}/>
|
|
500
|
-
|
|
501
|
-
{globalLoading && <div
|
|
502
|
-
className="self-center">
|
|
503
|
-
<CircularProgress size={"small"}/>
|
|
504
|
-
</div>}
|
|
505
|
-
|
|
506
|
-
<Tabs
|
|
507
|
-
value={selectedTabRef.current}
|
|
508
|
-
onValueChange={(value) => {
|
|
509
|
-
onSideTabClick(value);
|
|
510
|
-
}}
|
|
511
|
-
className="pl-4 pr-4 pt-0">
|
|
512
|
-
|
|
513
|
-
<Tab
|
|
514
|
-
disabled={!hasAdditionalViews}
|
|
515
|
-
value={MAIN_TAB_VALUE}
|
|
516
|
-
className={`${
|
|
517
|
-
!hasAdditionalViews ? "hidden" : ""
|
|
518
|
-
} text-sm min-w-[140px]`}
|
|
519
|
-
>{collection.singularName ?? collection.name}</Tab>
|
|
520
|
-
|
|
521
|
-
{customViewTabs}
|
|
522
|
-
|
|
523
|
-
{subcollectionTabs}
|
|
524
|
-
</Tabs>
|
|
1006
|
+
<div className="flex flex-col h-full w-full">
|
|
525
1007
|
|
|
526
|
-
|
|
1008
|
+
<div
|
|
1009
|
+
className={cls(defaultBorderMixin, "no-scrollbar h-16 border-b pl-2 pr-2 pt-1 flex items-end overflow-scroll bg-surface-50 dark:bg-surface-950")}>
|
|
527
1010
|
|
|
528
1011
|
<div
|
|
529
|
-
className=
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
1012
|
+
className="pb-1 self-center">
|
|
1013
|
+
<IconButton
|
|
1014
|
+
onClick={() => {
|
|
1015
|
+
onClose?.();
|
|
1016
|
+
return sideDialogContext.close(false);
|
|
1017
|
+
}}>
|
|
1018
|
+
<CloseIcon size={"small"}/>
|
|
1019
|
+
</IconButton>
|
|
1020
|
+
</div>
|
|
537
1021
|
|
|
538
|
-
|
|
539
|
-
role="tabpanel"
|
|
540
|
-
hidden={!mainViewVisible}
|
|
541
|
-
id={`form_${path}`}
|
|
542
|
-
className={" w-full"}>
|
|
1022
|
+
<div className={"flex-grow"}/>
|
|
543
1023
|
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
1024
|
+
{globalLoading && <div
|
|
1025
|
+
className="self-center">
|
|
1026
|
+
<CircularProgress size={"small"}/>
|
|
1027
|
+
</div>}
|
|
547
1028
|
|
|
548
|
-
|
|
1029
|
+
<Tabs
|
|
1030
|
+
value={selectedTab}
|
|
1031
|
+
onValueChange={(value) => {
|
|
1032
|
+
onSideTabClick(value);
|
|
1033
|
+
}}
|
|
1034
|
+
innerClassName="pl-4 pr-4 pt-0">
|
|
549
1035
|
|
|
550
|
-
|
|
1036
|
+
<Tab
|
|
1037
|
+
disabled={!hasAdditionalViews}
|
|
1038
|
+
value={MAIN_TAB_VALUE}
|
|
1039
|
+
className={`${
|
|
1040
|
+
!hasAdditionalViews ? "hidden" : ""
|
|
1041
|
+
} text-sm min-w-[140px]`}
|
|
1042
|
+
>{collection.singularName ?? collection.name}</Tab>
|
|
551
1043
|
|
|
552
|
-
{
|
|
1044
|
+
{customViewTabs}
|
|
1045
|
+
|
|
1046
|
+
{subcollectionTabs}
|
|
1047
|
+
</Tabs>
|
|
1048
|
+
|
|
1049
|
+
</div>
|
|
1050
|
+
|
|
1051
|
+
<form
|
|
1052
|
+
onSubmit={formex.handleSubmit}
|
|
1053
|
+
onReset={() => {
|
|
1054
|
+
formex.resetForm();
|
|
1055
|
+
return onDiscard && onDiscard();
|
|
1056
|
+
}}
|
|
1057
|
+
noValidate
|
|
1058
|
+
className={"flex-grow h-full flex overflow-auto flex-col w-full"}>
|
|
1059
|
+
|
|
1060
|
+
<div
|
|
1061
|
+
role="tabpanel"
|
|
1062
|
+
hidden={!mainViewVisible}
|
|
1063
|
+
id={`form_${path}`}
|
|
1064
|
+
className={"relative w-full"}>
|
|
1065
|
+
|
|
1066
|
+
{globalLoading
|
|
1067
|
+
? <CircularProgressCenter/>
|
|
1068
|
+
: entityView}
|
|
553
1069
|
|
|
554
1070
|
</div>
|
|
555
1071
|
|
|
556
|
-
|
|
557
|
-
|
|
1072
|
+
{customViewsView}
|
|
1073
|
+
|
|
1074
|
+
{subCollectionsViews}
|
|
1075
|
+
|
|
1076
|
+
{shouldShowEntityActions && dialogActions}
|
|
558
1077
|
|
|
559
|
-
|
|
1078
|
+
</form>
|
|
1079
|
+
|
|
1080
|
+
</div>
|
|
1081
|
+
</Formex>
|
|
560
1082
|
);
|
|
561
1083
|
}
|
|
1084
|
+
|
|
1085
|
+
function getDataSourceEntityValues<M extends object>(initialResolvedCollection: ResolvedEntityCollection,
|
|
1086
|
+
status: "new" | "existing" | "copy",
|
|
1087
|
+
entity: Entity<M> | undefined): Partial<EntityValues<M>> {
|
|
1088
|
+
|
|
1089
|
+
const properties = initialResolvedCollection.properties;
|
|
1090
|
+
if ((status === "existing" || status === "copy") && entity) {
|
|
1091
|
+
return entity.values ?? getDefaultValuesFor(properties);
|
|
1092
|
+
} else if (status === "new") {
|
|
1093
|
+
return getDefaultValuesFor(properties);
|
|
1094
|
+
} else {
|
|
1095
|
+
console.error({
|
|
1096
|
+
status,
|
|
1097
|
+
entity
|
|
1098
|
+
});
|
|
1099
|
+
throw new Error("Form has not been initialised with the correct parameters");
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
export type EntityFormSaveParams<M extends Record<string, any>> = {
|
|
1104
|
+
collection: ResolvedEntityCollection<M>,
|
|
1105
|
+
path: string,
|
|
1106
|
+
entityId: string | undefined,
|
|
1107
|
+
values: EntityValues<M>,
|
|
1108
|
+
previousValues?: EntityValues<M>,
|
|
1109
|
+
closeAfterSave: boolean,
|
|
1110
|
+
autoSave: boolean
|
|
1111
|
+
};
|
|
1112
|
+
|
|
1113
|
+
export function yupToFormErrors(yupError: ValidationError): Record<string, any> {
|
|
1114
|
+
let errors: Record<string, any> = {};
|
|
1115
|
+
if (yupError.inner) {
|
|
1116
|
+
if (yupError.inner.length === 0) {
|
|
1117
|
+
return setIn(errors, yupError.path!, yupError.message);
|
|
1118
|
+
}
|
|
1119
|
+
for (const err of yupError.inner) {
|
|
1120
|
+
if (!getIn(errors, err.path!)) {
|
|
1121
|
+
errors = setIn(errors, err.path!, err.message);
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
return errors;
|
|
1126
|
+
}
|