@firecms/core 3.0.0-canary.9 → 3.0.0-canary.90
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 +1 -1
- package/dist/app/AppBar.d.ts +12 -0
- package/dist/app/Drawer.d.ts +17 -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/CircularProgressCenter.d.ts +1 -1
- package/dist/components/ClearFilterSortButton.d.ts +5 -0
- 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 +5 -3
- 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 +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 -2
- package/dist/components/EntityCollectionView/EntityCollectionViewStartActions.d.ts +11 -0
- package/dist/components/EntityPreview.d.ts +5 -4
- 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/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/useDataSourceEntityCollectionTableController.d.ts +3 -0
- package/dist/components/index.d.ts +2 -1
- package/dist/contexts/AuthControllerContext.d.ts +1 -1
- 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 +9 -0
- package/dist/core/EntityEditView.d.ts +17 -3
- package/dist/core/FireCMS.d.ts +1 -1
- package/dist/core/NavigationRoutes.d.ts +3 -3
- package/dist/core/index.d.ts +3 -4
- package/dist/form/PropertiesForm.d.ts +8 -0
- package/dist/form/components/ErrorFocus.d.ts +1 -1
- package/dist/form/components/FieldHelperText.d.ts +3 -3
- package/dist/form/components/StorageItemPreview.d.ts +4 -4
- package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +2 -4
- package/dist/form/index.d.ts +0 -2
- 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 +1 -1
- package/dist/hooks/data/useEntityFetch.d.ts +3 -3
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/useBuildNavigationController.d.ts +1 -2
- package/dist/hooks/useProjectLog.d.ts +2 -2
- package/dist/hooks/useValidateAuthenticator.d.ts +21 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.es.js +15552 -11933
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +19643 -7
- package/dist/index.umd.js.map +1 -1
- package/dist/internal/useBuildDataSource.d.ts +1 -16
- package/dist/internal/useRestoreScroll.d.ts +1 -1
- package/dist/preview/PropertyPreviewProps.d.ts +6 -4
- package/dist/preview/components/ReferencePreview.d.ts +2 -1
- package/dist/preview/components/StorageThumbnail.d.ts +2 -1
- package/dist/preview/components/UrlComponentPreview.d.ts +2 -1
- package/dist/types/auth.d.ts +26 -2
- package/dist/types/collections.d.ts +31 -7
- package/dist/types/datasource.d.ts +34 -20
- 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/fields.d.ts +31 -30
- package/dist/types/index.d.ts +0 -1
- package/dist/types/navigation.d.ts +5 -5
- package/dist/types/plugins.d.ts +16 -6
- package/dist/types/properties.d.ts +17 -4
- package/dist/types/storage.d.ts +11 -3
- package/dist/util/collections.d.ts +1 -1
- package/dist/util/entities.d.ts +1 -1
- package/dist/util/icon_synonyms.d.ts +1 -97
- package/dist/util/icons.d.ts +2 -2
- package/dist/util/navigation_utils.d.ts +2 -2
- package/dist/util/objects.d.ts +1 -1
- package/dist/util/plurals.d.ts +0 -2
- package/dist/util/resolutions.d.ts +13 -13
- package/dist/util/storage.d.ts +23 -2
- package/dist/util/useStorageUploadController.d.ts +1 -1
- package/dist/util/useTraceUpdate.d.ts +1 -0
- package/package.json +130 -119
- package/src/app/AppBar.tsx +18 -0
- package/src/app/Drawer.tsx +25 -0
- package/src/app/Scaffold.tsx +249 -0
- package/src/app/index.ts +4 -0
- package/src/app/useApp.tsx +32 -0
- package/src/components/CircularProgressCenter.tsx +1 -1
- package/src/components/ClearFilterSortButton.tsx +41 -0
- package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +9 -18
- package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +21 -20
- package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +10 -6
- package/src/components/EntityCollectionTable/PropertyTableCell.tsx +38 -34
- package/src/components/EntityCollectionTable/column_utils.tsx +3 -3
- package/src/components/EntityCollectionTable/fields/TableReferenceField.tsx +11 -2
- package/src/components/EntityCollectionTable/fields/TableStorageUpload.tsx +14 -6
- 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 +4 -5
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +69 -45
- package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +68 -0
- package/src/components/EntityCollectionView/useSelectionController.tsx +19 -7
- package/src/components/EntityPreview.tsx +15 -9
- package/src/components/EntityView.tsx +5 -5
- package/src/components/ErrorView.tsx +1 -1
- package/src/components/HomePage/DefaultHomePage.tsx +3 -3
- package/src/components/HomePage/NavigationCard.tsx +3 -3
- package/src/components/HomePage/NavigationCardBinding.tsx +1 -1
- package/src/components/HomePage/SmallNavigationCard.tsx +5 -5
- package/src/components/PropertyIdCopyTooltipContent.tsx +2 -3
- package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +1 -0
- package/src/components/ReferenceWidget.tsx +22 -12
- package/src/components/SearchIconsView.tsx +5 -5
- package/src/components/SelectableTable/SelectableTable.tsx +7 -7
- package/src/components/SelectableTable/filters/BooleanFilterField.tsx +2 -3
- package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +22 -7
- package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +28 -6
- package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +35 -15
- package/src/components/VirtualTable/VirtualTable.tsx +70 -37
- package/src/components/VirtualTable/VirtualTableCell.tsx +1 -1
- package/src/components/VirtualTable/VirtualTableHeader.tsx +4 -4
- package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +2 -2
- package/src/components/VirtualTable/VirtualTableProps.tsx +18 -14
- 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 +2 -2
- 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 +11 -0
- package/src/components/common/useTableSearchHelper.ts +52 -12
- package/src/components/index.tsx +2 -1
- package/src/contexts/AuthControllerContext.tsx +1 -1
- package/src/contexts/DialogsProvider.tsx +2 -2
- package/src/{components/FireCMSAppBar.tsx → core/DefaultAppBar.tsx} +52 -37
- package/src/core/DefaultDrawer.tsx +177 -0
- package/src/core/DrawerNavigationItem.tsx +62 -0
- package/src/core/EntityEditView.tsx +676 -133
- package/src/core/EntitySidePanel.tsx +1 -2
- package/src/core/FireCMS.tsx +39 -44
- package/src/core/NavigationRoutes.tsx +7 -8
- package/src/core/field_configs.tsx +2 -3
- package/src/core/index.tsx +3 -4
- package/src/form/PropertiesForm.tsx +81 -0
- package/src/form/PropertyFieldBinding.tsx +29 -7
- package/src/form/components/FieldHelperText.tsx +3 -3
- package/src/form/components/StorageItemPreview.tsx +20 -11
- package/src/form/components/StorageUploadProgress.tsx +3 -3
- package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +8 -5
- package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +8 -5
- package/src/form/field_bindings/BlockFieldBinding.tsx +2 -2
- package/src/form/field_bindings/KeyValueFieldBinding.tsx +44 -39
- package/src/form/field_bindings/MapFieldBinding.tsx +11 -3
- package/src/form/field_bindings/MarkdownFieldBinding.tsx +2 -2
- package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +2 -9
- package/src/form/field_bindings/ReferenceFieldBinding.tsx +15 -13
- package/src/form/field_bindings/RepeatFieldBinding.tsx +10 -7
- package/src/form/field_bindings/SelectFieldBinding.tsx +3 -3
- package/src/form/field_bindings/StorageUploadFieldBinding.tsx +22 -43
- package/src/form/field_bindings/SwitchFieldBinding.tsx +1 -1
- package/src/form/index.tsx +4 -4
- package/src/form/validation.ts +1 -17
- package/src/hooks/data/delete.ts +3 -3
- package/src/hooks/data/save.ts +4 -2
- package/src/hooks/data/useDataSource.tsx +2 -2
- package/src/hooks/data/useEntityFetch.tsx +3 -3
- 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 +137 -61
- package/src/hooks/useProjectLog.tsx +21 -8
- package/src/hooks/useResolvedNavigationFrom.tsx +1 -1
- package/src/hooks/useValidateAuthenticator.tsx +115 -0
- package/src/index.ts +1 -0
- package/src/internal/useBuildDataSource.ts +56 -49
- package/src/internal/useBuildSideEntityController.tsx +88 -21
- package/src/preview/PropertyPreview.tsx +9 -16
- package/src/preview/PropertyPreviewProps.tsx +4 -8
- package/src/preview/components/BooleanPreview.tsx +4 -2
- package/src/preview/components/EnumValuesChip.tsx +1 -1
- package/src/preview/components/ImagePreview.tsx +21 -33
- package/src/preview/components/ReferencePreview.tsx +23 -23
- package/src/preview/components/StorageThumbnail.tsx +5 -1
- package/src/preview/components/UrlComponentPreview.tsx +44 -11
- 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 +2 -2
- package/src/types/auth.tsx +35 -2
- package/src/types/collections.ts +37 -8
- package/src/types/customization_controller.tsx +0 -1
- package/src/types/datasource.ts +41 -24
- package/src/types/entities.ts +9 -1
- package/src/types/entity_actions.tsx +16 -3
- package/src/types/entity_callbacks.ts +2 -2
- package/src/types/fields.tsx +33 -33
- package/src/types/index.ts +0 -1
- package/src/types/navigation.ts +6 -7
- package/src/types/plugins.tsx +18 -8
- package/src/types/properties.ts +22 -6
- package/src/types/storage.ts +12 -3
- package/src/util/collections.ts +1 -1
- package/src/util/entities.ts +5 -4
- 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/navigation_utils.ts +6 -6
- package/src/util/objects.ts +25 -28
- package/src/util/permissions.ts +1 -0
- package/src/util/plurals.ts +0 -2
- package/src/util/resolutions.ts +32 -31
- package/src/util/storage.ts +75 -21
- package/src/util/strings.ts +2 -2
- package/src/util/useStorageUploadController.tsx +21 -3
- package/src/util/useTraceUpdate.tsx +2 -1
- 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/internal/useBuildCustomizationController.d.ts +0 -2
- package/dist/internal/useLocaleConfig.d.ts +0 -1
- package/dist/types/appcheck.d.ts +0 -26
- 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/internal/useBuildCustomizationController.tsx +0 -5
- package/src/internal/useLocaleConfig.tsx +0 -18
- package/src/types/appcheck.ts +0 -29
|
@@ -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
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -5,12 +5,11 @@ import {
|
|
|
5
5
|
DeleteEntityProps,
|
|
6
6
|
Entity,
|
|
7
7
|
EntityCollection,
|
|
8
|
-
EntityReference,
|
|
9
8
|
EntityValues,
|
|
10
9
|
FetchCollectionProps,
|
|
11
10
|
FetchEntityProps,
|
|
12
11
|
FilterValues,
|
|
13
|
-
|
|
12
|
+
FireCMSContext,
|
|
14
13
|
ListenCollectionProps,
|
|
15
14
|
ListenEntityProps,
|
|
16
15
|
NavigationController,
|
|
@@ -207,20 +206,17 @@ export function useBuildDataSource({
|
|
|
207
206
|
|
|
208
207
|
const properties: ResolvedProperties<M> | undefined = resolvedCollection?.properties;
|
|
209
208
|
|
|
210
|
-
const firestoreValues = cmsToDelegateModel(
|
|
209
|
+
const firestoreValues = delegate.cmsToDelegateModel(
|
|
211
210
|
values,
|
|
212
|
-
delegate.buildReference,
|
|
213
|
-
delegate.buildGeoPoint,
|
|
214
|
-
delegate.buildDate,
|
|
215
|
-
delegate.buildDeleteFieldValue
|
|
216
211
|
);
|
|
212
|
+
|
|
217
213
|
const updatedFirestoreValues: EntityValues<M> = properties
|
|
218
214
|
? updateDateAutoValues(
|
|
219
215
|
{
|
|
220
216
|
inputValues: firestoreValues,
|
|
221
217
|
properties,
|
|
222
218
|
status,
|
|
223
|
-
timestampNowValue: delegate.currentTime(),
|
|
219
|
+
timestampNowValue: delegate.currentTime?.() ?? new Date(),
|
|
224
220
|
setDateToMidnight: delegate.setDateToMidnight
|
|
225
221
|
})
|
|
226
222
|
: firestoreValues;
|
|
@@ -294,7 +290,7 @@ export function useBuildDataSource({
|
|
|
294
290
|
filter,
|
|
295
291
|
orderBy,
|
|
296
292
|
order,
|
|
297
|
-
isCollectionGroup: Boolean(collection.collectionGroup)
|
|
293
|
+
isCollectionGroup: Boolean(collection.collectionGroup)
|
|
298
294
|
});
|
|
299
295
|
} : undefined,
|
|
300
296
|
|
|
@@ -316,48 +312,59 @@ export function useBuildDataSource({
|
|
|
316
312
|
sortBy
|
|
317
313
|
}
|
|
318
314
|
)
|
|
319
|
-
}, [delegate.isFilterCombinationValid])
|
|
315
|
+
}, [delegate.isFilterCombinationValid]),
|
|
316
|
+
|
|
317
|
+
initTextSearch: useCallback(async (props: {
|
|
318
|
+
context: FireCMSContext,
|
|
319
|
+
path: string,
|
|
320
|
+
collection: EntityCollection,
|
|
321
|
+
parentCollectionIds?: string[]
|
|
322
|
+
}): Promise<boolean> => {
|
|
323
|
+
if (!delegate.initTextSearch)
|
|
324
|
+
return false;
|
|
325
|
+
return delegate.initTextSearch(props)
|
|
326
|
+
}, [delegate.initTextSearch]),
|
|
320
327
|
|
|
321
328
|
};
|
|
322
329
|
|
|
323
330
|
}
|
|
324
331
|
|
|
325
|
-
/**
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
export function cmsToDelegateModel(data: any,
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
): any {
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
}
|
|
332
|
+
// /**
|
|
333
|
+
// * Recursive function that converts Firestore data types into CMS or plain
|
|
334
|
+
// * JS types.
|
|
335
|
+
// * FireCMS uses Javascript dates internally instead of Firestore timestamps.
|
|
336
|
+
// * This makes it easier to interact with the rest of the libraries and
|
|
337
|
+
// * bindings.
|
|
338
|
+
// * Also, Firestore references are replaced with {@link EntityReference}
|
|
339
|
+
// * @param data
|
|
340
|
+
// * @param buildReference
|
|
341
|
+
// * @param buildGeoPoint
|
|
342
|
+
// * @param buildDate
|
|
343
|
+
// * @param buildDelete
|
|
344
|
+
// * @group Firestore
|
|
345
|
+
// */
|
|
346
|
+
// export function cmsToDelegateModel(data: any,
|
|
347
|
+
// buildReference: (reference: EntityReference) => any,
|
|
348
|
+
// buildGeoPoint: (geoPoint: GeoPoint) => any,
|
|
349
|
+
// buildDate: (date: Date) => any,
|
|
350
|
+
// buildDelete: () => any
|
|
351
|
+
// ): any {
|
|
352
|
+
// if (data === undefined) {
|
|
353
|
+
// return buildDelete();
|
|
354
|
+
// } else if (data === null) {
|
|
355
|
+
// return null;
|
|
356
|
+
// } else if (Array.isArray(data)) {
|
|
357
|
+
// return data.map(v => cmsToDelegateModel(v, buildReference, buildGeoPoint, buildDate, buildDelete));
|
|
358
|
+
// } else if (data.isEntityReference && data.isEntityReference()) {
|
|
359
|
+
// return buildReference(data);
|
|
360
|
+
// } else if (data instanceof GeoPoint) {
|
|
361
|
+
// return buildGeoPoint(data);
|
|
362
|
+
// } else if (data instanceof Date) {
|
|
363
|
+
// return buildDate(data);
|
|
364
|
+
// } else if (data && typeof data === "object") {
|
|
365
|
+
// return Object.entries(data)
|
|
366
|
+
// .map(([key, v]) => ({ [key]: cmsToDelegateModel(v, buildReference, buildGeoPoint, buildDate, buildDelete) }))
|
|
367
|
+
// .reduce((a, b) => ({ ...a, ...b }), {});
|
|
368
|
+
// }
|
|
369
|
+
// return data;
|
|
370
|
+
// }
|
|
@@ -2,14 +2,15 @@ import { useCallback, useEffect, useRef } from "react";
|
|
|
2
2
|
import {
|
|
3
3
|
EntityCollection,
|
|
4
4
|
EntitySidePanelProps,
|
|
5
|
-
NavigationController,
|
|
5
|
+
NavigationController, PropertyConfig,
|
|
6
|
+
ResolvedProperty,
|
|
6
7
|
SideDialogPanelProps,
|
|
7
8
|
SideDialogsController,
|
|
8
9
|
SideEntityController
|
|
9
10
|
} from "../types";
|
|
10
11
|
import { getNavigationEntriesFromPathInternal, NavigationViewInternal } from "../util/navigation_from_path";
|
|
11
12
|
import { useLocation } from "react-router-dom";
|
|
12
|
-
import { removeInitialAndTrailingSlashes, resolveDefaultSelectedView } from "../util";
|
|
13
|
+
import { removeInitialAndTrailingSlashes, resolveCollection, resolveDefaultSelectedView } from "../util";
|
|
13
14
|
import { ADDITIONAL_TAB_WIDTH, CONTAINER_FULL_WIDTH, FORM_CONTAINER_WIDTH } from "./common";
|
|
14
15
|
import { useLargeLayout } from "../hooks";
|
|
15
16
|
import { EntitySidePanel } from "../core/EntitySidePanel";
|
|
@@ -19,8 +20,67 @@ const NEW_URL_HASH = "new";
|
|
|
19
20
|
export function getEntityViewWidth(props: EntitySidePanelProps<any>, small: boolean): string {
|
|
20
21
|
if (small) return CONTAINER_FULL_WIDTH;
|
|
21
22
|
const mainViewSelected = !props.selectedSubPath;
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
let resolvedWidth: string | undefined;
|
|
24
|
+
if (props.width) {
|
|
25
|
+
resolvedWidth = typeof props.width === "number" ? `${props.width}px` : props.width;
|
|
26
|
+
} else if (props.collection?.sideDialogWidth) {
|
|
27
|
+
resolvedWidth = typeof props.collection.sideDialogWidth === "number" ? `${props.collection.sideDialogWidth}px` : props.collection.sideDialogWidth;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (!mainViewSelected) {
|
|
31
|
+
return `calc(${ADDITIONAL_TAB_WIDTH} + ${resolvedWidth ?? FORM_CONTAINER_WIDTH})`
|
|
32
|
+
} else {
|
|
33
|
+
if (resolvedWidth) {
|
|
34
|
+
return resolvedWidth
|
|
35
|
+
} else if (!props.collection) {
|
|
36
|
+
return FORM_CONTAINER_WIDTH;
|
|
37
|
+
} else {
|
|
38
|
+
return calculateCollectionDesiredWidth(props.collection);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const collectionViewWidthCache: { [key: string]: string } = {};
|
|
44
|
+
|
|
45
|
+
function calculateCollectionDesiredWidth(collection: EntityCollection<any>): string {
|
|
46
|
+
if (collectionViewWidthCache[collection.id]) {
|
|
47
|
+
return collectionViewWidthCache[collection.id];
|
|
48
|
+
}
|
|
49
|
+
const resolvedCollection = resolveCollection({
|
|
50
|
+
collection,
|
|
51
|
+
path: "__ignored",
|
|
52
|
+
ignoreMissingFields: true
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
let result = FORM_CONTAINER_WIDTH
|
|
56
|
+
if (resolvedCollection?.properties) {
|
|
57
|
+
const values = Object.values(resolvedCollection.properties).map((p: ResolvedProperty) => getNestedPropertiesDepth(p));
|
|
58
|
+
const maxDepth = Math.max(...values);
|
|
59
|
+
if (maxDepth < 3) {
|
|
60
|
+
result = FORM_CONTAINER_WIDTH;
|
|
61
|
+
} else {
|
|
62
|
+
result = 768 + 32 * (maxDepth - 2) + "px";
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
collectionViewWidthCache[collection.id] = result;
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function getNestedPropertiesDepth(property: ResolvedProperty, accumulator: number = 0): number {
|
|
70
|
+
if (property.dataType === "map" && property.properties) {
|
|
71
|
+
const values = Object.values(property.properties).flatMap((property) => getNestedPropertiesDepth(property, accumulator + 1));
|
|
72
|
+
return Math.max(...values);
|
|
73
|
+
} else if (property.dataType === "array" && property.oneOf) {
|
|
74
|
+
return accumulator + 3;
|
|
75
|
+
} else if (property.dataType === "array" && property.of) {
|
|
76
|
+
if (Array.isArray(property.of)) {
|
|
77
|
+
return Math.max(...property.of.map((p) => getNestedPropertiesDepth(p, accumulator + 1)));
|
|
78
|
+
} else {
|
|
79
|
+
return getNestedPropertiesDepth(property.of, accumulator + 1);
|
|
80
|
+
}
|
|
81
|
+
} else {
|
|
82
|
+
return accumulator + 1;
|
|
83
|
+
}
|
|
24
84
|
}
|
|
25
85
|
|
|
26
86
|
export const useBuildSideEntityController = (navigation: NavigationController,
|
|
@@ -34,23 +94,26 @@ export const useBuildSideEntityController = (navigation: NavigationController,
|
|
|
34
94
|
// only on initialisation, create panels from URL
|
|
35
95
|
useEffect(() => {
|
|
36
96
|
if (!navigation.loading && !initialised.current) {
|
|
97
|
+
console.debug("Initialising side entity controller");
|
|
37
98
|
if (navigation.isUrlCollectionPath(location.pathname)) {
|
|
38
99
|
const newFlag = location.hash === `#${NEW_URL_HASH}`;
|
|
39
100
|
const entityOrCollectionPath = navigation.urlPathToDataPath(location.pathname);
|
|
40
101
|
const panelsFromUrl = buildSidePanelsFromUrl(entityOrCollectionPath, navigation.collections ?? [], newFlag);
|
|
41
102
|
for (let i = 0; i < panelsFromUrl.length; i++) {
|
|
42
|
-
const
|
|
103
|
+
const props = panelsFromUrl[i];
|
|
43
104
|
setTimeout(() => {
|
|
44
105
|
if (i === 0)
|
|
45
|
-
sideDialogsController.replace(propsToSidePanel(
|
|
106
|
+
sideDialogsController.replace(propsToSidePanel(props, navigation.buildUrlCollectionPath, navigation.resolveAliasesFrom, smallLayout));
|
|
46
107
|
else
|
|
47
|
-
sideDialogsController.open(propsToSidePanel(
|
|
108
|
+
sideDialogsController.open(propsToSidePanel(props, navigation.buildUrlCollectionPath, navigation.resolveAliasesFrom, smallLayout))
|
|
48
109
|
}, 1);
|
|
49
110
|
}
|
|
111
|
+
} else {
|
|
112
|
+
// console.warn("Location path is not a collection path");
|
|
50
113
|
}
|
|
51
114
|
initialised.current = true;
|
|
52
115
|
}
|
|
53
|
-
}, [location, navigation, sideDialogsController, smallLayout]);
|
|
116
|
+
}, [location, navigation.loading, navigation.isUrlCollectionPath, navigation.buildUrlCollectionPath, navigation.resolveAliasesFrom, sideDialogsController, smallLayout, navigation]);
|
|
54
117
|
|
|
55
118
|
const close = useCallback(() => {
|
|
56
119
|
sideDialogsController.close();
|
|
@@ -73,9 +136,9 @@ export const useBuildSideEntityController = (navigation: NavigationController,
|
|
|
73
136
|
sideDialogsController.open(propsToSidePanel({
|
|
74
137
|
selectedSubPath: defaultSelectedView,
|
|
75
138
|
...props,
|
|
76
|
-
}, navigation, smallLayout));
|
|
139
|
+
}, navigation.buildUrlCollectionPath, navigation.resolveAliasesFrom, smallLayout));
|
|
77
140
|
|
|
78
|
-
}, [sideDialogsController, navigation, smallLayout]);
|
|
141
|
+
}, [sideDialogsController, navigation.buildUrlCollectionPath, navigation.resolveAliasesFrom, smallLayout]);
|
|
79
142
|
|
|
80
143
|
const replace = useCallback((props: EntitySidePanelProps<any>) => {
|
|
81
144
|
|
|
@@ -83,9 +146,9 @@ export const useBuildSideEntityController = (navigation: NavigationController,
|
|
|
83
146
|
throw Error("If you want to copy an entity you need to provide an entityId");
|
|
84
147
|
}
|
|
85
148
|
|
|
86
|
-
sideDialogsController.replace(propsToSidePanel(props, navigation, smallLayout));
|
|
149
|
+
sideDialogsController.replace(propsToSidePanel(props, navigation.buildUrlCollectionPath, navigation.resolveAliasesFrom, smallLayout));
|
|
87
150
|
|
|
88
|
-
}, [navigation, sideDialogsController, smallLayout]);
|
|
151
|
+
}, [navigation.buildUrlCollectionPath, navigation.resolveAliasesFrom, sideDialogsController, smallLayout]);
|
|
89
152
|
|
|
90
153
|
return {
|
|
91
154
|
close,
|
|
@@ -116,7 +179,8 @@ export function buildSidePanelsFromUrl(path: string, collections: EntityCollecti
|
|
|
116
179
|
sidePanels.push({
|
|
117
180
|
path: navigationEntry.path,
|
|
118
181
|
entityId: navigationEntry.entityId,
|
|
119
|
-
copy: false
|
|
182
|
+
copy: false,
|
|
183
|
+
width: navigationEntry.parentCollection?.sideDialogWidth
|
|
120
184
|
}
|
|
121
185
|
);
|
|
122
186
|
} else if (navigationEntry.type === "custom_view") {
|
|
@@ -146,27 +210,30 @@ export function buildSidePanelsFromUrl(path: string, collections: EntityCollecti
|
|
|
146
210
|
return sidePanels;
|
|
147
211
|
}
|
|
148
212
|
|
|
149
|
-
const propsToSidePanel = (props: EntitySidePanelProps<any>,
|
|
213
|
+
const propsToSidePanel = (props: EntitySidePanelProps<any>,
|
|
214
|
+
buildUrlCollectionPath: (path: string) => string,
|
|
215
|
+
resolveAliasesFrom: (pathWithAliases: string) => string,
|
|
216
|
+
smallLayout: boolean): SideDialogPanelProps => {
|
|
150
217
|
|
|
151
218
|
const collectionPath = removeInitialAndTrailingSlashes(props.path);
|
|
152
219
|
|
|
153
220
|
const newPath = props.entityId
|
|
154
|
-
?
|
|
155
|
-
:
|
|
156
|
-
const resolvedPath =
|
|
221
|
+
? buildUrlCollectionPath(`${collectionPath}/${props.entityId}/${props.selectedSubPath || ""}`)
|
|
222
|
+
: buildUrlCollectionPath(`${collectionPath}#${NEW_URL_HASH}`);
|
|
223
|
+
const resolvedPath = resolveAliasesFrom(props.path);
|
|
157
224
|
|
|
158
225
|
const resolvedPanelProps: EntitySidePanelProps<any> = {
|
|
159
226
|
...props,
|
|
160
|
-
path: resolvedPath
|
|
227
|
+
path: resolvedPath,
|
|
161
228
|
};
|
|
162
229
|
|
|
163
|
-
return
|
|
230
|
+
return {
|
|
164
231
|
key: `${props.path}/${props.entityId}`,
|
|
165
232
|
component: <EntitySidePanel {...resolvedPanelProps}/>,
|
|
166
233
|
urlPath: newPath,
|
|
167
|
-
parentUrlPath:
|
|
234
|
+
parentUrlPath: buildUrlCollectionPath(collectionPath),
|
|
168
235
|
width: getEntityViewWidth(props, smallLayout),
|
|
169
236
|
onClose: props.onClose
|
|
170
|
-
}
|
|
237
|
+
};
|
|
171
238
|
}
|
|
172
239
|
;
|
|
@@ -47,13 +47,12 @@ export const PropertyPreview = React.memo(function PropertyPreview<T extends CMS
|
|
|
47
47
|
size,
|
|
48
48
|
height,
|
|
49
49
|
width,
|
|
50
|
-
|
|
50
|
+
interactive
|
|
51
51
|
} = props;
|
|
52
52
|
|
|
53
53
|
const property = resolveProperty({
|
|
54
54
|
propertyKey,
|
|
55
55
|
propertyOrBuilder: inputProperty,
|
|
56
|
-
propertyValue: value,
|
|
57
56
|
fields: customizationController.propertyConfigs
|
|
58
57
|
});
|
|
59
58
|
|
|
@@ -85,14 +84,17 @@ export const PropertyPreview = React.memo(function PropertyPreview<T extends CMS
|
|
|
85
84
|
content =
|
|
86
85
|
<UrlComponentPreview size={props.size}
|
|
87
86
|
url={value}
|
|
87
|
+
interactive={interactive}
|
|
88
88
|
previewType={stringProperty.url}/>;
|
|
89
89
|
} else if (stringProperty.storage) {
|
|
90
|
+
const filePath = stringProperty.storage.previewUrl ? stringProperty.storage.previewUrl(value) : value;
|
|
90
91
|
content = <StorageThumbnail
|
|
92
|
+
interactive={interactive}
|
|
91
93
|
storeUrl={property.storage?.storeUrl ?? false}
|
|
92
94
|
size={props.size}
|
|
93
|
-
storagePathOrDownloadUrl={
|
|
95
|
+
storagePathOrDownloadUrl={filePath}/>;
|
|
94
96
|
} else if (stringProperty.markdown) {
|
|
95
|
-
content = <Markdown source={value}/>;
|
|
97
|
+
content = <Markdown source={value} size={"small"}/>;
|
|
96
98
|
} else {
|
|
97
99
|
content = <StringPropertyPreview {...props}
|
|
98
100
|
property={stringProperty}
|
|
@@ -113,17 +115,7 @@ export const PropertyPreview = React.memo(function PropertyPreview<T extends CMS
|
|
|
113
115
|
content = <ArrayPropertyPreview {...props}
|
|
114
116
|
value={value}
|
|
115
117
|
property={property as ResolvedArrayProperty}/>;
|
|
116
|
-
}
|
|
117
|
-
// else if (arrayProperty.of.dataType === "map") {
|
|
118
|
-
// content =
|
|
119
|
-
// <ArrayOfMapsPreview propertyKey={propertyKey}
|
|
120
|
-
// property={property as ResolvedArrayProperty}
|
|
121
|
-
// value={value as Record<string, any>[]} // This might be wrong
|
|
122
|
-
// entity={entity}
|
|
123
|
-
// size={size}
|
|
124
|
-
// />;
|
|
125
|
-
// }
|
|
126
|
-
else if (arrayProperty.of.dataType === "reference") {
|
|
118
|
+
} else if (arrayProperty.of.dataType === "reference") {
|
|
127
119
|
content = <ArrayOfReferencesPreview {...props}
|
|
128
120
|
value={value}
|
|
129
121
|
property={property as ResolvedArrayProperty}/>;
|
|
@@ -182,8 +174,9 @@ export const PropertyPreview = React.memo(function PropertyPreview<T extends CMS
|
|
|
182
174
|
content = <ReferencePreview
|
|
183
175
|
disabled={!property.path}
|
|
184
176
|
previewProperties={property.previewProperties}
|
|
177
|
+
includeId={property.includeId}
|
|
178
|
+
includeEntityLink={property.includeEntityLink}
|
|
185
179
|
size={props.size}
|
|
186
|
-
// onClick={props.onClick}
|
|
187
180
|
reference={value as EntityReference}
|
|
188
181
|
/>;
|
|
189
182
|
} else {
|
|
@@ -8,7 +8,7 @@ export type PreviewSize = "medium" | "small" | "tiny";
|
|
|
8
8
|
/**
|
|
9
9
|
* @group Preview components
|
|
10
10
|
*/
|
|
11
|
-
export interface PropertyPreviewProps<T extends CMSType = any, CustomProps = any
|
|
11
|
+
export interface PropertyPreviewProps<T extends CMSType = any, CustomProps = any> {
|
|
12
12
|
/**
|
|
13
13
|
* Name of the property
|
|
14
14
|
*/
|
|
@@ -24,11 +24,6 @@ export interface PropertyPreviewProps<T extends CMSType = any, CustomProps = any
|
|
|
24
24
|
*/
|
|
25
25
|
property: Property<T> | ResolvedProperty<T>;
|
|
26
26
|
|
|
27
|
-
/**
|
|
28
|
-
* Click handler
|
|
29
|
-
*/
|
|
30
|
-
// onClick?: () => void;
|
|
31
|
-
|
|
32
27
|
/**
|
|
33
28
|
* Desired size of the preview, depending on the context.
|
|
34
29
|
*/
|
|
@@ -52,8 +47,9 @@ export interface PropertyPreviewProps<T extends CMSType = any, CustomProps = any
|
|
|
52
47
|
customProps?: CustomProps;
|
|
53
48
|
|
|
54
49
|
/**
|
|
55
|
-
*
|
|
50
|
+
* If the preview should be interactive or not.
|
|
51
|
+
* This applies only to videos.
|
|
56
52
|
*/
|
|
57
|
-
|
|
53
|
+
interactive?: boolean;
|
|
58
54
|
|
|
59
55
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { Checkbox } from "@firecms/ui";
|
|
2
|
+
import { Checkbox, cls } from "@firecms/ui";
|
|
3
3
|
import { PreviewSize } from "../PropertyPreviewProps";
|
|
4
4
|
import { Property } from "../../types";
|
|
5
5
|
|
|
@@ -17,8 +17,10 @@ export function BooleanPreview({
|
|
|
17
17
|
}): React.ReactElement {
|
|
18
18
|
return <div className={"flex flex-row gap-2 items-center"}>
|
|
19
19
|
<Checkbox checked={value}
|
|
20
|
+
padding={false}
|
|
20
21
|
size={size}
|
|
21
22
|
color={"secondary"}/>
|
|
22
|
-
{property.name && <span
|
|
23
|
+
{property.name && <span
|
|
24
|
+
className={cls("text-text-secondary dark:text-text-secondary-dark", size === "tiny" ? "text-sm" : "")}>{property.name}</span>}
|
|
23
25
|
</div>;
|
|
24
26
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
+
import { Chip } from "@firecms/ui";
|
|
2
3
|
import { EnumValues } from "../../types";
|
|
3
4
|
import { buildEnumLabel, enumToObjectEntries, getColorScheme, getLabelOrConfigFrom } from "../../util/enums";
|
|
4
|
-
import { Chip } from "@firecms/ui";
|
|
5
5
|
|
|
6
6
|
export interface EnumValuesChipProps {
|
|
7
7
|
enumValues?: EnumValues;
|