@firecms/collection_editor 3.0.0-canary.28 → 3.0.0-canary.280

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 (91) hide show
  1. package/LICENSE +114 -21
  2. package/README.md +165 -1
  3. package/dist/ConfigControllerProvider.d.ts +1 -2
  4. package/dist/index.d.ts +1 -0
  5. package/dist/index.es.js +10792 -4791
  6. package/dist/index.es.js.map +1 -1
  7. package/dist/index.umd.js +11458 -3
  8. package/dist/index.umd.js.map +1 -1
  9. package/dist/types/collection_editor_controller.d.ts +3 -2
  10. package/dist/types/collection_inference.d.ts +4 -1
  11. package/dist/types/config_controller.d.ts +3 -1
  12. package/dist/types/config_permissions.d.ts +2 -2
  13. package/dist/types/persisted_collection.d.ts +1 -1
  14. package/dist/ui/CollectionViewHeaderAction.d.ts +3 -2
  15. package/dist/ui/EditorCollectionActionStart.d.ts +2 -0
  16. package/dist/ui/EditorEntityAction.d.ts +2 -0
  17. package/dist/ui/PropertyAddColumnComponent.d.ts +3 -1
  18. package/dist/ui/collection_editor/CollectionDetailsForm.d.ts +3 -1
  19. package/dist/ui/collection_editor/CollectionEditorDialog.d.ts +3 -2
  20. package/dist/ui/collection_editor/CollectionEditorWelcomeView.d.ts +2 -2
  21. package/dist/ui/collection_editor/CollectionPropertiesEditorForm.d.ts +2 -2
  22. package/dist/ui/collection_editor/EntityActionsEditTab.d.ts +4 -0
  23. package/dist/ui/collection_editor/EntityActionsSelectDialog.d.ts +4 -0
  24. package/dist/ui/collection_editor/LayoutModeSwitch.d.ts +5 -0
  25. package/dist/ui/collection_editor/PropertyEditView.d.ts +8 -0
  26. package/dist/ui/collection_editor/PropertyTree.d.ts +11 -12
  27. package/dist/ui/collection_editor/SubcollectionsEditTab.d.ts +1 -1
  28. package/dist/ui/collection_editor/import/CollectionEditorImportDataPreview.d.ts +1 -1
  29. package/dist/ui/collection_editor/import/CollectionEditorImportMapping.d.ts +8 -1
  30. package/dist/ui/collection_editor/import/clean_import_data.d.ts +1 -1
  31. package/dist/ui/collection_editor/properties/MarkdownPropertyField.d.ts +4 -0
  32. package/dist/ui/collection_editor/properties/ReferencePropertyField.d.ts +2 -1
  33. package/dist/ui/collection_editor/properties/StringPropertyField.d.ts +1 -1
  34. package/dist/useCollectionEditorPlugin.d.ts +8 -11
  35. package/dist/utils/collections.d.ts +6 -0
  36. package/package.json +25 -37
  37. package/src/ConfigControllerProvider.tsx +64 -66
  38. package/src/index.ts +1 -0
  39. package/src/types/collection_editor_controller.tsx +6 -5
  40. package/src/types/collection_inference.ts +4 -1
  41. package/src/types/config_controller.tsx +4 -1
  42. package/src/types/config_permissions.ts +1 -1
  43. package/src/types/persisted_collection.ts +2 -3
  44. package/src/ui/CollectionViewHeaderAction.tsx +10 -5
  45. package/src/ui/EditorCollectionAction.tsx +12 -70
  46. package/src/ui/EditorCollectionActionStart.tsx +87 -0
  47. package/src/ui/EditorEntityAction.tsx +51 -0
  48. package/src/ui/HomePageEditorCollectionAction.tsx +21 -14
  49. package/src/ui/NewCollectionButton.tsx +1 -1
  50. package/src/ui/NewCollectionCard.tsx +3 -3
  51. package/src/ui/PropertyAddColumnComponent.tsx +11 -6
  52. package/src/ui/collection_editor/CollectionDetailsForm.tsx +157 -50
  53. package/src/ui/collection_editor/CollectionEditorDialog.tsx +119 -39
  54. package/src/ui/collection_editor/CollectionEditorWelcomeView.tsx +24 -33
  55. package/src/ui/collection_editor/CollectionPropertiesEditorForm.tsx +46 -41
  56. package/src/ui/collection_editor/EntityActionsEditTab.tsx +163 -0
  57. package/src/ui/collection_editor/EntityActionsSelectDialog.tsx +41 -0
  58. package/src/ui/collection_editor/EntityCustomViewsSelectDialog.tsx +11 -7
  59. package/src/ui/collection_editor/EnumForm.tsx +11 -7
  60. package/src/ui/collection_editor/GetCodeDialog.tsx +60 -28
  61. package/src/ui/collection_editor/LayoutModeSwitch.tsx +54 -0
  62. package/src/ui/collection_editor/PropertyEditView.tsx +266 -79
  63. package/src/ui/collection_editor/PropertyFieldPreview.tsx +8 -10
  64. package/src/ui/collection_editor/PropertyTree.tsx +184 -138
  65. package/src/ui/collection_editor/SubcollectionsEditTab.tsx +26 -19
  66. package/src/ui/collection_editor/UnsavedChangesDialog.tsx +9 -7
  67. package/src/ui/collection_editor/import/CollectionEditorImportDataPreview.tsx +41 -9
  68. package/src/ui/collection_editor/import/CollectionEditorImportMapping.tsx +43 -10
  69. package/src/ui/collection_editor/import/clean_import_data.ts +1 -1
  70. package/src/ui/collection_editor/properties/BlockPropertyField.tsx +32 -20
  71. package/src/ui/collection_editor/properties/DateTimePropertyField.tsx +54 -47
  72. package/src/ui/collection_editor/properties/EnumPropertyField.tsx +3 -1
  73. package/src/ui/collection_editor/properties/MapPropertyField.tsx +8 -7
  74. package/src/ui/collection_editor/properties/MarkdownPropertyField.tsx +139 -0
  75. package/src/ui/collection_editor/properties/ReferencePropertyField.tsx +7 -3
  76. package/src/ui/collection_editor/properties/RepeatPropertyField.tsx +0 -1
  77. package/src/ui/collection_editor/properties/StoragePropertyField.tsx +34 -19
  78. package/src/ui/collection_editor/properties/StringPropertyField.tsx +4 -9
  79. package/src/ui/collection_editor/properties/UrlPropertyField.tsx +1 -0
  80. package/src/ui/collection_editor/properties/advanced/AdvancedPropertyValidation.tsx +2 -0
  81. package/src/ui/collection_editor/properties/validation/ValidationPanel.tsx +2 -2
  82. package/src/ui/collection_editor/templates/pages_template.ts +1 -6
  83. package/src/ui/collection_editor/utils/strings.ts +13 -6
  84. package/src/ui/collection_editor/utils/supported_fields.tsx +2 -0
  85. package/src/ui/collection_editor/utils/update_property_for_widget.ts +37 -6
  86. package/src/useCollectionEditorPlugin.tsx +38 -32
  87. package/src/utils/collections.ts +46 -0
  88. package/dist/ui/RootCollectionSuggestions.d.ts +0 -3
  89. package/dist/ui/collection_editor/PropertySelectItem.d.ts +0 -8
  90. package/src/ui/RootCollectionSuggestions.tsx +0 -63
  91. package/src/ui/collection_editor/PropertySelectItem.tsx +0 -32
@@ -1,17 +1,33 @@
1
- import React, { useCallback } from "react";
1
+ import React from "react";
2
2
  import equal from "react-fast-compare"
3
3
 
4
4
  import {
5
5
  AdditionalFieldDelegate,
6
6
  CMSType,
7
- ErrorBoundary,
8
7
  isPropertyBuilder,
9
8
  PropertiesOrBuilders,
10
9
  PropertyOrBuilder
11
10
  } from "@firecms/core";
12
- import { AutoAwesomeIcon, defaultBorderMixin, DragHandleIcon, IconButton, RemoveIcon, Tooltip } from "@firecms/ui";
11
+ import { AutorenewIcon, defaultBorderMixin, DragHandleIcon, IconButton, RemoveIcon, Tooltip } from "@firecms/ui";
13
12
  import { NonEditablePropertyPreview, PropertyFieldPreview } from "./PropertyFieldPreview";
14
- import { DragDropContext, Draggable, DraggableProvided, Droppable } from "@hello-pangea/dnd";
13
+ import {
14
+ closestCenter,
15
+ DndContext,
16
+ DragEndEvent,
17
+ KeyboardSensor,
18
+ PointerSensor,
19
+ useSensor,
20
+ useSensors
21
+ } from "@dnd-kit/core";
22
+ import {
23
+ SortableContext,
24
+ sortableKeyboardCoordinates,
25
+ useSortable,
26
+ verticalListSortingStrategy
27
+ } from "@dnd-kit/sortable";
28
+ import { restrictToVerticalAxis } from "@dnd-kit/modifiers";
29
+
30
+ import { CSS } from "@dnd-kit/utilities";
15
31
  import { getFullId, getFullIdPath } from "./util";
16
32
  import { editableProperty } from "../../utils/entities";
17
33
 
@@ -48,103 +64,109 @@ export const PropertyTree = React.memo(
48
64
 
49
65
  const propertiesOrder = propertiesOrderProp ?? Object.keys(properties);
50
66
 
51
- const onDragEnd = useCallback((result: any) => {
52
- // dropped outside the list
53
- if (!result.destination) {
67
+ const sensors = useSensors(
68
+ useSensor(PointerSensor, {
69
+ activationConstraint: {
70
+ distance: 5,
71
+ }
72
+ }),
73
+ useSensor(KeyboardSensor, {
74
+ coordinateGetter: sortableKeyboardCoordinates,
75
+ })
76
+ );
77
+
78
+ const handleDragEnd = (event: DragEndEvent) => {
79
+ const {
80
+ active,
81
+ over
82
+ } = event;
83
+
84
+ if (!over || active.id === over.id) {
54
85
  return;
55
86
  }
56
- const startIndex = result.source.index;
57
- const endIndex = result.destination.index;
58
87
 
59
- const newPropertiesOrder = Array.from(propertiesOrder);
60
- const [removed] = newPropertiesOrder.splice(startIndex, 1);
61
- newPropertiesOrder.splice(endIndex, 0, removed);
62
- if (onPropertyMove)
63
- onPropertyMove(newPropertiesOrder, namespace);
64
- }, [namespace, onPropertyMove, propertiesOrder])
88
+ const activeId = String(active.id);
89
+ const overId = String(over.id);
90
+
91
+ // Extract property keys from the full IDs
92
+ const activeKey = activeId.includes(".") ? activeId.split(".").pop() : activeId;
93
+ const overKey = overId.includes(".") ? overId.split(".").pop() : overId;
94
+
95
+ if (!activeKey || !overKey) return;
96
+
97
+ const oldIndex = propertiesOrder.indexOf(activeKey);
98
+ const newIndex = propertiesOrder.indexOf(overKey);
99
+
100
+ if (oldIndex !== -1 && newIndex !== -1) {
101
+ const newPropertiesOrder = [...propertiesOrder];
102
+ const [removed] = newPropertiesOrder.splice(oldIndex, 1);
103
+ newPropertiesOrder.splice(newIndex, 0, removed);
104
+
105
+ if (onPropertyMove) {
106
+ onPropertyMove(newPropertiesOrder, namespace);
107
+ }
108
+ }
109
+ };
110
+
111
+ const items = propertiesOrder.map(key => getFullId(key, namespace));
65
112
 
66
113
  return (
67
- <>
68
-
69
- <DragDropContext onDragEnd={onDragEnd}>
70
- <Droppable droppableId={`droppable_${namespace}`}>
71
- {(droppableProvided, droppableSnapshot) => (
72
- <div
73
- {...droppableProvided.droppableProps}
74
- ref={droppableProvided.innerRef}
75
- className={className}>
76
- {propertiesOrder && propertiesOrder
77
- .map((propertyKey: string, index: number) => {
78
- const property = properties[propertyKey] as PropertyOrBuilder;
79
- const additionalField = additionalFields?.find(field => field.key === propertyKey);
80
-
81
- if (!property && !additionalField) {
82
- console.warn(`Property ${propertyKey} not found in properties or additionalFields`);
83
- return null;
84
- }
85
- return (
86
- <Draggable
87
- key={`array_field_${namespace}_${propertyKey}}`}
88
- draggableId={`array_field_${namespace}_${propertyKey}}`}
89
- index={index}>
90
- {(provided, snapshot) => {
91
- return (
92
- <ErrorBoundary>
93
- <PropertyTreeEntry
94
- propertyKey={propertyKey as string}
95
- propertyOrBuilder={property}
96
- additionalField={additionalField}
97
- provided={provided}
98
- errors={errors}
99
- namespace={namespace}
100
- inferredPropertyKeys={inferredPropertyKeys}
101
- onPropertyMove={onPropertyMove}
102
- onPropertyRemove={onPropertyRemove}
103
- onPropertyClick={snapshot.isDragging ? undefined : onPropertyClick}
104
- selectedPropertyKey={selectedPropertyKey}
105
- collectionEditable={collectionEditable}
106
- />
107
- </ErrorBoundary>
108
- );
109
- }}
110
- </Draggable>);
111
- }).filter(Boolean)}
112
-
113
- {droppableProvided.placeholder}
114
-
115
- </div>
116
- )}
117
- </Droppable>
118
- </DragDropContext>
119
-
120
- </>
114
+ <DndContext
115
+ sensors={sensors}
116
+ collisionDetection={closestCenter}
117
+ onDragEnd={handleDragEnd}
118
+ modifiers={[restrictToVerticalAxis]}
119
+ >
120
+ <SortableContext
121
+ items={items}
122
+ strategy={verticalListSortingStrategy}
123
+ >
124
+ <div className={className}>
125
+
126
+ {propertiesOrder && propertiesOrder
127
+ .map((propertyKey: string, index: number) => {
128
+ const property = properties[propertyKey] as PropertyOrBuilder;
129
+ const additionalField = additionalFields?.find(field => field.key === propertyKey);
130
+
131
+ if (!property && !additionalField) {
132
+ console.warn(`Property ${propertyKey} not found in properties or additionalFields`);
133
+ return null;
134
+ }
135
+
136
+ const id = getFullId(propertyKey, namespace);
137
+
138
+ return (
139
+ <PropertyTreeEntry
140
+ key={id}
141
+ id={id}
142
+ propertyKey={propertyKey}
143
+ propertyOrBuilder={property}
144
+ additionalField={additionalField}
145
+ errors={errors}
146
+ namespace={namespace}
147
+ inferredPropertyKeys={inferredPropertyKeys}
148
+ onPropertyMove={onPropertyMove}
149
+ onPropertyRemove={onPropertyRemove}
150
+ onPropertyClick={onPropertyClick}
151
+ selectedPropertyKey={selectedPropertyKey}
152
+ collectionEditable={collectionEditable}
153
+ />
154
+ );
155
+ }).filter(Boolean)}
156
+ </div>
157
+ </SortableContext>
158
+ </DndContext>
121
159
  );
122
160
  },
123
- (prevProps, nextProps) => {
124
-
125
- const isSelected = nextProps.selectedPropertyKey?.startsWith(nextProps.namespace ?? "");
126
- const wasSelected = prevProps.selectedPropertyKey?.startsWith(prevProps.namespace ?? "");
127
- if (isSelected || wasSelected)
128
- return false;
129
-
130
- return equal(prevProps.properties, nextProps.properties) &&
131
- prevProps.propertiesOrder === nextProps.propertiesOrder &&
132
- equal(prevProps.additionalFields, nextProps.additionalFields) &&
133
- equal(prevProps.errors, nextProps.errors) &&
134
- equal(prevProps.onPropertyClick, nextProps.onPropertyClick) &&
135
- // equal(prevProps.onPropertyMove, nextProps.onPropertyMove) &&
136
- // equal(prevProps.onPropertyRemove, nextProps.onPropertyRemove) &&
137
- prevProps.namespace === nextProps.namespace &&
138
- prevProps.collectionEditable === nextProps.collectionEditable;
139
- }
161
+ equal
140
162
  );
141
163
 
142
164
  export function PropertyTreeEntry({
165
+ id,
143
166
  propertyKey,
144
167
  namespace,
145
168
  propertyOrBuilder,
146
169
  additionalField,
147
- provided,
148
170
  selectedPropertyKey,
149
171
  errors,
150
172
  onPropertyClick,
@@ -153,12 +175,12 @@ export function PropertyTreeEntry({
153
175
  inferredPropertyKeys,
154
176
  collectionEditable
155
177
  }: {
178
+ id: string;
156
179
  propertyKey: string;
157
180
  namespace?: string;
158
181
  propertyOrBuilder: PropertyOrBuilder;
159
182
  additionalField?: AdditionalFieldDelegate<any>;
160
183
  selectedPropertyKey?: string;
161
- provided: DraggableProvided;
162
184
  errors: Record<string, any>;
163
185
  onPropertyClick?: (propertyKey: string, namespace?: string) => void;
164
186
  onPropertyMove?: (propertiesOrder: string[], namespace?: string) => void;
@@ -167,8 +189,27 @@ export function PropertyTreeEntry({
167
189
  collectionEditable: boolean;
168
190
  }) {
169
191
 
192
+ const {
193
+ attributes,
194
+ listeners,
195
+ setNodeRef,
196
+ transform,
197
+ transition,
198
+ isDragging
199
+ } = useSortable({
200
+ id
201
+ });
202
+
203
+ const style = {
204
+ // Key change: use Translate instead of Transform to prevent stretching
205
+ transform: CSS.Translate.toString(transform),
206
+ transition,
207
+ zIndex: isDragging ? 10 : undefined,
208
+ position: "relative" as const,
209
+ };
210
+
170
211
  const isPropertyInferred = inferredPropertyKeys?.includes(namespace ? `${namespace}.${propertyKey}` : propertyKey);
171
- const fullId = getFullId(propertyKey, namespace);
212
+ const fullId = id;
172
213
  const fullIdPath = getFullIdPath(propertyKey, namespace);
173
214
  const hasError = fullIdPath in errors;
174
215
 
@@ -190,63 +231,68 @@ export function PropertyTreeEntry({
190
231
  }
191
232
  }
192
233
 
193
- // const hasError = fullId ? getIn(errors, idToPropertiesPath(fullId)) : false;
194
234
  const selected = selectedPropertyKey === fullId;
195
235
  const editable = propertyOrBuilder && ((collectionEditable && !isPropertyBuilder(propertyOrBuilder)) || editableProperty(propertyOrBuilder));
196
236
 
197
237
  return (
198
238
  <div
199
- ref={provided.innerRef}
200
- {...provided.draggableProps}
201
- {...provided.dragHandleProps}
239
+ ref={setNodeRef}
240
+ style={style}
202
241
  className="relative -ml-8"
203
242
  >
204
- {subtree && <div
205
- className={"absolute border-l " + defaultBorderMixin}
206
- style={{
207
- left: "32px",
208
- top: "64px",
209
- bottom: "16px"
210
- }}/>}
211
-
212
- {!isPropertyBuilder(propertyOrBuilder) && !additionalField && editable
213
- ? <PropertyFieldPreview
214
- property={propertyOrBuilder}
215
- onClick={onPropertyClick ? () => onPropertyClick(propertyKey, namespace) : undefined}
216
- includeName={true}
217
- selected={selected}
218
- hasError={hasError}/>
219
- : <NonEditablePropertyPreview name={propertyKey}
220
- property={propertyOrBuilder}
221
- onClick={onPropertyClick ? () => onPropertyClick(propertyKey, namespace) : undefined}
222
- selected={selected}/>}
223
-
224
- <div className="absolute top-2 right-2 flex flex-row ">
225
-
226
- {isPropertyInferred && <Tooltip title={"Inferred property"}>
227
- <AutoAwesomeIcon size="small" className={"p-2"}/>
228
- </Tooltip>}
229
-
230
- {onPropertyRemove && <Tooltip title={"Remove"}>
231
- <IconButton size="small"
232
- color="inherit"
233
- onClick={() => onPropertyRemove(propertyKey, namespace)}>
234
- <RemoveIcon size={"small"}/>
235
- </IconButton>
236
- </Tooltip>}
237
-
238
- {onPropertyMove && <Tooltip title={"Move"}>
239
- <IconButton
240
- component={"span"}
241
- size="small"
242
- >
243
- <DragHandleIcon size={"small"}/>
244
- </IconButton>
245
- </Tooltip>}
246
- </div>
243
+ <div className="relative">
244
+ {subtree && <div
245
+ className={"absolute border-l " + defaultBorderMixin}
246
+ style={{
247
+ left: "32px",
248
+ top: "64px",
249
+ bottom: "16px"
250
+ }}/>}
247
251
 
248
- {subtree && <div className={"ml-16"}>{subtree}</div>}
252
+ <div>
253
+ {!isPropertyBuilder(propertyOrBuilder) && !additionalField && editable
254
+ ? <PropertyFieldPreview
255
+ property={propertyOrBuilder}
256
+ onClick={onPropertyClick ? () => onPropertyClick(propertyKey, namespace) : undefined}
257
+ includeName={true}
258
+ selected={selected}
259
+ hasError={hasError}/>
260
+ : <NonEditablePropertyPreview name={propertyKey}
261
+ property={propertyOrBuilder}
262
+ onClick={onPropertyClick ? () => onPropertyClick(propertyKey, namespace) : undefined}
263
+ selected={selected}/>}
264
+ </div>
265
+
266
+ <div className="absolute top-2 right-2 flex flex-row">
267
+ {isPropertyInferred && <Tooltip title={"Inferred property"}>
268
+ <AutorenewIcon size="small" className={"p-2"}/>
269
+ </Tooltip>}
270
+
271
+ {onPropertyRemove && !isPropertyInferred && <Tooltip title={"Remove"}
272
+ asChild={true}>
273
+ <IconButton size="small"
274
+ color="inherit"
275
+ onClick={() => onPropertyRemove(propertyKey, namespace)}>
276
+ <RemoveIcon size={"small"}/>
277
+ </IconButton>
278
+ </Tooltip>}
279
+
280
+ {onPropertyMove && <Tooltip title={"Move"}
281
+ asChild={true}>
282
+ <IconButton
283
+ component={"span"}
284
+ size="small"
285
+ {...attributes}
286
+ {...listeners}
287
+ >
288
+ <DragHandleIcon size={"small"}/>
289
+ </IconButton>
290
+ </Tooltip>}
291
+
292
+ </div>
293
+
294
+ {subtree && <div className={"ml-16"}>{subtree}</div>}
295
+ </div>
249
296
  </div>
250
297
  );
251
-
252
298
  }
@@ -1,6 +1,6 @@
1
1
  import React from "react";
2
2
  import {
3
- DeleteConfirmationDialog,
3
+ ConfirmationDialog,
4
4
  EntityCollection,
5
5
  EntityCustomView,
6
6
  resolveEntityView,
@@ -41,7 +41,7 @@ export function SubcollectionsEditTab({
41
41
  parentCollection?: EntityCollection,
42
42
  configController: CollectionsConfigController;
43
43
  collectionInference?: CollectionInference;
44
- getUser: (uid: string) => User | null;
44
+ getUser?: (uid: string) => User | null;
45
45
  parentCollectionIds?: string[];
46
46
  }) {
47
47
 
@@ -61,7 +61,7 @@ export function SubcollectionsEditTab({
61
61
  setFieldValue,
62
62
  } = useFormex<EntityCollection>();
63
63
 
64
- const subcollections = collection.subcollections ?? [];
64
+ const [subcollections, setSubcollections] = React.useState<EntityCollection[]>(collection.subcollections ?? []);
65
65
  const resolvedEntityViews = values.entityViews?.filter(e => typeof e === "string")
66
66
  .map(e => resolveEntityView(e, contextEntityViews))
67
67
  .filter(Boolean) as EntityCustomView[] ?? [];
@@ -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();
@@ -209,30 +211,32 @@ export function SubcollectionsEditTab({
209
211
  <div style={{ height: "52px" }}/>
210
212
 
211
213
  {subcollectionToDelete &&
212
- <DeleteConfirmationDialog open={Boolean(subcollectionToDelete)}
213
- onAccept={() => {
214
+ <ConfirmationDialog open={Boolean(subcollectionToDelete)}
215
+ onAccept={() => {
214
216
  const props = {
215
217
  id: subcollectionToDelete,
216
218
  parentCollectionIds: [...(parentCollectionIds ?? []), collection.id]
217
219
  };
218
220
  console.debug("Deleting subcollection", props)
219
- configController.deleteCollection(props);
220
- setSubcollectionToDelete(undefined);
221
+ configController.deleteCollection(props).then(() => {
222
+ setSubcollectionToDelete(undefined);
223
+ setSubcollections(subcollections?.filter(e => e.id !== subcollectionToDelete))
224
+ });
221
225
  }}
222
- onCancel={() => setSubcollectionToDelete(undefined)}
223
- title={<>Delete this subcollection?</>}
224
- body={<> This will <b>not
226
+ onCancel={() => setSubcollectionToDelete(undefined)}
227
+ title={<>Delete this subcollection?</>}
228
+ body={<> This will <b>not
225
229
  delete any data</b>, only
226
230
  the collection in the CMS</>}/>}
227
231
  {viewToDelete &&
228
- <DeleteConfirmationDialog open={Boolean(viewToDelete)}
229
- onAccept={() => {
232
+ <ConfirmationDialog open={Boolean(viewToDelete)}
233
+ onAccept={() => {
230
234
  setFieldValue("entityViews", values.entityViews?.filter(e => e !== viewToDelete));
231
235
  setViewToDelete(undefined);
232
236
  }}
233
- onCancel={() => setViewToDelete(undefined)}
234
- title={<>Remove this view?</>}
235
- body={<>This will <b>not
237
+ onCancel={() => setViewToDelete(undefined)}
238
+ title={<>Remove this view?</>}
239
+ body={<>This will <b>not
236
240
  delete any data</b>, only
237
241
  the view in the CMS</>}/>}
238
242
 
@@ -245,7 +249,10 @@ export function SubcollectionsEditTab({
245
249
  isNewCollection={false}
246
250
  {...currentDialog}
247
251
  getUser={getUser}
248
- handleClose={() => {
252
+ handleClose={(updatedCollection) => {
253
+ if (updatedCollection && !subcollections.map(e => e.id).includes(updatedCollection.id)) {
254
+ setSubcollections([...subcollections, updatedCollection]);
255
+ }
249
256
  setCurrentDialog(undefined);
250
257
  }}/>
251
258
 
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
- import { Button, Dialog, DialogActions, DialogContent, Typography } from "@firecms/ui";
2
+ import { Button, Dialog, DialogActions, DialogContent, DialogTitle, Typography } from "@firecms/ui";
3
3
 
4
4
  export interface UnsavedChangesDialogProps {
5
5
  open: boolean;
@@ -24,11 +24,9 @@ export function UnsavedChangesDialog({
24
24
  aria-labelledby="alert-dialog-title"
25
25
  aria-describedby="alert-dialog-description"
26
26
  >
27
- <DialogContent>
28
- <Typography variant={"h6"}>
29
- {title ?? "Unsaved changes"}
30
- </Typography>
31
27
 
28
+ <DialogTitle>{title ?? "Unsaved changes"}</DialogTitle>
29
+ <DialogContent>
32
30
  {body && <Typography>
33
31
  {body}
34
32
  </Typography>}
@@ -39,8 +37,12 @@ export function UnsavedChangesDialog({
39
37
  </DialogContent>
40
38
 
41
39
  <DialogActions>
42
- <Button variant="text" onClick={handleCancel} autoFocus> Cancel </Button>
43
- <Button onClick={handleOk}> Ok </Button>
40
+ <Button variant="text"
41
+ color={"primary"}
42
+ onClick={handleCancel} autoFocus> Cancel </Button>
43
+ <Button
44
+ color={"primary"}
45
+ onClick={handleOk}> Ok </Button>
44
46
  </DialogActions>
45
47
  </Dialog>
46
48
  );
@@ -1,21 +1,48 @@
1
- import { convertDataToEntity, getPropertiesMapping, ImportConfig } from "@firecms/data_import_export";
2
- import { EntityCollectionTable, Properties, useSelectionController } from "@firecms/core";
3
- import { useEffect } from "react";
1
+ import { convertDataToEntity, ImportConfig } from "@firecms/data_import";
2
+ import {
3
+ CircularProgressCenter,
4
+ EntityCollectionTable,
5
+ Properties,
6
+ useAuthController,
7
+ useNavigationController,
8
+ useSelectionController
9
+ } from "@firecms/core";
10
+ import { useEffect, useState } from "react";
4
11
  import { Typography } from "@firecms/ui";
5
12
 
6
- export function CollectionEditorImportDataPreview({ importConfig, properties, propertiesOrder }: {
13
+ export function CollectionEditorImportDataPreview({
14
+ importConfig,
15
+ properties,
16
+ propertiesOrder
17
+ }: {
7
18
  importConfig: ImportConfig,
8
19
  properties: Properties,
9
20
  propertiesOrder: string[]
10
21
  }) {
11
22
 
12
- useEffect(() => {
13
- const propertiesMapping = getPropertiesMapping(importConfig.originProperties, properties);
14
- const mappedData = importConfig.importData.map(d => convertDataToEntity(d, importConfig.idColumn, importConfig.headersMapping, properties, propertiesMapping, "TEMP_PATH"));
23
+ const authController = useAuthController();
24
+ const navigation = useNavigationController();
25
+ const [loading, setLoading] = useState<boolean>(false);
26
+
27
+ async function loadEntities() {
28
+ const mappedData = importConfig.importData.map(d => convertDataToEntity(authController,
29
+ navigation,
30
+ d,
31
+ importConfig.idColumn,
32
+ importConfig.headersMapping,
33
+ properties,
34
+ "TEMP_PATH",
35
+ importConfig.defaultValues));
15
36
  importConfig.setEntities(mappedData);
37
+ }
38
+
39
+ useEffect(() => {
40
+ loadEntities().finally(() => setLoading(false));
16
41
  }, []);
17
42
 
18
43
  const selectionController = useSelectionController();
44
+ if (loading)
45
+ return <CircularProgressCenter/>
19
46
 
20
47
  return <EntityCollectionTable
21
48
  title={<div>
@@ -31,7 +58,12 @@ export function CollectionEditorImportDataPreview({ importConfig, properties, pr
31
58
  filterable={false}
32
59
  sortable={false}
33
60
  selectionController={selectionController}
34
- displayedColumnIds={propertiesOrder.map(p => ({ key: p, disabled: false }))}
35
- properties={properties}/>
61
+ displayedColumnIds={propertiesOrder.map(p => ({
62
+ key: p,
63
+ disabled: false
64
+ }))}
65
+ openEntityMode={"side_panel"}
66
+ properties={properties}
67
+ enablePopupIcon={false}/>
36
68
 
37
69
  }