@firecms/collection_editor 3.0.0-beta.7 → 3.0.0-beta.9

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 (37) hide show
  1. package/LICENSE +2 -1
  2. package/dist/ConfigControllerProvider.d.ts +9 -0
  3. package/dist/index.es.js +4633 -3467
  4. package/dist/index.es.js.map +1 -1
  5. package/dist/index.umd.js +6679 -3
  6. package/dist/index.umd.js.map +1 -1
  7. package/dist/types/collection_editor_controller.d.ts +13 -1
  8. package/dist/ui/CollectionViewHeaderAction.d.ts +3 -2
  9. package/dist/ui/PropertyAddColumnComponent.d.ts +3 -1
  10. package/dist/ui/collection_editor/CollectionEditorDialog.d.ts +2 -1
  11. package/dist/ui/collection_editor/properties/MarkdownPropertyField.d.ts +4 -0
  12. package/dist/ui/collection_editor/properties/StringPropertyField.d.ts +1 -1
  13. package/dist/useCollectionEditorPlugin.d.ts +11 -2
  14. package/package.json +16 -30
  15. package/src/ConfigControllerProvider.tsx +26 -8
  16. package/src/types/collection_editor_controller.tsx +13 -3
  17. package/src/ui/CollectionViewHeaderAction.tsx +9 -4
  18. package/src/ui/EditorCollectionAction.tsx +10 -12
  19. package/src/ui/EditorCollectionActionStart.tsx +1 -0
  20. package/src/ui/HomePageEditorCollectionAction.tsx +11 -6
  21. package/src/ui/PropertyAddColumnComponent.tsx +9 -4
  22. package/src/ui/collection_editor/CollectionDetailsForm.tsx +34 -4
  23. package/src/ui/collection_editor/CollectionEditorDialog.tsx +12 -2
  24. package/src/ui/collection_editor/CollectionEditorWelcomeView.tsx +2 -1
  25. package/src/ui/collection_editor/CollectionPropertiesEditorForm.tsx +6 -3
  26. package/src/ui/collection_editor/GetCodeDialog.tsx +1 -1
  27. package/src/ui/collection_editor/PropertyEditView.tsx +10 -3
  28. package/src/ui/collection_editor/PropertySelectItem.tsx +1 -1
  29. package/src/ui/collection_editor/PropertyTree.tsx +4 -2
  30. package/src/ui/collection_editor/SubcollectionsEditTab.tsx +5 -3
  31. package/src/ui/collection_editor/properties/DateTimePropertyField.tsx +50 -47
  32. package/src/ui/collection_editor/properties/EnumPropertyField.tsx +1 -1
  33. package/src/ui/collection_editor/properties/MarkdownPropertyField.tsx +139 -0
  34. package/src/ui/collection_editor/properties/StoragePropertyField.tsx +31 -16
  35. package/src/ui/collection_editor/properties/StringPropertyField.tsx +1 -10
  36. package/src/ui/collection_editor/templates/pages_template.ts +0 -5
  37. package/src/useCollectionEditorPlugin.tsx +13 -4
@@ -351,7 +351,8 @@ export function CollectionPropertiesEditorForm({
351
351
  </div>}
352
352
 
353
353
  <div className="ml-1 mt-2 flex flex-row gap-2">
354
- <Tooltip title={"Get the code for this collection"}>
354
+ <Tooltip title={"Get the code for this collection"}
355
+ asChild={true}>
355
356
  <IconButton
356
357
  variant={"filled"}
357
358
  disabled={inferringProperties}
@@ -359,7 +360,8 @@ export function CollectionPropertiesEditorForm({
359
360
  <CodeIcon/>
360
361
  </IconButton>
361
362
  </Tooltip>
362
- {inferPropertiesFromData && <Tooltip title={"Add new properties based on data"}>
363
+ {inferPropertiesFromData && <Tooltip title={"Add new properties based on data"}
364
+ asChild={true}>
363
365
  <IconButton
364
366
  variant={"filled"}
365
367
  disabled={inferringProperties}
@@ -367,7 +369,8 @@ export function CollectionPropertiesEditorForm({
367
369
  {inferringProperties ? <CircularProgress size={"small"}/> : <AutoAwesomeIcon/>}
368
370
  </IconButton>
369
371
  </Tooltip>}
370
- <Tooltip title={"Add new property"}>
372
+ <Tooltip title={"Add new property"}
373
+ asChild={true}>
371
374
  <Button
372
375
  variant={"outlined"}
373
376
  onClick={() => setNewPropertyDialogOpen(true)}>
@@ -14,7 +14,7 @@ export function GetCodeDialog({
14
14
  const snackbarController = useSnackbarController();
15
15
 
16
16
  const code = collection
17
- ? "import { EntityCollection } from \"firecms\";\n\nconst " + (collection?.name ? camelCase(collection.name) : "my") + "Collection:EntityCollection = " + JSON5.stringify(collectionToCode(collection), null, "\t")
17
+ ? "import { EntityCollection } from \"@firecms/core\";\n\nconst " + (collection?.name ? camelCase(collection.name) : "my") + "Collection:EntityCollection = " + JSON5.stringify(collectionToCode(collection), null, "\t")
18
18
  : "No collection selected";
19
19
  return <Dialog open={open}
20
20
  onOpenChange={onOpenChange}
@@ -5,7 +5,6 @@ import { Formex, FormexController, getIn, useCreateFormex } from "@firecms/forme
5
5
  import {
6
6
  DEFAULT_FIELD_CONFIGS,
7
7
  DeleteConfirmationDialog,
8
- PropertyConfigId,
9
8
  getFieldConfig,
10
9
  getFieldId,
11
10
  isPropertyBuilder,
@@ -14,6 +13,7 @@ import {
14
13
  Property,
15
14
  PropertyConfig,
16
15
  PropertyConfigBadge,
16
+ PropertyConfigId,
17
17
  } from "@firecms/core";
18
18
  import {
19
19
  Button,
@@ -45,6 +45,7 @@ import { updatePropertyFromWidget } from "./utils/update_property_for_widget";
45
45
  import { PropertySelectItem } from "./PropertySelectItem";
46
46
  import { UrlPropertyField } from "./properties/UrlPropertyField";
47
47
  import { supportedFields } from "./utils/supported_fields";
48
+ import { MarkdownPropertyField } from "./properties/MarkdownPropertyField";
48
49
 
49
50
  export type PropertyWithId = Property & {
50
51
  id?: string
@@ -148,7 +149,10 @@ export const PropertyForm = React.memo(
148
149
  } = newPropertyWithId;
149
150
  doOnPropertyChanged({
150
151
  id,
151
- property: { ...property, editable: property.editable ?? true }
152
+ property: {
153
+ ...property,
154
+ editable: property.editable ?? true
155
+ }
152
156
  });
153
157
  if (!existingProperty)
154
158
  controller.resetForm({ values: initialValue });
@@ -388,7 +392,6 @@ function PropertyEditFormFields({
388
392
  let childComponent;
389
393
  if (selectedFieldConfigId === "text_field" ||
390
394
  selectedFieldConfigId === "multiline" ||
391
- selectedFieldConfigId === "markdown" ||
392
395
  selectedFieldConfigId === "email") {
393
396
  childComponent =
394
397
  <StringPropertyField widgetId={selectedFieldConfigId}
@@ -398,6 +401,10 @@ function PropertyEditFormFields({
398
401
  childComponent =
399
402
  <UrlPropertyField disabled={disabled}
400
403
  showErrors={showErrors}/>;
404
+ } else if (selectedFieldConfigId === "markdown") {
405
+ childComponent =
406
+ <MarkdownPropertyField disabled={disabled}
407
+ showErrors={showErrors}/>;
401
408
  } else if (selectedFieldConfigId === "select" ||
402
409
  selectedFieldConfigId === "number_select") {
403
410
  childComponent = <EnumPropertyField
@@ -14,7 +14,7 @@ export function PropertySelectItem({ value, optionDisabled, propertyConfig, exis
14
14
  className={"flex flex-row items-center"}>
15
15
  <div
16
16
  className={cls(
17
- "flex flex-row items-center text-base min-h-[52px]",
17
+ "flex flex-row items-center text-base min-h-[48px]",
18
18
  optionDisabled ? "w-full" : "")}>
19
19
  <div className={"mr-8"}>
20
20
  <PropertyConfigBadge propertyConfig={propertyConfig}/>
@@ -227,7 +227,8 @@ export function PropertyTreeEntry({
227
227
  <AutoAwesomeIcon size="small" className={"p-2"}/>
228
228
  </Tooltip>}
229
229
 
230
- {onPropertyRemove && <Tooltip title={"Remove"}>
230
+ {onPropertyRemove && <Tooltip title={"Remove"}
231
+ asChild={true}>
231
232
  <IconButton size="small"
232
233
  color="inherit"
233
234
  onClick={() => onPropertyRemove(propertyKey, namespace)}>
@@ -235,7 +236,8 @@ export function PropertyTreeEntry({
235
236
  </IconButton>
236
237
  </Tooltip>}
237
238
 
238
- {onPropertyMove && <Tooltip title={"Move"}>
239
+ {onPropertyMove && <Tooltip title={"Move"}
240
+ asChild={true}>
239
241
  <IconButton
240
242
  component={"span"}
241
243
  size="small"
@@ -95,7 +95,8 @@ export function SubcollectionsEditTab({
95
95
  </TableCell>
96
96
  <TableCell
97
97
  align="right">
98
- <Tooltip title={"Remove"}>
98
+ <Tooltip title={"Remove"}
99
+ asChild={true}>
99
100
  <IconButton size="small"
100
101
  onClick={(e) => {
101
102
  e.preventDefault();
@@ -135,7 +136,7 @@ export function SubcollectionsEditTab({
135
136
  {totalEntityViews === 0 &&
136
137
  <Alert action={<Button variant="text"
137
138
  size={"small"}
138
- href={"https://firecms.co/docs/customization_quickstart"}
139
+ href={"https://firecms.co/docs/cloud/quickstart"}
139
140
  component={"a"}
140
141
  rel="noopener noreferrer"
141
142
  target="_blank">More info</Button>}>
@@ -157,7 +158,8 @@ export function SubcollectionsEditTab({
157
158
  </TableCell>
158
159
  <TableCell
159
160
  align="right">
160
- <Tooltip title={"Remove"}>
161
+ <Tooltip title={"Remove"}
162
+ asChild={true}>
161
163
  <IconButton size="small"
162
164
  onClick={(e) => {
163
165
  e.preventDefault();
@@ -26,53 +26,56 @@ export function DateTimePropertyField({ disabled }: {
26
26
 
27
27
  return (
28
28
  <>
29
- <div className={"flex flex-col col-span-12"}>
30
- <Select name={modePath}
31
- value={modeValue ?? "date"}
32
- error={Boolean(modeError)}
33
- onValueChange={(v) => setFieldValue(modePath, v)}
34
- label={"Mode"}
35
- renderValue={(v) => {
36
- switch (v) {
37
- case "date_time":
38
- return "Date/Time";
39
- case "date":
40
- return "Date";
41
- default:
42
- return "";
43
- }
44
- }}
45
- disabled={disabled}>
46
- <SelectItem value={"date_time"}> Date/Time </SelectItem>
47
- <SelectItem value={"date"}> Date </SelectItem>
48
- </Select>
49
- <FieldCaption error={Boolean(modeError)}>
50
- {modeError}
51
- </FieldCaption>
52
-
53
- <Select name={autoValuePath}
54
- disabled={disabled}
55
- value={autoValueValue ?? ""}
56
- onValueChange={(v) => setFieldValue(autoValuePath, v === "none" ? null : v)}
57
- renderValue={(v) => {
58
- switch (v) {
59
- case "on_create":
60
- return "On create";
61
- case "on_update":
62
- return "On any update";
63
- default:
64
- return "None";
65
- }
66
- }}
67
- error={Boolean(autoValueError)}
68
- label={"Automatic value"}>
69
- <SelectItem value={"none"}> None </SelectItem>
70
- <SelectItem value={"on_create"}> On create </SelectItem>
71
- <SelectItem value={"on_update"}> On any update </SelectItem>
72
- </Select>
73
- <FieldCaption error={Boolean(autoValueError)}>
74
- {autoValueError ?? "Update this field automatically when creating or updating the entity"}
75
- </FieldCaption>
29
+ <div className={"flex flex-col col-span-12 gap-2"}>
30
+ <div>
31
+ <Select name={modePath}
32
+ value={modeValue ?? "date"}
33
+ error={Boolean(modeError)}
34
+ onValueChange={(v) => setFieldValue(modePath, v)}
35
+ label={"Mode"}
36
+ renderValue={(v) => {
37
+ switch (v) {
38
+ case "date_time":
39
+ return "Date/Time";
40
+ case "date":
41
+ return "Date";
42
+ default:
43
+ return "";
44
+ }
45
+ }}
46
+ disabled={disabled}>
47
+ <SelectItem value={"date_time"}> Date/Time </SelectItem>
48
+ <SelectItem value={"date"}> Date </SelectItem>
49
+ </Select>
50
+ <FieldCaption error={Boolean(modeError)}>
51
+ {modeError}
52
+ </FieldCaption>
53
+ </div>
54
+ <div>
55
+ <Select name={autoValuePath}
56
+ disabled={disabled}
57
+ value={autoValueValue ?? ""}
58
+ onValueChange={(v) => setFieldValue(autoValuePath, v === "none" ? null : v)}
59
+ renderValue={(v) => {
60
+ switch (v) {
61
+ case "on_create":
62
+ return "On create";
63
+ case "on_update":
64
+ return "On any update";
65
+ default:
66
+ return "None";
67
+ }
68
+ }}
69
+ error={Boolean(autoValueError)}
70
+ label={"Automatic value"}>
71
+ <SelectItem value={"none"}> None </SelectItem>
72
+ <SelectItem value={"on_create"}> On create </SelectItem>
73
+ <SelectItem value={"on_update"}> On any update </SelectItem>
74
+ </Select>
75
+ <FieldCaption error={Boolean(autoValueError)}>
76
+ {autoValueError ?? "Update this field automatically when creating or updating the entity"}
77
+ </FieldCaption>
78
+ </div>
76
79
 
77
80
  </div>
78
81
 
@@ -71,7 +71,7 @@ export function EnumPropertyField({
71
71
  }}
72
72
  getData={getData
73
73
  ? () => getData()
74
- .then(res => res.map(d => values.id && getIn(d, values.id)).filter(Boolean))
74
+ .then(res => res.map(entry => values.id && getIn(entry, values.id)).filter(Boolean))
75
75
  : undefined}
76
76
  onValuesChanged={onValuesChanged}/>
77
77
  </div>
@@ -0,0 +1,139 @@
1
+ import React from "react";
2
+ import { StringPropertyValidation } from "./validation/StringPropertyValidation";
3
+ import { ValidationPanel } from "./validation/ValidationPanel";
4
+ import { Field, getIn, useFormex } from "@firecms/formex";
5
+
6
+ import { DebouncedTextField, ExpandablePanel, FileUploadIcon, TextField, Typography } from "@firecms/ui";
7
+
8
+ export function MarkdownPropertyField({
9
+ disabled,
10
+ showErrors
11
+ }: {
12
+ disabled: boolean;
13
+ showErrors: boolean;
14
+ }) {
15
+
16
+ const {
17
+ values,
18
+ setFieldValue
19
+ } = useFormex();
20
+
21
+ const baseStoragePath = "storage";
22
+
23
+ const metadata = `${baseStoragePath}.metadata`;
24
+ const fileName = `${baseStoragePath}.fileName`;
25
+ const maxSize = `${baseStoragePath}.maxSize`;
26
+ const storagePath = `${baseStoragePath}.storagePath`;
27
+
28
+ const fileNameValue = getIn(values, fileName) ?? "{rand}_{file}";
29
+ const storagePathValue = getIn(values, storagePath) ?? "/";
30
+ const maxSizeValue = getIn(values, maxSize);
31
+
32
+ const hasFilenameCallback = typeof fileNameValue === "function";
33
+ const hasStoragePathCallback = typeof storagePathValue === "function";
34
+
35
+ return (
36
+ <>
37
+ <div className={"col-span-12"}>
38
+
39
+ <ValidationPanel>
40
+
41
+ <StringPropertyValidation disabled={disabled}
42
+ length={true}
43
+ lowercase={true}
44
+ max={true}
45
+ min={true}
46
+ trim={true}
47
+ uppercase={true}
48
+ showErrors={showErrors}/>
49
+
50
+ </ValidationPanel>
51
+
52
+ </div>
53
+
54
+ <div className={"col-span-12"}>
55
+ <ExpandablePanel
56
+ title={
57
+ <div className="flex flex-row text-gray-500">
58
+ <FileUploadIcon/>
59
+ <Typography variant={"subtitle2"}
60
+ className="ml-2">
61
+ File upload config
62
+ </Typography>
63
+ </div>
64
+ }>
65
+
66
+ <div className={"grid grid-cols-12 gap-2 p-4"}>
67
+
68
+
69
+ <div className={"col-span-12"}>
70
+ <Field name={fileName}
71
+ as={DebouncedTextField}
72
+ label={"File name"}
73
+ size={"small"}
74
+ disabled={hasFilenameCallback || disabled}
75
+ value={hasFilenameCallback ? "-" : fileNameValue}
76
+ />
77
+ </div>
78
+ <div className={"col-span-12"}>
79
+ <Field name={storagePath}
80
+ as={DebouncedTextField}
81
+ label={"Storage path"}
82
+ disabled={hasStoragePathCallback || disabled}
83
+ size={"small"}
84
+ value={hasStoragePathCallback ? "-" : storagePathValue}
85
+ />
86
+ <Typography variant={"caption"} className={"ml-3.5 mt-1 mb-2"}>
87
+ <p>You can use the following placeholders in
88
+ the file name
89
+ and storage path values:</p>
90
+ <ul>
91
+ <li>{"{file} - Full name of the uploaded file"}</li>
92
+ <li>{"{file.name} - Name of the uploaded file without extension"}</li>
93
+ <li>{"{file.ext} - Extension of the uploaded file"}</li>
94
+ <li>{"{entityId} - ID of the entity"}</li>
95
+ <li>{"{propertyKey} - ID of this field"}</li>
96
+ <li>{"{path} - Path of this entity"}</li>
97
+ <li>{"{rand} - Random value used to avoid name collisions"}</li>
98
+ </ul>
99
+ </Typography>
100
+
101
+ <Typography variant={"caption"} className={"ml-3.5 mt-1 mb-2"}>
102
+ When using Markdown, the URL of the uploaded files are always saved in the text value
103
+ (not
104
+ the path).
105
+ </Typography>
106
+ </div>
107
+
108
+ <div className={"col-span-12"}>
109
+ <DebouncedTextField name={maxSize}
110
+ type={"number"}
111
+ label={"Max size (in bytes)"}
112
+ size={"small"}
113
+ value={maxSizeValue !== undefined && maxSizeValue !== null ? maxSizeValue.toString() : ""}
114
+ onChange={(e) => {
115
+ const value = e.target.value;
116
+ if (value === "") setFieldValue(maxSize, undefined);
117
+ else setFieldValue(maxSize, parseInt(value));
118
+ }}
119
+ />
120
+ </div>
121
+
122
+ </div>
123
+ </ExpandablePanel>
124
+ </div>
125
+
126
+ <div className={"col-span-12"}>
127
+
128
+ <TextField name={"defaultValue"}
129
+ disabled={disabled}
130
+ onChange={(e: any) => {
131
+ setFieldValue("defaultValue", e.target.value === "" ? undefined : e.target.value);
132
+ }}
133
+ label={"Default value"}
134
+ value={getIn(values, "defaultValue") ?? ""}/>
135
+
136
+ </div>
137
+ </>
138
+ );
139
+ }
@@ -1,7 +1,6 @@
1
1
  import React from "react";
2
2
  import {
3
3
  Button,
4
- Checkbox,
5
4
  DebouncedTextField,
6
5
  ExpandablePanel,
7
6
  FileUploadIcon,
@@ -44,11 +43,13 @@ export function StoragePropertyField({
44
43
 
45
44
  const metadata = `${baseStoragePath}.metadata`;
46
45
  const fileName = `${baseStoragePath}.fileName`;
46
+ const maxSize = `${baseStoragePath}.maxSize`;
47
47
  const storagePath = `${baseStoragePath}.storagePath`;
48
48
  const storeUrl = `${baseStoragePath}.storeUrl`;
49
49
 
50
50
  const fileNameValue = getIn(values, fileName) ?? "{rand}_{file}";
51
51
  const storagePathValue = getIn(values, storagePath) ?? "/";
52
+ const maxSizeValue = getIn(values, maxSize);
52
53
 
53
54
  const storedValue = getIn(values, acceptedFiles);
54
55
  const fileTypesValue: string[] | undefined = Array.isArray(storedValue) ? storedValue : undefined;
@@ -56,10 +57,10 @@ export function StoragePropertyField({
56
57
 
57
58
  const handleTypesChange = (value: string[]) => {
58
59
  if (!value) setFieldValue(acceptedFiles, undefined);
59
- else if (value.includes("all")) setFieldValue(acceptedFiles, undefined);
60
- else if (value.length >= Object.keys(fileTypes).length) setFieldValue(acceptedFiles, undefined);
61
- else if (allFileTypesSelected)
62
- setFieldValue(acceptedFiles, Object.keys(fileTypes).filter((v) => !value.includes(v)));
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)));
63
64
  else setFieldValue(acceptedFiles, value);
64
65
  };
65
66
 
@@ -87,10 +88,12 @@ export function StoragePropertyField({
87
88
  <div className={"col-span-12"}>
88
89
 
89
90
  <MultiSelect
91
+ className={"w-full"}
92
+ placeholder={"All file types allowed"}
90
93
  disabled={disabled}
91
94
  name={acceptedFiles}
92
95
  value={fileTypesValue ?? []}
93
- onMultiValueChange={handleTypesChange}
96
+ onValueChange={handleTypesChange}
94
97
  label={allFileTypesSelected ? undefined : "Allowed file types"}
95
98
  renderValues={(selected) => {
96
99
  if (!selected || selected.length === 0) return "All file types allowed";
@@ -99,21 +102,15 @@ export function StoragePropertyField({
99
102
  .join(", ");
100
103
  }}>
101
104
 
102
- <MultiSelectItem key={"all"} value={"all"} className={"flex items-center gap-2"}>
103
- <Checkbox
104
- checked={!fileTypesValue}/>
105
- All
106
- </MultiSelectItem>
107
-
108
105
  {Object.entries(fileTypes).map(([value, label]) => (
109
106
  <MultiSelectItem key={value} value={value} className={"flex items-center gap-2"}>
110
- <Checkbox
111
- checked={allFileTypesSelected || fileTypesValue.indexOf(value) > -1}/>
107
+ {/*<Checkbox*/}
108
+ {/* checked={allFileTypesSelected || fileTypesValue.indexOf(value) > -1}/>*/}
112
109
  <div className={"flex-grow"}>
113
110
  {label}
114
111
  </div>
115
112
  <Button size={"small"}
116
- variant={"outlined"}
113
+ variant={"text"}
117
114
  onClick={(e) => {
118
115
  e.preventDefault();
119
116
  e.stopPropagation();
@@ -161,7 +158,10 @@ export function StoragePropertyField({
161
158
 
162
159
  <Field name={storeUrl}
163
160
  type="checkbox">
164
- {({ field, form }: FormexFieldProps) => {
161
+ {({
162
+ field,
163
+ form
164
+ }: FormexFieldProps) => {
165
165
  return <SwitchControl
166
166
  label={"Save URL instead of storage path"}
167
167
  disabled={existing || disabled}
@@ -178,6 +178,21 @@ export function StoragePropertyField({
178
178
  You can only change this prop upon creation.
179
179
  </Typography>
180
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
+
181
196
  </div>
182
197
  </ExpandablePanel>
183
198
 
@@ -10,7 +10,7 @@ export function StringPropertyField({
10
10
  disabled,
11
11
  showErrors
12
12
  }: {
13
- widgetId: "text_field" | "multiline" | "markdown" | "email";
13
+ widgetId: "text_field" | "multiline" | "email";
14
14
  disabled: boolean;
15
15
  showErrors: boolean;
16
16
  }) {
@@ -42,15 +42,6 @@ export function StringPropertyField({
42
42
  trim={true}
43
43
  uppercase={true}
44
44
  showErrors={showErrors}/>}
45
- {widgetId === "markdown" &&
46
- <StringPropertyValidation disabled={disabled}
47
- length={true}
48
- lowercase={true}
49
- max={true}
50
- min={true}
51
- trim={true}
52
- uppercase={true}
53
- showErrors={showErrors}/>}
54
45
 
55
46
  {widgetId === "email" &&
56
47
  <StringPropertyValidation disabled={disabled}
@@ -178,11 +178,6 @@ export const pagesCollectionTemplate: EntityCollection = {
178
178
  name: "Is Published",
179
179
  columnWidth: 100,
180
180
  description: "Should this page be live on the site?"
181
- },
182
- author_uid: {
183
- dataType: "reference",
184
- name: "Author",
185
- path: "users"
186
181
  }
187
182
  }
188
183
  };
@@ -51,6 +51,13 @@ export interface CollectionConfigControllerProps<EC extends PersistedCollection
51
51
 
52
52
  onAnalyticsEvent?: (event: string, params?: object) => void;
53
53
 
54
+ components?: {
55
+ /**
56
+ * Custom component to render the database field
57
+ */
58
+ DatabaseField?: React.ComponentType<{ databaseId?: string, onDatabaseIdUpdate: (databaseId:string) => void }>;
59
+ };
60
+
54
61
  }
55
62
 
56
63
  /**
@@ -60,7 +67,7 @@ export interface CollectionConfigControllerProps<EC extends PersistedCollection
60
67
  * @param configPermissions
61
68
  * @param reservedGroups
62
69
  * @param extraView
63
- * @param getPathsSuggestions
70
+ * @param getData
64
71
  * @param getUser
65
72
  * @param collectionInference
66
73
  */
@@ -74,7 +81,8 @@ export function useCollectionEditorPlugin<EC extends PersistedCollection = Persi
74
81
  getUser,
75
82
  collectionInference,
76
83
  getData,
77
- onAnalyticsEvent
84
+ onAnalyticsEvent,
85
+ components
78
86
  }: CollectionConfigControllerProps<EC, UserType>): FireCMSPlugin<any, any, PersistedCollection> {
79
87
 
80
88
  return {
@@ -91,7 +99,8 @@ export function useCollectionEditorPlugin<EC extends PersistedCollection = Persi
91
99
  getPathSuggestions,
92
100
  getUser,
93
101
  getData,
94
- onAnalyticsEvent
102
+ onAnalyticsEvent,
103
+ components
95
104
  }
96
105
  },
97
106
  homePage: {
@@ -147,7 +156,7 @@ export function IntroWidget({}: {}) {
147
156
  : undefined}>
148
157
  <AddIcon/>Create your first collection
149
158
  </Button>}
150
- <Typography variant={"caption"} color={"secondary"}>
159
+ <Typography color={"secondary"}>
151
160
  You can also define collections programmatically.
152
161
  </Typography>
153
162
  </Paper>