@firecms/core 3.0.0-canary.6 → 3.0.0-canary.60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/components/ClearFilterSortButton.d.ts +5 -0
- package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +11 -11
- package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +2 -2
- package/dist/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +5 -3
- package/dist/components/EntityCollectionTable/PropertyTableCell.d.ts +3 -2
- package/dist/components/EntityCollectionTable/column_utils.d.ts +1 -2
- package/dist/components/EntityCollectionTable/fields/TableReferenceField.d.ts +2 -0
- 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 +1 -1
- package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +12 -3
- package/dist/components/EntityCollectionView/EntityCollectionViewStartActions.d.ts +11 -0
- package/dist/components/EntityCollectionView/useSelectionController.d.ts +2 -0
- package/dist/components/EntityPreview.d.ts +26 -7
- package/dist/components/EntityView.d.ts +11 -0
- package/dist/components/FieldCaption.d.ts +5 -0
- package/dist/components/FireCMSAppBar.d.ts +4 -2
- package/dist/components/HomePage/NavigationCard.d.ts +8 -0
- package/dist/components/HomePage/{NavigationCollectionCard.d.ts → NavigationCardBinding.d.ts} +2 -2
- package/dist/components/HomePage/SmallNavigationCard.d.ts +6 -0
- package/dist/components/HomePage/index.d.ts +3 -1
- package/dist/components/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 +6 -7
- 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/useDataSourceEntityCollectionTableController.d.ts +3 -0
- package/dist/components/index.d.ts +5 -2
- package/dist/contexts/AuthControllerContext.d.ts +1 -1
- package/dist/core/Drawer.d.ts +5 -12
- package/dist/core/DrawerNavigationItem.d.ts +9 -0
- package/dist/core/{EntityView.d.ts → EntityEditView.d.ts} +2 -2
- package/dist/core/NavigationRoutes.d.ts +1 -1
- package/dist/core/Scaffold.d.ts +8 -12
- package/dist/core/index.d.ts +3 -4
- package/dist/form/EntityForm.d.ts +1 -1
- package/dist/form/components/ErrorFocus.d.ts +1 -1
- package/dist/form/components/StorageItemPreview.d.ts +3 -2
- package/dist/form/components/StorageUploadProgress.d.ts +1 -1
- package/dist/form/field_bindings/KeyValueFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +4 -3
- package/dist/form/field_bindings/TextFieldBinding.d.ts +2 -2
- package/dist/form/validation.d.ts +1 -1
- package/dist/hooks/data/delete.d.ts +2 -2
- package/dist/hooks/data/save.d.ts +2 -3
- package/dist/hooks/data/useDataSource.d.ts +2 -2
- package/dist/hooks/data/useEntityFetch.d.ts +3 -3
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/useBuildNavigationController.d.ts +6 -4
- package/dist/hooks/useProjectLog.d.ts +6 -2
- package/dist/hooks/useStorageSource.d.ts +2 -2
- package/dist/hooks/useValidateAuthenticator.d.ts +21 -0
- package/dist/index.es.js +10496 -9945
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +5 -5
- package/dist/index.umd.js.map +1 -1
- package/dist/internal/useBuildDataSource.d.ts +1 -16
- package/dist/preview/PropertyPreview.d.ts +1 -1
- package/dist/preview/PropertyPreviewProps.d.ts +1 -4
- package/dist/preview/components/BooleanPreview.d.ts +5 -1
- package/dist/preview/components/EnumValuesChip.d.ts +1 -1
- package/dist/preview/components/ReferencePreview.d.ts +3 -8
- package/dist/types/analytics.d.ts +1 -1
- package/dist/types/auth.d.ts +37 -1
- package/dist/types/collections.d.ts +30 -6
- package/dist/types/datasource.d.ts +21 -14
- package/dist/types/entities.d.ts +5 -1
- package/dist/types/entity_actions.d.ts +14 -0
- package/dist/types/entity_callbacks.d.ts +2 -2
- package/dist/types/entity_overrides.d.ts +6 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/types/navigation.d.ts +15 -14
- package/dist/types/permissions.d.ts +5 -1
- package/dist/types/plugins.d.ts +20 -20
- package/dist/types/properties.d.ts +12 -4
- package/dist/types/property_config.d.ts +2 -2
- package/dist/types/roles.d.ts +31 -0
- package/dist/types/storage.d.ts +11 -3
- package/dist/types/user.d.ts +5 -0
- package/dist/util/collections.d.ts +9 -1
- package/dist/util/entities.d.ts +1 -1
- package/dist/util/icon_synonyms.d.ts +1 -97
- package/dist/util/icons.d.ts +8 -2
- package/dist/util/navigation_utils.d.ts +2 -2
- package/dist/util/objects.d.ts +1 -1
- package/dist/util/permissions.d.ts +4 -4
- package/dist/util/references.d.ts +4 -2
- package/dist/util/resolutions.d.ts +14 -14
- package/dist/util/useTraceUpdate.d.ts +1 -0
- package/package.json +139 -119
- package/src/components/ClearFilterSortButton.tsx +41 -0
- package/src/components/DeleteEntityDialog.tsx +4 -4
- package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +4 -4
- package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +276 -279
- package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +9 -5
- package/src/components/EntityCollectionTable/PropertyTableCell.tsx +48 -45
- package/src/components/EntityCollectionTable/column_utils.tsx +3 -3
- package/src/components/EntityCollectionTable/fields/TableReferenceField.tsx +18 -17
- package/src/components/EntityCollectionTable/fields/TableStorageUpload.tsx +5 -5
- package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +29 -34
- package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +16 -12
- package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +2 -4
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +73 -72
- package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +5 -6
- package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +68 -0
- package/src/components/EntityCollectionView/useSelectionController.tsx +30 -0
- package/src/components/EntityPreview.tsx +209 -70
- package/src/components/EntityView.tsx +84 -0
- package/src/components/FieldCaption.tsx +14 -0
- package/src/components/FireCMSAppBar.tsx +40 -15
- package/src/components/HomePage/DefaultHomePage.tsx +15 -11
- package/src/components/HomePage/NavigationCard.tsx +69 -0
- package/src/components/HomePage/NavigationCardBinding.tsx +116 -0
- package/src/components/HomePage/SmallNavigationCard.tsx +45 -0
- package/src/components/HomePage/index.tsx +3 -1
- package/src/components/PropertyIdCopyTooltipContent.tsx +2 -3
- package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +4 -4
- package/src/components/ReferenceWidget.tsx +22 -12
- package/src/components/SearchIconsView.tsx +5 -5
- package/src/components/SelectableTable/SelectableTable.tsx +5 -3
- package/src/components/SelectableTable/filters/BooleanFilterField.tsx +2 -3
- package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +23 -8
- package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +38 -24
- package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +35 -15
- package/src/components/VirtualTable/VirtualTable.tsx +38 -29
- package/src/components/VirtualTable/VirtualTableHeader.tsx +4 -4
- package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +2 -2
- package/src/components/VirtualTable/VirtualTableProps.tsx +7 -7
- package/src/components/VirtualTable/VirtualTableRow.tsx +4 -5
- package/src/components/VirtualTable/fields/VirtualTableDateField.tsx +1 -1
- package/src/components/VirtualTable/types.tsx +2 -3
- package/src/components/{EntityCollectionTable/internal → common}/default_entity_actions.tsx +11 -7
- 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 +10 -2
- package/src/components/common/useDataSourceEntityCollectionTableController.tsx +12 -1
- package/src/components/common/useTableSearchHelper.ts +39 -9
- package/src/components/index.tsx +5 -2
- package/src/contexts/AuthControllerContext.tsx +1 -1
- package/src/core/Drawer.tsx +78 -103
- package/src/core/DrawerNavigationItem.tsx +62 -0
- package/src/core/{EntityView.tsx → EntityEditView.tsx} +27 -45
- package/src/core/EntitySidePanel.tsx +3 -3
- package/src/core/FireCMS.tsx +54 -43
- package/src/core/NavigationRoutes.tsx +11 -4
- package/src/core/Scaffold.tsx +80 -66
- package/src/core/field_configs.tsx +2 -3
- package/src/core/index.tsx +3 -4
- package/src/form/EntityForm.tsx +49 -33
- package/src/form/PropertyFieldBinding.tsx +0 -2
- package/src/form/components/StorageItemPreview.tsx +7 -5
- package/src/form/components/StorageUploadProgress.tsx +9 -8
- package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +10 -12
- package/src/form/field_bindings/BlockFieldBinding.tsx +2 -2
- package/src/form/field_bindings/DateTimeFieldBinding.tsx +1 -1
- package/src/form/field_bindings/KeyValueFieldBinding.tsx +19 -19
- package/src/form/field_bindings/MapFieldBinding.tsx +15 -15
- package/src/form/field_bindings/MarkdownFieldBinding.tsx +2 -2
- package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +3 -3
- package/src/form/field_bindings/ReferenceFieldBinding.tsx +16 -13
- package/src/form/field_bindings/SelectFieldBinding.tsx +3 -3
- package/src/form/field_bindings/StorageUploadFieldBinding.tsx +18 -9
- package/src/form/field_bindings/TextFieldBinding.tsx +7 -5
- package/src/form/validation.ts +3 -4
- package/src/hooks/data/delete.ts +3 -3
- package/src/hooks/data/save.ts +4 -2
- package/src/hooks/data/useCollectionFetch.tsx +1 -1
- package/src/hooks/data/useDataSource.tsx +8 -3
- package/src/hooks/data/useEntityFetch.tsx +4 -4
- package/src/hooks/index.tsx +3 -0
- package/src/hooks/useBuildLocalConfigurationPersistence.tsx +8 -10
- package/src/hooks/useBuildModeController.tsx +11 -5
- package/src/hooks/useBuildNavigationController.tsx +200 -83
- package/src/hooks/useProjectLog.tsx +17 -7
- package/src/hooks/useReferenceDialog.tsx +2 -2
- package/src/hooks/useResolvedNavigationFrom.tsx +1 -1
- package/src/hooks/useStorageSource.tsx +7 -2
- package/src/hooks/useValidateAuthenticator.tsx +115 -0
- package/src/internal/useBuildDataSource.ts +54 -47
- package/src/internal/useBuildSideEntityController.tsx +88 -21
- package/src/preview/PropertyPreview.tsx +5 -15
- package/src/preview/PropertyPreviewProps.tsx +1 -11
- package/src/preview/components/BooleanPreview.tsx +19 -4
- package/src/preview/components/EnumValuesChip.tsx +2 -2
- package/src/preview/components/ReferencePreview.tsx +72 -165
- package/src/preview/property_previews/ArrayOfMapsPreview.tsx +0 -1
- package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +2 -1
- package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +0 -1
- package/src/preview/property_previews/ArrayOfStringsPreview.tsx +0 -1
- package/src/preview/property_previews/ArrayOneOfPreview.tsx +2 -3
- package/src/preview/property_previews/ArrayPropertyPreview.tsx +2 -3
- package/src/preview/property_previews/MapPropertyPreview.tsx +5 -5
- package/src/preview/property_previews/StringPropertyPreview.tsx +8 -7
- package/src/types/analytics.ts +1 -0
- package/src/types/auth.tsx +50 -1
- package/src/types/collections.ts +37 -6
- package/src/types/datasource.ts +24 -17
- package/src/types/entities.ts +9 -1
- package/src/types/entity_actions.tsx +17 -0
- package/src/types/entity_callbacks.ts +2 -2
- package/src/types/entity_overrides.tsx +7 -0
- package/src/types/firecms.tsx +0 -1
- package/src/types/index.ts +2 -1
- package/src/types/navigation.ts +17 -17
- package/src/types/permissions.ts +6 -1
- package/src/types/plugins.tsx +26 -28
- package/src/types/properties.ts +18 -6
- package/src/types/property_config.tsx +2 -2
- package/src/types/roles.ts +41 -0
- package/src/types/side_entity_controller.tsx +1 -0
- package/src/types/storage.ts +12 -3
- package/src/types/user.ts +7 -0
- package/src/util/collections.ts +22 -0
- package/src/util/entities.ts +1 -1
- package/src/util/enums.ts +1 -1
- package/src/util/icon_list.ts +2 -2
- package/src/util/icon_synonyms.ts +3 -99
- package/src/util/icons.tsx +11 -3
- package/src/util/navigation_utils.ts +6 -6
- package/src/util/objects.ts +8 -21
- package/src/util/permissions.ts +11 -8
- package/src/util/references.ts +36 -5
- package/src/util/resolutions.ts +32 -31
- package/src/util/strings.ts +2 -2
- package/src/util/useTraceUpdate.tsx +2 -1
- package/dist/components/VirtualTable/common.d.ts +0 -2
- package/dist/core/SideEntityView.d.ts +0 -7
- 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/HomePage/NavigationCollectionCard.tsx +0 -146
- package/src/core/SideEntityView.tsx +0 -38
- package/src/internal/useBuildCustomizationController.tsx +0 -5
- package/src/internal/useLocaleConfig.tsx +0 -18
- package/src/types/appcheck.ts +0 -29
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
2
|
-
import { useLocation } from "react-router-dom";
|
|
3
2
|
import equal from "react-fast-compare"
|
|
4
3
|
|
|
5
4
|
import {
|
|
@@ -11,12 +10,14 @@ import {
|
|
|
11
10
|
EntityCollectionsBuilder,
|
|
12
11
|
EntityReference,
|
|
13
12
|
NavigationController,
|
|
13
|
+
PermissionsBuilder,
|
|
14
14
|
TopNavigationEntry,
|
|
15
15
|
TopNavigationResult,
|
|
16
16
|
User,
|
|
17
17
|
UserConfigurationPersistence
|
|
18
18
|
} from "../types";
|
|
19
19
|
import {
|
|
20
|
+
applyPermissionsFunctionIfEmpty,
|
|
20
21
|
getCollectionByPathOrId,
|
|
21
22
|
mergeDeep,
|
|
22
23
|
removeInitialAndTrailingSlashes,
|
|
@@ -28,12 +29,15 @@ import { getParentReferencesFromPath } from "../util/parent_references_from_path
|
|
|
28
29
|
const DEFAULT_BASE_PATH = "/";
|
|
29
30
|
const DEFAULT_COLLECTION_PATH = "/c";
|
|
30
31
|
|
|
31
|
-
type BuildNavigationContextProps<EC extends EntityCollection, UserType extends User> = {
|
|
32
|
+
export type BuildNavigationContextProps<EC extends EntityCollection, UserType extends User> = {
|
|
32
33
|
basePath?: string,
|
|
33
34
|
baseCollectionPath?: string,
|
|
34
35
|
authController: AuthController<UserType>;
|
|
35
36
|
collections?: EC[] | EntityCollectionsBuilder<EC>;
|
|
37
|
+
collectionPermissions?: PermissionsBuilder;
|
|
36
38
|
views?: CMSView[] | CMSViewsBuilder;
|
|
39
|
+
adminViews?: CMSView[] | CMSViewsBuilder;
|
|
40
|
+
viewsOrder?: string[];
|
|
37
41
|
userConfigPersistence?: UserConfigurationPersistence;
|
|
38
42
|
dataSourceDelegate: DataSourceDelegate;
|
|
39
43
|
/**
|
|
@@ -46,22 +50,25 @@ type BuildNavigationContextProps<EC extends EntityCollection, UserType extends U
|
|
|
46
50
|
injectCollections?: (collections: EntityCollection[]) => EntityCollection[];
|
|
47
51
|
};
|
|
48
52
|
|
|
49
|
-
export function useBuildNavigationController<EC extends EntityCollection, UserType extends User>({
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const
|
|
53
|
+
export function useBuildNavigationController<EC extends EntityCollection, UserType extends User>(props: BuildNavigationContextProps<EC, UserType>): NavigationController {
|
|
54
|
+
const {
|
|
55
|
+
basePath = DEFAULT_BASE_PATH,
|
|
56
|
+
baseCollectionPath = DEFAULT_COLLECTION_PATH,
|
|
57
|
+
authController,
|
|
58
|
+
collections: collectionsProp,
|
|
59
|
+
collectionPermissions,
|
|
60
|
+
views: viewsProp,
|
|
61
|
+
adminViews: adminViewsProp,
|
|
62
|
+
viewsOrder,
|
|
63
|
+
userConfigPersistence,
|
|
64
|
+
dataSourceDelegate,
|
|
65
|
+
injectCollections
|
|
66
|
+
} = props;
|
|
67
|
+
|
|
68
|
+
const collectionsRef = useRef<EntityCollection[] | undefined>();
|
|
69
|
+
const viewsRef = useRef<CMSView[] | undefined>();
|
|
70
|
+
const adminViewsRef = useRef<CMSView[] | undefined>();
|
|
71
|
+
|
|
65
72
|
const [initialised, setInitialised] = useState<boolean>(false);
|
|
66
73
|
|
|
67
74
|
const [topLevelNavigation, setTopLevelNavigation] = useState<TopNavigationResult | undefined>(undefined);
|
|
@@ -81,18 +88,18 @@ export function useBuildNavigationController<EC extends EntityCollection, UserTy
|
|
|
81
88
|
const buildUrlCollectionPath = useCallback((path: string): string => `${removeInitialAndTrailingSlashes(baseCollectionPath)}/${encodePath(path)}`,
|
|
82
89
|
[baseCollectionPath]);
|
|
83
90
|
|
|
84
|
-
const computeTopNavigation = useCallback((collections: EntityCollection[], views: CMSView[]): TopNavigationResult => {
|
|
85
|
-
|
|
91
|
+
const computeTopNavigation = useCallback((collections: EntityCollection[], views: CMSView[], adminViews: CMSView[], viewsOrder?: string[]): TopNavigationResult => {
|
|
92
|
+
let navigationEntries: TopNavigationEntry[] = [
|
|
86
93
|
...(collections ?? []).map(collection => (!collection.hideFromNavigation
|
|
87
|
-
? {
|
|
94
|
+
? ({
|
|
88
95
|
url: buildUrlCollectionPath(collection.id ?? collection.path),
|
|
89
96
|
type: "collection",
|
|
90
97
|
name: collection.name.trim(),
|
|
91
98
|
path: collection.id ?? collection.path,
|
|
92
99
|
collection,
|
|
93
100
|
description: collection.description?.trim(),
|
|
94
|
-
group: collection
|
|
95
|
-
}
|
|
101
|
+
group: getGroup(collection)
|
|
102
|
+
} satisfies TopNavigationEntry)
|
|
96
103
|
: undefined))
|
|
97
104
|
.filter(Boolean) as TopNavigationEntry[],
|
|
98
105
|
...(views ?? []).map(view =>
|
|
@@ -101,18 +108,74 @@ export function useBuildNavigationController<EC extends EntityCollection, UserTy
|
|
|
101
108
|
url: buildCMSUrlPath(Array.isArray(view.path) ? view.path[0] : view.path),
|
|
102
109
|
name: view.name.trim(),
|
|
103
110
|
type: "view",
|
|
111
|
+
path: view.path,
|
|
112
|
+
view,
|
|
113
|
+
description: view.description?.trim(),
|
|
114
|
+
group: getGroup(view)
|
|
115
|
+
} satisfies TopNavigationEntry)
|
|
116
|
+
: undefined)
|
|
117
|
+
.filter(Boolean) as TopNavigationEntry[],
|
|
118
|
+
...(adminViews ?? []).map(view =>
|
|
119
|
+
!view.hideFromNavigation
|
|
120
|
+
? ({
|
|
121
|
+
url: buildCMSUrlPath(Array.isArray(view.path) ? view.path[0] : view.path),
|
|
122
|
+
name: view.name.trim(),
|
|
123
|
+
type: "admin",
|
|
124
|
+
path: view.path,
|
|
104
125
|
view,
|
|
105
126
|
description: view.description?.trim(),
|
|
106
|
-
group:
|
|
107
|
-
})
|
|
127
|
+
group: "Admin"
|
|
128
|
+
} satisfies TopNavigationEntry)
|
|
108
129
|
: undefined)
|
|
109
130
|
.filter(Boolean) as TopNavigationEntry[]
|
|
110
131
|
];
|
|
111
132
|
|
|
133
|
+
// Sort by group, entries with group "Admin" will go last, and second to last will be the group "Views"
|
|
134
|
+
navigationEntries = navigationEntries.sort((a, b) => {
|
|
135
|
+
if (a.group !== "Views" && a.group !== "Admin" && (b.group === "Views" || b.group === "Admin")) {
|
|
136
|
+
return -1;
|
|
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;
|
|
154
|
+
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
if (viewsOrder) {
|
|
158
|
+
navigationEntries = navigationEntries.sort((a, b) => {
|
|
159
|
+
const aIndex = viewsOrder.indexOf(a.path);
|
|
160
|
+
const bIndex = viewsOrder.indexOf(b.path);
|
|
161
|
+
if (aIndex === -1 && bIndex === -1) {
|
|
162
|
+
return 0;
|
|
163
|
+
}
|
|
164
|
+
if (aIndex === -1) {
|
|
165
|
+
return 1;
|
|
166
|
+
}
|
|
167
|
+
if (bIndex === -1) {
|
|
168
|
+
return -1;
|
|
169
|
+
}
|
|
170
|
+
return aIndex - bIndex;
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
112
174
|
const groups: string[] = Object.values(navigationEntries)
|
|
113
175
|
.map(e => e.group)
|
|
114
176
|
.filter(Boolean)
|
|
115
177
|
.filter((value, index, array) => array.indexOf(value) === index) as string[];
|
|
178
|
+
|
|
116
179
|
return {
|
|
117
180
|
navigationEntries,
|
|
118
181
|
groups
|
|
@@ -124,17 +187,34 @@ export function useBuildNavigationController<EC extends EntityCollection, UserTy
|
|
|
124
187
|
if (authController.initialLoading)
|
|
125
188
|
return;
|
|
126
189
|
|
|
190
|
+
console.debug("Refreshing navigation");
|
|
191
|
+
|
|
127
192
|
try {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
193
|
+
|
|
194
|
+
const [resolvedCollections = [], resolvedViews, resolvedAdminViews = []] = await Promise.all([
|
|
195
|
+
resolveCollections(collectionsProp, collectionPermissions, authController, dataSourceDelegate, injectCollections),
|
|
196
|
+
resolveCMSViews(viewsProp, authController, dataSourceDelegate),
|
|
197
|
+
resolveCMSViews(adminViewsProp, authController, dataSourceDelegate)
|
|
131
198
|
]
|
|
132
199
|
);
|
|
133
|
-
|
|
200
|
+
|
|
201
|
+
let shouldUpdateTopLevelNav = false;
|
|
202
|
+
if (!areCollectionListsEqual(collectionsRef.current ?? [], resolvedCollections)) {
|
|
134
203
|
collectionsRef.current = resolvedCollections;
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
204
|
+
shouldUpdateTopLevelNav = true;
|
|
205
|
+
}
|
|
206
|
+
if (!equal(viewsRef.current, resolvedViews)) {
|
|
207
|
+
viewsRef.current = resolvedViews;
|
|
208
|
+
shouldUpdateTopLevelNav = true;
|
|
209
|
+
}
|
|
210
|
+
if (!equal(adminViewsRef.current, resolvedAdminViews)) {
|
|
211
|
+
adminViewsRef.current = resolvedAdminViews;
|
|
212
|
+
shouldUpdateTopLevelNav = true;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const computedTopLevelNav = computeTopNavigation(resolvedCollections, resolvedViews, resolvedAdminViews, viewsOrder);
|
|
216
|
+
if (shouldUpdateTopLevelNav && !equal(topLevelNavigation, computedTopLevelNav)) {
|
|
217
|
+
setTopLevelNavigation(computedTopLevelNav);
|
|
138
218
|
}
|
|
139
219
|
} catch (e) {
|
|
140
220
|
console.error(e);
|
|
@@ -143,26 +223,34 @@ export function useBuildNavigationController<EC extends EntityCollection, UserTy
|
|
|
143
223
|
|
|
144
224
|
setNavigationLoading(false);
|
|
145
225
|
setInitialised(true);
|
|
146
|
-
|
|
226
|
+
|
|
227
|
+
}, [
|
|
228
|
+
collectionsProp,
|
|
229
|
+
collectionPermissions,
|
|
230
|
+
authController.user,
|
|
231
|
+
authController.initialLoading,
|
|
232
|
+
viewsProp,
|
|
233
|
+
adminViewsProp,
|
|
234
|
+
computeTopNavigation,
|
|
235
|
+
injectCollections
|
|
236
|
+
]);
|
|
147
237
|
|
|
148
238
|
useEffect(() => {
|
|
149
239
|
refreshNavigation();
|
|
150
240
|
}, [refreshNavigation]);
|
|
151
241
|
|
|
152
|
-
const getCollection = useCallback(
|
|
242
|
+
const getCollection = useCallback((
|
|
153
243
|
idOrPath: string,
|
|
154
|
-
entityId?: string,
|
|
155
244
|
includeUserOverride = false
|
|
156
245
|
): EC | undefined => {
|
|
157
|
-
|
|
246
|
+
const collections = collectionsRef.current;
|
|
158
247
|
if (!collections)
|
|
159
248
|
return undefined;
|
|
160
249
|
|
|
161
250
|
const baseCollection = getCollectionByPathOrId(removeInitialAndTrailingSlashes(idOrPath), collections);
|
|
162
251
|
|
|
163
252
|
const userOverride = includeUserOverride ? userConfigPersistence?.getCollectionConfig(idOrPath) : undefined;
|
|
164
|
-
|
|
165
|
-
const overriddenCollection = baseCollection ? mergeDeep(baseCollection, userOverride) : undefined;
|
|
253
|
+
const overriddenCollection = baseCollection ? mergeDeep(baseCollection, userOverride ?? {}) : undefined;
|
|
166
254
|
|
|
167
255
|
let result: Partial<EntityCollection> | undefined = overriddenCollection;
|
|
168
256
|
|
|
@@ -182,16 +270,14 @@ export function useBuildNavigationController<EC extends EntityCollection, UserTy
|
|
|
182
270
|
|
|
183
271
|
return { ...overriddenCollection, ...result } as EC;
|
|
184
272
|
|
|
185
|
-
}, [
|
|
186
|
-
basePath,
|
|
187
|
-
baseCollectionPath,
|
|
188
|
-
collections,
|
|
189
|
-
]);
|
|
273
|
+
}, [userConfigPersistence]);
|
|
190
274
|
|
|
191
275
|
const getCollectionFromPaths = useCallback(<EC extends EntityCollection>(pathSegments: string[]): EC | undefined => {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
276
|
+
|
|
277
|
+
const collections = collectionsRef.current;
|
|
278
|
+
if (collections === undefined)
|
|
279
|
+
throw Error("getCollectionFromPaths: Collections have not been initialised yet");
|
|
280
|
+
let currentCollections: EntityCollection[] | undefined = [...(collections ?? [])];
|
|
195
281
|
|
|
196
282
|
for (let i = 0; i < pathSegments.length; i++) {
|
|
197
283
|
const pathSegment = pathSegments[i];
|
|
@@ -205,12 +291,14 @@ export function useBuildNavigationController<EC extends EntityCollection, UserTy
|
|
|
205
291
|
|
|
206
292
|
return undefined;
|
|
207
293
|
|
|
208
|
-
}, [
|
|
294
|
+
}, []);
|
|
209
295
|
|
|
210
296
|
const getCollectionFromIds = useCallback(<EC extends EntityCollection>(ids: string[]): EC | undefined => {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
297
|
+
|
|
298
|
+
const collections = collectionsRef.current;
|
|
299
|
+
if (collections === undefined)
|
|
300
|
+
throw Error("getCollectionFromIds: Collections have not been initialised yet");
|
|
301
|
+
let currentCollections: EntityCollection[] | undefined = [...(collections ?? [])];
|
|
214
302
|
|
|
215
303
|
for (let i = 0; i < ids.length; i++) {
|
|
216
304
|
const id = ids[i];
|
|
@@ -224,7 +312,7 @@ export function useBuildNavigationController<EC extends EntityCollection, UserTy
|
|
|
224
312
|
|
|
225
313
|
return undefined;
|
|
226
314
|
|
|
227
|
-
}, [
|
|
315
|
+
}, []);
|
|
228
316
|
|
|
229
317
|
const isUrlCollectionPath = useCallback(
|
|
230
318
|
(path: string): boolean => removeInitialAndTrailingSlashes(path + "/").startsWith(removeInitialAndTrailingSlashes(fullCollectionPath) + "/"),
|
|
@@ -246,25 +334,17 @@ export function useBuildNavigationController<EC extends EntityCollection, UserTy
|
|
|
246
334
|
[]);
|
|
247
335
|
|
|
248
336
|
const resolveAliasesFrom = useCallback((path: string): string => {
|
|
249
|
-
|
|
250
|
-
throw Error("Collections have not been initialised yet");
|
|
337
|
+
const collections = collectionsRef.current ?? [];
|
|
251
338
|
return resolveCollectionPathIds(path, collections);
|
|
252
|
-
}, [
|
|
253
|
-
|
|
254
|
-
const state = location.state as any;
|
|
255
|
-
/**
|
|
256
|
-
* The location can be overridden if `base_location` is set in the
|
|
257
|
-
* state field of the current location. This can happen if you open
|
|
258
|
-
* a side entity, like `products`, from a different one, like `users`
|
|
259
|
-
*/
|
|
260
|
-
const baseLocation = state && state.base_location ? state.base_location : location;
|
|
339
|
+
}, []);
|
|
261
340
|
|
|
262
341
|
const getAllParentReferencesForPath = useCallback((path: string): EntityReference[] => {
|
|
342
|
+
const collections = collectionsRef.current ?? [];
|
|
263
343
|
return getParentReferencesFromPath({
|
|
264
344
|
path,
|
|
265
345
|
collections
|
|
266
346
|
});
|
|
267
|
-
}, [
|
|
347
|
+
}, []);
|
|
268
348
|
|
|
269
349
|
const getParentCollectionIds = useCallback((path: string): string[] => {
|
|
270
350
|
|
|
@@ -283,23 +363,24 @@ export function useBuildNavigationController<EC extends EntityCollection, UserTy
|
|
|
283
363
|
}, [getAllParentReferencesForPath])
|
|
284
364
|
|
|
285
365
|
const convertIdsToPaths = useCallback((ids: string[]): string[] => {
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
return paths;
|
|
366
|
+
const collections = collectionsRef.current;
|
|
367
|
+
let currentCollections = collections;
|
|
368
|
+
const paths: string[] = [];
|
|
369
|
+
for (let i = 0; i < ids.length; i++) {
|
|
370
|
+
const id = ids[i];
|
|
371
|
+
const collection: EntityCollection | undefined = currentCollections!.find(c => c.id === id);
|
|
372
|
+
if (!collection)
|
|
373
|
+
throw Error(`Collection with id ${id} not found`);
|
|
374
|
+
paths.push(collection.path);
|
|
375
|
+
currentCollections = collection.subcollections;
|
|
297
376
|
}
|
|
298
|
-
|
|
377
|
+
return paths;
|
|
378
|
+
}, [getCollectionFromIds]);
|
|
299
379
|
|
|
300
380
|
return {
|
|
301
|
-
collections,
|
|
302
|
-
views,
|
|
381
|
+
collections: collectionsRef.current,
|
|
382
|
+
views: viewsRef.current,
|
|
383
|
+
adminViews: adminViewsRef.current,
|
|
303
384
|
loading: !initialised || navigationLoading,
|
|
304
385
|
navigationLoadingError,
|
|
305
386
|
homeUrl,
|
|
@@ -316,7 +397,6 @@ export function useBuildNavigationController<EC extends EntityCollection, UserTy
|
|
|
316
397
|
buildCMSUrlPath,
|
|
317
398
|
resolveAliasesFrom,
|
|
318
399
|
topLevelNavigation,
|
|
319
|
-
baseLocation,
|
|
320
400
|
refreshNavigation,
|
|
321
401
|
getParentReferencesFromPath: getAllParentReferencesForPath,
|
|
322
402
|
getParentCollectionIds,
|
|
@@ -341,8 +421,8 @@ function filterOutNotAllowedCollections(resolvedCollections: EntityCollection[],
|
|
|
341
421
|
return resolvedCollections
|
|
342
422
|
.filter((c) => {
|
|
343
423
|
if (!c.permissions) return true;
|
|
344
|
-
const resolvedPermissions = resolvePermissions(c, authController,
|
|
345
|
-
return resolvedPermissions
|
|
424
|
+
const resolvedPermissions = resolvePermissions(c, authController, c.path, null)
|
|
425
|
+
return resolvedPermissions?.read !== false;
|
|
346
426
|
})
|
|
347
427
|
.map((c) => {
|
|
348
428
|
if (!c.subcollections) return c;
|
|
@@ -354,9 +434,10 @@ function filterOutNotAllowedCollections(resolvedCollections: EntityCollection[],
|
|
|
354
434
|
}
|
|
355
435
|
|
|
356
436
|
async function resolveCollections(collections: undefined | EntityCollection[] | EntityCollectionsBuilder<any>,
|
|
437
|
+
collectionPermissions: PermissionsBuilder | undefined,
|
|
357
438
|
authController: AuthController,
|
|
358
439
|
dataSource: DataSourceDelegate,
|
|
359
|
-
injectCollections?: (collections: EntityCollection[]) => EntityCollection[]) {
|
|
440
|
+
injectCollections?: (collections: EntityCollection[]) => EntityCollection[]): Promise<EntityCollection[]> {
|
|
360
441
|
let resolvedCollections: EntityCollection[] = [];
|
|
361
442
|
if (typeof collections === "function") {
|
|
362
443
|
resolvedCollections = await collections({
|
|
@@ -368,12 +449,14 @@ async function resolveCollections(collections: undefined | EntityCollection[] |
|
|
|
368
449
|
resolvedCollections = collections;
|
|
369
450
|
}
|
|
370
451
|
|
|
371
|
-
resolvedCollections = filterOutNotAllowedCollections(resolvedCollections, authController);
|
|
372
|
-
|
|
373
452
|
if (injectCollections) {
|
|
374
453
|
resolvedCollections = injectCollections(resolvedCollections ?? []);
|
|
375
454
|
}
|
|
376
455
|
|
|
456
|
+
resolvedCollections = applyPermissionsFunctionIfEmpty(resolvedCollections, collectionPermissions);
|
|
457
|
+
|
|
458
|
+
resolvedCollections = filterOutNotAllowedCollections(resolvedCollections, authController);
|
|
459
|
+
|
|
377
460
|
return resolvedCollections;
|
|
378
461
|
}
|
|
379
462
|
|
|
@@ -390,3 +473,37 @@ async function resolveCMSViews(baseViews: CMSView[] | CMSViewsBuilder | undefine
|
|
|
390
473
|
}
|
|
391
474
|
return resolvedViews;
|
|
392
475
|
}
|
|
476
|
+
|
|
477
|
+
function getGroup(collectionOrView: EntityCollection<any, any> | CMSView) {
|
|
478
|
+
const trimmed = collectionOrView.group?.trim();
|
|
479
|
+
if (!trimmed || trimmed === "") {
|
|
480
|
+
return "Views";
|
|
481
|
+
}
|
|
482
|
+
return trimmed ?? "Views";
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
function areCollectionListsEqual(a: EntityCollection[], b: EntityCollection[]) {
|
|
486
|
+
if (a.length !== b.length) {
|
|
487
|
+
return false;
|
|
488
|
+
}
|
|
489
|
+
const aCopy = [...a];
|
|
490
|
+
const bCopy = [...b];
|
|
491
|
+
const aSorted = aCopy.sort((x, y) => x.id.localeCompare(y.id));
|
|
492
|
+
const bSorted = bCopy.sort((x, y) => x.id.localeCompare(y.id));
|
|
493
|
+
return aSorted.every((value, index) => areCollectionsEqual(value, bSorted[index]));
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
function areCollectionsEqual(a: EntityCollection, b: EntityCollection) {
|
|
497
|
+
const {
|
|
498
|
+
subcollections: subcollectionsA,
|
|
499
|
+
...restA
|
|
500
|
+
} = a;
|
|
501
|
+
const {
|
|
502
|
+
subcollections: subcollectionsB,
|
|
503
|
+
...restB
|
|
504
|
+
} = b;
|
|
505
|
+
if (!areCollectionListsEqual(subcollectionsA ?? [], subcollectionsB ?? [])) {
|
|
506
|
+
return false;
|
|
507
|
+
}
|
|
508
|
+
return equal(restA, restB);
|
|
509
|
+
}
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
import { useEffect, useRef } from "react";
|
|
2
|
-
import { AuthController } from "../types";
|
|
1
|
+
import { useEffect, useRef, useState } from "react";
|
|
2
|
+
import { AuthController, FireCMSPlugin } from "../types";
|
|
3
3
|
|
|
4
4
|
export const DEFAULT_SERVER_DEV = "https://api-kdoe6pj3qq-ey.a.run.app";
|
|
5
5
|
export const DEFAULT_SERVER = "https://api-drplyi3b6q-ey.a.run.app";
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
export type AccessResponse = {
|
|
8
|
+
blocked?: boolean;
|
|
9
|
+
message?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async function makeRequest(authController: AuthController, pluginKeys: string[] | undefined) {
|
|
8
13
|
const firebaseToken = await authController.getAuthToken();
|
|
9
14
|
return fetch(DEFAULT_SERVER + "/access_log",
|
|
10
15
|
{
|
|
@@ -14,18 +19,23 @@ async function makeRequest(authController: AuthController) {
|
|
|
14
19
|
"Content-Type": "application/json",
|
|
15
20
|
Authorization: `Basic ${firebaseToken}`,
|
|
16
21
|
},
|
|
17
|
-
body: JSON.stringify({})
|
|
22
|
+
body: JSON.stringify({ plugins: pluginKeys })
|
|
18
23
|
})
|
|
19
24
|
.then(async (res) => {
|
|
25
|
+
return res.json();
|
|
20
26
|
});
|
|
21
27
|
}
|
|
22
28
|
|
|
23
|
-
export function useProjectLog(authController: AuthController
|
|
29
|
+
export function useProjectLog(authController: AuthController,
|
|
30
|
+
plugins?: FireCMSPlugin<any, any, any>[]): AccessResponse | null {
|
|
31
|
+
const [accessResponse, setAccessResponse] = useState<AccessResponse | null>(null);
|
|
24
32
|
const accessedUserRef = useRef<string | null>(null);
|
|
33
|
+
const pluginKeys = plugins?.map(plugin => plugin.key);
|
|
25
34
|
useEffect(() => {
|
|
26
35
|
if (authController.user && authController.user.uid !== accessedUserRef.current && !authController.initialLoading) {
|
|
27
|
-
makeRequest(authController);
|
|
36
|
+
makeRequest(authController, pluginKeys).then(setAccessResponse);
|
|
28
37
|
accessedUserRef.current = authController.user.uid;
|
|
29
38
|
}
|
|
30
|
-
}, [authController]);
|
|
39
|
+
}, [authController, pluginKeys]);
|
|
40
|
+
return accessResponse;
|
|
31
41
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useSideDialogsController } from "./useSideDialogsController";
|
|
2
|
-
import {
|
|
2
|
+
import { ReferenceSelectionInnerProps, ReferenceSelectionTable } from "../components";
|
|
3
3
|
import { useCallback } from "react";
|
|
4
4
|
import { useNavigationController } from "./useNavigationController";
|
|
5
5
|
|
|
@@ -27,7 +27,7 @@ export function useReferenceDialog<M extends Record<string, any>>(referenceDialo
|
|
|
27
27
|
if (!usedCollection)
|
|
28
28
|
usedCollection = navigation.getCollection(referenceDialogProps.path);
|
|
29
29
|
if (!usedCollection)
|
|
30
|
-
throw Error("Not able to resolve the collection in useReferenceDialog");
|
|
30
|
+
throw Error("Not able to resolve the collection in useReferenceDialog. Make sure a collection is registered in path " + referenceDialogProps.path);
|
|
31
31
|
sideDialogsController.open({
|
|
32
32
|
key: `reference_${referenceDialogProps.path}`,
|
|
33
33
|
component:
|
|
@@ -80,7 +80,7 @@ export function resolveNavigationFrom<M extends Record<string, any>, UserType ex
|
|
|
80
80
|
if (entry.type === "collection") {
|
|
81
81
|
return Promise.resolve(entry);
|
|
82
82
|
} else if (entry.type === "entity") {
|
|
83
|
-
const collection = navigation.getCollection(entry.path
|
|
83
|
+
const collection = navigation.getCollection(entry.path);
|
|
84
84
|
if (!collection) {
|
|
85
85
|
throw Error(`No collection defined in the navigation for the entity with path ${entry.path}`);
|
|
86
86
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { StorageSource } from "../types";
|
|
1
|
+
import { EntityCollection, StorageSource } from "../types";
|
|
2
2
|
import { StorageSourceContext } from "../contexts/StorageSourceContext";
|
|
3
3
|
import { useContext } from "react";
|
|
4
4
|
|
|
@@ -6,4 +6,9 @@ import { useContext } from "react";
|
|
|
6
6
|
* Use this hook to get the storage source being used
|
|
7
7
|
* @group Hooks and utilities
|
|
8
8
|
*/
|
|
9
|
-
export const useStorageSource = (): StorageSource =>
|
|
9
|
+
export const useStorageSource = (collection?: EntityCollection): StorageSource => {
|
|
10
|
+
const defaultStorageSource = useContext(StorageSourceContext);
|
|
11
|
+
if (collection?.overrides?.storageSource)
|
|
12
|
+
return collection.overrides.storageSource;
|
|
13
|
+
return defaultStorageSource;
|
|
14
|
+
};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
2
|
+
import equal from "react-fast-compare";
|
|
3
|
+
|
|
4
|
+
import { AuthController, Authenticator, DataSourceDelegate, StorageSource, User } from "../index";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* This hook is used internally for validating an authenticator.
|
|
8
|
+
*
|
|
9
|
+
* @param authController
|
|
10
|
+
* @param authentication
|
|
11
|
+
* @param storageSource
|
|
12
|
+
* @param dataSourceDelegate
|
|
13
|
+
*/
|
|
14
|
+
export function useValidateAuthenticator<UserType extends User = User, Controller extends AuthController<UserType> = AuthController<UserType>>
|
|
15
|
+
({
|
|
16
|
+
disabled,
|
|
17
|
+
authController,
|
|
18
|
+
authenticator,
|
|
19
|
+
storageSource,
|
|
20
|
+
dataSourceDelegate
|
|
21
|
+
}:
|
|
22
|
+
{
|
|
23
|
+
disabled?: boolean,
|
|
24
|
+
authController: Controller,
|
|
25
|
+
authenticator?: boolean | Authenticator<UserType, Controller>,
|
|
26
|
+
dataSourceDelegate: DataSourceDelegate;
|
|
27
|
+
storageSource: StorageSource;
|
|
28
|
+
}): {
|
|
29
|
+
canAccessMainView: boolean,
|
|
30
|
+
authLoading: boolean,
|
|
31
|
+
notAllowedError: any,
|
|
32
|
+
authVerified: boolean,
|
|
33
|
+
} {
|
|
34
|
+
|
|
35
|
+
const authenticationEnabled = Boolean(authenticator);
|
|
36
|
+
|
|
37
|
+
const [authLoading, setAuthLoading] = useState<boolean>(authenticationEnabled);
|
|
38
|
+
const [notAllowedError, setNotAllowedError] = useState<any>(false);
|
|
39
|
+
const [authVerified, setAuthVerified] = useState<boolean>(!authenticationEnabled || Boolean(authController.loginSkipped));
|
|
40
|
+
|
|
41
|
+
const canAccessMainView = (authVerified) &&
|
|
42
|
+
(!authenticationEnabled || Boolean(authController.user) || Boolean(authController.loginSkipped)) &&
|
|
43
|
+
!notAllowedError;
|
|
44
|
+
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
if (authController.loginSkipped)
|
|
47
|
+
setAuthVerified(true);
|
|
48
|
+
}, [authController.loginSkipped]);
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* We use this ref to check the authentication only if the user has
|
|
52
|
+
* changed.
|
|
53
|
+
*/
|
|
54
|
+
const checkedUserRef = useRef<User | undefined>();
|
|
55
|
+
|
|
56
|
+
const checkAuthentication = useCallback(async () => {
|
|
57
|
+
|
|
58
|
+
if (disabled) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (authController.initialLoading) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (!authController.user && !authController.loginSkipped) {
|
|
67
|
+
checkedUserRef.current = undefined;
|
|
68
|
+
setAuthLoading(false);
|
|
69
|
+
setAuthVerified(false);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const delegateUser = authController.user;
|
|
74
|
+
|
|
75
|
+
if (authenticator instanceof Function && delegateUser && !equal(checkedUserRef.current?.uid, delegateUser.uid)) {
|
|
76
|
+
setAuthLoading(true);
|
|
77
|
+
try {
|
|
78
|
+
const allowed = await authenticator({
|
|
79
|
+
user: delegateUser,
|
|
80
|
+
authController,
|
|
81
|
+
dataSourceDelegate,
|
|
82
|
+
storageSource
|
|
83
|
+
});
|
|
84
|
+
if (!allowed) {
|
|
85
|
+
authController.signOut();
|
|
86
|
+
setNotAllowedError(true);
|
|
87
|
+
}
|
|
88
|
+
} catch (e) {
|
|
89
|
+
setNotAllowedError(e);
|
|
90
|
+
authController.signOut();
|
|
91
|
+
}
|
|
92
|
+
setAuthLoading(false);
|
|
93
|
+
setAuthVerified(true);
|
|
94
|
+
checkedUserRef.current = delegateUser;
|
|
95
|
+
} else {
|
|
96
|
+
setAuthLoading(false);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (!authController.initialLoading && !delegateUser) {
|
|
100
|
+
setAuthVerified(true);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
}, [disabled, authController, authenticator, dataSourceDelegate, storageSource]);
|
|
104
|
+
|
|
105
|
+
useEffect(() => {
|
|
106
|
+
checkAuthentication();
|
|
107
|
+
}, [checkAuthentication]);
|
|
108
|
+
|
|
109
|
+
return {
|
|
110
|
+
canAccessMainView,
|
|
111
|
+
authLoading: authenticationEnabled && authLoading,
|
|
112
|
+
notAllowedError,
|
|
113
|
+
authVerified
|
|
114
|
+
}
|
|
115
|
+
}
|