@firecms/core 3.0.0-canary.99 → 3.0.0-rc.2
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/app/Drawer.d.ts +0 -1
- package/dist/app/Scaffold.d.ts +4 -0
- package/dist/components/ArrayContainer.d.ts +31 -12
- package/dist/components/{DeleteConfirmationDialog.d.ts → ConfirmationDialog.d.ts} +1 -1
- package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +3 -1
- package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +2 -2
- package/dist/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +17 -3
- package/dist/components/EntityCollectionTable/fields/TableReferenceField.d.ts +1 -1
- package/dist/components/EntityCollectionTable/index.d.ts +1 -1
- package/dist/components/EntityCollectionTable/internal/popup_field/PopupFormField.d.ts +6 -3
- package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +8 -0
- package/dist/components/EntityCollectionView/utils.d.ts +3 -0
- package/dist/components/EntityJsonPreview.d.ts +3 -0
- package/dist/components/EntityPreview.d.ts +8 -6
- package/dist/components/HomePage/DefaultHomePage.d.ts +2 -15
- package/dist/components/HomePage/HomePageDnD.d.ts +76 -0
- package/dist/components/HomePage/NavigationCard.d.ts +3 -1
- package/dist/components/HomePage/NavigationCardBinding.d.ts +3 -2
- package/dist/components/HomePage/NavigationGroup.d.ts +8 -1
- package/dist/components/HomePage/RenameGroupDialog.d.ts +9 -0
- package/dist/components/PropertyConfigBadge.d.ts +2 -1
- package/dist/components/PropertyIdCopyTooltip.d.ts +8 -0
- package/dist/components/SelectableTable/SelectableTable.d.ts +13 -3
- package/dist/components/SelectableTable/filters/ReferenceFilterField.d.ts +1 -1
- package/dist/components/UnsavedChangesDialog.d.ts +8 -0
- package/dist/components/UserDisplay.d.ts +7 -0
- package/dist/components/VirtualTable/VirtualTableProps.d.ts +11 -2
- package/dist/components/VirtualTable/fields/VirtualTableUserSelect.d.ts +12 -0
- package/dist/components/common/default_entity_actions.d.ts +0 -2
- package/dist/components/common/index.d.ts +1 -1
- package/dist/components/common/useColumnsIds.d.ts +1 -0
- package/dist/components/common/{useDataSourceEntityCollectionTableController.d.ts → useDataSourceTableController.d.ts} +10 -2
- package/dist/components/common/useDebouncedCallback.d.ts +1 -0
- package/dist/components/common/useScrollRestoration.d.ts +14 -0
- package/dist/components/index.d.ts +3 -1
- package/dist/contexts/BreacrumbsContext.d.ts +8 -0
- package/dist/contexts/InternalUserManagementContext.d.ts +3 -0
- package/dist/core/DefaultAppBar.d.ts +8 -2
- package/dist/core/DrawerNavigationItem.d.ts +2 -1
- package/dist/core/EntityEditView.d.ts +40 -22
- package/dist/core/EntityEditViewFormActions.d.ts +2 -0
- package/dist/core/FireCMS.d.ts +2 -3
- package/dist/core/FireCMSRouter.d.ts +4 -0
- package/dist/core/NavigationRoutes.d.ts +0 -1
- package/dist/core/SideDialogs.d.ts +4 -2
- package/dist/core/field_configs.d.ts +1 -1
- package/dist/core/index.d.ts +2 -1
- package/dist/form/EntityForm.d.ts +50 -0
- package/dist/form/EntityFormActions.d.ts +21 -0
- package/dist/form/PropertyFieldBinding.d.ts +1 -1
- package/dist/form/components/FormEntry.d.ts +6 -0
- package/dist/form/components/FormLayout.d.ts +5 -0
- package/dist/form/components/LabelWithIcon.d.ts +1 -1
- package/dist/form/components/LabelWithIconAndTooltip.d.ts +15 -0
- package/dist/form/components/index.d.ts +3 -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/ReferenceAsStringFieldBinding.d.ts +9 -0
- 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 +4 -10
- package/dist/form/field_bindings/SwitchFieldBinding.d.ts +1 -2
- package/dist/form/field_bindings/TextFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/UserSelectFieldBinding.d.ts +12 -0
- package/dist/form/index.d.ts +17 -16
- package/dist/form/useClearRestoreValue.d.ts +2 -2
- package/dist/hooks/data/delete.d.ts +4 -4
- package/dist/hooks/data/save.d.ts +3 -3
- package/dist/hooks/data/useCollectionFetch.d.ts +1 -1
- package/dist/hooks/data/useEntityFetch.d.ts +4 -3
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/useAuthController.d.ts +1 -1
- package/dist/hooks/useBreadcrumbsController.d.ts +26 -0
- package/dist/hooks/useBuildNavigationController.d.ts +57 -12
- package/dist/hooks/useCollapsedGroups.d.ts +9 -0
- package/dist/hooks/useFireCMSContext.d.ts +1 -1
- package/dist/hooks/useInternalUserManagementController.d.ts +12 -0
- package/dist/hooks/useModeController.d.ts +1 -2
- package/dist/hooks/useProjectLog.d.ts +7 -1
- package/dist/hooks/useResolvedNavigationFrom.d.ts +3 -3
- package/dist/hooks/useValidateAuthenticator.d.ts +3 -3
- package/dist/index.es.js +20480 -14434
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +20250 -14209
- package/dist/index.umd.js.map +1 -1
- package/dist/internal/useBuildDataSource.d.ts +3 -2
- package/dist/internal/useBuildSideEntityController.d.ts +3 -3
- package/dist/internal/useUnsavedChangesDialog.d.ts +7 -9
- package/dist/preview/PropertyPreviewProps.d.ts +1 -1
- package/dist/preview/components/EnumValuesChip.d.ts +1 -1
- package/dist/preview/components/ReferencePreview.d.ts +2 -2
- package/dist/preview/components/UserPreview.d.ts +8 -0
- package/dist/preview/index.d.ts +1 -0
- package/dist/preview/util.d.ts +3 -3
- package/dist/routes/CustomCMSRoute.d.ts +4 -0
- package/dist/routes/FireCMSRoute.d.ts +1 -0
- package/dist/routes/HomePageRoute.d.ts +3 -0
- package/dist/types/analytics.d.ts +1 -1
- package/dist/types/auth.d.ts +7 -9
- package/dist/types/collections.d.ts +88 -25
- package/dist/types/customization_controller.d.ts +8 -0
- package/dist/types/datasource.d.ts +19 -17
- package/dist/types/dialogs_controller.d.ts +7 -3
- package/dist/types/entities.d.ts +7 -2
- package/dist/types/entity_actions.d.ts +58 -8
- 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 +43 -17
- package/dist/types/firecms.d.ts +31 -3
- package/dist/types/firecms_context.d.ts +17 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/internal_user_management.d.ts +20 -0
- package/dist/types/navigation.d.ts +60 -17
- package/dist/types/permissions.d.ts +4 -4
- package/dist/types/plugins.d.ts +44 -9
- package/dist/types/properties.d.ts +74 -22
- package/dist/types/property_config.d.ts +1 -3
- package/dist/types/roles.d.ts +3 -0
- package/dist/types/side_dialogs_controller.d.ts +10 -0
- package/dist/types/side_entity_controller.d.ts +14 -1
- package/dist/types/storage.d.ts +75 -0
- package/dist/types/user.d.ts +2 -1
- package/dist/util/builders.d.ts +3 -3
- package/dist/util/callbacks.d.ts +2 -0
- package/dist/util/createFormexStub.d.ts +2 -0
- package/dist/util/entities.d.ts +2 -2
- package/dist/util/entity_actions.d.ts +2 -0
- package/dist/util/entity_cache.d.ts +23 -0
- package/dist/util/icon_synonyms.d.ts +0 -1
- package/dist/util/icons.d.ts +5 -2
- package/dist/util/index.d.ts +3 -0
- package/dist/util/navigation_from_path.d.ts +10 -1
- package/dist/util/navigation_utils.d.ts +13 -1
- package/dist/util/objects.d.ts +2 -1
- package/dist/util/permissions.d.ts +4 -4
- package/dist/util/property_utils.d.ts +4 -4
- package/dist/util/references.d.ts +2 -2
- package/dist/util/resolutions.d.ts +30 -6
- package/dist/util/storage.d.ts +1 -1
- package/dist/util/useStorageUploadController.d.ts +2 -2
- package/package.json +133 -125
- package/src/app/Drawer.tsx +0 -1
- package/src/app/Scaffold.tsx +33 -29
- package/src/components/ArrayContainer.tsx +447 -229
- package/src/components/CircularProgressCenter.tsx +1 -1
- package/src/components/ClearFilterSortButton.tsx +1 -1
- package/src/components/{DeleteConfirmationDialog.tsx → ConfirmationDialog.tsx} +12 -11
- package/src/components/DeleteEntityDialog.tsx +13 -20
- package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +59 -25
- package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +23 -17
- package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +20 -3
- package/src/components/EntityCollectionTable/PropertyTableCell.tsx +47 -9
- package/src/components/EntityCollectionTable/fields/TableReferenceField.tsx +21 -16
- package/src/components/EntityCollectionTable/fields/TableStorageUpload.tsx +6 -12
- package/src/components/EntityCollectionTable/index.tsx +1 -1
- package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +6 -6
- package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +35 -26
- package/src/components/EntityCollectionTable/internal/EntityTableCellActions.tsx +20 -8
- package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +132 -101
- package/src/components/EntityCollectionTable/internal/popup_field/useDraggable.tsx +9 -9
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +178 -85
- package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +7 -4
- package/src/components/EntityCollectionView/useSelectionController.tsx +5 -4
- package/src/components/EntityCollectionView/utils.ts +19 -0
- package/src/components/EntityJsonPreview.tsx +66 -0
- package/src/components/EntityPreview.tsx +75 -57
- package/src/components/EntityView.tsx +8 -5
- package/src/components/ErrorView.tsx +3 -3
- package/src/components/FireCMSLogo.tsx +7 -51
- package/src/components/HomePage/DefaultHomePage.tsx +506 -161
- package/src/components/HomePage/FavouritesView.tsx +9 -14
- package/src/components/HomePage/HomePageDnD.tsx +600 -0
- package/src/components/HomePage/NavigationCard.tsx +47 -38
- package/src/components/HomePage/NavigationCardBinding.tsx +16 -15
- package/src/components/HomePage/NavigationGroup.tsx +144 -30
- package/src/components/HomePage/RenameGroupDialog.tsx +123 -0
- package/src/components/HomePage/SmallNavigationCard.tsx +1 -2
- package/src/components/NotFoundPage.tsx +2 -2
- package/src/components/PropertyConfigBadge.tsx +10 -4
- package/src/components/PropertyIdCopyTooltip.tsx +47 -0
- package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +22 -13
- package/src/components/SearchIconsView.tsx +2 -2
- package/src/components/SelectableTable/SelectableTable.tsx +154 -142
- package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +4 -2
- package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +10 -8
- package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +60 -11
- package/src/components/UnsavedChangesDialog.tsx +46 -0
- package/src/components/UserDisplay.tsx +55 -0
- package/src/components/VirtualTable/VirtualTable.tsx +65 -44
- package/src/components/VirtualTable/VirtualTableCell.tsx +0 -8
- package/src/components/VirtualTable/VirtualTableHeader.tsx +8 -8
- package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +1 -1
- package/src/components/VirtualTable/VirtualTableProps.tsx +12 -2
- package/src/components/VirtualTable/VirtualTableRow.tsx +1 -1
- package/src/components/VirtualTable/fields/VirtualTableDateField.tsx +4 -4
- package/src/components/VirtualTable/fields/VirtualTableInput.tsx +2 -2
- package/src/components/VirtualTable/fields/VirtualTableNumberInput.tsx +2 -1
- package/src/components/VirtualTable/fields/VirtualTableSelect.tsx +16 -28
- package/src/components/VirtualTable/fields/VirtualTableUserSelect.tsx +99 -0
- package/src/components/common/default_entity_actions.tsx +62 -42
- package/src/components/common/index.ts +1 -1
- package/src/components/common/useColumnsIds.tsx +2 -9
- package/src/components/common/useDataSourceTableController.tsx +420 -0
- package/src/components/common/useDebouncedCallback.tsx +20 -0
- package/src/components/common/useScrollRestoration.tsx +68 -0
- package/src/components/common/useTableSearchHelper.ts +1 -0
- package/src/components/index.tsx +4 -1
- package/src/contexts/BreacrumbsContext.tsx +38 -0
- package/src/contexts/DialogsProvider.tsx +3 -2
- package/src/contexts/InternalUserManagementContext.tsx +4 -0
- package/src/contexts/ModeController.tsx +1 -3
- package/src/contexts/SnackbarProvider.tsx +2 -0
- package/src/core/DefaultAppBar.tsx +124 -85
- package/src/core/DefaultDrawer.tsx +30 -22
- package/src/core/DrawerNavigationItem.tsx +32 -28
- package/src/core/EntityEditView.tsx +388 -995
- package/src/core/EntityEditViewFormActions.tsx +329 -0
- package/src/core/EntitySidePanel.tsx +88 -20
- package/src/core/FireCMS.tsx +58 -28
- package/src/core/FireCMSRouter.tsx +17 -0
- package/src/core/NavigationRoutes.tsx +23 -32
- package/src/core/SideDialogs.tsx +22 -12
- package/src/core/field_configs.tsx +39 -11
- package/src/core/index.tsx +4 -2
- package/src/form/EntityForm.tsx +814 -0
- package/src/form/EntityFormActions.tsx +211 -0
- package/src/form/PropertyFieldBinding.tsx +59 -41
- package/src/form/components/CustomIdField.tsx +9 -3
- package/src/form/components/FieldHelperText.tsx +1 -1
- package/src/form/components/FormEntry.tsx +22 -0
- package/src/form/components/FormLayout.tsx +16 -0
- package/src/form/components/LabelWithIcon.tsx +30 -19
- package/src/form/components/LabelWithIconAndTooltip.tsx +28 -0
- package/src/form/components/StorageItemPreview.tsx +5 -4
- package/src/form/components/StorageUploadProgress.tsx +2 -3
- package/src/form/components/index.tsx +3 -1
- package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +30 -18
- package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +47 -36
- package/src/form/field_bindings/BlockFieldBinding.tsx +55 -33
- package/src/form/field_bindings/DateTimeFieldBinding.tsx +18 -14
- package/src/form/field_bindings/KeyValueFieldBinding.tsx +19 -15
- package/src/form/field_bindings/MapFieldBinding.tsx +72 -62
- package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +159 -0
- package/src/form/field_bindings/{MultiSelectBinding.tsx → MultiSelectFieldBinding.tsx} +26 -21
- package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +10 -8
- package/src/form/field_bindings/ReferenceAsStringFieldBinding.tsx +135 -0
- package/src/form/field_bindings/ReferenceFieldBinding.tsx +28 -19
- package/src/form/field_bindings/RepeatFieldBinding.tsx +56 -32
- package/src/form/field_bindings/SelectFieldBinding.tsx +22 -13
- package/src/form/field_bindings/StorageUploadFieldBinding.tsx +247 -168
- package/src/form/field_bindings/SwitchFieldBinding.tsx +29 -24
- package/src/form/field_bindings/TextFieldBinding.tsx +28 -24
- package/src/form/field_bindings/UserSelectFieldBinding.tsx +94 -0
- package/src/form/index.tsx +17 -37
- package/src/form/useClearRestoreValue.tsx +2 -2
- package/src/form/validation.ts +12 -6
- package/src/hooks/data/delete.ts +6 -5
- package/src/hooks/data/save.ts +26 -35
- package/src/hooks/data/useCollectionFetch.tsx +3 -3
- package/src/hooks/data/useDataSource.tsx +10 -2
- package/src/hooks/data/useEntityFetch.tsx +10 -6
- package/src/hooks/index.tsx +3 -0
- package/src/hooks/useAuthController.tsx +1 -1
- package/src/hooks/useBreadcrumbsController.tsx +31 -0
- package/src/hooks/useBrowserTitleAndIcon.tsx +1 -1
- package/src/hooks/useBuildModeController.tsx +15 -28
- package/src/hooks/useBuildNavigationController.tsx +386 -124
- package/src/hooks/useCollapsedGroups.ts +64 -0
- package/src/hooks/useFireCMSContext.tsx +9 -35
- package/src/hooks/useInternalUserManagementController.tsx +16 -0
- package/src/hooks/useLargeLayout.tsx +0 -35
- package/src/hooks/useModeController.tsx +1 -2
- package/src/hooks/useProjectLog.tsx +16 -5
- package/src/hooks/useResolvedNavigationFrom.tsx +9 -11
- package/src/hooks/useValidateAuthenticator.tsx +3 -3
- package/src/internal/useBuildDataSource.ts +67 -80
- package/src/internal/useBuildSideDialogsController.tsx +4 -2
- package/src/internal/useBuildSideEntityController.tsx +149 -86
- package/src/internal/useUnsavedChangesDialog.tsx +127 -91
- package/src/preview/PropertyPreview.tsx +36 -12
- package/src/preview/PropertyPreviewProps.tsx +1 -1
- package/src/preview/components/BooleanPreview.tsx +1 -1
- package/src/preview/components/EmptyValue.tsx +1 -1
- package/src/preview/components/EnumValuesChip.tsx +1 -1
- package/src/preview/components/ImagePreview.tsx +10 -9
- package/src/preview/components/ReferencePreview.tsx +10 -18
- package/src/preview/components/UrlComponentPreview.tsx +20 -21
- package/src/preview/components/UserPreview.tsx +27 -0
- package/src/preview/index.ts +1 -0
- package/src/preview/property_previews/ArrayOfMapsPreview.tsx +6 -5
- package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +5 -4
- package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +5 -3
- package/src/preview/property_previews/ArrayOfStringsPreview.tsx +4 -3
- package/src/preview/property_previews/ArrayOneOfPreview.tsx +6 -4
- package/src/preview/property_previews/ArrayPropertyPreview.tsx +6 -4
- package/src/preview/property_previews/MapPropertyPreview.tsx +7 -6
- package/src/preview/property_previews/SkeletonPropertyComponent.tsx +13 -13
- package/src/preview/property_previews/StringPropertyPreview.tsx +2 -2
- package/src/preview/util.ts +10 -10
- package/src/routes/CustomCMSRoute.tsx +21 -0
- package/src/routes/FireCMSRoute.tsx +246 -0
- package/src/routes/HomePageRoute.tsx +17 -0
- package/src/types/analytics.ts +3 -0
- package/src/types/auth.tsx +8 -12
- package/src/types/collections.ts +103 -28
- package/src/types/customization_controller.tsx +9 -0
- package/src/types/datasource.ts +21 -20
- package/src/types/dialogs_controller.tsx +7 -3
- package/src/types/entities.ts +10 -2
- package/src/types/entity_actions.tsx +71 -8
- 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 +52 -19
- package/src/types/firecms.tsx +34 -4
- package/src/types/firecms_context.tsx +18 -1
- package/src/types/index.ts +1 -0
- package/src/types/internal_user_management.ts +24 -0
- package/src/types/navigation.ts +76 -22
- package/src/types/permissions.ts +5 -5
- package/src/types/plugins.tsx +53 -9
- package/src/types/properties.ts +84 -22
- package/src/types/property_config.tsx +2 -2
- package/src/types/roles.ts +3 -0
- package/src/types/side_dialogs_controller.tsx +15 -0
- package/src/types/side_entity_controller.tsx +16 -1
- package/src/types/storage.ts +82 -0
- package/src/types/user.ts +3 -1
- package/src/util/builders.ts +10 -8
- package/src/util/callbacks.ts +119 -0
- package/src/util/createFormexStub.tsx +62 -0
- package/src/util/entities.ts +6 -4
- package/src/util/entity_actions.ts +28 -0
- package/src/util/entity_cache.ts +204 -0
- package/src/util/icon_list.ts +1 -1
- package/src/util/icon_synonyms.ts +0 -1
- package/src/util/icons.tsx +36 -11
- package/src/util/index.ts +3 -0
- package/src/util/join_collections.ts +9 -2
- package/src/util/make_properties_editable.ts +13 -5
- package/src/util/navigation_from_path.ts +33 -12
- package/src/util/navigation_utils.ts +135 -19
- package/src/util/objects.ts +74 -14
- package/src/util/parent_references_from_path.ts +3 -3
- package/src/util/permissions.ts +8 -8
- package/src/util/property_utils.tsx +17 -6
- package/src/util/references.ts +19 -8
- package/src/util/resolutions.ts +93 -24
- package/src/util/storage.ts +6 -2
- package/src/util/useStorageUploadController.tsx +74 -29
- package/dist/components/EntityCollectionTable/internal/popup_field/ElementResizeListener.d.ts +0 -5
- package/dist/components/PropertyIdCopyTooltipContent.d.ts +0 -3
- package/dist/form/PropertiesForm.d.ts +0 -8
- package/dist/form/components/FormikArrayContainer.d.ts +0 -18
- package/dist/form/field_bindings/MarkdownFieldBinding.d.ts +0 -9
- package/src/components/EntityCollectionTable/internal/popup_field/ElementResizeListener.tsx +0 -59
- package/src/components/PropertyIdCopyTooltipContent.tsx +0 -27
- package/src/components/common/useDataSourceEntityCollectionTableController.tsx +0 -236
- package/src/form/PropertiesForm.tsx +0 -81
- package/src/form/components/FormikArrayContainer.tsx +0 -44
- package/src/form/field_bindings/MarkdownFieldBinding.tsx +0 -695
- /package/src/util/{common.tsx → common.ts} +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
2
2
|
import equal from "react-fast-compare"
|
|
3
|
+
import { useBlocker, useNavigate } from "react-router-dom";
|
|
3
4
|
|
|
4
5
|
import {
|
|
5
6
|
AuthController,
|
|
@@ -9,10 +10,13 @@ import {
|
|
|
9
10
|
EntityCollection,
|
|
10
11
|
EntityCollectionsBuilder,
|
|
11
12
|
EntityReference,
|
|
13
|
+
FireCMSPlugin,
|
|
14
|
+
NavigationBlocker,
|
|
12
15
|
NavigationController,
|
|
16
|
+
NavigationEntry,
|
|
17
|
+
NavigationGroupMapping,
|
|
18
|
+
NavigationResult,
|
|
13
19
|
PermissionsBuilder,
|
|
14
|
-
TopNavigationEntry,
|
|
15
|
-
TopNavigationResult,
|
|
16
20
|
User,
|
|
17
21
|
UserConfigurationPersistence
|
|
18
22
|
} from "../types";
|
|
@@ -20,6 +24,7 @@ import {
|
|
|
20
24
|
applyPermissionsFunctionIfEmpty,
|
|
21
25
|
getCollectionByPathOrId,
|
|
22
26
|
mergeDeep,
|
|
27
|
+
removeFunctions,
|
|
23
28
|
removeInitialAndTrailingSlashes,
|
|
24
29
|
resolveCollectionPathIds,
|
|
25
30
|
resolvePermissions
|
|
@@ -29,28 +34,76 @@ import { getParentReferencesFromPath } from "../util/parent_references_from_path
|
|
|
29
34
|
const DEFAULT_BASE_PATH = "/";
|
|
30
35
|
const DEFAULT_COLLECTION_PATH = "/c";
|
|
31
36
|
|
|
32
|
-
export
|
|
37
|
+
export const NAVIGATION_DEFAULT_GROUP_NAME = "Views";
|
|
38
|
+
export const NAVIGATION_ADMIN_GROUP_NAME = "Admin";
|
|
39
|
+
|
|
40
|
+
export type BuildNavigationContextProps<EC extends EntityCollection, USER extends User> = {
|
|
41
|
+
/**
|
|
42
|
+
* Base path for the CMS, used to build the all the URLs.
|
|
43
|
+
* Defaults to "/".
|
|
44
|
+
*/
|
|
33
45
|
basePath?: string,
|
|
46
|
+
/**
|
|
47
|
+
* Base path for the collections, used to build the collection URLs.
|
|
48
|
+
* Defaults to "c" (e.g. "/c/products").
|
|
49
|
+
*/
|
|
34
50
|
baseCollectionPath?: string,
|
|
35
|
-
|
|
51
|
+
/**
|
|
52
|
+
* The auth controller used to manage the user authentication and permissions.
|
|
53
|
+
*/
|
|
54
|
+
authController: AuthController<USER>;
|
|
55
|
+
/**
|
|
56
|
+
* The collections to be used in the CMS.
|
|
57
|
+
* This can be a static array of collections or a function that returns a promise
|
|
58
|
+
* resolving to an array of collections.
|
|
59
|
+
*/
|
|
36
60
|
collections?: EC[] | EntityCollectionsBuilder<EC>;
|
|
61
|
+
/**
|
|
62
|
+
* Optional permissions builder to be applied to the collections.
|
|
63
|
+
* If not provided, the permissions will be resolved from the collection configuration.
|
|
64
|
+
*/
|
|
37
65
|
collectionPermissions?: PermissionsBuilder;
|
|
66
|
+
/**
|
|
67
|
+
* Custom views to be added to the CMS, these will be available in the main navigation.
|
|
68
|
+
* This can be a static array of views or a function that returns a promise
|
|
69
|
+
* resolving to an array of views.
|
|
70
|
+
*/
|
|
38
71
|
views?: CMSView[] | CMSViewsBuilder;
|
|
72
|
+
/**
|
|
73
|
+
* Custom views to be added to the CMS admin navigation.
|
|
74
|
+
* This can be a static array of views or a function that returns a promise
|
|
75
|
+
* resolving to an array of views.
|
|
76
|
+
*/
|
|
39
77
|
adminViews?: CMSView[] | CMSViewsBuilder;
|
|
40
|
-
|
|
78
|
+
/**
|
|
79
|
+
* Controller for storing user preferences.
|
|
80
|
+
*/
|
|
41
81
|
userConfigPersistence?: UserConfigurationPersistence;
|
|
82
|
+
/**
|
|
83
|
+
* Delegate for data source operations, used to resolve collections and views.
|
|
84
|
+
*/
|
|
42
85
|
dataSourceDelegate: DataSourceDelegate;
|
|
43
86
|
/**
|
|
44
|
-
*
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
*
|
|
87
|
+
* Plugins to be used in the CMS.
|
|
88
|
+
*/
|
|
89
|
+
plugins?: FireCMSPlugin[];
|
|
90
|
+
/**
|
|
91
|
+
* Used to define the name of groups and order of the navigation entries.
|
|
92
|
+
*/
|
|
93
|
+
navigationGroupMappings?: NavigationGroupMapping[];
|
|
94
|
+
/**
|
|
95
|
+
* If true, the navigation logic will not be updated until this flag is false
|
|
49
96
|
*/
|
|
50
|
-
|
|
97
|
+
disabled?: boolean;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* @deprecated
|
|
101
|
+
* Use `navigationGroupMappings` instead.
|
|
102
|
+
*/
|
|
103
|
+
viewsOrder?: string[];
|
|
51
104
|
};
|
|
52
105
|
|
|
53
|
-
export function useBuildNavigationController<EC extends EntityCollection,
|
|
106
|
+
export function useBuildNavigationController<EC extends EntityCollection, USER extends User>(props: BuildNavigationContextProps<EC, USER>): NavigationController {
|
|
54
107
|
const {
|
|
55
108
|
basePath = DEFAULT_BASE_PATH,
|
|
56
109
|
baseCollectionPath = DEFAULT_COLLECTION_PATH,
|
|
@@ -60,18 +113,23 @@ export function useBuildNavigationController<EC extends EntityCollection, UserTy
|
|
|
60
113
|
views: viewsProp,
|
|
61
114
|
adminViews: adminViewsProp,
|
|
62
115
|
viewsOrder,
|
|
116
|
+
plugins,
|
|
63
117
|
userConfigPersistence,
|
|
64
118
|
dataSourceDelegate,
|
|
65
|
-
|
|
119
|
+
disabled,
|
|
120
|
+
navigationGroupMappings
|
|
66
121
|
} = props;
|
|
67
122
|
|
|
123
|
+
const navigate = useNavigate();
|
|
124
|
+
|
|
68
125
|
const collectionsRef = useRef<EntityCollection[] | undefined>();
|
|
69
126
|
const viewsRef = useRef<CMSView[] | undefined>();
|
|
70
127
|
const adminViewsRef = useRef<CMSView[] | undefined>();
|
|
128
|
+
const navigationEntriesOrderRef = useRef<string[] | undefined>();
|
|
71
129
|
|
|
72
130
|
const [initialised, setInitialised] = useState<boolean>(false);
|
|
73
131
|
|
|
74
|
-
const [topLevelNavigation, setTopLevelNavigation] = useState<
|
|
132
|
+
const [topLevelNavigation, setTopLevelNavigation] = useState<NavigationResult | undefined>(undefined);
|
|
75
133
|
const [navigationLoading, setNavigationLoading] = useState<boolean>(true);
|
|
76
134
|
const [navigationLoadingError, setNavigationLoadingError] = useState<Error | undefined>(undefined);
|
|
77
135
|
|
|
@@ -88,103 +146,159 @@ export function useBuildNavigationController<EC extends EntityCollection, UserTy
|
|
|
88
146
|
const buildUrlCollectionPath = useCallback((path: string): string => `${removeInitialAndTrailingSlashes(baseCollectionPath)}/${encodePath(path)}`,
|
|
89
147
|
[baseCollectionPath]);
|
|
90
148
|
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
149
|
+
const allPluginGroups = plugins?.flatMap(plugin => plugin.homePage?.navigationEntries ? plugin.homePage.navigationEntries.map(e => e.name) : []) ?? [];
|
|
150
|
+
const pluginGroups = [...new Set(allPluginGroups)];
|
|
151
|
+
|
|
152
|
+
const onNavigationEntriesOrderUpdate = useCallback((entries: NavigationGroupMapping[]) => {
|
|
153
|
+
if (!plugins) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
// remove all groups that have no entries
|
|
157
|
+
const filteredEntries = entries.filter(entry => entry.entries.length > 0);
|
|
158
|
+
if (plugins.some(plugin => plugin.homePage?.onNavigationEntriesUpdate)) {
|
|
159
|
+
plugins.forEach(plugin => {
|
|
160
|
+
if (plugin.homePage?.onNavigationEntriesUpdate) {
|
|
161
|
+
plugin.homePage.onNavigationEntriesUpdate(filteredEntries);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
}, [plugins]);
|
|
167
|
+
|
|
168
|
+
const computeTopNavigation = useCallback((collections: EntityCollection[], views: CMSView[], adminViews: CMSView[], viewsOrder?: string[]): NavigationResult => {
|
|
169
|
+
|
|
170
|
+
const finalNavigationGroupMappings: NavigationGroupMapping[] = computeNavigationGroups({
|
|
171
|
+
navigationGroupMappings: navigationGroupMappings,
|
|
172
|
+
collections,
|
|
173
|
+
views,
|
|
174
|
+
plugins: plugins
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
const allPluginNavigationEntries = finalNavigationGroupMappings.map((g) => g.entries).flat() ?? [];
|
|
178
|
+
const navigationEntriesOrder = ([...new Set(allPluginNavigationEntries)]);
|
|
179
|
+
|
|
180
|
+
let navigationEntries: NavigationEntry[] = [
|
|
181
|
+
...(collections ?? []).reduce((acc, collection) => {
|
|
182
|
+
if (collection.hideFromNavigation) return acc;
|
|
183
|
+
|
|
184
|
+
const pathKey = collection.id ?? collection.path;
|
|
185
|
+
let groupName = getGroup(collection); // Initial group
|
|
186
|
+
|
|
187
|
+
if (finalNavigationGroupMappings) {
|
|
188
|
+
for (const pluginGroupDef of finalNavigationGroupMappings) {
|
|
189
|
+
if (pluginGroupDef.entries.includes(pathKey)) {
|
|
190
|
+
groupName = pluginGroupDef.name;
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
acc.push({
|
|
197
|
+
id: `collection:${pathKey}`,
|
|
198
|
+
url: buildUrlCollectionPath(pathKey),
|
|
96
199
|
type: "collection",
|
|
97
200
|
name: collection.name.trim(),
|
|
98
|
-
path:
|
|
201
|
+
path: pathKey,
|
|
99
202
|
collection,
|
|
100
203
|
description: collection.description?.trim(),
|
|
101
|
-
group:
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
:
|
|
130
|
-
|
|
204
|
+
group: groupName ?? NAVIGATION_DEFAULT_GROUP_NAME
|
|
205
|
+
});
|
|
206
|
+
return acc;
|
|
207
|
+
}, [] as NavigationEntry[]),
|
|
208
|
+
|
|
209
|
+
...(views ?? []).reduce((acc, view) => {
|
|
210
|
+
if (view.hideFromNavigation) return acc;
|
|
211
|
+
|
|
212
|
+
const pathKey = Array.isArray(view.path) ? view.path[0] : view.path;
|
|
213
|
+
let groupName = getGroup(view); // Initial group
|
|
214
|
+
|
|
215
|
+
if (finalNavigationGroupMappings) {
|
|
216
|
+
for (const pluginGroupDef of finalNavigationGroupMappings) {
|
|
217
|
+
if (pluginGroupDef.entries.includes(pathKey)) {
|
|
218
|
+
groupName = pluginGroupDef.name;
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
acc.push({
|
|
225
|
+
id: `view:${pathKey}`,
|
|
226
|
+
url: buildCMSUrlPath(pathKey),
|
|
227
|
+
name: view.name.trim(),
|
|
228
|
+
type: "view",
|
|
229
|
+
path: view.path,
|
|
230
|
+
view,
|
|
231
|
+
description: view.description?.trim(),
|
|
232
|
+
group: groupName ?? NAVIGATION_DEFAULT_GROUP_NAME
|
|
233
|
+
});
|
|
234
|
+
return acc;
|
|
235
|
+
}, [] as NavigationEntry[]),
|
|
236
|
+
|
|
237
|
+
...(adminViews ?? []).reduce((acc, view) => {
|
|
238
|
+
if (view.hideFromNavigation) return acc;
|
|
239
|
+
|
|
240
|
+
const pathKey = Array.isArray(view.path) ? view.path[0] : view.path;
|
|
241
|
+
const groupName = NAVIGATION_ADMIN_GROUP_NAME;
|
|
242
|
+
|
|
243
|
+
acc.push({
|
|
244
|
+
id: `admin:${pathKey}`,
|
|
245
|
+
url: buildCMSUrlPath(pathKey),
|
|
246
|
+
name: view.name.trim(),
|
|
247
|
+
type: "admin",
|
|
248
|
+
path: view.path,
|
|
249
|
+
view,
|
|
250
|
+
description: view.description?.trim(),
|
|
251
|
+
group: groupName
|
|
252
|
+
});
|
|
253
|
+
return acc;
|
|
254
|
+
}, [] as NavigationEntry[])
|
|
131
255
|
];
|
|
132
256
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
}
|
|
138
|
-
if (b.group !== "Views" && b.group !== "Admin" && (a.group === "Views" || a.group === "Admin")) {
|
|
139
|
-
return 1;
|
|
140
|
-
}
|
|
141
|
-
if (a.group === "Admin" && b.group !== "Admin") {
|
|
142
|
-
return 1;
|
|
143
|
-
}
|
|
144
|
-
if (a.group !== "Admin" && b.group === "Admin") {
|
|
145
|
-
return -1;
|
|
146
|
-
}
|
|
147
|
-
if (a.group === "Views" && b.group !== "Views") {
|
|
148
|
-
return -1;
|
|
149
|
-
}
|
|
150
|
-
if (a.group !== "Views" && b.group === "Views") {
|
|
151
|
-
return 1;
|
|
152
|
-
}
|
|
153
|
-
return 0;
|
|
257
|
+
const groupOrderValue = (groupName?: string): number => {
|
|
258
|
+
if (groupName === NAVIGATION_ADMIN_GROUP_NAME) return 1;
|
|
259
|
+
return 0; // Other groups
|
|
260
|
+
};
|
|
154
261
|
|
|
262
|
+
navigationEntries = navigationEntries.sort((a, b) => {
|
|
263
|
+
return groupOrderValue(a.group) - groupOrderValue(b.group);
|
|
155
264
|
});
|
|
156
265
|
|
|
157
|
-
|
|
266
|
+
const usedViewsOrder = viewsOrder ?? navigationEntriesOrder;
|
|
267
|
+
if (usedViewsOrder) {
|
|
158
268
|
navigationEntries = navigationEntries.sort((a, b) => {
|
|
159
|
-
const
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
if (
|
|
165
|
-
return 1;
|
|
166
|
-
}
|
|
167
|
-
if (bIndex === -1) {
|
|
168
|
-
return -1;
|
|
169
|
-
}
|
|
269
|
+
const getSortPath = (navEntry: NavigationEntry) => typeof navEntry.path === "string" ? navEntry.path : navEntry.path[0];
|
|
270
|
+
const aIndex = usedViewsOrder.indexOf(getSortPath(a));
|
|
271
|
+
const bIndex = usedViewsOrder.indexOf(getSortPath(b));
|
|
272
|
+
if (aIndex === -1 && bIndex === -1) return 0;
|
|
273
|
+
if (aIndex === -1) return 1;
|
|
274
|
+
if (bIndex === -1) return -1;
|
|
170
275
|
return aIndex - bIndex;
|
|
171
276
|
});
|
|
172
277
|
}
|
|
173
278
|
|
|
174
|
-
const
|
|
279
|
+
const collectedGroupsFromEntries = navigationEntries
|
|
175
280
|
.map(e => e.group)
|
|
176
|
-
.filter(Boolean)
|
|
177
|
-
|
|
281
|
+
.filter(Boolean) as string[];
|
|
282
|
+
|
|
283
|
+
const allDefinedGroups = [
|
|
284
|
+
...(pluginGroups ?? []),
|
|
285
|
+
...collectedGroupsFromEntries
|
|
286
|
+
];
|
|
287
|
+
|
|
288
|
+
const uniqueGroups = [...new Set(allDefinedGroups)]
|
|
289
|
+
.sort((a, b) => groupOrderValue(a) - groupOrderValue(b));
|
|
178
290
|
|
|
179
291
|
return {
|
|
292
|
+
allowDragAndDrop: plugins?.some(plugin => plugin.homePage?.allowDragAndDrop) ?? false,
|
|
180
293
|
navigationEntries,
|
|
181
|
-
groups
|
|
294
|
+
groups: uniqueGroups,
|
|
295
|
+
onNavigationEntriesUpdate: onNavigationEntriesOrderUpdate,
|
|
182
296
|
};
|
|
183
|
-
}, [buildCMSUrlPath, buildUrlCollectionPath]);
|
|
297
|
+
}, [navigationGroupMappings, buildCMSUrlPath, buildUrlCollectionPath, pluginGroups, onNavigationEntriesOrderUpdate]);
|
|
184
298
|
|
|
185
299
|
const refreshNavigation = useCallback(async () => {
|
|
186
300
|
|
|
187
|
-
if (authController.initialLoading)
|
|
301
|
+
if (disabled || authController.initialLoading)
|
|
188
302
|
return;
|
|
189
303
|
|
|
190
304
|
console.debug("Refreshing navigation");
|
|
@@ -192,15 +306,18 @@ export function useBuildNavigationController<EC extends EntityCollection, UserTy
|
|
|
192
306
|
try {
|
|
193
307
|
|
|
194
308
|
const [resolvedCollections = [], resolvedViews, resolvedAdminViews = []] = await Promise.all([
|
|
195
|
-
resolveCollections(collectionsProp, collectionPermissions, authController, dataSourceDelegate,
|
|
309
|
+
resolveCollections(collectionsProp, collectionPermissions, authController, dataSourceDelegate, plugins),
|
|
196
310
|
resolveCMSViews(viewsProp, authController, dataSourceDelegate),
|
|
197
311
|
resolveCMSViews(adminViewsProp, authController, dataSourceDelegate)
|
|
198
312
|
]
|
|
199
313
|
);
|
|
200
314
|
|
|
315
|
+
const computedTopLevelNav = computeTopNavigation(resolvedCollections, resolvedViews, resolvedAdminViews, viewsOrder);
|
|
316
|
+
|
|
201
317
|
let shouldUpdateTopLevelNav = false;
|
|
202
318
|
if (!areCollectionListsEqual(collectionsRef.current ?? [], resolvedCollections)) {
|
|
203
319
|
collectionsRef.current = resolvedCollections;
|
|
320
|
+
console.debug("Collections have changed", resolvedCollections);
|
|
204
321
|
shouldUpdateTopLevelNav = true;
|
|
205
322
|
}
|
|
206
323
|
if (collectionsRef.current === undefined) {
|
|
@@ -216,7 +333,12 @@ export function useBuildNavigationController<EC extends EntityCollection, UserTy
|
|
|
216
333
|
shouldUpdateTopLevelNav = true;
|
|
217
334
|
}
|
|
218
335
|
|
|
219
|
-
const
|
|
336
|
+
const navigationEntriesOrder = computedTopLevelNav.navigationEntries.map(e => e.id);
|
|
337
|
+
if (!equal(navigationEntriesOrderRef.current, navigationEntriesOrder)) {
|
|
338
|
+
navigationEntriesOrderRef.current = navigationEntriesOrder;
|
|
339
|
+
shouldUpdateTopLevelNav = true;
|
|
340
|
+
}
|
|
341
|
+
|
|
220
342
|
if (shouldUpdateTopLevelNav && !equal(topLevelNavigation, computedTopLevelNav)) {
|
|
221
343
|
setTopLevelNavigation(computedTopLevelNav);
|
|
222
344
|
}
|
|
@@ -225,18 +347,20 @@ export function useBuildNavigationController<EC extends EntityCollection, UserTy
|
|
|
225
347
|
setNavigationLoadingError(e as any);
|
|
226
348
|
}
|
|
227
349
|
|
|
228
|
-
|
|
229
|
-
|
|
350
|
+
if (navigationLoading)
|
|
351
|
+
setNavigationLoading(false);
|
|
352
|
+
if (!initialised)
|
|
353
|
+
setInitialised(true);
|
|
230
354
|
|
|
231
355
|
}, [
|
|
232
356
|
collectionsProp,
|
|
233
357
|
collectionPermissions,
|
|
234
358
|
authController.user,
|
|
235
359
|
authController.initialLoading,
|
|
360
|
+
disabled,
|
|
236
361
|
viewsProp,
|
|
237
362
|
adminViewsProp,
|
|
238
363
|
computeTopNavigation,
|
|
239
|
-
injectCollections
|
|
240
364
|
]);
|
|
241
365
|
|
|
242
366
|
useEffect(() => {
|
|
@@ -276,6 +400,16 @@ export function useBuildNavigationController<EC extends EntityCollection, UserTy
|
|
|
276
400
|
|
|
277
401
|
}, [userConfigPersistence]);
|
|
278
402
|
|
|
403
|
+
const getCollectionById = useCallback((id: string): EC | undefined => {
|
|
404
|
+
const collections = collectionsRef.current;
|
|
405
|
+
if (collections === undefined)
|
|
406
|
+
throw Error("getCollectionById: Collections have not been initialised yet");
|
|
407
|
+
const collection: EntityCollection | undefined = collections.find(c => c.id === id);
|
|
408
|
+
if (!collection)
|
|
409
|
+
return undefined;
|
|
410
|
+
return collection as EC;
|
|
411
|
+
}, []);
|
|
412
|
+
|
|
279
413
|
const getCollectionFromPaths = useCallback(<EC extends EntityCollection>(pathSegments: string[]): EC | undefined => {
|
|
280
414
|
|
|
281
415
|
const collections = collectionsRef.current;
|
|
@@ -328,16 +462,7 @@ export function useBuildNavigationController<EC extends EntityCollection, UserTy
|
|
|
328
462
|
throw Error("Expected path starting with " + fullCollectionPath);
|
|
329
463
|
}, [fullCollectionPath]);
|
|
330
464
|
|
|
331
|
-
const
|
|
332
|
-
path
|
|
333
|
-
}: {
|
|
334
|
-
path: string
|
|
335
|
-
}): string => {
|
|
336
|
-
return `s/edit/${encodePath(path)}`;
|
|
337
|
-
},
|
|
338
|
-
[]);
|
|
339
|
-
|
|
340
|
-
const resolveAliasesFrom = useCallback((path: string): string => {
|
|
465
|
+
const resolveIdsFrom = useCallback((path: string): string => {
|
|
341
466
|
const collections = collectionsRef.current ?? [];
|
|
342
467
|
return resolveCollectionPathIds(path, collections);
|
|
343
468
|
}, []);
|
|
@@ -392,29 +517,23 @@ export function useBuildNavigationController<EC extends EntityCollection, UserTy
|
|
|
392
517
|
baseCollectionPath,
|
|
393
518
|
initialised,
|
|
394
519
|
getCollection,
|
|
520
|
+
getCollectionById,
|
|
395
521
|
getCollectionFromPaths,
|
|
396
522
|
getCollectionFromIds,
|
|
397
523
|
isUrlCollectionPath,
|
|
398
524
|
urlPathToDataPath,
|
|
399
525
|
buildUrlCollectionPath,
|
|
400
|
-
|
|
401
|
-
buildCMSUrlPath,
|
|
402
|
-
resolveAliasesFrom,
|
|
526
|
+
resolveIdsFrom,
|
|
403
527
|
topLevelNavigation,
|
|
404
528
|
refreshNavigation,
|
|
405
529
|
getParentReferencesFromPath: getAllParentReferencesForPath,
|
|
406
530
|
getParentCollectionIds,
|
|
407
|
-
convertIdsToPaths
|
|
531
|
+
convertIdsToPaths,
|
|
532
|
+
navigate,
|
|
533
|
+
plugins
|
|
408
534
|
};
|
|
409
535
|
}
|
|
410
536
|
|
|
411
|
-
export function getSidePanelKey(path: string, entityId?: string) {
|
|
412
|
-
if (entityId)
|
|
413
|
-
return `${removeInitialAndTrailingSlashes(path)}/${removeInitialAndTrailingSlashes(entityId)}`;
|
|
414
|
-
else
|
|
415
|
-
return removeInitialAndTrailingSlashes(path);
|
|
416
|
-
}
|
|
417
|
-
|
|
418
537
|
function encodePath(input: string) {
|
|
419
538
|
return encodeURIComponent(removeInitialAndTrailingSlashes(input))
|
|
420
539
|
.replaceAll("%2F", "/")
|
|
@@ -423,9 +542,10 @@ function encodePath(input: string) {
|
|
|
423
542
|
|
|
424
543
|
function filterOutNotAllowedCollections(resolvedCollections: EntityCollection[], authController: AuthController<User>): EntityCollection[] {
|
|
425
544
|
return resolvedCollections
|
|
545
|
+
.filter((c) => Boolean(c.path))
|
|
426
546
|
.filter((c) => {
|
|
427
547
|
if (!c.permissions) return true;
|
|
428
|
-
const resolvedPermissions = resolvePermissions(c, authController, c.path, null)
|
|
548
|
+
const resolvedPermissions = resolvePermissions(c, authController, c.path, null);
|
|
429
549
|
return resolvedPermissions?.read !== false;
|
|
430
550
|
})
|
|
431
551
|
.map((c) => {
|
|
@@ -437,11 +557,24 @@ function filterOutNotAllowedCollections(resolvedCollections: EntityCollection[],
|
|
|
437
557
|
});
|
|
438
558
|
}
|
|
439
559
|
|
|
560
|
+
function applyPluginModifyCollection(resolvedCollections: EntityCollection[], modifyCollection: (collection: EntityCollection) => EntityCollection) {
|
|
561
|
+
return resolvedCollections.map((collection: EntityCollection): EntityCollection => {
|
|
562
|
+
const modifiedCollection = modifyCollection(collection);
|
|
563
|
+
if (modifiedCollection.subcollections) {
|
|
564
|
+
return {
|
|
565
|
+
...modifiedCollection,
|
|
566
|
+
subcollections: applyPluginModifyCollection(modifiedCollection.subcollections, modifyCollection)
|
|
567
|
+
} satisfies EntityCollection;
|
|
568
|
+
}
|
|
569
|
+
return modifiedCollection;
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
|
|
440
573
|
async function resolveCollections(collections: undefined | EntityCollection[] | EntityCollectionsBuilder<any>,
|
|
441
574
|
collectionPermissions: PermissionsBuilder | undefined,
|
|
442
575
|
authController: AuthController,
|
|
443
576
|
dataSource: DataSourceDelegate,
|
|
444
|
-
|
|
577
|
+
plugins: FireCMSPlugin[] | undefined): Promise<EntityCollection[]> {
|
|
445
578
|
let resolvedCollections: EntityCollection[] = [];
|
|
446
579
|
if (typeof collections === "function") {
|
|
447
580
|
resolvedCollections = await collections({
|
|
@@ -453,14 +586,20 @@ async function resolveCollections(collections: undefined | EntityCollection[] |
|
|
|
453
586
|
resolvedCollections = collections;
|
|
454
587
|
}
|
|
455
588
|
|
|
456
|
-
if (
|
|
457
|
-
|
|
589
|
+
if (plugins) {
|
|
590
|
+
for (const plugin of plugins) {
|
|
591
|
+
if (plugin.collection?.modifyCollection) {
|
|
592
|
+
resolvedCollections = applyPluginModifyCollection(resolvedCollections, plugin.collection.modifyCollection);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
if (plugin.collection?.injectCollections) {
|
|
596
|
+
resolvedCollections = plugin.collection.injectCollections(resolvedCollections ?? []);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
458
599
|
}
|
|
459
600
|
|
|
460
601
|
resolvedCollections = applyPermissionsFunctionIfEmpty(resolvedCollections, collectionPermissions);
|
|
461
|
-
|
|
462
602
|
resolvedCollections = filterOutNotAllowedCollections(resolvedCollections, authController);
|
|
463
|
-
|
|
464
603
|
return resolvedCollections;
|
|
465
604
|
}
|
|
466
605
|
|
|
@@ -481,9 +620,9 @@ async function resolveCMSViews(baseViews: CMSView[] | CMSViewsBuilder | undefine
|
|
|
481
620
|
function getGroup(collectionOrView: EntityCollection<any, any> | CMSView) {
|
|
482
621
|
const trimmed = collectionOrView.group?.trim();
|
|
483
622
|
if (!trimmed || trimmed === "") {
|
|
484
|
-
return
|
|
623
|
+
return NAVIGATION_DEFAULT_GROUP_NAME;
|
|
485
624
|
}
|
|
486
|
-
return trimmed ??
|
|
625
|
+
return trimmed ?? NAVIGATION_DEFAULT_GROUP_NAME;
|
|
487
626
|
}
|
|
488
627
|
|
|
489
628
|
function areCollectionListsEqual(a: EntityCollection[], b: EntityCollection[]) {
|
|
@@ -509,5 +648,128 @@ function areCollectionsEqual(a: EntityCollection, b: EntityCollection) {
|
|
|
509
648
|
if (!areCollectionListsEqual(subcollectionsA ?? [], subcollectionsB ?? [])) {
|
|
510
649
|
return false;
|
|
511
650
|
}
|
|
512
|
-
return equal(restA, restB);
|
|
651
|
+
return equal(removeFunctions(restA), removeFunctions(restB));
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
function useCustomBlocker(): NavigationBlocker {
|
|
655
|
+
const [blockListeners, setBlockListeners] = useState<Record<string, {
|
|
656
|
+
block: boolean,
|
|
657
|
+
basePath?: string
|
|
658
|
+
}>>({});
|
|
659
|
+
|
|
660
|
+
const shouldBlock = Object.values(blockListeners).some(b => b.block);
|
|
661
|
+
|
|
662
|
+
let blocker: any;
|
|
663
|
+
try {
|
|
664
|
+
blocker = useBlocker(({
|
|
665
|
+
nextLocation
|
|
666
|
+
}) => {
|
|
667
|
+
const allBasePaths = Object.values(blockListeners).map(b => b.basePath).filter(Boolean) as string[];
|
|
668
|
+
if (allBasePaths && allBasePaths.some(path => nextLocation.pathname.startsWith(path)))
|
|
669
|
+
return false;
|
|
670
|
+
return shouldBlock;
|
|
671
|
+
});
|
|
672
|
+
} catch (e) {
|
|
673
|
+
// console.warn("Blocker not available, navigation will not be blocked");
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
const updateBlockListener = (path: string, block: boolean, basePath?: string) => {
|
|
677
|
+
setBlockListeners(prev => ({
|
|
678
|
+
...prev,
|
|
679
|
+
[path]: {
|
|
680
|
+
block,
|
|
681
|
+
basePath
|
|
682
|
+
}
|
|
683
|
+
}));
|
|
684
|
+
return () => setBlockListeners(prev => {
|
|
685
|
+
const {
|
|
686
|
+
[path]: removed,
|
|
687
|
+
...rest
|
|
688
|
+
} = prev;
|
|
689
|
+
return rest;
|
|
690
|
+
})
|
|
691
|
+
};
|
|
692
|
+
|
|
693
|
+
const isBlocked = (path: string) => {
|
|
694
|
+
return (blockListeners[path]?.block ?? false) && blocker?.state === "blocked";
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
return {
|
|
698
|
+
updateBlockListener,
|
|
699
|
+
isBlocked,
|
|
700
|
+
proceed: blocker?.proceed,
|
|
701
|
+
reset: blocker?.reset
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
function computeNavigationGroups({
|
|
706
|
+
navigationGroupMappings,
|
|
707
|
+
collections,
|
|
708
|
+
views,
|
|
709
|
+
plugins
|
|
710
|
+
}: {
|
|
711
|
+
navigationGroupMappings?: NavigationGroupMapping[],
|
|
712
|
+
collections?: EntityCollection[],
|
|
713
|
+
views?: CMSView[],
|
|
714
|
+
plugins?: FireCMSPlugin[]
|
|
715
|
+
}): NavigationGroupMapping[] {
|
|
716
|
+
|
|
717
|
+
let result = navigationGroupMappings;
|
|
718
|
+
|
|
719
|
+
result = plugins ? plugins?.reduce((acc, plugin) => {
|
|
720
|
+
if (plugin.homePage?.navigationEntries) {
|
|
721
|
+
plugin.homePage.navigationEntries.forEach((entry) => {
|
|
722
|
+
const {
|
|
723
|
+
name,
|
|
724
|
+
entries
|
|
725
|
+
} = entry;
|
|
726
|
+
const existingGroup = acc.find(entry => entry.name === name);
|
|
727
|
+
if (existingGroup) {
|
|
728
|
+
existingGroup.entries.push(...entries);
|
|
729
|
+
} else {
|
|
730
|
+
acc.push({
|
|
731
|
+
name,
|
|
732
|
+
entries: [...entries]
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
});
|
|
736
|
+
|
|
737
|
+
}
|
|
738
|
+
return acc;
|
|
739
|
+
}, [...(result ?? [])] as NavigationGroupMapping[]) : result;
|
|
740
|
+
|
|
741
|
+
if (!result) {
|
|
742
|
+
// Convert views and collections to navigation group mappings, grouped by their group name
|
|
743
|
+
result = [];
|
|
744
|
+
const groupMap: Record<string, string[]> = {};
|
|
745
|
+
|
|
746
|
+
// Add collections
|
|
747
|
+
(collections ?? []).forEach(collection => {
|
|
748
|
+
const name = getGroup(collection);
|
|
749
|
+
const entry = collection.id ?? collection.path;
|
|
750
|
+
if (!groupMap[name]) groupMap[name] = [];
|
|
751
|
+
groupMap[name].push(entry);
|
|
752
|
+
});
|
|
753
|
+
|
|
754
|
+
// Add views
|
|
755
|
+
(views ?? []).forEach(view => {
|
|
756
|
+
const name = getGroup(view);
|
|
757
|
+
const entry = Array.isArray(view.path) ? view.path[0] : view.path;
|
|
758
|
+
if (!groupMap[name]) groupMap[name] = [];
|
|
759
|
+
groupMap[name].push(entry);
|
|
760
|
+
});
|
|
761
|
+
|
|
762
|
+
// Convert groupMap to initialGroupMappings array
|
|
763
|
+
result = Object.entries(groupMap).map(([name, entries]) => ({
|
|
764
|
+
name,
|
|
765
|
+
entries
|
|
766
|
+
}));
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
// Remove duplicates in entries
|
|
770
|
+
result.forEach(group => {
|
|
771
|
+
group.entries = [...new Set(group.entries)];
|
|
772
|
+
});
|
|
773
|
+
|
|
774
|
+
return result;
|
|
513
775
|
}
|