@firecms/core 3.0.0-beta.11 → 3.0.0-beta.13
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/dist/app/Scaffold.d.ts +4 -0
- package/dist/components/ArrayContainer.d.ts +14 -3
- package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +2 -1
- package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +2 -2
- package/dist/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +15 -1
- package/dist/components/EntityCollectionTable/index.d.ts +1 -1
- package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +8 -0
- package/dist/components/EntityJsonPreview.d.ts +3 -0
- package/dist/components/PropertyIdCopyTooltip.d.ts +1 -1
- package/dist/components/SelectableTable/SelectableTable.d.ts +12 -2
- package/dist/components/SelectableTable/filters/ReferenceFilterField.d.ts +1 -1
- package/dist/components/UnsavedChangesDialog.d.ts +8 -0
- package/dist/components/VirtualTable/VirtualTableProps.d.ts +13 -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/contexts/BreacrumbsContext.d.ts +8 -0
- package/dist/core/DefaultAppBar.d.ts +8 -2
- package/dist/core/EntityEditView.d.ts +36 -21
- package/dist/core/EntityEditViewFormActions.d.ts +2 -0
- package/dist/core/FireCMS.d.ts +2 -2
- 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/index.d.ts +2 -1
- package/dist/form/EntityForm.d.ts +49 -0
- package/dist/form/EntityFormActions.d.ts +17 -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/index.d.ts +2 -0
- 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/MapFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/MarkdownEditorFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/RepeatFieldBinding.d.ts +1 -1
- package/dist/form/index.d.ts +16 -16
- package/dist/hooks/data/save.d.ts +1 -1
- package/dist/hooks/data/useEntityFetch.d.ts +2 -1
- package/dist/hooks/useBreadcrumbsController.d.ts +26 -0
- package/dist/hooks/useBuildNavigationController.d.ts +4 -1
- package/dist/hooks/useModeController.d.ts +1 -2
- package/dist/index.es.js +15842 -14396
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +15833 -14389
- 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/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/collections.d.ts +36 -10
- package/dist/types/datasource.d.ts +2 -2
- package/dist/types/dialogs_controller.d.ts +7 -3
- package/dist/types/entities.d.ts +1 -1
- package/dist/types/entity_actions.d.ts +10 -0
- package/dist/types/fields.d.ts +13 -3
- package/dist/types/firecms.d.ts +1 -1
- package/dist/types/navigation.d.ts +33 -12
- package/dist/types/plugins.d.ts +2 -0
- package/dist/types/properties.d.ts +40 -4
- package/dist/types/side_entity_controller.d.ts +6 -1
- package/dist/util/builders.d.ts +1 -1
- package/dist/util/createFormexStub.d.ts +2 -0
- package/dist/util/entity_actions.d.ts +2 -0
- package/dist/util/entity_cache.d.ts +23 -0
- package/dist/util/index.d.ts +1 -0
- package/dist/util/navigation_from_path.d.ts +6 -1
- package/dist/util/navigation_utils.d.ts +13 -1
- package/dist/util/objects.d.ts +1 -1
- package/dist/util/property_utils.d.ts +2 -2
- package/dist/util/references.d.ts +2 -2
- package/dist/util/resolutions.d.ts +12 -2
- package/package.json +20 -21
- package/src/app/Scaffold.tsx +13 -3
- package/src/components/ArrayContainer.tsx +60 -24
- package/src/components/CircularProgressCenter.tsx +1 -1
- package/src/components/DeleteEntityDialog.tsx +5 -3
- package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +46 -23
- package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +10 -4
- package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +18 -1
- package/src/components/EntityCollectionTable/index.tsx +1 -1
- package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +3 -3
- package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +10 -13
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +105 -47
- package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +4 -2
- package/src/components/EntityJsonPreview.tsx +66 -0
- package/src/components/EntityPreview.tsx +10 -3
- package/src/components/EntityView.tsx +4 -1
- package/src/components/NotFoundPage.tsx +2 -2
- package/src/components/PropertyIdCopyTooltip.tsx +2 -3
- package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +14 -7
- package/src/components/SelectableTable/SelectableTable.tsx +18 -3
- package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +7 -7
- package/src/components/UnsavedChangesDialog.tsx +42 -0
- package/src/components/VirtualTable/VirtualTable.tsx +48 -3
- package/src/components/VirtualTable/VirtualTableProps.tsx +15 -0
- package/src/components/VirtualTable/fields/VirtualTableInput.tsx +1 -1
- package/src/components/common/default_entity_actions.tsx +37 -37
- package/src/components/common/index.ts +1 -1
- package/src/components/common/useColumnsIds.tsx +1 -1
- 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/contexts/BreacrumbsContext.tsx +38 -0
- package/src/contexts/DialogsProvider.tsx +3 -2
- package/src/contexts/ModeController.tsx +1 -3
- package/src/core/DefaultAppBar.tsx +59 -17
- package/src/core/DefaultDrawer.tsx +1 -1
- package/src/core/EntityEditView.tsx +354 -1000
- package/src/core/EntityEditViewFormActions.tsx +199 -0
- package/src/core/EntitySidePanel.tsx +85 -15
- package/src/core/FireCMS.tsx +20 -16
- package/src/core/FireCMSRouter.tsx +17 -0
- package/src/core/NavigationRoutes.tsx +23 -32
- package/src/core/SideDialogs.tsx +20 -11
- package/src/core/index.tsx +4 -2
- package/src/form/EntityForm.tsx +782 -0
- package/src/form/EntityFormActions.tsx +169 -0
- package/src/form/PropertyFieldBinding.tsx +21 -16
- package/src/form/components/FormEntry.tsx +22 -0
- package/src/form/components/FormLayout.tsx +16 -0
- package/src/form/components/LabelWithIcon.tsx +6 -3
- package/src/form/components/StorageUploadProgress.tsx +1 -1
- package/src/form/components/index.tsx +2 -0
- package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +8 -5
- package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +5 -2
- package/src/form/field_bindings/BlockFieldBinding.tsx +5 -3
- package/src/form/field_bindings/DateTimeFieldBinding.tsx +1 -0
- package/src/form/field_bindings/KeyValueFieldBinding.tsx +1 -1
- package/src/form/field_bindings/MapFieldBinding.tsx +14 -16
- package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +15 -8
- package/src/form/field_bindings/MultiSelectFieldBinding.tsx +3 -3
- package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +2 -2
- package/src/form/field_bindings/ReferenceFieldBinding.tsx +1 -1
- package/src/form/field_bindings/RepeatFieldBinding.tsx +13 -4
- package/src/form/field_bindings/SelectFieldBinding.tsx +2 -2
- package/src/form/field_bindings/StorageUploadFieldBinding.tsx +11 -6
- package/src/form/field_bindings/SwitchFieldBinding.tsx +1 -0
- package/src/form/field_bindings/TextFieldBinding.tsx +1 -0
- package/src/form/index.tsx +16 -32
- package/src/form/validation.ts +12 -6
- package/src/hooks/data/save.ts +25 -30
- package/src/hooks/data/useCollectionFetch.tsx +1 -1
- package/src/hooks/data/useEntityFetch.tsx +5 -1
- package/src/hooks/useBreadcrumbsController.tsx +31 -0
- package/src/hooks/useBuildModeController.tsx +15 -28
- package/src/hooks/useBuildNavigationController.tsx +81 -24
- package/src/hooks/useFireCMSContext.tsx +0 -30
- package/src/hooks/useLargeLayout.tsx +0 -35
- package/src/hooks/useModeController.tsx +1 -2
- package/src/hooks/useResolvedNavigationFrom.tsx +4 -6
- package/src/internal/useBuildDataSource.ts +9 -5
- package/src/internal/useBuildSideDialogsController.tsx +3 -2
- package/src/internal/useBuildSideEntityController.tsx +135 -88
- package/src/internal/useUnsavedChangesDialog.tsx +126 -92
- package/src/preview/PropertyPreview.tsx +12 -10
- package/src/preview/components/UrlComponentPreview.tsx +17 -18
- package/src/preview/property_previews/ArrayOfMapsPreview.tsx +4 -3
- package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +4 -3
- package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +4 -2
- package/src/preview/property_previews/ArrayOfStringsPreview.tsx +4 -3
- package/src/preview/property_previews/ArrayOneOfPreview.tsx +4 -2
- package/src/preview/property_previews/ArrayPropertyPreview.tsx +4 -2
- package/src/preview/property_previews/MapPropertyPreview.tsx +3 -2
- package/src/routes/CustomCMSRoute.tsx +21 -0
- package/src/routes/FireCMSRoute.tsx +246 -0
- package/src/routes/HomePageRoute.tsx +17 -0
- package/src/types/collections.ts +45 -13
- package/src/types/datasource.ts +2 -1
- package/src/types/dialogs_controller.tsx +7 -3
- package/src/types/entities.ts +1 -1
- package/src/types/entity_actions.tsx +12 -0
- package/src/types/fields.tsx +18 -3
- package/src/types/firecms.tsx +1 -1
- package/src/types/navigation.ts +41 -16
- package/src/types/plugins.tsx +2 -0
- package/src/types/properties.ts +48 -4
- package/src/types/side_dialogs_controller.tsx +2 -0
- package/src/types/side_entity_controller.tsx +11 -1
- package/src/util/builders.ts +5 -3
- package/src/util/createFormexStub.tsx +62 -0
- package/src/util/entity_actions.ts +28 -0
- package/src/util/entity_cache.ts +204 -0
- package/src/util/index.ts +1 -0
- package/src/util/join_collections.ts +6 -1
- package/src/util/navigation_from_path.ts +18 -7
- package/src/util/navigation_utils.ts +115 -14
- package/src/util/objects.ts +9 -2
- package/src/util/parent_references_from_path.ts +3 -3
- package/src/util/property_utils.tsx +7 -3
- package/src/util/references.ts +8 -6
- package/src/util/resolutions.ts +41 -12
- package/src/util/useStorageUploadController.tsx +60 -23
- package/src/components/common/useDataSourceEntityCollectionTableController.tsx +0 -236
- /package/src/util/{common.tsx → common.ts} +0 -0
package/src/util/resolutions.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ArrayProperty,
|
|
3
|
+
AuthController,
|
|
3
4
|
CMSType,
|
|
5
|
+
CustomizationController,
|
|
4
6
|
EntityCollection,
|
|
5
7
|
EntityCustomView,
|
|
6
8
|
EntityValues,
|
|
@@ -26,9 +28,7 @@ import { getDefaultValuesFor, isPropertyBuilder } from "./entities";
|
|
|
26
28
|
import { DEFAULT_ONE_OF_TYPE } from "./common";
|
|
27
29
|
import { getIn } from "@firecms/formex";
|
|
28
30
|
import { enumToObjectEntries } from "./enums";
|
|
29
|
-
import { isDefaultFieldConfigId } from "../core
|
|
30
|
-
|
|
31
|
-
// import util from "util";
|
|
31
|
+
import { isDefaultFieldConfigId } from "../core";
|
|
32
32
|
|
|
33
33
|
export const resolveCollection = <M extends Record<string, any>, >
|
|
34
34
|
({
|
|
@@ -39,7 +39,8 @@ export const resolveCollection = <M extends Record<string, any>, >
|
|
|
39
39
|
previousValues,
|
|
40
40
|
userConfigPersistence,
|
|
41
41
|
propertyConfigs,
|
|
42
|
-
ignoreMissingFields = false
|
|
42
|
+
ignoreMissingFields = false,
|
|
43
|
+
authController
|
|
43
44
|
}: {
|
|
44
45
|
collection: EntityCollection<M> | ResolvedEntityCollection<M>;
|
|
45
46
|
path: string,
|
|
@@ -49,6 +50,7 @@ export const resolveCollection = <M extends Record<string, any>, >
|
|
|
49
50
|
userConfigPersistence?: UserConfigurationPersistence;
|
|
50
51
|
propertyConfigs?: Record<string, PropertyConfig>;
|
|
51
52
|
ignoreMissingFields?: boolean;
|
|
53
|
+
authController: AuthController;
|
|
52
54
|
}): ResolvedEntityCollection<M> => {
|
|
53
55
|
|
|
54
56
|
const collectionOverride = userConfigPersistence?.getCollectionConfig<M>(path);
|
|
@@ -68,7 +70,8 @@ export const resolveCollection = <M extends Record<string, any>, >
|
|
|
68
70
|
path,
|
|
69
71
|
entityId,
|
|
70
72
|
propertyConfigs: propertyConfigs,
|
|
71
|
-
ignoreMissingFields
|
|
73
|
+
ignoreMissingFields,
|
|
74
|
+
authController
|
|
72
75
|
});
|
|
73
76
|
if (!childResolvedProperty) return {};
|
|
74
77
|
return ({
|
|
@@ -113,6 +116,7 @@ export function resolveProperty<T extends CMSType = CMSType, M extends Record<st
|
|
|
113
116
|
fromBuilder?: boolean;
|
|
114
117
|
propertyConfigs?: Record<string, PropertyConfig<any>>;
|
|
115
118
|
ignoreMissingFields?: boolean;
|
|
119
|
+
authController: AuthController;
|
|
116
120
|
}): ResolvedProperty<T> | null {
|
|
117
121
|
|
|
118
122
|
if (typeof propertyOrBuilder === "object" && "resolved" in propertyOrBuilder) {
|
|
@@ -218,11 +222,11 @@ export function resolveProperty<T extends CMSType = CMSType, M extends Record<st
|
|
|
218
222
|
}
|
|
219
223
|
|
|
220
224
|
export function getArrayResolvedProperties<M>({
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
225
|
+
propertyKey,
|
|
226
|
+
propertyValue,
|
|
227
|
+
property,
|
|
228
|
+
...props
|
|
229
|
+
}: {
|
|
226
230
|
propertyValue: any,
|
|
227
231
|
propertyKey?: string,
|
|
228
232
|
property: ArrayProperty<any> | ResolvedArrayProperty<any>,
|
|
@@ -233,7 +237,8 @@ export function getArrayResolvedProperties<M>({
|
|
|
233
237
|
entityId?: string;
|
|
234
238
|
index?: number;
|
|
235
239
|
fromBuilder?: boolean;
|
|
236
|
-
propertyConfigs?: Record<string, PropertyConfig
|
|
240
|
+
propertyConfigs?: Record<string, PropertyConfig>;
|
|
241
|
+
authController: AuthController;
|
|
237
242
|
}) {
|
|
238
243
|
|
|
239
244
|
const of = property.of;
|
|
@@ -265,6 +270,7 @@ export function resolveArrayProperty<T extends any[], M>({
|
|
|
265
270
|
fromBuilder?: boolean;
|
|
266
271
|
propertyConfigs?: Record<string, PropertyConfig>;
|
|
267
272
|
ignoreMissingFields?: boolean;
|
|
273
|
+
authController: AuthController;
|
|
268
274
|
}): ResolvedArrayProperty {
|
|
269
275
|
const propertyValue = propertyKey ? getIn(props.values, propertyKey) : undefined;
|
|
270
276
|
|
|
@@ -280,7 +286,7 @@ export function resolveArrayProperty<T extends any[], M>({
|
|
|
280
286
|
propertyOrBuilder: p as Property<any>,
|
|
281
287
|
ignoreMissingFields,
|
|
282
288
|
...props,
|
|
283
|
-
index
|
|
289
|
+
index,
|
|
284
290
|
});
|
|
285
291
|
})
|
|
286
292
|
} as ResolvedArrayProperty;
|
|
@@ -372,6 +378,7 @@ export function resolveProperties<M extends Record<string, any>>({
|
|
|
372
378
|
fromBuilder?: boolean;
|
|
373
379
|
propertyConfigs?: Record<string, PropertyConfig>;
|
|
374
380
|
ignoreMissingFields?: boolean;
|
|
381
|
+
authController: AuthController;
|
|
375
382
|
}): ResolvedProperties<M> {
|
|
376
383
|
return Object.entries<PropertyOrBuilder>(properties as Record<string, PropertyOrBuilder>)
|
|
377
384
|
.map(([key, property]) => {
|
|
@@ -430,3 +437,25 @@ export function resolveEntityView(entityView: string | EntityCustomView<any>, co
|
|
|
430
437
|
return entityView;
|
|
431
438
|
}
|
|
432
439
|
}
|
|
440
|
+
|
|
441
|
+
export function resolvedSelectedEntityView<M extends Record<string, any>>(
|
|
442
|
+
customViews: (string | EntityCustomView<M>)[] | undefined,
|
|
443
|
+
customizationController: CustomizationController,
|
|
444
|
+
selectedTab?: string,
|
|
445
|
+
canEdit?: boolean,
|
|
446
|
+
) {
|
|
447
|
+
const resolvedEntityViews = customViews ? customViews
|
|
448
|
+
.map(e => resolveEntityView(e, customizationController.entityViews))
|
|
449
|
+
.filter((e): e is EntityCustomView<M> => Boolean(e))
|
|
450
|
+
// .filter((e) => canEdit || !e.includeActions)
|
|
451
|
+
: [];
|
|
452
|
+
|
|
453
|
+
const selectedEntityView = resolvedEntityViews.find(e => e.key === selectedTab);
|
|
454
|
+
const selectedSecondaryForm = customViews
|
|
455
|
+
&& resolvedEntityViews.filter(e => e.includeActions).find(e => e.key === selectedTab);
|
|
456
|
+
return {
|
|
457
|
+
resolvedEntityViews,
|
|
458
|
+
selectedEntityView,
|
|
459
|
+
selectedSecondaryForm
|
|
460
|
+
};
|
|
461
|
+
}
|
|
@@ -18,6 +18,7 @@ import { PreviewSize } from "../preview";
|
|
|
18
18
|
import { randomString } from "./strings";
|
|
19
19
|
import { resolveStorageFilenameString, resolveStoragePathString } from "./storage";
|
|
20
20
|
import { resolveProperty } from "./resolutions";
|
|
21
|
+
import { useAuthController } from "../hooks";
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
24
|
* Internal representation of an item in the storage
|
|
@@ -45,18 +46,19 @@ export function useStorageUploadController<M extends object>({
|
|
|
45
46
|
disabled,
|
|
46
47
|
onChange
|
|
47
48
|
}:
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
49
|
+
{
|
|
50
|
+
entityId: string,
|
|
51
|
+
entityValues: EntityValues<M>,
|
|
52
|
+
value: string | string[] | null;
|
|
53
|
+
path?: string,
|
|
54
|
+
propertyKey: string,
|
|
55
|
+
property: StringProperty | ArrayProperty<string[]> | ResolvedStringProperty | ResolvedArrayProperty<string[]>,
|
|
56
|
+
storageSource: StorageSource,
|
|
57
|
+
disabled: boolean,
|
|
58
|
+
onChange: (value: string | string[] | null) => void
|
|
59
|
+
}) {
|
|
60
|
+
|
|
61
|
+
const authController = useAuthController();
|
|
60
62
|
const storage: StorageConfig | undefined = property.dataType === "string"
|
|
61
63
|
? property.storage
|
|
62
64
|
: property.dataType === "array" &&
|
|
@@ -69,22 +71,15 @@ export function useStorageUploadController<M extends object>({
|
|
|
69
71
|
if (!storage)
|
|
70
72
|
throw Error("Storage meta must be specified");
|
|
71
73
|
|
|
74
|
+
const processFile = storage?.processFile;
|
|
75
|
+
|
|
72
76
|
const metadata: Record<string, any> | undefined = storage?.metadata;
|
|
73
77
|
const size = multipleFilesSupported ? "medium" : "large";
|
|
74
78
|
|
|
75
79
|
const compression: ImageCompression | undefined = storage?.imageCompression;
|
|
76
80
|
|
|
77
81
|
const internalInitialValue: StorageFieldItem[] =
|
|
78
|
-
(multipleFilesSupported
|
|
79
|
-
? (value ?? []) as string[]
|
|
80
|
-
: value ? [value as string] : []).map(entry => (
|
|
81
|
-
{
|
|
82
|
-
id: getRandomId(),
|
|
83
|
-
storagePathOrDownloadUrl: entry,
|
|
84
|
-
metadata,
|
|
85
|
-
size
|
|
86
|
-
}
|
|
87
|
-
));
|
|
82
|
+
getInternalInitialValue(multipleFilesSupported, value, metadata, size);
|
|
88
83
|
|
|
89
84
|
const [initialValue, setInitialValue] = useState<string | string[] | null>(value);
|
|
90
85
|
const [internalValue, setInternalValue] = useState<StorageFieldItem[]>(internalInitialValue);
|
|
@@ -98,7 +93,8 @@ export function useStorageUploadController<M extends object>({
|
|
|
98
93
|
|
|
99
94
|
const resolvedProperty = resolveProperty({
|
|
100
95
|
propertyOrBuilder: property as PropertyOrBuilder,
|
|
101
|
-
values: entityValues
|
|
96
|
+
values: entityValues,
|
|
97
|
+
authController
|
|
102
98
|
}) as ResolvedStringProperty | ResolvedArrayProperty<string[]>;
|
|
103
99
|
|
|
104
100
|
const fileNameBuilder = useCallback(async (file: File) => {
|
|
@@ -178,7 +174,22 @@ export function useStorageUploadController<M extends object>({
|
|
|
178
174
|
if (!acceptedFiles.length || disabled)
|
|
179
175
|
return;
|
|
180
176
|
|
|
177
|
+
if (processFile) {
|
|
178
|
+
try {
|
|
179
|
+
acceptedFiles = await Promise.all(acceptedFiles.map(async file => {
|
|
180
|
+
const processedFile = await processFile(file);
|
|
181
|
+
if (!processedFile) {
|
|
182
|
+
return file;
|
|
183
|
+
}
|
|
184
|
+
return processedFile;
|
|
185
|
+
}));
|
|
186
|
+
} catch (e) {
|
|
187
|
+
console.error("Error processing file with custom code. Attempting to continue uploading.", e);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
181
191
|
let newInternalValue: StorageFieldItem[];
|
|
192
|
+
|
|
182
193
|
if (multipleFilesSupported) {
|
|
183
194
|
newInternalValue = [...internalValue,
|
|
184
195
|
...(await Promise.all(acceptedFiles.map(async file => {
|
|
@@ -226,6 +237,32 @@ export function useStorageUploadController<M extends object>({
|
|
|
226
237
|
}
|
|
227
238
|
}
|
|
228
239
|
|
|
240
|
+
function getInternalInitialValue(multipleFilesSupported: boolean,
|
|
241
|
+
value: string | string[] | null,
|
|
242
|
+
metadata: Record<string, any> | undefined,
|
|
243
|
+
size: PreviewSize): StorageFieldItem[] {
|
|
244
|
+
let strings: string[] = [];
|
|
245
|
+
if (multipleFilesSupported) {
|
|
246
|
+
if (Array.isArray(value) && value.every((v) => typeof v === "string")) {
|
|
247
|
+
strings = (value ?? []) as string[];
|
|
248
|
+
}
|
|
249
|
+
} else {
|
|
250
|
+
if (typeof value === "string") {
|
|
251
|
+
strings = value ? [value as string] : [];
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return strings
|
|
256
|
+
.map(entry => (
|
|
257
|
+
{
|
|
258
|
+
id: getRandomId(),
|
|
259
|
+
storagePathOrDownloadUrl: entry,
|
|
260
|
+
metadata,
|
|
261
|
+
size
|
|
262
|
+
}
|
|
263
|
+
));
|
|
264
|
+
}
|
|
265
|
+
|
|
229
266
|
function removeDuplicates(items: StorageFieldItem[]) {
|
|
230
267
|
return items.filter(
|
|
231
268
|
(item, i) => {
|
|
@@ -1,236 +0,0 @@
|
|
|
1
|
-
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
|
2
|
-
|
|
3
|
-
import { useDataSource, useFireCMSContext, useNavigationController } from "../../hooks";
|
|
4
|
-
import { useDataOrder } from "../../hooks/data/useDataOrder";
|
|
5
|
-
import {
|
|
6
|
-
Entity,
|
|
7
|
-
EntityCollection,
|
|
8
|
-
EntityTableController,
|
|
9
|
-
FilterValues,
|
|
10
|
-
FireCMSContext,
|
|
11
|
-
SelectedCellProps,
|
|
12
|
-
User
|
|
13
|
-
} from "../../types";
|
|
14
|
-
import { useDebouncedData } from "./useDebouncedData";
|
|
15
|
-
import equal from "react-fast-compare"
|
|
16
|
-
|
|
17
|
-
const DEFAULT_PAGE_SIZE = 50;
|
|
18
|
-
|
|
19
|
-
export type DataSourceEntityCollectionTableControllerProps<M extends Record<string, any> = any> = {
|
|
20
|
-
/**
|
|
21
|
-
* Full path where the data of this table is located
|
|
22
|
-
*/
|
|
23
|
-
fullPath: string;
|
|
24
|
-
/**
|
|
25
|
-
* The collection that is represented by this config.
|
|
26
|
-
*/
|
|
27
|
-
collection: EntityCollection<M>;
|
|
28
|
-
/**
|
|
29
|
-
* List of entities that will be displayed on top, no matter the ordering.
|
|
30
|
-
* This is used for reference fields selection
|
|
31
|
-
*/
|
|
32
|
-
entitiesDisplayedFirst?: Entity<M>[];
|
|
33
|
-
|
|
34
|
-
lastDeleteTimestamp?: number;
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Force filter to be applied to the table.
|
|
38
|
-
*/
|
|
39
|
-
forceFilter?: FilterValues<string>;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Use this hook to build a controller for the {@link EntityCollectionTable}.
|
|
44
|
-
* This controller is bound to data in a path in your specified datasource.
|
|
45
|
-
*
|
|
46
|
-
* Note that you can build your own hook returning a {@link EntityTableController}
|
|
47
|
-
* if you would like to display different data.
|
|
48
|
-
*
|
|
49
|
-
* @param fullPath
|
|
50
|
-
* @param collection
|
|
51
|
-
* @param entitiesDisplayedFirst
|
|
52
|
-
* @param lastDeleteTimestamp
|
|
53
|
-
* @param forceFilterFromProps
|
|
54
|
-
*/
|
|
55
|
-
export function useDataSourceEntityCollectionTableController<M extends Record<string, any> = any, USER extends User = User>(
|
|
56
|
-
{
|
|
57
|
-
fullPath,
|
|
58
|
-
collection,
|
|
59
|
-
entitiesDisplayedFirst,
|
|
60
|
-
lastDeleteTimestamp,
|
|
61
|
-
forceFilter: forceFilterFromProps,
|
|
62
|
-
}: DataSourceEntityCollectionTableControllerProps<M>)
|
|
63
|
-
: EntityTableController<M> {
|
|
64
|
-
|
|
65
|
-
const {
|
|
66
|
-
initialFilter,
|
|
67
|
-
initialSort,
|
|
68
|
-
forceFilter: forceFilterFromCollection
|
|
69
|
-
} = collection;
|
|
70
|
-
|
|
71
|
-
const [popupCell, setPopupCell] = React.useState<SelectedCellProps<M> | undefined>(undefined);
|
|
72
|
-
const navigation = useNavigationController();
|
|
73
|
-
const dataSource = useDataSource(collection);
|
|
74
|
-
const resolvedPath = useMemo(() => navigation.resolveAliasesFrom(fullPath), [fullPath, navigation.resolveAliasesFrom]);
|
|
75
|
-
|
|
76
|
-
const forceFilter = forceFilterFromProps ?? forceFilterFromCollection;
|
|
77
|
-
const paginationEnabled = collection.pagination === undefined || Boolean(collection.pagination);
|
|
78
|
-
const pageSize = typeof collection.pagination === "number" ? collection.pagination : DEFAULT_PAGE_SIZE;
|
|
79
|
-
|
|
80
|
-
const [searchString, setSearchString] = React.useState<string | undefined>();
|
|
81
|
-
const [itemCount, setItemCount] = React.useState<number | undefined>(paginationEnabled ? pageSize : undefined);
|
|
82
|
-
|
|
83
|
-
const checkFilterCombination = useCallback((filterValues: FilterValues<any>,
|
|
84
|
-
sortBy?: [string, "asc" | "desc"]) => {
|
|
85
|
-
if (!dataSource.isFilterCombinationValid)
|
|
86
|
-
return true;
|
|
87
|
-
return dataSource.isFilterCombinationValid({
|
|
88
|
-
path: resolvedPath,
|
|
89
|
-
collection,
|
|
90
|
-
filterValues,
|
|
91
|
-
sortBy
|
|
92
|
-
})
|
|
93
|
-
}, []);
|
|
94
|
-
|
|
95
|
-
const initialSortInternal = useMemo(() => {
|
|
96
|
-
if (initialSort && forceFilter && !checkFilterCombination(forceFilter, initialSort)) {
|
|
97
|
-
console.warn("Initial sort is not compatible with the force filter. Ignoring initial sort");
|
|
98
|
-
return undefined;
|
|
99
|
-
}
|
|
100
|
-
return initialSort;
|
|
101
|
-
}, [initialSort, forceFilter]);
|
|
102
|
-
|
|
103
|
-
useEffect(() => {
|
|
104
|
-
if (!equal(forceFilter, filterValues)) {
|
|
105
|
-
setFilterValues(forceFilter)
|
|
106
|
-
}
|
|
107
|
-
}, [forceFilter]);
|
|
108
|
-
|
|
109
|
-
const [filterValues, setFilterValues] = React.useState<FilterValues<Extract<keyof M, string>> | undefined>(forceFilter ?? initialFilter ?? undefined);
|
|
110
|
-
const [sortBy, setSortBy] = React.useState<[Extract<keyof M, string>, "asc" | "desc"] | undefined>(initialSortInternal);
|
|
111
|
-
|
|
112
|
-
const sortByProperty = sortBy ? sortBy[0] : undefined;
|
|
113
|
-
const currentSort = sortBy ? sortBy[1] : undefined;
|
|
114
|
-
|
|
115
|
-
const context: FireCMSContext<USER> = useFireCMSContext();
|
|
116
|
-
|
|
117
|
-
const [rawData, setRawData] = useState<Entity<M>[]>([]);
|
|
118
|
-
|
|
119
|
-
const [dataLoading, setDataLoading] = useState<boolean>(false);
|
|
120
|
-
const [dataLoadingError, setDataLoadingError] = useState<Error | undefined>();
|
|
121
|
-
const [noMoreToLoad, setNoMoreToLoad] = useState<boolean>(false);
|
|
122
|
-
|
|
123
|
-
const clearFilter = useCallback(() => setFilterValues(forceFilter ?? undefined), [forceFilter]);
|
|
124
|
-
|
|
125
|
-
const updateFilterValues = useCallback((updatedFilter: FilterValues<Extract<keyof M, string>> | undefined) => {
|
|
126
|
-
if (forceFilter) {
|
|
127
|
-
console.warn("Filter is not compatible with the force filter. Ignoring filter");
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
if (updatedFilter && Object.keys(updatedFilter).length === 0) {
|
|
131
|
-
setFilterValues(undefined);
|
|
132
|
-
} else {
|
|
133
|
-
setFilterValues(updatedFilter);
|
|
134
|
-
}
|
|
135
|
-
}, [forceFilter]);
|
|
136
|
-
|
|
137
|
-
useEffect(() => {
|
|
138
|
-
|
|
139
|
-
setDataLoading(true);
|
|
140
|
-
|
|
141
|
-
const onEntitiesUpdate = async (entities: Entity<M>[]) => {
|
|
142
|
-
if (collection.callbacks?.onFetch) {
|
|
143
|
-
try {
|
|
144
|
-
entities = await Promise.all(
|
|
145
|
-
entities.map((entity) =>
|
|
146
|
-
collection.callbacks!.onFetch!({
|
|
147
|
-
collection,
|
|
148
|
-
path: resolvedPath,
|
|
149
|
-
entity,
|
|
150
|
-
context
|
|
151
|
-
})));
|
|
152
|
-
} catch (e: any) {
|
|
153
|
-
console.error(e);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
setDataLoading(false);
|
|
157
|
-
setDataLoadingError(undefined);
|
|
158
|
-
setRawData(entities.map(e => ({
|
|
159
|
-
...e,
|
|
160
|
-
// values: sanitizeData(e.values, resolvedCollection.properties)
|
|
161
|
-
})));
|
|
162
|
-
setNoMoreToLoad(!itemCount || entities.length < itemCount);
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
const onError = (error: Error) => {
|
|
166
|
-
console.error("ERROR", error);
|
|
167
|
-
setDataLoading(false);
|
|
168
|
-
setRawData([]);
|
|
169
|
-
setDataLoadingError(error);
|
|
170
|
-
};
|
|
171
|
-
|
|
172
|
-
if (dataSource.listenCollection) {
|
|
173
|
-
return dataSource.listenCollection<M>({
|
|
174
|
-
path: resolvedPath,
|
|
175
|
-
collection,
|
|
176
|
-
onUpdate: onEntitiesUpdate,
|
|
177
|
-
onError,
|
|
178
|
-
searchString,
|
|
179
|
-
filter: filterValues,
|
|
180
|
-
limit: itemCount,
|
|
181
|
-
startAfter: undefined,
|
|
182
|
-
orderBy: sortByProperty,
|
|
183
|
-
order: currentSort
|
|
184
|
-
});
|
|
185
|
-
} else {
|
|
186
|
-
dataSource.fetchCollection<M>({
|
|
187
|
-
path: resolvedPath,
|
|
188
|
-
collection,
|
|
189
|
-
searchString,
|
|
190
|
-
filter: filterValues,
|
|
191
|
-
limit: itemCount,
|
|
192
|
-
startAfter: undefined,
|
|
193
|
-
orderBy: sortByProperty,
|
|
194
|
-
order: currentSort
|
|
195
|
-
})
|
|
196
|
-
.then(onEntitiesUpdate)
|
|
197
|
-
.catch(onError);
|
|
198
|
-
return () => {
|
|
199
|
-
};
|
|
200
|
-
}
|
|
201
|
-
}, [resolvedPath, itemCount, currentSort, sortByProperty, filterValues, searchString]);
|
|
202
|
-
|
|
203
|
-
const orderedData = useDataOrder({
|
|
204
|
-
data: rawData,
|
|
205
|
-
entitiesDisplayedFirst
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
// hack to fix Firestore listeners firing with incomplete data
|
|
209
|
-
const data = useDebouncedData(orderedData, {
|
|
210
|
-
filterValues,
|
|
211
|
-
sortBy,
|
|
212
|
-
searchString,
|
|
213
|
-
lastDeleteTimestamp
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
return {
|
|
217
|
-
data,
|
|
218
|
-
dataLoading,
|
|
219
|
-
noMoreToLoad,
|
|
220
|
-
dataLoadingError,
|
|
221
|
-
filterValues,
|
|
222
|
-
setFilterValues: updateFilterValues,
|
|
223
|
-
sortBy,
|
|
224
|
-
setSortBy,
|
|
225
|
-
searchString,
|
|
226
|
-
setSearchString,
|
|
227
|
-
clearFilter,
|
|
228
|
-
itemCount,
|
|
229
|
-
setItemCount,
|
|
230
|
-
paginationEnabled,
|
|
231
|
-
pageSize,
|
|
232
|
-
checkFilterCombination,
|
|
233
|
-
popupCell,
|
|
234
|
-
setPopupCell
|
|
235
|
-
}
|
|
236
|
-
}
|
|
File without changes
|