@firecms/collection_editor 3.0.0-alpha.5 → 3.0.0-alpha.50

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/dist/ConfigControllerProvider.d.ts +36 -0
  2. package/dist/index.d.ts +11 -0
  3. package/dist/index.es.js +6998 -0
  4. package/dist/index.es.js.map +1 -0
  5. package/dist/index.umd.js +4 -0
  6. package/dist/index.umd.js.map +1 -0
  7. package/dist/types/collection_editor_controller.d.ts +35 -0
  8. package/dist/types/collection_inference.d.ts +2 -0
  9. package/dist/types/config_controller.d.ts +41 -0
  10. package/dist/types/config_permissions.d.ts +19 -0
  11. package/dist/types/persisted_collection.d.ts +6 -0
  12. package/dist/ui/CollectionViewHeaderAction.d.ts +10 -0
  13. package/dist/ui/EditorCollectionAction.d.ts +2 -0
  14. package/dist/ui/HomePageEditorCollectionAction.d.ts +2 -0
  15. package/dist/ui/MissingReferenceWidget.d.ts +3 -0
  16. package/dist/ui/NewCollectionCard.d.ts +2 -0
  17. package/dist/ui/PropertyAddColumnComponent.d.ts +6 -0
  18. package/dist/ui/RootCollectionSuggestions.d.ts +1 -0
  19. package/dist/ui/collection_editor/CollectionDetailsForm.d.ts +9 -0
  20. package/dist/ui/collection_editor/CollectionEditorDialog.d.ts +38 -0
  21. package/dist/ui/collection_editor/CollectionEditorWelcomeView.d.ts +15 -0
  22. package/dist/ui/collection_editor/CollectionPropertiesEditorForm.d.ts +20 -0
  23. package/dist/ui/collection_editor/CollectionYupValidation.d.ts +14 -0
  24. package/dist/ui/collection_editor/EntityCustomViewsSelectDialog.d.ts +4 -0
  25. package/dist/ui/collection_editor/EnumForm.d.ts +13 -0
  26. package/dist/ui/collection_editor/GetCodeDialog.d.ts +5 -0
  27. package/dist/ui/collection_editor/PropertyEditView.d.ts +40 -0
  28. package/dist/ui/collection_editor/PropertyFieldPreview.d.ts +15 -0
  29. package/dist/ui/collection_editor/PropertySelectItem.d.ts +8 -0
  30. package/dist/ui/collection_editor/PropertyTree.d.ts +32 -0
  31. package/dist/ui/collection_editor/SelectIcons.d.ts +6 -0
  32. package/dist/ui/collection_editor/SubcollectionsEditTab.d.ts +12 -0
  33. package/dist/ui/collection_editor/UnsavedChangesDialog.d.ts +9 -0
  34. package/dist/ui/collection_editor/import/CollectionEditorImportDataPreview.d.ts +7 -0
  35. package/dist/ui/collection_editor/import/CollectionEditorImportMapping.d.ts +7 -0
  36. package/dist/ui/collection_editor/import/clean_import_data.d.ts +7 -0
  37. package/dist/ui/collection_editor/properties/BlockPropertyField.d.ts +8 -0
  38. package/dist/ui/collection_editor/properties/BooleanPropertyField.d.ts +3 -0
  39. package/dist/ui/collection_editor/properties/CommonPropertyFields.d.ts +10 -0
  40. package/dist/ui/collection_editor/properties/DateTimePropertyField.d.ts +3 -0
  41. package/dist/ui/collection_editor/properties/EnumPropertyField.d.ts +8 -0
  42. package/dist/ui/collection_editor/properties/FieldHelperView.d.ts +4 -0
  43. package/dist/ui/collection_editor/properties/KeyValuePropertyField.d.ts +3 -0
  44. package/dist/ui/collection_editor/properties/MapPropertyField.d.ts +8 -0
  45. package/dist/ui/collection_editor/properties/NumberPropertyField.d.ts +3 -0
  46. package/dist/ui/collection_editor/properties/ReferencePropertyField.d.ts +13 -0
  47. package/dist/ui/collection_editor/properties/RepeatPropertyField.d.ts +10 -0
  48. package/dist/ui/collection_editor/properties/StoragePropertyField.d.ts +5 -0
  49. package/dist/ui/collection_editor/properties/StringPropertyField.d.ts +5 -0
  50. package/dist/ui/collection_editor/properties/UrlPropertyField.d.ts +4 -0
  51. package/dist/ui/collection_editor/properties/advanced/AdvancedPropertyValidation.d.ts +3 -0
  52. package/dist/ui/collection_editor/properties/validation/ArrayPropertyValidation.d.ts +5 -0
  53. package/dist/ui/collection_editor/properties/validation/GeneralPropertyValidation.d.ts +4 -0
  54. package/dist/ui/collection_editor/properties/validation/NumberPropertyValidation.d.ts +3 -0
  55. package/dist/ui/collection_editor/properties/validation/StringPropertyValidation.d.ts +11 -0
  56. package/dist/ui/collection_editor/properties/validation/ValidationPanel.d.ts +2 -0
  57. package/dist/ui/collection_editor/templates/blog_template.d.ts +2 -0
  58. package/dist/ui/collection_editor/templates/products_template.d.ts +2 -0
  59. package/dist/ui/collection_editor/templates/users_template.d.ts +2 -0
  60. package/dist/ui/collection_editor/util.d.ts +4 -0
  61. package/dist/ui/collection_editor/utils/strings.d.ts +1 -0
  62. package/dist/ui/collection_editor/utils/supported_fields.d.ts +3 -0
  63. package/dist/ui/collection_editor/utils/update_property_for_widget.d.ts +2 -0
  64. package/dist/ui/collection_editor/utils/useTraceUpdate.d.ts +1 -0
  65. package/dist/useCollectionEditorController.d.ts +6 -0
  66. package/dist/useCollectionEditorPlugin.d.ts +45 -0
  67. package/dist/useCollectionsConfigController.d.ts +6 -0
  68. package/dist/utils/arrays.d.ts +1 -0
  69. package/dist/utils/entities.d.ts +3 -0
  70. package/dist/utils/icons.d.ts +1 -0
  71. package/dist/utils/synonyms.d.ts +1951 -0
  72. package/package.json +26 -23
  73. package/src/ConfigControllerProvider.tsx +321 -0
  74. package/src/index.ts +35 -0
  75. package/src/types/collection_editor_controller.tsx +42 -0
  76. package/src/types/collection_inference.ts +3 -0
  77. package/src/types/config_controller.tsx +50 -0
  78. package/src/types/config_permissions.ts +20 -0
  79. package/src/types/persisted_collection.ts +9 -0
  80. package/src/ui/CollectionViewHeaderAction.tsx +42 -0
  81. package/src/ui/EditorCollectionAction.tsx +95 -0
  82. package/src/ui/HomePageEditorCollectionAction.tsx +88 -0
  83. package/src/ui/MissingReferenceWidget.tsx +34 -0
  84. package/src/ui/NewCollectionCard.tsx +46 -0
  85. package/src/ui/PropertyAddColumnComponent.tsx +41 -0
  86. package/src/ui/RootCollectionSuggestions.tsx +62 -0
  87. package/src/ui/collection_editor/CollectionDetailsForm.tsx +353 -0
  88. package/src/ui/collection_editor/CollectionEditorDialog.tsx +744 -0
  89. package/src/ui/collection_editor/CollectionEditorWelcomeView.tsx +212 -0
  90. package/src/ui/collection_editor/CollectionPropertiesEditorForm.tsx +480 -0
  91. package/src/ui/collection_editor/CollectionYupValidation.tsx +7 -0
  92. package/src/ui/collection_editor/EntityCustomViewsSelectDialog.tsx +36 -0
  93. package/src/ui/collection_editor/EnumForm.tsx +356 -0
  94. package/src/ui/collection_editor/GetCodeDialog.tsx +118 -0
  95. package/src/ui/collection_editor/PropertyEditView.tsx +564 -0
  96. package/src/ui/collection_editor/PropertyFieldPreview.tsx +201 -0
  97. package/src/ui/collection_editor/PropertySelectItem.tsx +31 -0
  98. package/src/ui/collection_editor/PropertyTree.tsx +238 -0
  99. package/src/ui/collection_editor/SelectIcons.tsx +72 -0
  100. package/src/ui/collection_editor/SubcollectionsEditTab.tsx +252 -0
  101. package/src/ui/collection_editor/UnsavedChangesDialog.tsx +47 -0
  102. package/src/ui/collection_editor/import/CollectionEditorImportDataPreview.tsx +37 -0
  103. package/src/ui/collection_editor/import/CollectionEditorImportMapping.tsx +275 -0
  104. package/src/ui/collection_editor/import/clean_import_data.ts +53 -0
  105. package/src/ui/collection_editor/properties/BlockPropertyField.tsx +134 -0
  106. package/src/ui/collection_editor/properties/BooleanPropertyField.tsx +36 -0
  107. package/src/ui/collection_editor/properties/CommonPropertyFields.tsx +111 -0
  108. package/src/ui/collection_editor/properties/DateTimePropertyField.tsx +86 -0
  109. package/src/ui/collection_editor/properties/EnumPropertyField.tsx +116 -0
  110. package/src/ui/collection_editor/properties/FieldHelperView.tsx +13 -0
  111. package/src/ui/collection_editor/properties/KeyValuePropertyField.tsx +20 -0
  112. package/src/ui/collection_editor/properties/MapPropertyField.tsx +157 -0
  113. package/src/ui/collection_editor/properties/NumberPropertyField.tsx +38 -0
  114. package/src/ui/collection_editor/properties/ReferencePropertyField.tsx +184 -0
  115. package/src/ui/collection_editor/properties/RepeatPropertyField.tsx +107 -0
  116. package/src/ui/collection_editor/properties/StoragePropertyField.tsx +194 -0
  117. package/src/ui/collection_editor/properties/StringPropertyField.tsx +79 -0
  118. package/src/ui/collection_editor/properties/UrlPropertyField.tsx +89 -0
  119. package/src/ui/collection_editor/properties/advanced/AdvancedPropertyValidation.tsx +36 -0
  120. package/src/ui/collection_editor/properties/validation/ArrayPropertyValidation.tsx +50 -0
  121. package/src/ui/collection_editor/properties/validation/GeneralPropertyValidation.tsx +49 -0
  122. package/src/ui/collection_editor/properties/validation/NumberPropertyValidation.tsx +99 -0
  123. package/src/ui/collection_editor/properties/validation/StringPropertyValidation.tsx +131 -0
  124. package/src/ui/collection_editor/properties/validation/ValidationPanel.tsx +28 -0
  125. package/src/ui/collection_editor/templates/blog_template.ts +115 -0
  126. package/src/ui/collection_editor/templates/products_template.ts +88 -0
  127. package/src/ui/collection_editor/templates/users_template.ts +34 -0
  128. package/src/ui/collection_editor/util.ts +21 -0
  129. package/src/ui/collection_editor/utils/strings.ts +8 -0
  130. package/src/ui/collection_editor/utils/supported_fields.tsx +28 -0
  131. package/src/ui/collection_editor/utils/update_property_for_widget.ts +271 -0
  132. package/src/ui/collection_editor/utils/useTraceUpdate.tsx +23 -0
  133. package/src/useCollectionEditorController.tsx +9 -0
  134. package/src/useCollectionEditorPlugin.tsx +128 -0
  135. package/src/useCollectionsConfigController.tsx +9 -0
  136. package/src/utils/arrays.ts +3 -0
  137. package/src/utils/entities.ts +38 -0
  138. package/src/utils/icons.ts +17 -0
  139. package/src/utils/synonyms.ts +1952 -0
  140. package/src/vite-env.d.ts +1 -0
@@ -0,0 +1,88 @@
1
+ import { EntityCollection, makePropertiesEditable } from "@firecms/core";
2
+
3
+ export const productsCollectionTemplate: EntityCollection = {
4
+ id: "products",
5
+ path: "products",
6
+ name: "Products",
7
+ singularName: "Product",
8
+ icon: "shopping_cart",
9
+ description: "List of the products currently sold in your shop",
10
+ properties: makePropertiesEditable({
11
+ name: {
12
+ dataType: "string",
13
+ name: "Name",
14
+ description: "Name of this product",
15
+ validation: {
16
+ required: true
17
+ }
18
+ },
19
+ brand: {
20
+ dataType: "string",
21
+ name: "Brand",
22
+ validation: {
23
+ required: true
24
+ }
25
+ },
26
+ description: {
27
+ dataType: "string",
28
+ name: "Description",
29
+ description: "Description of this product, supports markdown",
30
+ markdown: true
31
+ },
32
+ main_image: {
33
+ dataType: "string",
34
+ name: "Image",
35
+ storage: {
36
+ storagePath: "images",
37
+ acceptedFiles: ["image/*"],
38
+ },
39
+ description: "Upload field for images"
40
+ },
41
+ available: {
42
+ dataType: "boolean",
43
+ name: "Available",
44
+ columnWidth: 100,
45
+ description: "Is this product available in the website"
46
+ },
47
+ price: {
48
+ dataType: "number",
49
+ name: "Price",
50
+ validation: {
51
+ requiredMessage: "You must set a positive price",
52
+ min: 0
53
+ }
54
+ },
55
+ images: {
56
+ dataType: "array",
57
+ name: "Images",
58
+ hideFromCollection: true,
59
+ of: {
60
+ dataType: "string",
61
+ storage: {
62
+ storagePath: "images",
63
+ acceptedFiles: ["image/*"]
64
+ }
65
+ }
66
+ },
67
+ related_products: {
68
+ dataType: "array",
69
+ name: "Related products",
70
+ description: "Products related to this one",
71
+ of: {
72
+ dataType: "reference",
73
+ path: "products"
74
+ }
75
+ },
76
+ metadata: {
77
+ name: "Metadata",
78
+ description: "This is an example of a map property",
79
+ dataType: "map",
80
+ keyValue: true
81
+ },
82
+ added_on: {
83
+ dataType: "date",
84
+ name: "Added on",
85
+ autoValue: "on_create"
86
+ }
87
+ })
88
+ };
@@ -0,0 +1,34 @@
1
+ import { EntityCollection, makePropertiesEditable } from "@firecms/core";
2
+
3
+ export const usersCollectionTemplate: EntityCollection = {
4
+ id: "users",
5
+ path: "users",
6
+ name: "Users",
7
+ singularName: "User",
8
+ description: "Registered users in the app/web",
9
+ icon: "person",
10
+ properties: makePropertiesEditable({
11
+ displayName: {
12
+ name: "Display name",
13
+ dataType: "string"
14
+ },
15
+ email: {
16
+ name: "Email",
17
+ dataType: "string",
18
+ email: true
19
+ },
20
+ emailVerified: {
21
+ name: "Email verified",
22
+ dataType: "boolean"
23
+ },
24
+ phone: {
25
+ name: "Phone",
26
+ dataType: "string"
27
+ },
28
+ photoURL: {
29
+ name: "Photo URL",
30
+ dataType: "string",
31
+ url: "image"
32
+ }
33
+ }),
34
+ };
@@ -0,0 +1,21 @@
1
+ export function idToPropertiesPath(id: string): string {
2
+ return "properties." + id.replaceAll(".", ".properties.");
3
+ }
4
+
5
+ export function namespaceToPropertiesPath(namespace?: string): string {
6
+ return namespace
7
+ ? "properties." + namespace.replaceAll(".", ".properties.") + ".properties"
8
+ : "properties";
9
+ }
10
+
11
+ export function namespaceToPropertiesOrderPath(namespace?: string): string {
12
+ return namespace
13
+ ? "properties." + namespace.replaceAll(".", ".properties.") + ".propertiesOrder"
14
+ : "propertiesOrder";
15
+ }
16
+
17
+ export function getFullId(propertyKey: string, propertyNamespace?: string): string {
18
+ return propertyNamespace
19
+ ? `${propertyNamespace}.${propertyKey}`
20
+ : propertyKey;
21
+ }
@@ -0,0 +1,8 @@
1
+ export function camelCase(str: string): string {
2
+ return (str.slice(0, 1).toLowerCase() + str.slice(1))
3
+ .replace(/([-_ ]){1,}/g, ' ')
4
+ .split(/[-_ ]/)
5
+ .reduce((cur, acc) => {
6
+ return cur + acc[0].toUpperCase() + acc.substring(1);
7
+ });
8
+ }
@@ -0,0 +1,28 @@
1
+ import { DEFAULT_FIELD_CONFIGS, FieldConfigId } from "@firecms/core";
2
+
3
+ export const supportedFieldsIds: FieldConfigId[] = [
4
+ "text_field",
5
+ "multiline",
6
+ "markdown",
7
+ "url",
8
+ "email",
9
+ "select",
10
+ "multi_select",
11
+ "number_input",
12
+ "number_select",
13
+ "multi_number_select",
14
+ "file_upload",
15
+ "multi_file_upload",
16
+ "group",
17
+ "key_value",
18
+ "reference",
19
+ "multi_references",
20
+ "switch",
21
+ "date_time",
22
+ "repeat",
23
+ "block"
24
+ ];
25
+
26
+ export const supportedFields = Object.entries(DEFAULT_FIELD_CONFIGS).filter(([id]) =>
27
+ supportedFieldsIds.includes(id as FieldConfigId)
28
+ );
@@ -0,0 +1,271 @@
1
+ import {
2
+ ArrayProperty,
3
+ BooleanProperty,
4
+ DateProperty,
5
+ MapProperty,
6
+ mergeDeep,
7
+ NumberProperty,
8
+ Property,
9
+ PropertyConfig,
10
+ StringProperty
11
+ } from "@firecms/core";
12
+
13
+ export function updatePropertyFromWidget(propertyData: any,
14
+ selectedWidgetId: string | undefined,
15
+ propertyConfigs: Record<string, PropertyConfig>): Property {
16
+
17
+ let updatedProperty;
18
+ if (selectedWidgetId === "text_field") {
19
+ updatedProperty = mergeDeep(
20
+ propertyData,
21
+ {
22
+ dataType: "string",
23
+ propertyConfig: "text_field",
24
+ editable: propertyData.editable !== undefined ? propertyData.editable : true,
25
+ storage: undefined,
26
+ multiline: undefined,
27
+ markdown: undefined,
28
+ email: undefined,
29
+ url: undefined,
30
+ enumValues: undefined
31
+ } satisfies StringProperty
32
+ );
33
+ } else if (selectedWidgetId === "multiline") {
34
+ updatedProperty = mergeDeep(
35
+ propertyData,
36
+ {
37
+ dataType: "string",
38
+ propertyConfig: "multiline",
39
+ editable: propertyData.editable !== undefined ? propertyData.editable : true,
40
+ multiline: true,
41
+ storage: undefined,
42
+ markdown: undefined,
43
+ email: undefined,
44
+ url: undefined,
45
+ enumValues: undefined
46
+ } satisfies StringProperty
47
+ );
48
+ } else if (selectedWidgetId === "markdown") {
49
+ updatedProperty = mergeDeep(
50
+ propertyData,
51
+ {
52
+ dataType: "string",
53
+ propertyConfig: "markdown",
54
+ editable: propertyData.editable !== undefined ? propertyData.editable : true,
55
+ storage: undefined,
56
+ multiline: undefined,
57
+ markdown: true,
58
+ email: undefined,
59
+ url: undefined
60
+ } satisfies StringProperty
61
+ );
62
+ } else if (selectedWidgetId === "url") {
63
+ updatedProperty = mergeDeep(
64
+ propertyData,
65
+ {
66
+ dataType: "string",
67
+ propertyConfig: "url",
68
+ editable: propertyData.editable !== undefined ? propertyData.editable : true,
69
+ storage: undefined,
70
+ multiline: undefined,
71
+ markdown: undefined,
72
+ email: undefined,
73
+ url: true,
74
+ enumValues: undefined
75
+ } satisfies StringProperty
76
+ );
77
+ } else if (selectedWidgetId === "email") {
78
+ updatedProperty = mergeDeep(
79
+ propertyData,
80
+ {
81
+ dataType: "string",
82
+ propertyConfig: "email",
83
+ editable: propertyData.editable !== undefined ? propertyData.editable : true,
84
+ storage: undefined,
85
+ multiline: undefined,
86
+ markdown: undefined,
87
+ email: true,
88
+ url: undefined,
89
+ enumValues: undefined
90
+ } satisfies StringProperty
91
+ );
92
+ } else if (selectedWidgetId === "select") {
93
+ updatedProperty = mergeDeep(
94
+ propertyData,
95
+ {
96
+ dataType: "string",
97
+ propertyConfig: "select",
98
+ editable: propertyData.editable !== undefined ? propertyData.editable : true,
99
+ storage: undefined,
100
+ multiline: undefined,
101
+ markdown: undefined,
102
+ email: undefined,
103
+ url: undefined,
104
+ enumValues: propertyData.enumValues ?? []
105
+ } satisfies StringProperty
106
+ );
107
+ } else if (selectedWidgetId === "multi_select") {
108
+ updatedProperty = mergeDeep(
109
+ propertyData,
110
+ {
111
+ dataType: "array",
112
+ propertyConfig: "multi_select",
113
+ editable: propertyData.editable !== undefined ? propertyData.editable : true,
114
+ of: {
115
+ dataType: "string",
116
+ enumValues: propertyData.of?.enumValues ?? []
117
+ }
118
+ } satisfies ArrayProperty
119
+ );
120
+ } else if (selectedWidgetId === "number_input") {
121
+ updatedProperty = mergeDeep(
122
+ propertyData,
123
+ {
124
+ dataType: "number",
125
+ propertyConfig: "number_input",
126
+ editable: propertyData.editable !== undefined ? propertyData.editable : true,
127
+ enumValues: undefined
128
+ } satisfies NumberProperty
129
+ );
130
+ } else if (selectedWidgetId === "number_select") {
131
+ updatedProperty = mergeDeep(
132
+ propertyData,
133
+ {
134
+ dataType: "number",
135
+ propertyConfig: "number_select",
136
+ editable: propertyData.editable !== undefined ? propertyData.editable : true,
137
+ enumValues: propertyData.enumValues ?? []
138
+ } satisfies NumberProperty
139
+ );
140
+ } else if (selectedWidgetId === "multi_number_select") {
141
+ updatedProperty = mergeDeep(
142
+ propertyData,
143
+ {
144
+ dataType: "array",
145
+ propertyConfig: "multi_number_select",
146
+ editable: propertyData.editable !== undefined ? propertyData.editable : true,
147
+ of: {
148
+ dataType: "number",
149
+ enumValues: propertyData.of?.enumValues ?? []
150
+ }
151
+ } satisfies ArrayProperty
152
+ );
153
+ } else if (selectedWidgetId === "file_upload") {
154
+ updatedProperty = mergeDeep(
155
+ propertyData,
156
+ {
157
+ dataType: "string",
158
+ propertyConfig: "file_upload",
159
+ editable: propertyData.editable !== undefined ? propertyData.editable : true,
160
+ storage: {
161
+ storagePath: "/"
162
+ }
163
+ } satisfies StringProperty
164
+ );
165
+ } else if (selectedWidgetId === "multi_file_upload") {
166
+ updatedProperty = mergeDeep(
167
+ propertyData,
168
+ {
169
+ dataType: "array",
170
+ propertyConfig: "multi_file_upload",
171
+ editable: propertyData.editable !== undefined ? propertyData.editable : true,
172
+ of: {
173
+ dataType: "string",
174
+ storage: propertyData.of?.storage ?? {
175
+ storagePath: "/"
176
+ }
177
+ }
178
+ } satisfies ArrayProperty
179
+ );
180
+ } else if (selectedWidgetId === "group") {
181
+ updatedProperty = mergeDeep(
182
+ propertyData,
183
+ {
184
+ dataType: "map",
185
+ propertyConfig: "group",
186
+ editable: propertyData.editable !== undefined ? propertyData.editable : true,
187
+ keyValue: false,
188
+ properties: propertyData.properties ?? {}
189
+ } satisfies MapProperty
190
+ );
191
+ } else if (selectedWidgetId === "key_value") {
192
+ updatedProperty = mergeDeep(
193
+ propertyData,
194
+ {
195
+ dataType: "map",
196
+ propertyConfig: "key_value",
197
+ editable: propertyData.editable !== undefined ? propertyData.editable : true,
198
+ keyValue: true,
199
+ properties: undefined
200
+ } satisfies MapProperty
201
+ );
202
+ } else if (selectedWidgetId === "reference") {
203
+ updatedProperty = mergeDeep(
204
+ propertyData,
205
+ {
206
+ dataType: "reference",
207
+ propertyConfig: "reference",
208
+ editable: propertyData.editable !== undefined ? propertyData.editable : true
209
+ } satisfies Property
210
+ );
211
+ } else if (selectedWidgetId === "multi_references") {
212
+ updatedProperty = mergeDeep(
213
+ propertyData,
214
+ {
215
+ dataType: "array",
216
+ propertyConfig: "multi_references",
217
+ editable: propertyData.editable !== undefined ? propertyData.editable : true,
218
+ of: {
219
+ dataType: "reference"
220
+ }
221
+ } satisfies ArrayProperty
222
+ );
223
+ } else if (selectedWidgetId === "switch") {
224
+ updatedProperty = mergeDeep(
225
+ propertyData,
226
+ {
227
+ dataType: "boolean",
228
+ propertyConfig: "switch",
229
+ editable: propertyData.editable !== undefined ? propertyData.editable : true
230
+ } satisfies BooleanProperty
231
+ );
232
+ } else if (selectedWidgetId === "date_time") {
233
+ updatedProperty = mergeDeep(
234
+ propertyData,
235
+ {
236
+ dataType: "date",
237
+ propertyConfig: "date_time",
238
+ editable: propertyData.editable !== undefined ? propertyData.editable : true,
239
+ mode: "date_time"
240
+ } satisfies DateProperty
241
+ );
242
+ } else if (selectedWidgetId === "repeat") {
243
+ updatedProperty = mergeDeep(
244
+ propertyData,
245
+ {
246
+ dataType: "array",
247
+ propertyConfig: "repeat",
248
+ editable: propertyData.editable !== undefined ? propertyData.editable : true
249
+ } satisfies ArrayProperty
250
+ );
251
+ } else if (selectedWidgetId === "block") {
252
+ updatedProperty = mergeDeep(
253
+ propertyData,
254
+ {
255
+ dataType: "array",
256
+ propertyConfig: "block",
257
+ editable: propertyData.editable !== undefined ? propertyData.editable : true,
258
+ oneOf: {
259
+ properties: {}
260
+ }
261
+ } satisfies ArrayProperty
262
+ );
263
+ } else if (selectedWidgetId && propertyConfigs[selectedWidgetId]) {
264
+ updatedProperty = {
265
+ ...propertyConfigs[selectedWidgetId].property,
266
+ propertyConfig: selectedWidgetId
267
+ };
268
+ }
269
+
270
+ return updatedProperty;
271
+ }
@@ -0,0 +1,23 @@
1
+ import { useEffect, useRef } from "react";
2
+
3
+ function printChanged(props: any, prev: any, path = "", depth = 0) {
4
+ if (depth > 10) {
5
+ return;
6
+ }
7
+ if (props && prev && typeof props === "object" && typeof prev === "object") {
8
+ Object.keys(props).forEach((key) => {
9
+ printChanged(props[key], prev[key], path + "." + key, depth + 1);
10
+ });
11
+ } else if (props !== prev) {
12
+ console.log("Changed props:", path);
13
+ }
14
+
15
+ }
16
+
17
+ export function useTraceUpdate(props: any) {
18
+ const prev = useRef(props);
19
+ useEffect(() => {
20
+ printChanged(props, prev.current, "");
21
+ prev.current = props;
22
+ });
23
+ }
@@ -0,0 +1,9 @@
1
+ import { useContext } from "react";
2
+ import { CollectionEditorController } from "./types/collection_editor_controller";
3
+ import { CollectionEditorContext } from "./ConfigControllerProvider";
4
+
5
+ /**
6
+ * Hook to access the collection editor controller.
7
+ * The methods in this controller can be used to open the collection editor dialog.
8
+ */
9
+ export const useCollectionEditorController = (): CollectionEditorController => useContext(CollectionEditorContext);
@@ -0,0 +1,128 @@
1
+ import React, { useCallback } from "react";
2
+ import {
3
+ EntityCollection,
4
+ FireCMSPlugin,
5
+ joinCollectionLists,
6
+ makePropertiesEditable,
7
+ ModifyCollectionProps,
8
+ Properties,
9
+ User
10
+ } from "@firecms/core";
11
+ import { ConfigControllerProvider } from "./ConfigControllerProvider";
12
+ import { CollectionEditorPermissionsBuilder } from "./types/config_permissions";
13
+ import { EditorCollectionAction } from "./ui/EditorCollectionAction";
14
+ import { HomePageEditorCollectionAction } from "./ui/HomePageEditorCollectionAction";
15
+ import { NewCollectionCard } from "./ui/NewCollectionCard";
16
+ import { PersistedCollection } from "./types/persisted_collection";
17
+ import { CollectionInference } from "./types/collection_inference";
18
+ import { CollectionsConfigController } from "./types/config_controller";
19
+ import { RootCollectionSuggestions } from "./ui/RootCollectionSuggestions";
20
+ import { CollectionViewHeaderAction } from "./ui/CollectionViewHeaderAction";
21
+ import { PropertyAddColumnComponent } from "./ui/PropertyAddColumnComponent";
22
+
23
+ export interface CollectionConfigControllerProps<EC extends PersistedCollection = PersistedCollection, UserType extends User = User> {
24
+
25
+ /**
26
+ * Firebase app where the configuration is saved.
27
+ */
28
+ collectionConfigController: CollectionsConfigController;
29
+
30
+ modifyCollection?: (props: ModifyCollectionProps) => EntityCollection | void;
31
+
32
+ /**
33
+ * Define what actions can be performed on the configuration.
34
+ */
35
+ configPermissions?: CollectionEditorPermissionsBuilder<UserType, EC>;
36
+
37
+ /**
38
+ * The words you define here will not be allowed to be used as group
39
+ * names when creating collections.
40
+ * e.g. ["admin"]
41
+ */
42
+ reservedGroups: string[];
43
+
44
+ extraView?: {
45
+ View: React.ComponentType<{
46
+ path: string
47
+ }>,
48
+ icon: React.ReactNode
49
+ };
50
+
51
+ pathSuggestions?: (path: string) => Promise<string[]>;
52
+
53
+ collectionInference?: CollectionInference;
54
+
55
+ getData?: (path: string) => Promise<object[]>;
56
+
57
+ getUser: (uid: string) => UserType | null;
58
+
59
+ }
60
+
61
+
62
+ /**
63
+ * Use this hook to initialise the Collection Editor plugin.
64
+ * This is likely the only hook you will need to use.
65
+ * @param firebaseApp Firebase app where your project data lives.
66
+ * @param configPermissions
67
+ * @param reservedGroups
68
+ * @param extraView
69
+ * @param pathSuggestions
70
+ * @param getUser
71
+ * @param collectionInference
72
+ */
73
+ export function useCollectionEditorPlugin<EC extends PersistedCollection = PersistedCollection, UserType extends User = User>
74
+ ({
75
+ collectionConfigController,
76
+ modifyCollection,
77
+ configPermissions,
78
+ reservedGroups,
79
+ extraView,
80
+ pathSuggestions,
81
+ getUser,
82
+ collectionInference,
83
+ getData
84
+ }: CollectionConfigControllerProps<EC, UserType>): FireCMSPlugin<any, any, PersistedCollection> {
85
+
86
+ const injectCollections = useCallback(
87
+ (collections: EntityCollection[]) => {
88
+ const markAsEditable = (c: PersistedCollection) => {
89
+ makePropertiesEditable(c.properties as Properties);
90
+ c.subcollections?.forEach(markAsEditable);
91
+ };
92
+ const storedCollections = collectionConfigController.collections ?? [];
93
+ storedCollections.forEach(markAsEditable);
94
+ return joinCollectionLists(collections, storedCollections, [], modifyCollection);
95
+ },
96
+ [collectionConfigController.collections, modifyCollection]);
97
+
98
+ return {
99
+ name: "Collection Editor",
100
+ loading: collectionConfigController.loading,
101
+ collections: {
102
+ injectCollections,
103
+ CollectionActions: EditorCollectionAction
104
+ },
105
+ provider: {
106
+ Component: ConfigControllerProvider,
107
+ props: {
108
+ collectionConfigController,
109
+ configPermissions,
110
+ collectionInference,
111
+ reservedGroups,
112
+ extraView,
113
+ pathSuggestions,
114
+ getUser,
115
+ getData
116
+ }
117
+ },
118
+ homePage: {
119
+ additionalChildrenEnd: <RootCollectionSuggestions/>,
120
+ CollectionActions: HomePageEditorCollectionAction,
121
+ AdditionalCards: NewCollectionCard,
122
+ },
123
+ collectionView: {
124
+ HeaderAction: CollectionViewHeaderAction,
125
+ AddColumnComponent: PropertyAddColumnComponent
126
+ }
127
+ };
128
+ }
@@ -0,0 +1,9 @@
1
+ import { useContext } from "react";
2
+ import { CollectionsConfigController } from "./types/config_controller";
3
+ import { ConfigControllerContext } from "./ConfigControllerProvider";
4
+
5
+ /**
6
+ * Use this hook to access the configuration controller.
7
+ * You can use it to get the list of collections, and to save/delete collections.
8
+ */
9
+ export const useCollectionsConfigController = (): CollectionsConfigController => useContext(ConfigControllerContext);
@@ -0,0 +1,3 @@
1
+ export function toArray<T>(input?: T | T[]):T[] {
2
+ return Array.isArray(input) ? input : (input ? [input] : []);
3
+ }
@@ -0,0 +1,38 @@
1
+ import { isPropertyBuilder, Properties, PropertiesOrBuilders, Property, PropertyOrBuilder } from "@firecms/core";
2
+
3
+ export function editableProperty(property: PropertyOrBuilder | PropertyOrBuilder): boolean {
4
+ if (isPropertyBuilder(property))
5
+ return false;
6
+ if (isPropertyBuilder(property as PropertyOrBuilder))
7
+ return false;
8
+ else {
9
+ const eProperty = property as Property;
10
+ if (eProperty.dataType === "array" && typeof eProperty.of === "function")
11
+ return false;
12
+ else if (eProperty.dataType === "array" && Array.isArray(eProperty.of))
13
+ return false;
14
+ return Boolean(eProperty.editable);
15
+ }
16
+ }
17
+
18
+ export function removeNonEditableProperties(properties: PropertiesOrBuilders<any>): Properties {
19
+ return Object.entries(properties)
20
+ .filter(([_, property]) => editableProperty(property))
21
+ .map(([key, propertyOrBuilder]) => {
22
+ const property = propertyOrBuilder as Property;
23
+ if (!editableProperty(property)) {
24
+ return undefined;
25
+ } else if (property.dataType === "map" && property.properties) {
26
+ return {
27
+ [key]: {
28
+ ...property,
29
+ properties: removeNonEditableProperties(property.properties as PropertiesOrBuilders)
30
+ }
31
+ };
32
+ } else {
33
+ return { [key]: property };
34
+ }
35
+ })
36
+ .filter((e) => Boolean(e))
37
+ .reduce((a, b) => ({ ...a, ...b }), {}) as Properties;
38
+ }
@@ -0,0 +1,17 @@
1
+ import synonyms from "./synonyms";
2
+ import { iconKeys } from "@firecms/core";
3
+
4
+ // @ts-ignore
5
+ import * as JsSearch from "js-search";
6
+
7
+ export const iconsSearch = new JsSearch.Search("key");
8
+ iconsSearch.addIndex("synonyms");
9
+
10
+ iconsSearch.addDocuments(iconKeys
11
+ .map((importName) => {
12
+ return {
13
+ key: importName,
14
+ // @ts-ignore
15
+ synonyms: synonyms[importName] ?? [],
16
+ }
17
+ }));