@firecms/collection_editor 3.0.0-3.0.0-beta.4.pre.1.0

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 (140) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1 -0
  3. package/dist/ConfigControllerProvider.d.ts +37 -0
  4. package/dist/index.d.ts +11 -0
  5. package/dist/index.es.js +5454 -0
  6. package/dist/index.es.js.map +1 -0
  7. package/dist/index.umd.js +4 -0
  8. package/dist/index.umd.js.map +1 -0
  9. package/dist/types/collection_editor_controller.d.ts +36 -0
  10. package/dist/types/collection_inference.d.ts +2 -0
  11. package/dist/types/config_controller.d.ts +51 -0
  12. package/dist/types/config_permissions.d.ts +19 -0
  13. package/dist/types/persisted_collection.d.ts +6 -0
  14. package/dist/ui/CollectionViewHeaderAction.d.ts +10 -0
  15. package/dist/ui/EditorCollectionAction.d.ts +2 -0
  16. package/dist/ui/HomePageEditorCollectionAction.d.ts +2 -0
  17. package/dist/ui/MissingReferenceWidget.d.ts +3 -0
  18. package/dist/ui/NewCollectionButton.d.ts +1 -0
  19. package/dist/ui/NewCollectionCard.d.ts +2 -0
  20. package/dist/ui/PropertyAddColumnComponent.d.ts +6 -0
  21. package/dist/ui/RootCollectionSuggestions.d.ts +3 -0
  22. package/dist/ui/collection_editor/CollectionDetailsForm.d.ts +10 -0
  23. package/dist/ui/collection_editor/CollectionEditorDialog.d.ts +36 -0
  24. package/dist/ui/collection_editor/CollectionEditorWelcomeView.d.ts +15 -0
  25. package/dist/ui/collection_editor/CollectionPropertiesEditorForm.d.ts +19 -0
  26. package/dist/ui/collection_editor/CollectionYupValidation.d.ts +14 -0
  27. package/dist/ui/collection_editor/EntityCustomViewsSelectDialog.d.ts +4 -0
  28. package/dist/ui/collection_editor/EnumForm.d.ts +12 -0
  29. package/dist/ui/collection_editor/GetCodeDialog.d.ts +5 -0
  30. package/dist/ui/collection_editor/PropertyEditView.d.ts +40 -0
  31. package/dist/ui/collection_editor/PropertyFieldPreview.d.ts +15 -0
  32. package/dist/ui/collection_editor/PropertySelectItem.d.ts +8 -0
  33. package/dist/ui/collection_editor/PropertyTree.d.ts +33 -0
  34. package/dist/ui/collection_editor/SubcollectionsEditTab.d.ts +12 -0
  35. package/dist/ui/collection_editor/SwitchControl.d.ts +8 -0
  36. package/dist/ui/collection_editor/UnsavedChangesDialog.d.ts +9 -0
  37. package/dist/ui/collection_editor/import/CollectionEditorImportDataPreview.d.ts +7 -0
  38. package/dist/ui/collection_editor/import/CollectionEditorImportMapping.d.ts +7 -0
  39. package/dist/ui/collection_editor/import/clean_import_data.d.ts +7 -0
  40. package/dist/ui/collection_editor/properties/BlockPropertyField.d.ts +8 -0
  41. package/dist/ui/collection_editor/properties/BooleanPropertyField.d.ts +3 -0
  42. package/dist/ui/collection_editor/properties/CommonPropertyFields.d.ts +10 -0
  43. package/dist/ui/collection_editor/properties/DateTimePropertyField.d.ts +3 -0
  44. package/dist/ui/collection_editor/properties/EnumPropertyField.d.ts +8 -0
  45. package/dist/ui/collection_editor/properties/KeyValuePropertyField.d.ts +3 -0
  46. package/dist/ui/collection_editor/properties/MapPropertyField.d.ts +8 -0
  47. package/dist/ui/collection_editor/properties/NumberPropertyField.d.ts +3 -0
  48. package/dist/ui/collection_editor/properties/ReferencePropertyField.d.ts +13 -0
  49. package/dist/ui/collection_editor/properties/RepeatPropertyField.d.ts +10 -0
  50. package/dist/ui/collection_editor/properties/StoragePropertyField.d.ts +5 -0
  51. package/dist/ui/collection_editor/properties/StringPropertyField.d.ts +5 -0
  52. package/dist/ui/collection_editor/properties/UrlPropertyField.d.ts +4 -0
  53. package/dist/ui/collection_editor/properties/advanced/AdvancedPropertyValidation.d.ts +3 -0
  54. package/dist/ui/collection_editor/properties/validation/ArrayPropertyValidation.d.ts +5 -0
  55. package/dist/ui/collection_editor/properties/validation/GeneralPropertyValidation.d.ts +4 -0
  56. package/dist/ui/collection_editor/properties/validation/NumberPropertyValidation.d.ts +3 -0
  57. package/dist/ui/collection_editor/properties/validation/StringPropertyValidation.d.ts +11 -0
  58. package/dist/ui/collection_editor/properties/validation/ValidationPanel.d.ts +2 -0
  59. package/dist/ui/collection_editor/templates/blog_template.d.ts +2 -0
  60. package/dist/ui/collection_editor/templates/pages_template.d.ts +2 -0
  61. package/dist/ui/collection_editor/templates/products_template.d.ts +2 -0
  62. package/dist/ui/collection_editor/templates/users_template.d.ts +2 -0
  63. package/dist/ui/collection_editor/util.d.ts +5 -0
  64. package/dist/ui/collection_editor/utils/strings.d.ts +1 -0
  65. package/dist/ui/collection_editor/utils/supported_fields.d.ts +3 -0
  66. package/dist/ui/collection_editor/utils/update_property_for_widget.d.ts +2 -0
  67. package/dist/ui/collection_editor/utils/useTraceUpdate.d.ts +1 -0
  68. package/dist/useCollectionEditorController.d.ts +6 -0
  69. package/dist/useCollectionEditorPlugin.d.ts +49 -0
  70. package/dist/useCollectionsConfigController.d.ts +6 -0
  71. package/dist/utils/arrays.d.ts +1 -0
  72. package/dist/utils/entities.d.ts +3 -0
  73. package/package.json +85 -0
  74. package/src/ConfigControllerProvider.tsx +338 -0
  75. package/src/index.ts +35 -0
  76. package/src/types/collection_editor_controller.tsx +43 -0
  77. package/src/types/collection_inference.ts +3 -0
  78. package/src/types/config_controller.tsx +60 -0
  79. package/src/types/config_permissions.ts +20 -0
  80. package/src/types/persisted_collection.ts +9 -0
  81. package/src/ui/CollectionViewHeaderAction.tsx +43 -0
  82. package/src/ui/EditorCollectionAction.tsx +109 -0
  83. package/src/ui/HomePageEditorCollectionAction.tsx +84 -0
  84. package/src/ui/MissingReferenceWidget.tsx +37 -0
  85. package/src/ui/NewCollectionButton.tsx +16 -0
  86. package/src/ui/NewCollectionCard.tsx +48 -0
  87. package/src/ui/PropertyAddColumnComponent.tsx +42 -0
  88. package/src/ui/RootCollectionSuggestions.tsx +63 -0
  89. package/src/ui/collection_editor/CollectionDetailsForm.tsx +365 -0
  90. package/src/ui/collection_editor/CollectionEditorDialog.tsx +801 -0
  91. package/src/ui/collection_editor/CollectionEditorWelcomeView.tsx +213 -0
  92. package/src/ui/collection_editor/CollectionPropertiesEditorForm.tsx +506 -0
  93. package/src/ui/collection_editor/CollectionYupValidation.tsx +7 -0
  94. package/src/ui/collection_editor/EntityCustomViewsSelectDialog.tsx +37 -0
  95. package/src/ui/collection_editor/EnumForm.tsx +357 -0
  96. package/src/ui/collection_editor/GetCodeDialog.tsx +110 -0
  97. package/src/ui/collection_editor/PropertyEditView.tsx +615 -0
  98. package/src/ui/collection_editor/PropertyFieldPreview.tsx +207 -0
  99. package/src/ui/collection_editor/PropertySelectItem.tsx +32 -0
  100. package/src/ui/collection_editor/PropertyTree.tsx +252 -0
  101. package/src/ui/collection_editor/SubcollectionsEditTab.tsx +262 -0
  102. package/src/ui/collection_editor/SwitchControl.tsx +39 -0
  103. package/src/ui/collection_editor/UnsavedChangesDialog.tsx +47 -0
  104. package/src/ui/collection_editor/import/CollectionEditorImportDataPreview.tsx +37 -0
  105. package/src/ui/collection_editor/import/CollectionEditorImportMapping.tsx +268 -0
  106. package/src/ui/collection_editor/import/clean_import_data.ts +53 -0
  107. package/src/ui/collection_editor/properties/BlockPropertyField.tsx +138 -0
  108. package/src/ui/collection_editor/properties/BooleanPropertyField.tsx +40 -0
  109. package/src/ui/collection_editor/properties/CommonPropertyFields.tsx +110 -0
  110. package/src/ui/collection_editor/properties/DateTimePropertyField.tsx +86 -0
  111. package/src/ui/collection_editor/properties/EnumPropertyField.tsx +114 -0
  112. package/src/ui/collection_editor/properties/KeyValuePropertyField.tsx +20 -0
  113. package/src/ui/collection_editor/properties/MapPropertyField.tsx +150 -0
  114. package/src/ui/collection_editor/properties/NumberPropertyField.tsx +38 -0
  115. package/src/ui/collection_editor/properties/ReferencePropertyField.tsx +160 -0
  116. package/src/ui/collection_editor/properties/RepeatPropertyField.tsx +109 -0
  117. package/src/ui/collection_editor/properties/StoragePropertyField.tsx +200 -0
  118. package/src/ui/collection_editor/properties/StringPropertyField.tsx +79 -0
  119. package/src/ui/collection_editor/properties/UrlPropertyField.tsx +89 -0
  120. package/src/ui/collection_editor/properties/advanced/AdvancedPropertyValidation.tsx +45 -0
  121. package/src/ui/collection_editor/properties/validation/ArrayPropertyValidation.tsx +50 -0
  122. package/src/ui/collection_editor/properties/validation/GeneralPropertyValidation.tsx +61 -0
  123. package/src/ui/collection_editor/properties/validation/NumberPropertyValidation.tsx +115 -0
  124. package/src/ui/collection_editor/properties/validation/StringPropertyValidation.tsx +150 -0
  125. package/src/ui/collection_editor/properties/validation/ValidationPanel.tsx +28 -0
  126. package/src/ui/collection_editor/templates/blog_template.ts +115 -0
  127. package/src/ui/collection_editor/templates/pages_template.ts +188 -0
  128. package/src/ui/collection_editor/templates/products_template.ts +88 -0
  129. package/src/ui/collection_editor/templates/users_template.ts +42 -0
  130. package/src/ui/collection_editor/util.ts +28 -0
  131. package/src/ui/collection_editor/utils/strings.ts +9 -0
  132. package/src/ui/collection_editor/utils/supported_fields.tsx +29 -0
  133. package/src/ui/collection_editor/utils/update_property_for_widget.ts +271 -0
  134. package/src/ui/collection_editor/utils/useTraceUpdate.tsx +23 -0
  135. package/src/useCollectionEditorController.tsx +9 -0
  136. package/src/useCollectionEditorPlugin.tsx +154 -0
  137. package/src/useCollectionsConfigController.tsx +9 -0
  138. package/src/utils/arrays.ts +3 -0
  139. package/src/utils/entities.ts +38 -0
  140. package/src/vite-env.d.ts +1 -0
@@ -0,0 +1,53 @@
1
+ import { Properties, slugify } from "@firecms/core";
2
+ import { ImportConfig } from "@firecms/data_import_export";
3
+
4
+ export function cleanPropertiesFromImport(properties: Properties, parentSlug = ""): {
5
+ headersMapping: ImportConfig["headersMapping"],
6
+ properties: Properties,
7
+ idColumn?: ImportConfig["idColumn"],
8
+ } {
9
+
10
+ const result = Object.keys(properties).reduce((acc, key) => {
11
+ const property = properties[key];
12
+ const slug = slugify(key);
13
+ const fullSlug = parentSlug ? `${parentSlug}.${slug}` : slug;
14
+
15
+ if (property.dataType === "map" && property.properties) {
16
+ const slugifiedResult = cleanPropertiesFromImport(property.properties as Properties, fullSlug);
17
+ return {
18
+ headersMapping: { ...acc.headersMapping, [key]: fullSlug },
19
+ properties: {
20
+ ...acc.properties,
21
+ [slug]: {
22
+ ...property,
23
+ properties: slugifiedResult.properties,
24
+ propertiesOrder: Object.keys(slugifiedResult.properties)
25
+ }
26
+ }
27
+ }
28
+ }
29
+
30
+ const updatedProperties = {
31
+ ...acc.properties,
32
+ [slug]: property
33
+ } as Properties;
34
+
35
+ const headersMapping = { ...acc.headersMapping, [key]: fullSlug } as Record<string, string>;
36
+
37
+ return {
38
+ headersMapping,
39
+ properties: updatedProperties,
40
+ }
41
+ }, { headersMapping: {}, properties: {} });
42
+
43
+ const firstKey = Object.keys(result.headersMapping)?.[0];
44
+ let idColumn: string | undefined;
45
+ if (firstKey?.includes("id") || firstKey?.includes("key")) {
46
+ idColumn = firstKey;
47
+ }
48
+
49
+ return {
50
+ ...result,
51
+ idColumn
52
+ };
53
+ }
@@ -0,0 +1,138 @@
1
+ import React, { useCallback, useState } from "react";
2
+ import { AddIcon, Button, Paper, Typography } from "@firecms/ui";
3
+ import { getIn, useFormex } from "@firecms/formex";
4
+ import { PropertyFormDialog } from "../PropertyEditView";
5
+ import { getFullId, idToPropertiesPath, namespaceToPropertiesOrderPath } from "../util";
6
+ import { PropertyTree } from "../PropertyTree";
7
+ import { ArrayProperty, Property, PropertyConfig } from "@firecms/core";
8
+
9
+ export function BlockPropertyField({ disabled, getData, allowDataInference, propertyConfigs, collectionEditable }: {
10
+ disabled: boolean;
11
+ getData?: () => Promise<object[]>;
12
+ allowDataInference: boolean;
13
+ propertyConfigs: Record<string, PropertyConfig>,
14
+ collectionEditable: boolean;
15
+ }) {
16
+
17
+ const {
18
+ values,
19
+ setFieldValue
20
+ } = useFormex<ArrayProperty>();
21
+
22
+ const [propertyDialogOpen, setPropertyDialogOpen] = useState<boolean>(false);
23
+ const [selectedPropertyKey, setSelectedPropertyKey] = useState<string | undefined>();
24
+ const [selectedPropertyNamespace, setSelectedPropertyNamespace] = useState<string | undefined>();
25
+
26
+ const onPropertyChanged = ({
27
+ id,
28
+ property
29
+ }: { id?: string, property: Property }) => {
30
+ if (!id)
31
+ throw Error();
32
+
33
+ setFieldValue("oneOf.properties", {
34
+ ...(values.oneOf?.properties ?? {}),
35
+ [id]: property
36
+ }, false);
37
+ const currentPropertiesOrder = values.oneOf?.propertiesOrder ?? Object.keys(values.oneOf?.properties ?? {});
38
+ const newPropertiesOrder = currentPropertiesOrder.includes(id) ? currentPropertiesOrder : [...currentPropertiesOrder, id];
39
+ setFieldValue("oneOf.propertiesOrder", newPropertiesOrder, false);
40
+ setPropertyDialogOpen(false);
41
+ };
42
+
43
+ const selectedPropertyFullId = selectedPropertyKey ? getFullId(selectedPropertyKey, selectedPropertyNamespace) : undefined;
44
+ const selectedProperty = selectedPropertyFullId ? getIn(values.oneOf?.properties, selectedPropertyFullId.replaceAll(".", ".properties.")) : undefined;
45
+
46
+ const deleteProperty = useCallback((propertyKey?: string, namespace?: string) => {
47
+ const fullId = propertyKey ? getFullId(propertyKey, namespace) : undefined;
48
+ if (!fullId)
49
+ throw Error("collection editor miss config");
50
+
51
+ setFieldValue(`oneOf.${idToPropertiesPath(fullId)}`, undefined, false);
52
+ const propertiesOrderPath = `oneOf.${namespaceToPropertiesOrderPath(namespace)}`;
53
+ const currentPropertiesOrder: string[] = getIn(values, propertiesOrderPath);
54
+ setFieldValue(propertiesOrderPath, currentPropertiesOrder.filter((p) => p !== propertyKey), false);
55
+
56
+ setPropertyDialogOpen(false);
57
+ setSelectedPropertyKey(undefined);
58
+ setSelectedPropertyNamespace(undefined);
59
+ }, [setFieldValue, values]);
60
+
61
+ const addChildButton = <Button
62
+ autoFocus
63
+ color="primary"
64
+
65
+ onClick={() => setPropertyDialogOpen(true)}
66
+ startIcon={<AddIcon/>}
67
+ >
68
+ Add property to {values.name ?? "this block"}
69
+ </Button>;
70
+
71
+ const onPropertyMove = useCallback((propertiesOrder: string[], namespace?: string) => {
72
+ setFieldValue(`oneOf.${namespaceToPropertiesOrderPath(namespace)}`, propertiesOrder, false);
73
+ }, []);
74
+
75
+ return (
76
+ <>
77
+ <div className={"col-span-12"}>
78
+ <div className={"flex justify-between items-end mt-8 mb-4"}>
79
+ <Typography variant={"subtitle2"}>Properties in this
80
+ block</Typography>
81
+ {addChildButton}
82
+ </div>
83
+ <Paper className="p-2 pl-8">
84
+
85
+ <PropertyTree
86
+ properties={values.oneOf?.properties ?? {}}
87
+ propertiesOrder={values.oneOf?.propertiesOrder}
88
+ errors={{}}
89
+ collectionEditable={collectionEditable}
90
+ onPropertyClick={disabled
91
+ ? undefined
92
+ : (propertyKey, namespace) => {
93
+ setSelectedPropertyKey(propertyKey);
94
+ setSelectedPropertyNamespace(namespace);
95
+ setPropertyDialogOpen(true);
96
+ }}
97
+ onPropertyMove={disabled
98
+ ? undefined
99
+ : onPropertyMove}/>
100
+
101
+ {!disabled && !values.oneOf?.propertiesOrder?.length &&
102
+ <div className="h-full flex items-center justify-center p-4">
103
+ Add the first property to this block
104
+ </div>}
105
+
106
+ </Paper>
107
+ </div>
108
+
109
+ {!disabled && <PropertyFormDialog
110
+ inArray={false}
111
+ forceShowErrors={false}
112
+ open={propertyDialogOpen}
113
+ getData={getData}
114
+ allowDataInference={allowDataInference}
115
+ onCancel={() => {
116
+ setPropertyDialogOpen(false);
117
+ setSelectedPropertyKey(undefined);
118
+ setSelectedPropertyNamespace(undefined);
119
+ }}
120
+ onOkClicked={() => {
121
+ setPropertyDialogOpen(false);
122
+ setSelectedPropertyKey(undefined);
123
+ setSelectedPropertyNamespace(undefined);
124
+ }}
125
+ collectionEditable={collectionEditable}
126
+ onDelete={deleteProperty}
127
+ propertyKey={selectedPropertyKey}
128
+ propertyNamespace={selectedPropertyNamespace}
129
+ property={selectedProperty}
130
+ existingProperty={Boolean(selectedPropertyKey)}
131
+ autoUpdateId={!selectedPropertyKey}
132
+ autoOpenTypeSelect={!selectedPropertyKey}
133
+ onPropertyChanged={onPropertyChanged}
134
+ existingPropertyKeys={selectedPropertyKey ? undefined : values.oneOf?.propertiesOrder}
135
+ propertyConfigs={propertyConfigs}/>}
136
+
137
+ </>);
138
+ }
@@ -0,0 +1,40 @@
1
+ import React from "react";
2
+ import { Field, FormexFieldProps, getIn, useFormex } from "@firecms/formex";
3
+
4
+ import { GeneralPropertyValidation } from "./validation/GeneralPropertyValidation";
5
+ import { ValidationPanel } from "./validation/ValidationPanel";
6
+ import { SwitchControl } from "../SwitchControl";
7
+
8
+ export function BooleanPropertyField({ disabled }: {
9
+ disabled: boolean;
10
+ }) {
11
+ const { values } = useFormex();
12
+ const defaultValue = getIn(values, "defaultValue");
13
+
14
+ return (
15
+ <>
16
+ <div className={"col-span-12"}>
17
+
18
+ <ValidationPanel>
19
+ <GeneralPropertyValidation disabled={disabled}/>
20
+ </ValidationPanel>
21
+
22
+ </div>
23
+
24
+ <div className={"col-span-12"}>
25
+
26
+ <Field
27
+ name={"defaultValue"}>
28
+ {({ field, form }: FormexFieldProps) => {
29
+ return <SwitchControl
30
+ label={defaultValue === null || defaultValue === undefined ? "Default value not set" : ("Default value is " + defaultValue.toString())}
31
+ disabled={disabled}
32
+ allowIndeterminate={true} field={field}
33
+ form={form}/>
34
+ }}
35
+ </Field>
36
+
37
+ </div>
38
+ </>
39
+ );
40
+ }
@@ -0,0 +1,110 @@
1
+ import { Field, getIn, useFormex } from "@firecms/formex";
2
+ import { DebouncedTextField } from "@firecms/ui";
3
+ import { PropertyWithId } from "../PropertyEditView";
4
+ import React from "react";
5
+ import { FieldCaption, toSnakeCase, unslugify } from "@firecms/core";
6
+
7
+ type CommonPropertyFieldsProps = {
8
+ showErrors: boolean,
9
+ disabledId: boolean,
10
+ disabled: boolean;
11
+ isNewProperty: boolean;
12
+ autoUpdateId: boolean;
13
+ };
14
+
15
+ export const CommonPropertyFields = React.forwardRef<HTMLDivElement, CommonPropertyFieldsProps>(
16
+ function CommonPropertyFields({
17
+ showErrors,
18
+ disabledId,
19
+ disabled,
20
+ autoUpdateId,
21
+ isNewProperty
22
+ }, ref) {
23
+
24
+ const {
25
+ errors,
26
+ values,
27
+ setFieldValue,
28
+ setFieldTouched,
29
+ touched,
30
+ validate
31
+ } = useFormex<PropertyWithId>();
32
+
33
+ const name = "name";
34
+ const nameError = showErrors && getIn(errors, name);
35
+
36
+ const id = "id";
37
+ const idError = showErrors && getIn(errors, id);
38
+
39
+ const description = "description";
40
+ const descriptionError = showErrors && getIn(errors, description);
41
+
42
+ return (
43
+ <div className={"flex flex-col gap-2 col-span-12"}>
44
+
45
+ <div>
46
+ <Field
47
+ name={name}
48
+ inputRef={ref}
49
+ as={DebouncedTextField}
50
+ value={values[name]}
51
+ onChange={(e: any) => {
52
+ const newNameValue = e.target.value;
53
+ const idTouched = getIn(touched, id);
54
+ if (!idTouched && autoUpdateId) {
55
+ setFieldValue(id, newNameValue ? toSnakeCase(newNameValue) : "", false)
56
+ }
57
+ setFieldValue(name, newNameValue, true);
58
+ setFieldTouched(name, true);
59
+ }}
60
+ style={{ fontSize: 20 }}
61
+ placeholder={"Field name"}
62
+ required
63
+ disabled={disabled}
64
+ error={Boolean(nameError)}/>
65
+
66
+ <FieldCaption error={Boolean(nameError)}>
67
+ {nameError}
68
+ </FieldCaption>
69
+ </div>
70
+
71
+ <div>
72
+ <Field
73
+ name={id}
74
+ as={DebouncedTextField}
75
+ label={"ID"}
76
+ value={values[id]}
77
+ onChange={(e: any) => {
78
+ const newIdValue = e.target.value;
79
+ const nameTouched = getIn(touched, name);
80
+ if (!nameTouched && autoUpdateId) {
81
+ setFieldValue(name, newIdValue ? unslugify(newIdValue) : "")
82
+ }
83
+ setFieldValue(id, newIdValue, true);
84
+ setFieldTouched(id, true);
85
+ }}
86
+ disabled={disabledId || disabled}
87
+ required
88
+ size="small"
89
+ error={Boolean(idError)}/>
90
+ <FieldCaption error={Boolean(idError)}>
91
+ {idError}
92
+ </FieldCaption>
93
+ </div>
94
+
95
+ <div>
96
+ <Field name={description}
97
+ as={DebouncedTextField}
98
+ label={"Description"}
99
+ disabled={disabled}
100
+ error={Boolean(descriptionError)}/>
101
+ <FieldCaption error={Boolean(descriptionError)}>
102
+ {descriptionError}
103
+ </FieldCaption>
104
+ </div>
105
+
106
+ </div>
107
+ );
108
+
109
+ }
110
+ );
@@ -0,0 +1,86 @@
1
+ import React from "react";
2
+ import { getIn, useFormex } from "@firecms/formex";
3
+ import { FieldCaption, NumberProperty, StringProperty } from "@firecms/core";
4
+ import { Select, SelectItem } from "@firecms/ui";
5
+ import { GeneralPropertyValidation } from "./validation/GeneralPropertyValidation";
6
+ import { ValidationPanel } from "./validation/ValidationPanel";
7
+
8
+ export function DateTimePropertyField({ disabled }: {
9
+ disabled: boolean;
10
+ }) {
11
+
12
+ const {
13
+ values,
14
+ errors,
15
+ touched,
16
+ setFieldValue
17
+ } = useFormex<StringProperty | NumberProperty>();
18
+
19
+ const modePath = "mode";
20
+ const modeValue: string | undefined = getIn(values, modePath);
21
+ const modeError: string | undefined = getIn(touched, modePath) && getIn(errors, modePath);
22
+
23
+ const autoValuePath = "autoValue";
24
+ const autoValueValue: string | undefined = getIn(values, autoValuePath);
25
+ const autoValueError: string | undefined = getIn(touched, autoValuePath) && getIn(errors, autoValuePath);
26
+
27
+ return (
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>
76
+
77
+ </div>
78
+
79
+ <div className={"col-span-12"}>
80
+ <ValidationPanel>
81
+ <GeneralPropertyValidation disabled={disabled}/>
82
+ </ValidationPanel>
83
+ </div>
84
+ </>
85
+ );
86
+ }
@@ -0,0 +1,114 @@
1
+ import React, { useMemo } from "react";
2
+ import { getIn, useFormex } from "@firecms/formex";
3
+ import { EnumValueConfig, resolveEnumValues, useSnackbarController } from "@firecms/core";
4
+ import { Select, SelectItem } from "@firecms/ui";
5
+ import { EnumForm } from "../EnumForm";
6
+ import { StringPropertyValidation } from "./validation/StringPropertyValidation";
7
+ import { ArrayPropertyValidation } from "./validation/ArrayPropertyValidation";
8
+ import { ValidationPanel } from "./validation/ValidationPanel";
9
+ import { PropertyWithId } from "../PropertyEditView";
10
+
11
+ export function EnumPropertyField({
12
+ multiselect,
13
+ updateIds,
14
+ disabled,
15
+ showErrors,
16
+ allowDataInference,
17
+ getData
18
+ }: {
19
+ multiselect: boolean;
20
+ updateIds: boolean;
21
+ disabled: boolean;
22
+ showErrors: boolean;
23
+ allowDataInference?: boolean;
24
+ getData?: () => Promise<object[]>;
25
+ }) {
26
+
27
+ const {
28
+ values,
29
+ setFieldError,
30
+ setFieldValue
31
+ } = useFormex<PropertyWithId>();
32
+
33
+ const snackbarContext = useSnackbarController();
34
+
35
+ const enumValuesPath = multiselect ? "of.enumValues" : "enumValues";
36
+
37
+ const defaultValue = getIn(values, "defaultValue");
38
+
39
+ const valuesEnumValues = getIn(values, enumValuesPath);
40
+ const enumValues: EnumValueConfig[] = useMemo(() => {
41
+ if (!valuesEnumValues || typeof valuesEnumValues === "boolean")
42
+ return [] as EnumValueConfig[];
43
+ return resolveEnumValues(valuesEnumValues) ?? [] as EnumValueConfig[];
44
+ }, [valuesEnumValues]);
45
+
46
+ const onValuesChanged = (value: EnumValueConfig[]) => {
47
+ if (!values)
48
+ return;
49
+ setFieldValue(enumValuesPath, value);
50
+ if (!multiselect) {
51
+ const enumIds = value.filter(v => Boolean(v?.id)).map((v: any) => v.id);
52
+ if (defaultValue && !enumIds.includes(defaultValue)) {
53
+ setFieldValue("defaultValue", undefined);
54
+ snackbarContext.open({
55
+ type: "warning",
56
+ message: "Default value was cleared"
57
+ })
58
+ }
59
+ }
60
+ };
61
+
62
+ return (
63
+ <>
64
+ <div className={"col-span-12"}>
65
+ <EnumForm enumValues={enumValues}
66
+ updateIds={updateIds}
67
+ disabled={disabled}
68
+ allowDataInference={allowDataInference}
69
+ onError={(hasError) => {
70
+ setFieldError(enumValuesPath, hasError ? "This enum property is missing some values" : undefined);
71
+ }}
72
+ getData={getData
73
+ ? () => getData()
74
+ .then(res => res.map(d => values.id && getIn(d, values.id)).filter(Boolean))
75
+ : undefined}
76
+ onValuesChanged={onValuesChanged}/>
77
+ </div>
78
+
79
+ <div className={"col-span-12"}>
80
+
81
+ <ValidationPanel>
82
+ {!multiselect &&
83
+ <StringPropertyValidation disabled={disabled}
84
+ showErrors={showErrors}/>}
85
+ {multiselect &&
86
+ <ArrayPropertyValidation disabled={disabled}/>}
87
+ </ValidationPanel>
88
+
89
+ </div>
90
+
91
+ {!multiselect && <div className={"col-span-12"}>
92
+
93
+ <Select
94
+ disabled={disabled}
95
+ position={"item-aligned"}
96
+ onValueChange={(value: string) => {
97
+ setFieldValue("defaultValue", value);
98
+ }}
99
+ label={"Default value"}
100
+ value={defaultValue ?? ""}>
101
+ {enumValues
102
+ .filter((enumValue) => Boolean(enumValue?.id))
103
+ .map((enumValue) => (
104
+ <SelectItem key={enumValue.id}
105
+ value={enumValue.id?.toString()}>
106
+ {enumValue.label}
107
+ </SelectItem>
108
+ ))}
109
+ </Select>
110
+
111
+ </div>}
112
+ </>
113
+ );
114
+ }
@@ -0,0 +1,20 @@
1
+ import React from "react";
2
+ import { ValidationPanel } from "./validation/ValidationPanel";
3
+ import { GeneralPropertyValidation } from "./validation/GeneralPropertyValidation";
4
+
5
+ export function KeyValuePropertyField({ disabled }: {
6
+ disabled: boolean;
7
+ }) {
8
+
9
+ return (
10
+ <>
11
+ <div className={"col-span-12"}>
12
+
13
+ <ValidationPanel>
14
+ <GeneralPropertyValidation disabled={disabled}/>
15
+ </ValidationPanel>
16
+
17
+ </div>
18
+ </>
19
+ );
20
+ }