@firecms/collection_editor 3.0.0-alpha.9 → 3.0.0-beta.10

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.
Files changed (149) hide show
  1. package/LICENSE +114 -21
  2. package/dist/ConfigControllerProvider.d.ts +13 -3
  3. package/dist/index.d.ts +4 -2
  4. package/dist/index.es.js +5587 -4976
  5. package/dist/index.es.js.map +1 -1
  6. package/dist/index.umd.js +6829 -1
  7. package/dist/index.umd.js.map +1 -1
  8. package/dist/types/collection_editor_controller.d.ts +36 -8
  9. package/dist/types/collection_inference.d.ts +1 -1
  10. package/dist/types/config_controller.d.ts +33 -6
  11. package/dist/types/persisted_collection.d.ts +4 -2
  12. package/dist/ui/CollectionViewHeaderAction.d.ts +11 -0
  13. package/dist/{components → ui}/EditorCollectionAction.d.ts +1 -1
  14. package/dist/ui/EditorCollectionActionStart.d.ts +2 -0
  15. package/dist/ui/MissingReferenceWidget.d.ts +3 -0
  16. package/dist/ui/NewCollectionButton.d.ts +1 -0
  17. package/dist/ui/PropertyAddColumnComponent.d.ts +8 -0
  18. package/dist/{components → ui}/collection_editor/CollectionDetailsForm.d.ts +3 -2
  19. package/dist/{components → ui}/collection_editor/CollectionEditorDialog.d.ts +15 -11
  20. package/dist/{components → ui}/collection_editor/CollectionEditorWelcomeView.d.ts +3 -3
  21. package/dist/{components → ui}/collection_editor/CollectionPropertiesEditorForm.d.ts +8 -6
  22. package/dist/{components → ui}/collection_editor/CollectionYupValidation.d.ts +3 -0
  23. package/dist/ui/collection_editor/EntityCustomViewsSelectDialog.d.ts +4 -0
  24. package/dist/{components → ui}/collection_editor/EnumForm.d.ts +1 -2
  25. package/dist/ui/collection_editor/GetCodeDialog.d.ts +5 -0
  26. package/dist/{components → ui}/collection_editor/PropertyEditView.d.ts +21 -11
  27. package/dist/{components → ui}/collection_editor/PropertyFieldPreview.d.ts +4 -3
  28. package/dist/{components → ui}/collection_editor/PropertyTree.d.ts +11 -7
  29. package/dist/{components → ui}/collection_editor/SubcollectionsEditTab.d.ts +3 -3
  30. package/dist/ui/collection_editor/SwitchControl.d.ts +8 -0
  31. package/dist/{components → ui}/collection_editor/import/CollectionEditorImportDataPreview.d.ts +1 -1
  32. package/dist/ui/collection_editor/import/CollectionEditorImportMapping.d.ts +14 -0
  33. package/dist/{components → ui}/collection_editor/import/clean_import_data.d.ts +1 -1
  34. package/dist/{components → ui}/collection_editor/properties/BlockPropertyField.d.ts +4 -1
  35. package/dist/{components → ui}/collection_editor/properties/CommonPropertyFields.d.ts +1 -1
  36. package/dist/{components → ui}/collection_editor/properties/MapPropertyField.d.ts +4 -1
  37. package/dist/ui/collection_editor/properties/MarkdownPropertyField.d.ts +4 -0
  38. package/dist/{components → ui}/collection_editor/properties/RepeatPropertyField.d.ts +4 -1
  39. package/dist/{components → ui}/collection_editor/properties/StringPropertyField.d.ts +1 -1
  40. package/dist/ui/collection_editor/properties/UrlPropertyField.d.ts +4 -0
  41. package/dist/ui/collection_editor/templates/blog_template.d.ts +2 -0
  42. package/dist/ui/collection_editor/templates/pages_template.d.ts +2 -0
  43. package/dist/ui/collection_editor/templates/products_template.d.ts +2 -0
  44. package/dist/ui/collection_editor/templates/users_template.d.ts +2 -0
  45. package/dist/{components → ui}/collection_editor/util.d.ts +1 -0
  46. package/dist/ui/collection_editor/utils/strings.d.ts +1 -0
  47. package/dist/ui/collection_editor/utils/supported_fields.d.ts +3 -0
  48. package/dist/ui/collection_editor/utils/update_property_for_widget.d.ts +2 -0
  49. package/dist/useCollectionEditorPlugin.d.ts +17 -6
  50. package/dist/utils/collections.d.ts +6 -0
  51. package/dist/utils/entities.d.ts +3 -4
  52. package/package.json +35 -37
  53. package/src/ConfigControllerProvider.tsx +350 -0
  54. package/src/index.ts +36 -0
  55. package/src/types/collection_editor_controller.tsx +53 -0
  56. package/src/types/collection_inference.ts +3 -0
  57. package/src/types/config_controller.tsx +60 -0
  58. package/src/types/config_permissions.ts +20 -0
  59. package/src/types/persisted_collection.ts +9 -0
  60. package/src/ui/CollectionViewHeaderAction.tsx +48 -0
  61. package/src/ui/EditorCollectionAction.tsx +56 -0
  62. package/src/ui/EditorCollectionActionStart.tsx +88 -0
  63. package/src/ui/HomePageEditorCollectionAction.tsx +89 -0
  64. package/src/ui/MissingReferenceWidget.tsx +37 -0
  65. package/src/ui/NewCollectionButton.tsx +18 -0
  66. package/src/ui/NewCollectionCard.tsx +48 -0
  67. package/src/ui/PropertyAddColumnComponent.tsx +47 -0
  68. package/src/ui/collection_editor/CollectionDetailsForm.tsx +426 -0
  69. package/src/ui/collection_editor/CollectionEditorDialog.tsx +826 -0
  70. package/src/ui/collection_editor/CollectionEditorWelcomeView.tsx +214 -0
  71. package/src/ui/collection_editor/CollectionPropertiesEditorForm.tsx +513 -0
  72. package/src/ui/collection_editor/CollectionYupValidation.tsx +7 -0
  73. package/src/ui/collection_editor/EntityCustomViewsSelectDialog.tsx +37 -0
  74. package/src/ui/collection_editor/EnumForm.tsx +357 -0
  75. package/src/ui/collection_editor/GetCodeDialog.tsx +122 -0
  76. package/src/ui/collection_editor/PropertyEditView.tsx +789 -0
  77. package/src/ui/collection_editor/PropertyFieldPreview.tsx +204 -0
  78. package/src/ui/collection_editor/PropertyTree.tsx +254 -0
  79. package/src/ui/collection_editor/SubcollectionsEditTab.tsx +269 -0
  80. package/src/ui/collection_editor/SwitchControl.tsx +39 -0
  81. package/src/ui/collection_editor/UnsavedChangesDialog.tsx +47 -0
  82. package/src/ui/collection_editor/import/CollectionEditorImportDataPreview.tsx +53 -0
  83. package/src/ui/collection_editor/import/CollectionEditorImportMapping.tsx +299 -0
  84. package/src/ui/collection_editor/import/clean_import_data.ts +53 -0
  85. package/src/ui/collection_editor/properties/BlockPropertyField.tsx +144 -0
  86. package/src/ui/collection_editor/properties/BooleanPropertyField.tsx +40 -0
  87. package/src/ui/collection_editor/properties/CommonPropertyFields.tsx +110 -0
  88. package/src/ui/collection_editor/properties/DateTimePropertyField.tsx +89 -0
  89. package/src/ui/collection_editor/properties/EnumPropertyField.tsx +114 -0
  90. package/src/ui/collection_editor/properties/KeyValuePropertyField.tsx +20 -0
  91. package/src/ui/collection_editor/properties/MapPropertyField.tsx +150 -0
  92. package/src/ui/collection_editor/properties/MarkdownPropertyField.tsx +139 -0
  93. package/src/ui/collection_editor/properties/NumberPropertyField.tsx +38 -0
  94. package/src/ui/collection_editor/properties/ReferencePropertyField.tsx +160 -0
  95. package/src/ui/collection_editor/properties/RepeatPropertyField.tsx +108 -0
  96. package/src/ui/collection_editor/properties/StoragePropertyField.tsx +215 -0
  97. package/src/ui/collection_editor/properties/StringPropertyField.tsx +70 -0
  98. package/src/ui/collection_editor/properties/UrlPropertyField.tsx +89 -0
  99. package/src/ui/collection_editor/properties/advanced/AdvancedPropertyValidation.tsx +45 -0
  100. package/src/ui/collection_editor/properties/validation/ArrayPropertyValidation.tsx +50 -0
  101. package/src/ui/collection_editor/properties/validation/GeneralPropertyValidation.tsx +61 -0
  102. package/src/ui/collection_editor/properties/validation/NumberPropertyValidation.tsx +115 -0
  103. package/src/ui/collection_editor/properties/validation/StringPropertyValidation.tsx +150 -0
  104. package/src/ui/collection_editor/properties/validation/ValidationPanel.tsx +28 -0
  105. package/src/ui/collection_editor/templates/blog_template.ts +115 -0
  106. package/src/ui/collection_editor/templates/pages_template.ts +183 -0
  107. package/src/ui/collection_editor/templates/products_template.ts +88 -0
  108. package/src/ui/collection_editor/templates/users_template.ts +42 -0
  109. package/src/ui/collection_editor/util.ts +28 -0
  110. package/src/ui/collection_editor/utils/strings.ts +9 -0
  111. package/src/ui/collection_editor/utils/supported_fields.tsx +29 -0
  112. package/src/ui/collection_editor/utils/update_property_for_widget.ts +271 -0
  113. package/src/ui/collection_editor/utils/useTraceUpdate.tsx +23 -0
  114. package/src/useCollectionEditorController.tsx +9 -0
  115. package/src/useCollectionEditorPlugin.tsx +164 -0
  116. package/src/useCollectionsConfigController.tsx +9 -0
  117. package/src/utils/arrays.ts +3 -0
  118. package/src/utils/collections.ts +30 -0
  119. package/src/utils/entities.ts +38 -0
  120. package/src/vite-env.d.ts +1 -0
  121. package/dist/components/collection_editor/PropertySelectItem.d.ts +0 -8
  122. package/dist/components/collection_editor/SelectIcons.d.ts +0 -6
  123. package/dist/components/collection_editor/import/CollectionEditorImportMapping.d.ts +0 -4
  124. package/dist/components/collection_editor/properties/FieldHelperView.d.ts +0 -4
  125. package/dist/components/collection_editor/templates/blog_template.d.ts +0 -10
  126. package/dist/components/collection_editor/templates/products_template.d.ts +0 -12
  127. package/dist/components/collection_editor/templates/users_template.d.ts +0 -7
  128. package/dist/components/collection_editor/utils/supported_fields.d.ts +0 -3
  129. package/dist/components/collection_editor/utils/update_property_for_widget.d.ts +0 -3
  130. package/dist/types/editable_properties.d.ts +0 -10
  131. package/dist/utils/icons.d.ts +0 -2
  132. package/dist/utils/synonyms.d.ts +0 -1951
  133. /package/dist/{components → ui}/HomePageEditorCollectionAction.d.ts +0 -0
  134. /package/dist/{components → ui}/NewCollectionCard.d.ts +0 -0
  135. /package/dist/{components → ui}/collection_editor/UnsavedChangesDialog.d.ts +0 -0
  136. /package/dist/{components → ui}/collection_editor/properties/BooleanPropertyField.d.ts +0 -0
  137. /package/dist/{components → ui}/collection_editor/properties/DateTimePropertyField.d.ts +0 -0
  138. /package/dist/{components → ui}/collection_editor/properties/EnumPropertyField.d.ts +0 -0
  139. /package/dist/{components → ui}/collection_editor/properties/KeyValuePropertyField.d.ts +0 -0
  140. /package/dist/{components → ui}/collection_editor/properties/NumberPropertyField.d.ts +0 -0
  141. /package/dist/{components → ui}/collection_editor/properties/ReferencePropertyField.d.ts +0 -0
  142. /package/dist/{components → ui}/collection_editor/properties/StoragePropertyField.d.ts +0 -0
  143. /package/dist/{components → ui}/collection_editor/properties/advanced/AdvancedPropertyValidation.d.ts +0 -0
  144. /package/dist/{components → ui}/collection_editor/properties/validation/ArrayPropertyValidation.d.ts +0 -0
  145. /package/dist/{components → ui}/collection_editor/properties/validation/GeneralPropertyValidation.d.ts +0 -0
  146. /package/dist/{components → ui}/collection_editor/properties/validation/NumberPropertyValidation.d.ts +0 -0
  147. /package/dist/{components → ui}/collection_editor/properties/validation/StringPropertyValidation.d.ts +0 -0
  148. /package/dist/{components → ui}/collection_editor/properties/validation/ValidationPanel.d.ts +0 -0
  149. /package/dist/{components → ui}/collection_editor/utils/useTraceUpdate.d.ts +0 -0
@@ -0,0 +1,160 @@
1
+ import React from "react";
2
+ import { Field, getIn, useFormex } from "@firecms/formex";
3
+ import { FieldCaption, IconForView, NumberProperty, StringProperty, useNavigationController } from "@firecms/core";
4
+ import { CircularProgress, Select, SelectGroup, SelectItem, Typography, } from "@firecms/ui";
5
+
6
+ export function ReferencePropertyField({
7
+ existing,
8
+ multiple,
9
+ disabled,
10
+ showErrors
11
+ }: {
12
+ existing: boolean,
13
+ multiple: boolean,
14
+ disabled: boolean,
15
+ showErrors: boolean
16
+ }) {
17
+
18
+ const {
19
+ values,
20
+ handleChange,
21
+ errors,
22
+ } = useFormex<StringProperty | NumberProperty>();
23
+
24
+ const navigation = useNavigationController();
25
+
26
+ if (!navigation)
27
+ return <div className={"col-span-12"}>
28
+ <CircularProgress/>
29
+ </div>;
30
+
31
+ const pathPath = multiple ? "of.path" : "path";
32
+ const pathValue: string | undefined = getIn(values, pathPath);
33
+ const pathError: string | undefined = showErrors && getIn(errors, pathPath);
34
+
35
+ return (
36
+ <>
37
+ <div className={"col-span-12"}>
38
+
39
+ <Field name={pathPath}
40
+ pathPath={pathPath}
41
+ type="select"
42
+ disabled={(existing && Boolean(pathValue)) || disabled}
43
+ value={pathValue}
44
+ error={pathError}
45
+ handleChange={handleChange}
46
+ as={CollectionsSelect}/>
47
+
48
+ </div>
49
+
50
+ </>
51
+ );
52
+ }
53
+
54
+ export function CollectionsSelect({
55
+ disabled,
56
+ pathPath,
57
+ value,
58
+ handleChange,
59
+ error,
60
+ ...props
61
+ }: {
62
+ disabled: boolean,
63
+ pathPath: string,
64
+ value?: string,
65
+ handleChange: (event: any) => void,
66
+ error?: string
67
+ }) {
68
+
69
+ const navigation = useNavigationController();
70
+
71
+ if (!navigation)
72
+ return <div className={"col-span-12"}>
73
+ <CircularProgress/>
74
+ </div>;
75
+
76
+ const collections = navigation?.collections ?? [];
77
+
78
+ const groups: string[] = Array.from(new Set(
79
+ Object.values(collections).map(e => e.group).filter(Boolean) as string[]
80
+ ).values());
81
+
82
+ const ungroupedCollections = collections.filter((col) => !col.group);
83
+
84
+ return (
85
+ <>
86
+ <Select
87
+ error={Boolean(error)}
88
+ disabled={disabled}
89
+ value={value ?? ""}
90
+ position={"item-aligned"}
91
+ name={pathPath}
92
+ onChange={handleChange}
93
+ label={"Target collection"}
94
+ renderValue={(selected) => {
95
+ const selectedCollection = collections.find(collection => collection.id === selected || collection.path === selected);
96
+ if (!selectedCollection) return null;
97
+ return (
98
+ <div className="flex flex-row">
99
+ <IconForView collectionOrView={selectedCollection}/>
100
+ <Typography
101
+ variant={"subtitle2"}
102
+ className="font-medium ml-4">
103
+ {selectedCollection?.name.toUpperCase()}
104
+ </Typography>
105
+ </div>)
106
+ }}
107
+ {...props}>
108
+
109
+ {groups.flatMap((group) => (
110
+ <SelectGroup label={group || "Views"}
111
+ key={`group_${group}`}>
112
+ {
113
+ collections.filter(collection => collection.group === group)
114
+ .map((collection) => {
115
+ return <SelectItem
116
+ key={`${collection.id ?? collection.path}-${group}`}
117
+ value={collection.id ?? collection.path}>
118
+ <div className="flex flex-row">
119
+ <IconForView collectionOrView={collection}/>
120
+ <Typography
121
+ variant={"subtitle2"}
122
+ className="font-medium ml-4">
123
+ {collection?.name.toUpperCase()}
124
+ </Typography>
125
+ </div>
126
+ </SelectItem>;
127
+ })
128
+
129
+ }
130
+ </SelectGroup>
131
+ ))}
132
+
133
+ {ungroupedCollections && <SelectGroup label={"Views"}>
134
+ {ungroupedCollections
135
+ .map((collection) => {
136
+ return <SelectItem key={collection.id ?? collection.path}
137
+ value={collection.id ?? collection.path}>
138
+ <div className="flex flex-row">
139
+ <IconForView collectionOrView={collection}/>
140
+ <Typography
141
+ variant={"subtitle2"}
142
+ className="font-medium ml-4">
143
+ {collection?.name.toUpperCase()}
144
+ </Typography>
145
+ </div>
146
+ </SelectItem>;
147
+ })
148
+
149
+ }
150
+ </SelectGroup>}
151
+
152
+ </Select>
153
+
154
+ <FieldCaption>
155
+ You can only edit the reference collection upon field
156
+ creation.
157
+ </FieldCaption>
158
+ </>
159
+ );
160
+ }
@@ -0,0 +1,108 @@
1
+ import React, { useState } from "react";
2
+ import { ArrayProperty, getFieldConfig, Property, PropertyConfig } from "@firecms/core";
3
+ import { Button, Paper, Typography } from "@firecms/ui";
4
+ import { Field, getIn, useFormex } from "@firecms/formex";
5
+ import { PropertyFormDialog } from "../PropertyEditView";
6
+ import { PropertyFieldPreview } from "../PropertyFieldPreview";
7
+ import { ArrayPropertyValidation } from "./validation/ArrayPropertyValidation";
8
+ import { ValidationPanel } from "./validation/ValidationPanel";
9
+
10
+ export function RepeatPropertyField({
11
+ showErrors,
12
+ existing,
13
+ disabled,
14
+ getData,
15
+ allowDataInference,
16
+ propertyConfigs,
17
+ collectionEditable
18
+ }: {
19
+ showErrors: boolean,
20
+ existing: boolean,
21
+ disabled: boolean,
22
+ getData?: () => Promise<object[]>;
23
+ allowDataInference: boolean;
24
+ propertyConfigs: Record<string, PropertyConfig>,
25
+ collectionEditable: boolean;
26
+ }) {
27
+
28
+ const {
29
+ values,
30
+ handleChange,
31
+ errors,
32
+ setFieldValue,
33
+ touched
34
+ } = useFormex<ArrayProperty>();
35
+
36
+ const [propertyDialogOpen, setPropertyDialogOpen] = useState(false);
37
+ const ofProperty = getIn(values, "of");
38
+ const ofPropertyError = getIn(touched, "of") && getIn(errors, "of");
39
+
40
+ const onPropertyChanged = ({ id, property, namespace }:
41
+ { id?: string, property: Property, namespace?: string }) => {
42
+ setFieldValue("of", property);
43
+ };
44
+
45
+ const widget = ofProperty && getFieldConfig(ofProperty, propertyConfigs);
46
+ return (
47
+ <>
48
+ <div className={"col-span-12"}>
49
+ <Typography variant={"subtitle2"}>
50
+ Repeat component
51
+ </Typography>
52
+ <Field
53
+ name={"of"}
54
+ value={ofProperty}
55
+ // validate={(property: Property) => {
56
+ // return property?.dataType ? undefined : "You need to specify a repeat field";
57
+ // }}
58
+ >
59
+ {({}) => (
60
+ <Paper className="p-2 mt-4">
61
+
62
+ {ofProperty && <PropertyFieldPreview
63
+ property={ofProperty}
64
+ onClick={disabled ? undefined : () => setPropertyDialogOpen(true)}
65
+ includeName={false}
66
+ includeEditButton={true}
67
+ selected={false}
68
+ hasError={false}/>}
69
+
70
+ {!disabled && !ofProperty && <Button variant={"text"}
71
+ size={"large"}
72
+ color={ofPropertyError ? "error" : "primary"}
73
+ onClick={() => setPropertyDialogOpen(true)}>
74
+ Edit {`${widget ? widget.name : "repeat component"}`}
75
+ </Button>}
76
+
77
+ <PropertyFormDialog
78
+ inArray={true}
79
+ open={propertyDialogOpen}
80
+ existingProperty={existing}
81
+ getData={getData}
82
+ autoUpdateId={!existing}
83
+ autoOpenTypeSelect={!existing}
84
+ onOkClicked={() => setPropertyDialogOpen(false)}
85
+ allowDataInference={allowDataInference}
86
+ property={ofProperty}
87
+ includeIdAndName={false}
88
+ onPropertyChanged={onPropertyChanged}
89
+ forceShowErrors={showErrors}
90
+ propertyConfigs={propertyConfigs}
91
+ collectionEditable={collectionEditable}
92
+ />
93
+ </Paper>
94
+ )}
95
+ </Field>
96
+
97
+ </div>
98
+
99
+ <div className={"col-span-12"}>
100
+
101
+ <ValidationPanel>
102
+ <ArrayPropertyValidation disabled={disabled}/>
103
+ </ValidationPanel>
104
+
105
+ </div>
106
+ </>
107
+ );
108
+ }
@@ -0,0 +1,215 @@
1
+ import React from "react";
2
+ import {
3
+ Button,
4
+ DebouncedTextField,
5
+ ExpandablePanel,
6
+ FileUploadIcon,
7
+ MultiSelect,
8
+ MultiSelectItem,
9
+ Typography
10
+ } from "@firecms/ui";
11
+
12
+ import { Field, FormexFieldProps, getIn, useFormex } from "@firecms/formex";
13
+ import { GeneralPropertyValidation } from "./validation/GeneralPropertyValidation";
14
+ import { ArrayPropertyValidation } from "./validation/ArrayPropertyValidation";
15
+ import { ValidationPanel } from "./validation/ValidationPanel";
16
+ import { SwitchControl } from "../SwitchControl";
17
+
18
+ const fileTypes: Record<string, string> = {
19
+ "image/*": "Images",
20
+ "video/*": "Videos",
21
+ "audio/*": "Audio files",
22
+ "application/*": "Files (pdf, zip, csv, excel...)",
23
+ "text/*": "Text files"
24
+ }
25
+
26
+ export function StoragePropertyField({
27
+ multiple,
28
+ existing,
29
+ disabled
30
+ }: {
31
+ multiple: boolean;
32
+ existing: boolean;
33
+ disabled: boolean;
34
+ }) {
35
+
36
+ const {
37
+ values,
38
+ setFieldValue
39
+ } = useFormex();
40
+
41
+ const baseStoragePath = multiple ? "of.storage" : "storage";
42
+ const acceptedFiles = `${baseStoragePath}.acceptedFiles`;
43
+
44
+ const metadata = `${baseStoragePath}.metadata`;
45
+ const fileName = `${baseStoragePath}.fileName`;
46
+ const maxSize = `${baseStoragePath}.maxSize`;
47
+ const storagePath = `${baseStoragePath}.storagePath`;
48
+ const storeUrl = `${baseStoragePath}.storeUrl`;
49
+
50
+ const fileNameValue = getIn(values, fileName) ?? "{rand}_{file}";
51
+ const storagePathValue = getIn(values, storagePath) ?? "/";
52
+ const maxSizeValue = getIn(values, maxSize);
53
+
54
+ const storedValue = getIn(values, acceptedFiles);
55
+ const fileTypesValue: string[] | undefined = Array.isArray(storedValue) ? storedValue : undefined;
56
+ const allFileTypesSelected = !fileTypesValue || fileTypesValue.length === 0;
57
+
58
+ const handleTypesChange = (value: string[]) => {
59
+ if (!value) setFieldValue(acceptedFiles, undefined);
60
+ // else if (value.includes("all")) setFieldValue(acceptedFiles, undefined);
61
+ // else if (value.length >= Object.keys(fileTypes).length) setFieldValue(acceptedFiles, undefined);
62
+ // else if (allFileTypesSelected)
63
+ // setFieldValue(acceptedFiles, Object.keys(fileTypes).filter((v) => !value.includes(v)));
64
+ else setFieldValue(acceptedFiles, value);
65
+ };
66
+
67
+ const hasFilenameCallback = typeof fileNameValue === "function";
68
+ const hasStoragePathCallback = typeof storagePathValue === "function";
69
+
70
+ return (
71
+ <>
72
+
73
+ <div className={"col-span-12"}>
74
+
75
+ <ExpandablePanel
76
+ title={
77
+ <div className="flex flex-row text-gray-500">
78
+ <FileUploadIcon/>
79
+ <Typography variant={"subtitle2"}
80
+ className="ml-2">
81
+ File upload config
82
+ </Typography>
83
+ </div>
84
+ }>
85
+
86
+ <div className={"grid grid-cols-12 gap-2 p-4"}>
87
+
88
+ <div className={"col-span-12"}>
89
+
90
+ <MultiSelect
91
+ className={"w-full"}
92
+ placeholder={"All file types allowed"}
93
+ disabled={disabled}
94
+ name={acceptedFiles}
95
+ value={fileTypesValue ?? []}
96
+ onValueChange={handleTypesChange}
97
+ label={allFileTypesSelected ? undefined : "Allowed file types"}
98
+ renderValues={(selected) => {
99
+ if (!selected || selected.length === 0) return "All file types allowed";
100
+ return selected.map((v: string) => fileTypes[v])
101
+ .filter((v: string) => Boolean(v))
102
+ .join(", ");
103
+ }}>
104
+
105
+ {Object.entries(fileTypes).map(([value, label]) => (
106
+ <MultiSelectItem key={value} value={value} className={"flex items-center gap-2"}>
107
+ {/*<Checkbox*/}
108
+ {/* checked={allFileTypesSelected || fileTypesValue.indexOf(value) > -1}/>*/}
109
+ <div className={"flex-grow"}>
110
+ {label}
111
+ </div>
112
+ <Button size={"small"}
113
+ variant={"text"}
114
+ onClick={(e) => {
115
+ e.preventDefault();
116
+ e.stopPropagation();
117
+ return setFieldValue(acceptedFiles, [value]);
118
+ }}>
119
+ Only
120
+ </Button>
121
+ </MultiSelectItem>
122
+ ))}
123
+
124
+ </MultiSelect>
125
+ </div>
126
+
127
+ <div className={"col-span-12"}>
128
+ <Field name={fileName}
129
+ as={DebouncedTextField}
130
+ label={"File name"}
131
+ size={"small"}
132
+ disabled={hasFilenameCallback || disabled}
133
+ value={hasFilenameCallback ? "-" : fileNameValue}
134
+ />
135
+ </div>
136
+ <div className={"col-span-12"}>
137
+ <Field name={storagePath}
138
+ as={DebouncedTextField}
139
+ label={"Storage path"}
140
+ disabled={hasStoragePathCallback || disabled}
141
+ size={"small"}
142
+ value={hasStoragePathCallback ? "-" : storagePathValue}
143
+ />
144
+ <Typography variant={"caption"} className={"ml-3.5 mt-1 mb-2"}>
145
+ <p>You can use the following placeholders in
146
+ the file name
147
+ and storage path values:</p>
148
+ <ul>
149
+ <li>{"{file} - Full name of the uploaded file"}</li>
150
+ <li>{"{file.name} - Name of the uploaded file without extension"}</li>
151
+ <li>{"{file.ext} - Extension of the uploaded file"}</li>
152
+ <li>{"{entityId} - ID of the entity"}</li>
153
+ <li>{"{propertyKey} - ID of this field"}</li>
154
+ <li>{"{path} - Path of this entity"}</li>
155
+ <li>{"{rand} - Random value used to avoid name collisions"}</li>
156
+ </ul>
157
+ </Typography>
158
+
159
+ <Field name={storeUrl}
160
+ type="checkbox">
161
+ {({
162
+ field,
163
+ form
164
+ }: FormexFieldProps) => {
165
+ return <SwitchControl
166
+ label={"Save URL instead of storage path"}
167
+ disabled={existing || disabled}
168
+ form={form}
169
+ field={field}/>
170
+ }}
171
+ </Field>
172
+
173
+ <Typography variant={"caption"} className={"ml-3.5 mt-1 mb-2"}>
174
+ Turn this setting on, if you prefer to save
175
+ the download
176
+ URL of the uploaded file instead of the
177
+ storage path.
178
+ You can only change this prop upon creation.
179
+ </Typography>
180
+ </div>
181
+
182
+ <div className={"col-span-12"}>
183
+ <DebouncedTextField name={maxSize}
184
+ type={"number"}
185
+ label={"Max size (in bytes)"}
186
+ size={"small"}
187
+ value={maxSizeValue !== undefined && maxSizeValue !== null ? maxSizeValue.toString() : ""}
188
+ onChange={(e) => {
189
+ const value = e.target.value;
190
+ if (value === "") setFieldValue(maxSize, undefined);
191
+ else setFieldValue(maxSize, parseInt(value));
192
+ }}
193
+ />
194
+ </div>
195
+
196
+ </div>
197
+ </ExpandablePanel>
198
+
199
+ </div>
200
+
201
+ <div className={"col-span-12"}>
202
+
203
+ <ValidationPanel>
204
+ {!multiple && <div className={"grid grid-cols-12 gap-2"}>
205
+ <GeneralPropertyValidation disabled={disabled}/>
206
+ </div>}
207
+ {multiple && <div className={"col-span-12"}>
208
+ <ArrayPropertyValidation disabled={disabled}/>
209
+ </div>}
210
+ </ValidationPanel>
211
+
212
+ </div>
213
+ </>
214
+ );
215
+ }
@@ -0,0 +1,70 @@
1
+ import React from "react";
2
+ import { StringPropertyValidation } from "./validation/StringPropertyValidation";
3
+ import { ValidationPanel } from "./validation/ValidationPanel";
4
+ import { getIn, useFormex } from "@firecms/formex";
5
+
6
+ import { TextField } from "@firecms/ui";
7
+
8
+ export function StringPropertyField({
9
+ widgetId,
10
+ disabled,
11
+ showErrors
12
+ }: {
13
+ widgetId: "text_field" | "multiline" | "email";
14
+ disabled: boolean;
15
+ showErrors: boolean;
16
+ }) {
17
+
18
+ const { values, setFieldValue } = useFormex();
19
+
20
+ return (
21
+ <>
22
+ <div className={"col-span-12"}>
23
+
24
+ <ValidationPanel>
25
+
26
+ {widgetId === "text_field" &&
27
+ <StringPropertyValidation disabled={disabled}
28
+ length={true}
29
+ lowercase={true}
30
+ matches={true}
31
+ max={true}
32
+ min={true}
33
+ trim={true}
34
+ uppercase={true}
35
+ showErrors={showErrors}/>}
36
+ {widgetId === "multiline" &&
37
+ <StringPropertyValidation disabled={disabled}
38
+ length={true}
39
+ lowercase={true}
40
+ max={true}
41
+ min={true}
42
+ trim={true}
43
+ uppercase={true}
44
+ showErrors={showErrors}/>}
45
+
46
+ {widgetId === "email" &&
47
+ <StringPropertyValidation disabled={disabled}
48
+ max={true}
49
+ min={true}
50
+ trim={true}
51
+ showErrors={showErrors}/>}
52
+
53
+ </ValidationPanel>
54
+
55
+ </div>
56
+
57
+ <div className={"col-span-12"}>
58
+
59
+ <TextField name={"defaultValue"}
60
+ disabled={disabled}
61
+ onChange={(e: any) => {
62
+ setFieldValue("defaultValue", e.target.value === "" ? undefined : e.target.value);
63
+ }}
64
+ label={"Default value"}
65
+ value={getIn(values, "defaultValue") ?? ""}/>
66
+
67
+ </div>
68
+ </>
69
+ );
70
+ }
@@ -0,0 +1,89 @@
1
+ import React from "react";
2
+ import { StringPropertyValidation } from "./validation/StringPropertyValidation";
3
+ import { ValidationPanel } from "./validation/ValidationPanel";
4
+ import { getIn, useFormex } from "@firecms/formex";
5
+
6
+ import { Select, SelectItem, TextField } from "@firecms/ui";
7
+
8
+ export function UrlPropertyField({
9
+ disabled,
10
+ showErrors
11
+ }: {
12
+ disabled: boolean;
13
+ showErrors: boolean;
14
+ }) {
15
+
16
+ const { values, setFieldValue } = useFormex();
17
+
18
+ const urlValue = getIn(values, "url");
19
+
20
+ return (
21
+ <>
22
+ <div className={"col-span-12"}>
23
+
24
+ <Select
25
+ disabled={disabled}
26
+ position={"item-aligned"}
27
+ onValueChange={(value: string) => {
28
+ if (value === "[NONE]")
29
+ setFieldValue("url", true);
30
+ else
31
+ setFieldValue("url", value);
32
+ }}
33
+ label={"Preview type"}
34
+ renderValue={(value: string) => {
35
+ switch (value) {
36
+ case "image":
37
+ return "Image";
38
+ case "video":
39
+ return "Video";
40
+ case "audio":
41
+ return "Audio";
42
+ default:
43
+ return "Display URL";
44
+ }
45
+ }}
46
+ value={urlValue ?? "[NONE]"}>
47
+ <SelectItem value={"[NONE]"}>
48
+ Display URL
49
+ </SelectItem>
50
+ <SelectItem value={"image"}>
51
+ Image
52
+ </SelectItem>
53
+ <SelectItem value={"video"}>
54
+ Video
55
+ </SelectItem>
56
+ <SelectItem value={"audio"}>
57
+ Audio
58
+ </SelectItem>
59
+ </Select>
60
+ </div>
61
+
62
+ <div className={"col-span-12"}>
63
+
64
+ <ValidationPanel>
65
+
66
+ <StringPropertyValidation disabled={disabled}
67
+ max={true}
68
+ min={true}
69
+ trim={true}
70
+ showErrors={showErrors}/>
71
+
72
+ </ValidationPanel>
73
+
74
+ </div>
75
+
76
+ <div className={"col-span-12"}>
77
+
78
+ <TextField name={"defaultValue"}
79
+ disabled={disabled}
80
+ onChange={(e: any) => {
81
+ setFieldValue("defaultValue", e.target.value === "" ? undefined : e.target.value);
82
+ }}
83
+ label={"Default value"}
84
+ value={getIn(values, "defaultValue") ?? ""}/>
85
+
86
+ </div>
87
+ </>
88
+ );
89
+ }