@firecms/core 3.1.0-canary.1df3b2c → 3.1.0-canary.24c8270
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/components/EntityCollectionTable/internal/popup_field/useDraggable.d.ts +2 -2
- package/dist/components/EntityCollectionView/ViewModeToggle.d.ts +5 -10
- package/dist/components/ErrorBoundary.d.ts +1 -1
- package/dist/components/VirtualTable/VirtualTableHeader.d.ts +1 -1
- package/dist/form/components/ErrorFocus.d.ts +1 -1
- package/dist/index.es.js +302 -227
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +300 -225
- package/dist/index.umd.js.map +1 -1
- package/dist/internal/useRestoreScroll.d.ts +1 -1
- package/dist/types/analytics.d.ts +1 -1
- package/dist/types/collections.d.ts +8 -0
- package/dist/types/plugins.d.ts +16 -0
- package/dist/util/entities.d.ts +1 -1
- package/dist/util/resolutions.d.ts +2 -2
- package/package.json +9 -9
- package/src/components/EntityCollectionTable/internal/EntityTableCellActions.tsx +1 -1
- package/src/components/EntityCollectionTable/internal/popup_field/useDraggable.tsx +11 -11
- package/src/components/EntityCollectionView/EntityBoardCard.tsx +1 -1
- package/src/components/EntityCollectionView/EntityCard.tsx +4 -0
- package/src/components/EntityCollectionView/EntityCollectionBoardView.tsx +23 -3
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +50 -16
- package/src/components/EntityCollectionView/ViewModeToggle.tsx +27 -30
- package/src/components/VirtualTable/VirtualTable.tsx +116 -113
- package/src/components/VirtualTable/VirtualTableHeader.tsx +42 -42
- package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +1 -1
- package/src/components/VirtualTable/fields/VirtualTableSelect.tsx +3 -3
- package/src/components/common/useDataSourceTableController.tsx +21 -4
- package/src/core/DefaultAppBar.tsx +1 -1
- package/src/core/EntityEditView.tsx +1 -1
- package/src/core/EntitySidePanel.tsx +28 -26
- package/src/core/field_configs.tsx +14 -9
- package/src/form/EntityForm.tsx +69 -60
- package/src/form/PropertyFieldBinding.tsx +3 -3
- package/src/form/components/ErrorFocus.tsx +3 -3
- package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +1 -1
- package/src/form/field_bindings/StorageUploadFieldBinding.tsx +83 -83
- package/src/hooks/useBuildNavigationController.tsx +29 -9
- package/src/hooks/useValidateAuthenticator.tsx +1 -1
- package/src/internal/useBuildDataSource.ts +1 -2
- package/src/internal/useBuildSideEntityController.tsx +22 -20
- package/src/preview/PropertyPreview.tsx +1 -0
- package/src/types/analytics.ts +10 -0
- package/src/types/collections.ts +9 -0
- package/src/types/plugins.tsx +18 -0
- package/src/util/entities.ts +1 -1
- package/src/util/join_collections.ts +10 -8
- package/src/util/previews.ts +2 -2
- package/src/util/property_utils.tsx +1 -1
- package/src/util/resolutions.ts +5 -3
|
@@ -105,7 +105,7 @@ export function EntitySidePanel(props: EntitySidePanelProps) {
|
|
|
105
105
|
}, [collection?.name, setBlocked, setBlockedNavigationMessage]);
|
|
106
106
|
|
|
107
107
|
if (!props || !collection) {
|
|
108
|
-
return <div className={"w-full"}/>;
|
|
108
|
+
return <div className={"w-full"} />;
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
return (
|
|
@@ -120,32 +120,34 @@ export function EntitySidePanel(props: EntitySidePanelProps) {
|
|
|
120
120
|
onValuesModified={onValuesModified}
|
|
121
121
|
onSaved={onUpdate}
|
|
122
122
|
barActions={({
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
123
|
+
status,
|
|
124
|
+
values
|
|
125
|
+
}) => <>
|
|
126
|
+
<IconButton
|
|
127
|
+
className="self-center"
|
|
128
|
+
size={"smallest"}
|
|
129
|
+
onClick={onClose}>
|
|
130
|
+
<CloseIcon size={"smallest"} />
|
|
131
|
+
</IconButton>
|
|
132
|
+
{allowFullScreen && <IconButton
|
|
133
|
+
className="self-center"
|
|
134
|
+
size={"smallest"}
|
|
135
|
+
onClick={() => {
|
|
136
|
+
const key = (status === "new" || status === "copy") ? path + "#new" : path + "/" + entityId;
|
|
137
|
+
saveEntityToMemoryCache(key, values);
|
|
138
|
+
if (entityId)
|
|
139
|
+
navigate(location.pathname + location.search);
|
|
140
|
+
else
|
|
141
|
+
navigate(location.pathname + location.search + "#new");
|
|
142
|
+
}}>
|
|
143
|
+
<OpenInFullIcon size={"smallest"} />
|
|
144
|
+
</IconButton>}
|
|
145
|
+
</>}
|
|
144
146
|
onTabChange={({
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
147
|
+
entityId,
|
|
148
|
+
selectedTab,
|
|
149
|
+
collection,
|
|
150
|
+
}) => {
|
|
149
151
|
sideEntityController.replace({
|
|
150
152
|
path,
|
|
151
153
|
entityId,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
|
|
3
|
-
import { ArrayProperty, FieldProps, Property, PropertyConfig, ResolvedProperty } from "../types";
|
|
3
|
+
import { ArrayProperty, FieldProps, NumberProperty, Property, PropertyConfig, ResolvedProperty, StringProperty } from "../types";
|
|
4
4
|
import {
|
|
5
5
|
ArrayCustomShapedFieldBinding,
|
|
6
6
|
ArrayOfReferencesFieldBinding,
|
|
@@ -397,14 +397,19 @@ export function getDefaultFieldId(property: Property | ResolvedProperty) {
|
|
|
397
397
|
return "custom_array";
|
|
398
398
|
} else if (isPropertyBuilder(of)) {
|
|
399
399
|
return "repeat";
|
|
400
|
-
} else if (of
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
400
|
+
} else if (of) {
|
|
401
|
+
const ofProperty = of as Property;
|
|
402
|
+
if (ofProperty.dataType === "string" && (ofProperty as StringProperty).enumValues) {
|
|
403
|
+
return "multi_select";
|
|
404
|
+
} else if (ofProperty.dataType === "number" && (ofProperty as NumberProperty).enumValues) {
|
|
405
|
+
return "multi_number_select";
|
|
406
|
+
} else if (ofProperty.dataType === "string" && (ofProperty as StringProperty).storage) {
|
|
407
|
+
return "multi_file_upload";
|
|
408
|
+
} else if (ofProperty.dataType === "reference") {
|
|
409
|
+
return "multi_references";
|
|
410
|
+
} else {
|
|
411
|
+
return "repeat";
|
|
412
|
+
}
|
|
408
413
|
} else {
|
|
409
414
|
return "repeat";
|
|
410
415
|
}
|
package/src/form/EntityForm.tsx
CHANGED
|
@@ -181,30 +181,30 @@ export function getChanges<T extends object>(source: Partial<T>, comparison: Par
|
|
|
181
181
|
}
|
|
182
182
|
|
|
183
183
|
export function EntityForm<M extends Record<string, any>>({
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
184
|
+
path,
|
|
185
|
+
fullIdPath,
|
|
186
|
+
entityId: entityIdProp,
|
|
187
|
+
collection,
|
|
188
|
+
onValuesModified,
|
|
189
|
+
onIdChange,
|
|
190
|
+
onSaved,
|
|
191
|
+
entity,
|
|
192
|
+
initialDirtyValues,
|
|
193
|
+
onFormContextReady,
|
|
194
|
+
forceActionsAtTheBottom,
|
|
195
|
+
initialStatus,
|
|
196
|
+
className,
|
|
197
|
+
onStatusChange,
|
|
198
|
+
onEntityChange,
|
|
199
|
+
openEntityMode = "full_screen",
|
|
200
|
+
formex: formexProp,
|
|
201
|
+
disabled: disabledProp,
|
|
202
|
+
Builder,
|
|
203
|
+
EntityFormActionsComponent = EntityFormActions,
|
|
204
|
+
showDefaultActions = true,
|
|
205
|
+
showEntityPath = true,
|
|
206
|
+
children
|
|
207
|
+
}: EntityFormProps<M>) {
|
|
208
208
|
|
|
209
209
|
if (collection.customId && collection.formAutoSave) {
|
|
210
210
|
console.warn(`The collection ${collection.path} has customId and formAutoSave enabled. This is not supported and formAutoSave will be ignored`);
|
|
@@ -455,12 +455,12 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
455
455
|
}, [entityId, path, snackbarController]);
|
|
456
456
|
|
|
457
457
|
const saveEntity = ({
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
458
|
+
values,
|
|
459
|
+
previousValues,
|
|
460
|
+
entityId,
|
|
461
|
+
collection,
|
|
462
|
+
path
|
|
463
|
+
}: {
|
|
464
464
|
collection: EntityCollection<M>,
|
|
465
465
|
path: string,
|
|
466
466
|
entityId: string | undefined,
|
|
@@ -493,13 +493,13 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
493
493
|
};
|
|
494
494
|
|
|
495
495
|
const onSaveEntityRequest = async ({
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
496
|
+
collection,
|
|
497
|
+
path,
|
|
498
|
+
entityId,
|
|
499
|
+
values,
|
|
500
|
+
previousValues,
|
|
501
|
+
autoSave
|
|
502
|
+
}: EntityFormSaveParams<M>): Promise<void> => {
|
|
503
503
|
if (!status)
|
|
504
504
|
return;
|
|
505
505
|
if (autoSave) {
|
|
@@ -567,6 +567,7 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
567
567
|
}, [snackbarController]);
|
|
568
568
|
|
|
569
569
|
const pluginActions: React.ReactNode[] = [];
|
|
570
|
+
const pluginBeforeTitle: React.ReactNode[] = [];
|
|
570
571
|
const plugins = customizationController.plugins;
|
|
571
572
|
|
|
572
573
|
const actionsDisabled = disabled || formex.isSubmitting || (status === "existing" && !formex.dirty) || Boolean(disabledProp);
|
|
@@ -590,6 +591,12 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
590
591
|
key={`actions_${plugin.key}`} {...actionProps} />
|
|
591
592
|
: null
|
|
592
593
|
)).filter(Boolean));
|
|
594
|
+
pluginBeforeTitle.push(...plugins.map((plugin) => (
|
|
595
|
+
plugin.form?.BeforeTitle
|
|
596
|
+
? <plugin.form.BeforeTitle
|
|
597
|
+
key={`before_title_${plugin.key}`} {...actionProps} />
|
|
598
|
+
: null
|
|
599
|
+
)).filter(Boolean));
|
|
593
600
|
}
|
|
594
601
|
|
|
595
602
|
const titlePropertyKey = getEntityTitlePropertyKey(resolvedCollection, customizationController.propertyConfigs);
|
|
@@ -631,17 +638,17 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
631
638
|
const modified = formex.dirty;
|
|
632
639
|
|
|
633
640
|
const uniqueFieldValidator: CustomFieldValidator = useCallback(({
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
641
|
+
name,
|
|
642
|
+
value
|
|
643
|
+
}) => dataSource.checkUniqueField(path, name, value, entityId, collection),
|
|
637
644
|
[dataSource, path, entityId]);
|
|
638
645
|
|
|
639
646
|
const validationSchema = useMemo(() => entityId
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
647
|
+
? getYupEntitySchema(
|
|
648
|
+
entityId,
|
|
649
|
+
resolvedCollection.properties,
|
|
650
|
+
uniqueFieldValidator)
|
|
651
|
+
: undefined,
|
|
645
652
|
[entityId, resolvedCollection.properties, uniqueFieldValidator]);
|
|
646
653
|
|
|
647
654
|
useOnAutoSave(autoSave, formex, lastSavedValues, save);
|
|
@@ -699,8 +706,8 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
699
706
|
|
|
700
707
|
return (
|
|
701
708
|
<FormEntry propertyKey={key}
|
|
702
|
-
|
|
703
|
-
|
|
709
|
+
widthPercentage={widthPercentage}
|
|
710
|
+
key={`field_${key}`}>
|
|
704
711
|
<PropertyFieldBinding {...cmsFormFieldProps} />
|
|
705
712
|
</FormEntry>
|
|
706
713
|
);
|
|
@@ -713,7 +720,7 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
713
720
|
throw new Error("When using additional fields you need to provide a Builder or a value");
|
|
714
721
|
}
|
|
715
722
|
const child = Builder
|
|
716
|
-
? <Builder entity={entity} context={context}/>
|
|
723
|
+
? <Builder entity={entity} context={context} />
|
|
717
724
|
: <div className={"w-full"}>
|
|
718
725
|
{additionalField.value?.({
|
|
719
726
|
entity,
|
|
@@ -725,9 +732,9 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
725
732
|
<div key={`additional_${key}`} className={"w-full"}>
|
|
726
733
|
<LabelWithIconAndTooltip
|
|
727
734
|
propertyKey={key}
|
|
728
|
-
icon={<NotesIcon size={"small"}/>}
|
|
735
|
+
icon={<NotesIcon size={"small"} />}
|
|
729
736
|
title={additionalField.name}
|
|
730
|
-
className={"text-text-secondary dark:text-text-secondary-dark ml-3.5"}/>
|
|
737
|
+
className={"text-text-secondary dark:text-text-secondary-dark ml-3.5"} />
|
|
731
738
|
<div
|
|
732
739
|
className={cls(paperMixin, "w-full min-h-14 p-4 md:p-6 overflow-x-scroll no-scrollbar")}>
|
|
733
740
|
<ErrorBoundary>
|
|
@@ -749,6 +756,8 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
749
756
|
|
|
750
757
|
const formView = <ErrorBoundary>
|
|
751
758
|
<>
|
|
759
|
+
{pluginBeforeTitle}
|
|
760
|
+
|
|
752
761
|
{!Builder && <div className={"w-full py-2 flex flex-col items-start my-4 lg:my-6"}>
|
|
753
762
|
<Typography
|
|
754
763
|
className={"my-4 flex-grow line-clamp-1 " + (collection.hideIdFromForm ? "mb-6" : "")}
|
|
@@ -777,22 +786,22 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
777
786
|
|
|
778
787
|
{!Builder && !collection.hideIdFromForm &&
|
|
779
788
|
<CustomIdField customId={collection.customId}
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
789
|
+
entityId={entityId}
|
|
790
|
+
status={status}
|
|
791
|
+
onChange={setEntityId}
|
|
792
|
+
error={entityIdError}
|
|
793
|
+
loading={customIdLoading}
|
|
794
|
+
entity={entity} />
|
|
786
795
|
}
|
|
787
796
|
|
|
788
797
|
{entityId && formContext && <>
|
|
789
798
|
<div className="mt-12 flex flex-col gap-8" ref={formRef}>
|
|
790
799
|
{formFields()}
|
|
791
|
-
<ErrorFocus containerRef={formRef}/>
|
|
800
|
+
<ErrorFocus containerRef={formRef} />
|
|
792
801
|
</div>
|
|
793
802
|
</>}
|
|
794
803
|
|
|
795
|
-
{forceActionsAtTheBottom && <div className="h-16"/>}
|
|
804
|
+
{forceActionsAtTheBottom && <div className="h-16" />}
|
|
796
805
|
</>
|
|
797
806
|
</ErrorBoundary>;
|
|
798
807
|
|
|
@@ -852,12 +861,12 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
852
861
|
{formex.dirty
|
|
853
862
|
? <Tooltip title={"This form has been modified"}>
|
|
854
863
|
<Chip size={"small"} className={"py-1"} colorScheme={"orangeDarker"}>
|
|
855
|
-
<EditIcon size={"smallest"}/>
|
|
864
|
+
<EditIcon size={"smallest"} />
|
|
856
865
|
</Chip>
|
|
857
866
|
</Tooltip>
|
|
858
867
|
: <Tooltip title={"The current form is in sync with the database"}>
|
|
859
868
|
<Chip size={"small"} className={"py-1"}>
|
|
860
|
-
<CheckIcon size={"smallest"}/>
|
|
869
|
+
<CheckIcon size={"smallest"} />
|
|
861
870
|
</Chip>
|
|
862
871
|
</Tooltip>}
|
|
863
872
|
</div>
|
|
@@ -137,7 +137,7 @@ function PropertyFieldBindingInternal<T extends CMSType = CMSType, M extends Rec
|
|
|
137
137
|
}
|
|
138
138
|
const configProperty = resolveProperty({
|
|
139
139
|
propertyKey,
|
|
140
|
-
propertyOrBuilder: propertyConfig.property,
|
|
140
|
+
propertyOrBuilder: propertyConfig.property as any,
|
|
141
141
|
values: fieldProps.form.values,
|
|
142
142
|
path: context.path,
|
|
143
143
|
entityId: context.entityId,
|
|
@@ -145,7 +145,7 @@ function PropertyFieldBindingInternal<T extends CMSType = CMSType, M extends Rec
|
|
|
145
145
|
index,
|
|
146
146
|
authController
|
|
147
147
|
});
|
|
148
|
-
Component = configProperty
|
|
148
|
+
Component = configProperty?.Field as ComponentType<FieldProps<T>> | undefined;
|
|
149
149
|
}
|
|
150
150
|
if (!Component) {
|
|
151
151
|
console.warn(`No field component found for property ${propertyKey}`);
|
|
@@ -302,7 +302,7 @@ const shouldPropertyReRender = (property: PropertyOrBuilder | ResolvedProperty,
|
|
|
302
302
|
if (plugins?.some((plugin) => plugin.form?.fieldBuilder)) {
|
|
303
303
|
return true;
|
|
304
304
|
}
|
|
305
|
-
if (isPropertyBuilder(property)) {
|
|
305
|
+
if (isPropertyBuilder(property as any)) {
|
|
306
306
|
return true;
|
|
307
307
|
}
|
|
308
308
|
const defAProperty = property as Property | ResolvedProperty;
|
|
@@ -2,9 +2,9 @@ import React, { useEffect, useRef } from "react";
|
|
|
2
2
|
import { useFormex } from "@firecms/formex";
|
|
3
3
|
|
|
4
4
|
export const ErrorFocus = ({ containerRef }:
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
{
|
|
6
|
+
containerRef?: React.RefObject<HTMLDivElement | null>
|
|
7
|
+
}) => {
|
|
8
8
|
const {
|
|
9
9
|
isValidating,
|
|
10
10
|
errors,
|
|
@@ -65,7 +65,7 @@ export function MarkdownEditorFieldBinding({
|
|
|
65
65
|
}, [value]);
|
|
66
66
|
|
|
67
67
|
const resolvedProperty = resolveProperty({
|
|
68
|
-
propertyOrBuilder: property as PropertyOrBuilder
|
|
68
|
+
propertyOrBuilder: property as PropertyOrBuilder<string>,
|
|
69
69
|
values: entityValues,
|
|
70
70
|
authController
|
|
71
71
|
}) as ResolvedStringProperty | ResolvedArrayProperty<string[]>;
|
|
@@ -52,18 +52,18 @@ const rejectDropClasses = "transition-colors duration-200 ease-[cubic-bezier(0,0
|
|
|
52
52
|
type StorageUploadFieldProps = FieldProps<string | string[]>;
|
|
53
53
|
|
|
54
54
|
export function StorageUploadFieldBinding({
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
55
|
+
propertyKey,
|
|
56
|
+
value,
|
|
57
|
+
setValue,
|
|
58
|
+
error,
|
|
59
|
+
showError,
|
|
60
|
+
autoFocus,
|
|
61
|
+
minimalistView,
|
|
62
|
+
property,
|
|
63
|
+
includeDescription,
|
|
64
|
+
context,
|
|
65
|
+
isSubmitting,
|
|
66
|
+
}: StorageUploadFieldProps) {
|
|
67
67
|
|
|
68
68
|
const authController = useAuthController();
|
|
69
69
|
|
|
@@ -100,7 +100,7 @@ export function StorageUploadFieldBinding({
|
|
|
100
100
|
});
|
|
101
101
|
|
|
102
102
|
const resolvedProperty = resolveProperty({
|
|
103
|
-
propertyOrBuilder: property as PropertyOrBuilder
|
|
103
|
+
propertyOrBuilder: property as PropertyOrBuilder<string>,
|
|
104
104
|
authController
|
|
105
105
|
}) as ResolvedStringProperty | ResolvedArrayProperty<string[]>;
|
|
106
106
|
|
|
@@ -114,7 +114,7 @@ export function StorageUploadFieldBinding({
|
|
|
114
114
|
icon={getIconForProperty(property, "small")}
|
|
115
115
|
required={property.validation?.required}
|
|
116
116
|
title={property.name}
|
|
117
|
-
className={"h-8 text-text-secondary dark:text-text-secondary-dark ml-3.5"}/>}
|
|
117
|
+
className={"h-8 text-text-secondary dark:text-text-secondary-dark ml-3.5"} />}
|
|
118
118
|
|
|
119
119
|
<StorageUpload
|
|
120
120
|
value={internalValue}
|
|
@@ -128,13 +128,13 @@ export function StorageUploadFieldBinding({
|
|
|
128
128
|
onFileUploadComplete={onFileUploadComplete}
|
|
129
129
|
storagePathBuilder={storagePathBuilder}
|
|
130
130
|
storage={storage}
|
|
131
|
-
multipleFilesSupported={multipleFilesSupported}/>
|
|
131
|
+
multipleFilesSupported={multipleFilesSupported} />
|
|
132
132
|
|
|
133
133
|
<FieldHelperText includeDescription={includeDescription}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
134
|
+
showError={showError}
|
|
135
|
+
error={error}
|
|
136
|
+
disabled={disabled}
|
|
137
|
+
property={property} />
|
|
138
138
|
|
|
139
139
|
</>
|
|
140
140
|
);
|
|
@@ -154,15 +154,15 @@ interface SortableStorageItemProps {
|
|
|
154
154
|
}
|
|
155
155
|
|
|
156
156
|
function SortableStorageItem({
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
157
|
+
id,
|
|
158
|
+
entry,
|
|
159
|
+
property,
|
|
160
|
+
metadata,
|
|
161
|
+
storagePathBuilder,
|
|
162
|
+
onFileUploadComplete,
|
|
163
|
+
onClear,
|
|
164
|
+
disabled,
|
|
165
|
+
}: SortableStorageItemProps) {
|
|
166
166
|
|
|
167
167
|
const {
|
|
168
168
|
attributes,
|
|
@@ -201,7 +201,7 @@ function SortableStorageItem({
|
|
|
201
201
|
disabled={disabled}
|
|
202
202
|
value={entry.storagePathOrDownloadUrl}
|
|
203
203
|
onRemove={() => onClear(entry.storagePathOrDownloadUrl!)}
|
|
204
|
-
size={entry.size}/>
|
|
204
|
+
size={entry.size} />
|
|
205
205
|
);
|
|
206
206
|
} else if (entry.file) {
|
|
207
207
|
child = (
|
|
@@ -231,21 +231,21 @@ function SortableStorageItem({
|
|
|
231
231
|
}
|
|
232
232
|
|
|
233
233
|
function FileDropComponent({
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
234
|
+
storage,
|
|
235
|
+
disabled,
|
|
236
|
+
onFilesAdded,
|
|
237
|
+
multipleFilesSupported,
|
|
238
|
+
autoFocus,
|
|
239
|
+
internalValue,
|
|
240
|
+
property,
|
|
241
|
+
onClear,
|
|
242
|
+
metadata,
|
|
243
|
+
storagePathBuilder,
|
|
244
|
+
onFileUploadComplete,
|
|
245
|
+
name,
|
|
246
|
+
helpText,
|
|
247
|
+
isDndItemDragging
|
|
248
|
+
}: {
|
|
249
249
|
storage: StorageConfig,
|
|
250
250
|
disabled: boolean,
|
|
251
251
|
onFilesAdded: (acceptedFiles: File[]) => Promise<void>,
|
|
@@ -271,33 +271,33 @@ function FileDropComponent({
|
|
|
271
271
|
isDragAccept,
|
|
272
272
|
isDragReject
|
|
273
273
|
} = useDropzone({
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
}
|
|
274
|
+
accept: storage.acceptedFiles ? storage.acceptedFiles.reduce((acc, ext) => ({
|
|
275
|
+
...acc,
|
|
276
|
+
[ext]: []
|
|
277
|
+
}), {}) : undefined,
|
|
278
|
+
disabled: disabled || isDndItemDragging,
|
|
279
|
+
noDragEventsBubbling: true,
|
|
280
|
+
maxSize: storage.maxSize,
|
|
281
|
+
onDrop: onFilesAdded,
|
|
282
|
+
onDropRejected: (fileRejections) => {
|
|
283
|
+
for (const fileRejection of fileRejections) {
|
|
284
|
+
for (const error of fileRejection.errors) {
|
|
285
|
+
console.error("Error uploading file: ", error);
|
|
286
|
+
if (error.code === "file-too-large") {
|
|
287
|
+
snackbarContext.open({
|
|
288
|
+
type: "error",
|
|
289
|
+
message: `Error uploading file: File is larger than ${storage.maxSize} bytes`
|
|
290
|
+
});
|
|
291
|
+
} else if (error.code === "file-invalid-type") {
|
|
292
|
+
snackbarContext.open({
|
|
293
|
+
type: "error",
|
|
294
|
+
message: "Error uploading file: File type is not supported"
|
|
295
|
+
});
|
|
297
296
|
}
|
|
298
297
|
}
|
|
299
298
|
}
|
|
300
299
|
}
|
|
300
|
+
}
|
|
301
301
|
);
|
|
302
302
|
|
|
303
303
|
return (
|
|
@@ -349,8 +349,8 @@ function FileDropComponent({
|
|
|
349
349
|
<div
|
|
350
350
|
className="flex-grow min-h-[38px] box-border m-2 text-center">
|
|
351
351
|
<Typography align={"center"}
|
|
352
|
-
|
|
353
|
-
|
|
352
|
+
variant={"label"}
|
|
353
|
+
className={disabled ? "text-surface-accent-600 dark:text-surface-accent-500" : ""}>
|
|
354
354
|
{helpText}
|
|
355
355
|
</Typography>
|
|
356
356
|
</div>
|
|
@@ -374,19 +374,19 @@ export interface StorageUploadProps {
|
|
|
374
374
|
}
|
|
375
375
|
|
|
376
376
|
export function StorageUpload({
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
377
|
+
property,
|
|
378
|
+
name,
|
|
379
|
+
value, // This is internalValue from useStorageUploadController
|
|
380
|
+
setInternalValue,
|
|
381
|
+
onChange,
|
|
382
|
+
multipleFilesSupported,
|
|
383
|
+
onFileUploadComplete,
|
|
384
|
+
disabled,
|
|
385
|
+
onFilesAdded,
|
|
386
|
+
autoFocus,
|
|
387
|
+
storage,
|
|
388
|
+
storagePathBuilder,
|
|
389
|
+
}: StorageUploadProps) {
|
|
390
390
|
|
|
391
391
|
if (multipleFilesSupported) {
|
|
392
392
|
const arrayProperty = property as ResolvedArrayProperty<string[]>;
|
|
@@ -500,6 +500,6 @@ export function StorageUpload({
|
|
|
500
500
|
);
|
|
501
501
|
} else {
|
|
502
502
|
// For single file, no D&D context is needed
|
|
503
|
-
return <FileDropComponent {...fileDropProps} isDndItemDragging={false}/>;
|
|
503
|
+
return <FileDropComponent {...fileDropProps} isDndItemDragging={false} />;
|
|
504
504
|
}
|
|
505
505
|
}
|