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

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 (42) hide show
  1. package/LICENSE +113 -21
  2. package/dist/ConfigControllerProvider.d.ts +2 -2
  3. package/dist/index.d.ts +1 -0
  4. package/dist/index.es.js +1814 -1772
  5. package/dist/index.es.js.map +1 -1
  6. package/dist/index.umd.js +2 -2
  7. package/dist/index.umd.js.map +1 -1
  8. package/dist/types/collection_editor_controller.d.ts +1 -1
  9. package/dist/ui/EditorCollectionActionStart.d.ts +2 -0
  10. package/dist/ui/collection_editor/CollectionEditorDialog.d.ts +1 -1
  11. package/dist/ui/collection_editor/CollectionEditorWelcomeView.d.ts +1 -1
  12. package/dist/ui/collection_editor/CollectionPropertiesEditorForm.d.ts +1 -1
  13. package/dist/ui/collection_editor/PropertyTree.d.ts +9 -9
  14. package/dist/ui/collection_editor/SubcollectionsEditTab.d.ts +1 -1
  15. package/dist/useCollectionEditorPlugin.d.ts +6 -9
  16. package/dist/utils/collections.d.ts +6 -0
  17. package/package.json +21 -21
  18. package/src/ConfigControllerProvider.tsx +52 -58
  19. package/src/index.ts +1 -0
  20. package/src/types/collection_editor_controller.tsx +1 -1
  21. package/src/ui/EditorCollectionAction.tsx +0 -51
  22. package/src/ui/EditorCollectionActionStart.tsx +87 -0
  23. package/src/ui/HomePageEditorCollectionAction.tsx +5 -5
  24. package/src/ui/NewCollectionCard.tsx +3 -3
  25. package/src/ui/collection_editor/CollectionDetailsForm.tsx +34 -4
  26. package/src/ui/collection_editor/CollectionEditorDialog.tsx +39 -24
  27. package/src/ui/collection_editor/CollectionEditorWelcomeView.tsx +4 -4
  28. package/src/ui/collection_editor/CollectionPropertiesEditorForm.tsx +21 -19
  29. package/src/ui/collection_editor/PropertyEditView.tsx +5 -4
  30. package/src/ui/collection_editor/PropertyFieldPreview.tsx +3 -6
  31. package/src/ui/collection_editor/PropertySelectItem.tsx +2 -2
  32. package/src/ui/collection_editor/PropertyTree.tsx +3 -3
  33. package/src/ui/collection_editor/SubcollectionsEditTab.tsx +1 -1
  34. package/src/ui/collection_editor/import/CollectionEditorImportDataPreview.tsx +25 -9
  35. package/src/ui/collection_editor/import/CollectionEditorImportMapping.tsx +9 -7
  36. package/src/ui/collection_editor/properties/BlockPropertyField.tsx +14 -8
  37. package/src/ui/collection_editor/properties/MapPropertyField.tsx +5 -5
  38. package/src/ui/collection_editor/properties/RepeatPropertyField.tsx +0 -1
  39. package/src/useCollectionEditorPlugin.tsx +27 -26
  40. package/src/utils/collections.ts +30 -0
  41. package/dist/ui/RootCollectionSuggestions.d.ts +0 -3
  42. package/src/ui/RootCollectionSuggestions.tsx +0 -63
@@ -5,7 +5,8 @@ import {
5
5
  AutocompleteItem,
6
6
  BooleanSwitchWithLabel,
7
7
  Chip,
8
- cn,
8
+ ClearIcon,
9
+ cls,
9
10
  Container,
10
11
  DebouncedTextField,
11
12
  Dialog,
@@ -146,7 +147,7 @@ export function CollectionDetailsForm({
146
147
  </FieldCaption>
147
148
  </div>
148
149
 
149
- <div className={cn("col-span-12 ", isSubcollection ? "" : "sm:col-span-8")}>
150
+ <div className={cls("col-span-12 ", isSubcollection ? "" : "sm:col-span-8")}>
150
151
  <Field name={"path"}
151
152
  as={DebouncedTextField}
152
153
  label={"Path"}
@@ -216,7 +217,7 @@ export function CollectionDetailsForm({
216
217
  label={"Collection id"}
217
218
  error={showErrors && Boolean(errors.id)}/>
218
219
  <FieldCaption error={touched.id && Boolean(errors.id)}>
219
- {touched.id && Boolean(errors.id) ? errors.id : "This id identifies this collection"}
220
+ {touched.id && Boolean(errors.id) ? errors.id : "This id identifies this collection. Typically the same as the path."}
220
221
  </FieldCaption>
221
222
  </div>
222
223
 
@@ -235,6 +236,35 @@ export function CollectionDetailsForm({
235
236
  {showErrors && Boolean(errors.singularName) ? errors.singularName : "Optionally define a singular name for your entities"}
236
237
  </FieldCaption>
237
238
  </div>
239
+ <div className={"col-span-12"}>
240
+ <TextField
241
+ error={showErrors && Boolean(errors.sideDialogWidth)}
242
+ name={"sideDialogWidth"}
243
+ type={"number"}
244
+ aria-describedby={"sideDialogWidth-helper"}
245
+ onChange={(e) => {
246
+ setFieldTouched("sideDialogWidth", true);
247
+ const value = e.target.value;
248
+ if (!value) {
249
+ setFieldValue("sideDialogWidth", null);
250
+ } else if (!isNaN(Number(value))) {
251
+ setFieldValue("sideDialogWidth", Number(value));
252
+ }
253
+ }}
254
+ endAdornment={<IconButton
255
+ size={"small"}
256
+ onClick={() => {
257
+ setFieldValue("sideDialogWidth", null);
258
+ }}
259
+ disabled={!values.sideDialogWidth}>
260
+ <ClearIcon size={"small"}/>
261
+ </IconButton>}
262
+ value={values.sideDialogWidth ?? ""}
263
+ label={"Side dialog width"}/>
264
+ <FieldCaption error={showErrors && Boolean(errors.singularName)}>
265
+ {showErrors && Boolean(errors.singularName) ? errors.singularName : "Optionally define the width (in pixels) of entities side dialog. Default is 768px"}
266
+ </FieldCaption>
267
+ </div>
238
268
  <div className={"col-span-12"}>
239
269
  <TextField
240
270
  error={showErrors && Boolean(errors.description)}
@@ -272,7 +302,7 @@ export function CollectionDetailsForm({
272
302
  <div className={"col-span-12"}>
273
303
  <Select
274
304
  name="customId"
275
- label="Data IDs generation"
305
+ label="Document IDs generation"
276
306
  position={"item-aligned"}
277
307
  disabled={customIdValue === "code_defined"}
278
308
  onValueChange={(v) => {
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import { useCallback, useEffect, useRef, useState } from "react";
2
+ import { useEffect, useRef, useState } from "react";
3
3
  import {
4
4
  CircularProgressCenter,
5
5
  EntityCollection,
@@ -25,7 +25,7 @@ import {
25
25
  import {
26
26
  ArrowBackIcon,
27
27
  Button,
28
- cn,
28
+ cls,
29
29
  coolIconKeys,
30
30
  defaultBorderMixin,
31
31
  Dialog,
@@ -76,7 +76,7 @@ export interface CollectionEditorDialogProps {
76
76
  icon: React.ReactNode
77
77
  };
78
78
  pathSuggestions?: (path?: string) => Promise<string[]>;
79
- getUser: (uid: string) => User | null;
79
+ getUser?: (uid: string) => User | null;
80
80
  getData?: (path: string, parentPaths: string[]) => Promise<object[]>;
81
81
  parentCollection?: PersistedCollection;
82
82
  }
@@ -88,13 +88,13 @@ export function CollectionEditorDialog(props: CollectionEditorDialogProps) {
88
88
  const [formDirty, setFormDirty] = React.useState<boolean>(false);
89
89
  const [unsavedChangesDialogOpen, setUnsavedChangesDialogOpen] = React.useState<boolean>(false);
90
90
 
91
- const handleCancel = useCallback(() => {
91
+ const handleCancel = () => {
92
92
  if (!formDirty) {
93
93
  props.handleClose(undefined);
94
94
  } else {
95
95
  setUnsavedChangesDialogOpen(true);
96
96
  }
97
- }, [formDirty, props.handleClose]);
97
+ };
98
98
 
99
99
  useEffect(() => {
100
100
  if (!open) {
@@ -170,7 +170,8 @@ export function CollectionEditor(props: CollectionEditorDialogProps & {
170
170
  } catch (e) {
171
171
  console.error(e);
172
172
  }
173
- }, [navigation.getCollectionFromPaths, props.editedCollectionId, props.parentCollectionIds, navigation.initialised]);
173
+ }, [props.editedCollectionId, props.parentCollectionIds, navigation.initialised, navigation.getCollectionFromPaths]);
174
+
174
175
  if (!topLevelNavigation) {
175
176
  throw Error("Internal: Navigation not ready in collection editor");
176
177
  }
@@ -293,7 +294,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
293
294
  });
294
295
  };
295
296
 
296
- const setNextMode = useCallback(() => {
297
+ const setNextMode = () => {
297
298
  if (currentView === "details") {
298
299
  if (importConfig.inUse) {
299
300
  setCurrentView("import_data_saving");
@@ -314,14 +315,14 @@ function CollectionEditorInternal<M extends Record<string, any>>({
314
315
  setCurrentView("details");
315
316
  }
316
317
 
317
- }, [currentView, importConfig.inUse, extraView]);
318
+ };
318
319
 
319
- const doCollectionInference = useCallback((collection: PersistedCollection<any>) => {
320
+ const doCollectionInference = (collection: PersistedCollection<any>) => {
320
321
  if (!collectionInference) return undefined;
321
322
  return collectionInference?.(collection.path, collection.collectionGroup ?? false, parentCollectionIds ?? []);
322
- }, [collectionInference, parentCollectionIds]);
323
+ };
323
324
 
324
- const inferCollectionFromData = useCallback(async (newCollection: PersistedCollection<M>) => {
325
+ const inferCollectionFromData = async (newCollection: PersistedCollection<M>) => {
325
326
 
326
327
  try {
327
328
  if (!doCollectionInference) {
@@ -365,10 +366,10 @@ function CollectionEditorInternal<M extends Record<string, any>>({
365
366
  });
366
367
  return newCollection;
367
368
  }
368
- }, [parentCollectionIds, doCollectionInference]);
369
+ };
369
370
 
370
371
  const onSubmit = (newCollectionState: PersistedCollection<M>, formexController: FormexController<PersistedCollection<M>>) => {
371
- console.log("Submitting collection", newCollectionState);
372
+ console.debug("Submitting collection", newCollectionState);
372
373
  try {
373
374
 
374
375
  if (!isNewCollection) {
@@ -486,19 +487,23 @@ function CollectionEditorInternal<M extends Record<string, any>>({
486
487
  setFormDirty(dirty);
487
488
  }, [dirty]);
488
489
 
489
- function onImportDataSet(data: object[]) {
490
+ function onImportDataSet(data: object[], propertiesOrder?: string[]) {
490
491
  importConfig.setInUse(true);
491
492
  buildEntityPropertiesFromData(data, getInferenceType)
492
493
  .then((properties) => {
493
494
  const res = cleanPropertiesFromImport(properties);
494
495
 
495
- setFieldValue("properties", res.properties);
496
- setFieldValue("propertiesOrder", Object.keys(res.properties));
497
-
498
496
  importConfig.setIdColumn(res.idColumn);
499
497
  importConfig.setImportData(data);
500
498
  importConfig.setHeadersMapping(res.headersMapping);
499
+ const filteredHeadingsOrder = ((propertiesOrder ?? [])
500
+ .filter((key) => res.headersMapping[key]) as string[]) ?? Object.keys(res.properties);
501
+ importConfig.setHeadingsOrder(filteredHeadingsOrder);
501
502
  importConfig.setOriginProperties(res.properties);
503
+
504
+ const mappedHeadings = (propertiesOrder ?? []).map((key) => res.headersMapping[key]).filter(Boolean) as string[] ?? Object.keys(res.properties);
505
+ setFieldValue("properties", res.properties);
506
+ setFieldValue("propertiesOrder", mappedHeadings);
502
507
  });
503
508
  }
504
509
 
@@ -521,7 +526,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
521
526
 
522
527
  <>
523
528
  {!isNewCollection && <Tabs value={currentView}
524
- className={cn(defaultBorderMixin, "justify-end bg-gray-50 dark:bg-gray-950 border-b")}
529
+ className={cls(defaultBorderMixin, "justify-end bg-gray-50 dark:bg-gray-950 border-b")}
525
530
  onValueChange={(v) => setCurrentView(v as EditorView)}>
526
531
  <Tab value={"details"}>
527
532
  Details
@@ -536,7 +541,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
536
541
 
537
542
  <form noValidate
538
543
  onSubmit={formController.handleSubmit}
539
- className={cn(
544
+ className={cls(
540
545
  isNewCollection ? "h-full" : "h-[calc(100%-48px)]",
541
546
  "flex-grow flex flex-col relative")}>
542
547
 
@@ -551,9 +556,10 @@ function CollectionEditorInternal<M extends Record<string, any>>({
551
556
  {currentView === "welcome" &&
552
557
  <CollectionEditorWelcomeView
553
558
  path={path}
554
- onContinue={(importData) => {
559
+ onContinue={(importData, propertiesOrder) => {
560
+ // console.log("Import data", importData, propertiesOrder)
555
561
  if (importData) {
556
- onImportDataSet(importData);
562
+ onImportDataSet(importData, propertiesOrder);
557
563
  setCurrentView("import_data_mapping");
558
564
  } else {
559
565
  setCurrentView("details");
@@ -733,7 +739,10 @@ function CollectionEditorInternal<M extends Record<string, any>>({
733
739
  }
734
740
 
735
741
  function applyPropertyConfigs<M extends Record<string, any> = any>(collection: PersistedCollection<M>, propertyConfigs: Record<string, PropertyConfig<any>>): PersistedCollection<M> {
736
- const { properties, ...rest } = collection;
742
+ const {
743
+ properties,
744
+ ...rest
745
+ } = collection;
737
746
  const propertiesResult: PropertiesOrBuilders<any> = {};
738
747
  if (properties) {
739
748
  Object.keys(properties).forEach((key) => {
@@ -741,7 +750,10 @@ function applyPropertyConfigs<M extends Record<string, any> = any>(collection: P
741
750
  });
742
751
  }
743
752
 
744
- return { ...rest, properties: propertiesResult };
753
+ return {
754
+ ...rest,
755
+ properties: propertiesResult
756
+ };
745
757
  }
746
758
 
747
759
  function applyPropertiesConfig(property: PropertyOrBuilder, propertyConfigs: Record<string, PropertyConfig<any>>) {
@@ -761,7 +773,10 @@ function applyPropertiesConfig(property: PropertyOrBuilder, propertyConfigs: Rec
761
773
  Object.keys(internalProperty.properties).forEach((key) => {
762
774
  properties[key] = applyPropertiesConfig(((internalProperty as MapProperty).properties as Properties)[key] as Property, propertyConfigs);
763
775
  });
764
- internalProperty = { ...internalProperty, properties };
776
+ internalProperty = {
777
+ ...internalProperty,
778
+ properties
779
+ };
765
780
  }
766
781
 
767
782
  }
@@ -1,6 +1,6 @@
1
1
  import React, { useEffect, useState } from "react";
2
2
  import { EntityCollection, unslugify, } from "@firecms/core";
3
- import { Button, Card, Chip, CircularProgress, cn, Container, Icon, Tooltip, Typography, } from "@firecms/ui";
3
+ import { Button, Card, Chip, CircularProgress, cls, Container, Icon, Tooltip, Typography, } from "@firecms/ui";
4
4
 
5
5
  import { productsCollectionTemplate } from "./templates/products_template";
6
6
  import { blogCollectionTemplate } from "./templates/blog_template";
@@ -19,7 +19,7 @@ export function CollectionEditorWelcomeView({
19
19
  path: string;
20
20
  pathSuggestions?: (path: string) => Promise<string[]>;
21
21
  parentCollection?: EntityCollection;
22
- onContinue: (importData?: object[]) => void;
22
+ onContinue: (importData?: object[], propertiesOrder?: string[]) => void;
23
23
  existingCollectionPaths?: string[];
24
24
  }) {
25
25
 
@@ -154,7 +154,7 @@ export function CollectionEditorWelcomeView({
154
154
  ● Create a collection from a file (csv, json, xls, xslx...)
155
155
  </Typography>
156
156
 
157
- <ImportFileUpload onDataAdded={(data) => onContinue(data)}/>
157
+ <ImportFileUpload onDataAdded={(data, propertiesOrder) => onContinue(data, propertiesOrder)}/>
158
158
 
159
159
  </div>}
160
160
 
@@ -188,7 +188,7 @@ export function TemplateButton({
188
188
  <Tooltip title={subtitle}>
189
189
  <Card
190
190
  onClick={onClick}
191
- className={cn(
191
+ className={cls(
192
192
  "my-2 rounded-md border mx-0 p-6 px-4 focus:outline-none transition ease-in-out duration-150 flex flex-row gap-4 items-center",
193
193
  "text-gray-700 dark:text-slate-300",
194
194
  "hover:border-primary-dark hover:text-primary-dark dark:hover:text-primary focus:ring-primary hover:ring-1 hover:ring-primary",
@@ -1,4 +1,4 @@
1
- import React, { useCallback, useEffect, useMemo, useState } from "react";
1
+ import React, { useEffect, useMemo, useState } from "react";
2
2
 
3
3
  import { Field, getIn, useFormex } from "@firecms/formex";
4
4
  import {
@@ -19,7 +19,7 @@ import {
19
19
  AutoAwesomeIcon,
20
20
  Button,
21
21
  CircularProgress,
22
- cn,
22
+ cls,
23
23
  CodeIcon,
24
24
  DebouncedTextField,
25
25
  defaultBorderMixin,
@@ -43,7 +43,7 @@ type CollectionEditorFormProps = {
43
43
  setDirty?: (dirty: boolean) => void;
44
44
  reservedGroups?: string[];
45
45
  extraIcon: React.ReactNode;
46
- getUser: (uid: string) => User | null;
46
+ getUser?: (uid: string) => User | null;
47
47
  getData?: () => Promise<object[]>;
48
48
  doCollectionInference: (collection: PersistedCollection) => Promise<Partial<EntityCollection> | null> | undefined;
49
49
  propertyConfigs: Record<string, PropertyConfig>;
@@ -158,20 +158,20 @@ export function CollectionPropertiesEditorForm({
158
158
  }
159
159
  : undefined;
160
160
 
161
- const getCurrentPropertiesOrder = useCallback((namespace?: string) => {
162
- if (!namespace) return currentPropertiesOrderRef.current[""];
161
+ const getCurrentPropertiesOrder = (namespace?: string) => {
162
+ if (!namespace) return currentPropertiesOrderRef.current[""] ?? getIn(values, namespaceToPropertiesOrderPath());
163
163
  return currentPropertiesOrderRef.current[namespace] ?? getIn(values, namespaceToPropertiesOrderPath(namespace));
164
- }, [values]);
164
+ };
165
165
 
166
- const updatePropertiesOrder = useCallback((newPropertiesOrder: string[], namespace?: string) => {
166
+ const updatePropertiesOrder = (newPropertiesOrder: string[], namespace?: string) => {
167
167
  const propertiesOrderPath = namespaceToPropertiesOrderPath(namespace);
168
168
 
169
169
  setFieldValue(propertiesOrderPath, newPropertiesOrder, false);
170
170
  currentPropertiesOrderRef.current[namespace ?? ""] = newPropertiesOrder;
171
171
 
172
- }, [setFieldValue]);
172
+ };
173
173
 
174
- const deleteProperty = useCallback((propertyKey?: string, namespace?: string) => {
174
+ const deleteProperty = (propertyKey?: string, namespace?: string) => {
175
175
  const fullId = propertyKey ? getFullId(propertyKey, namespace) : undefined;
176
176
  if (!fullId)
177
177
  throw Error("collection editor miss config");
@@ -179,15 +179,17 @@ export function CollectionPropertiesEditorForm({
179
179
  setFieldValue(idToPropertiesPath(fullId), undefined, false);
180
180
 
181
181
  const currentPropertiesOrder = getCurrentPropertiesOrder(namespace);
182
- const newPropertiesOrder = currentPropertiesOrder.filter((p) => p !== propertyKey);
183
- updatePropertiesOrder(newPropertiesOrder, namespace);
182
+ if (currentPropertiesOrder) {
183
+ const newPropertiesOrder = currentPropertiesOrder.filter((p) => p !== propertyKey);
184
+ updatePropertiesOrder(newPropertiesOrder, namespace);
185
+ }
184
186
 
185
187
  setNewPropertyDialogOpen(false);
186
188
 
187
189
  setSelectedPropertyIndex(undefined);
188
190
  setSelectedPropertyKey(undefined);
189
191
  setSelectedPropertyNamespace(undefined);
190
- }, [getCurrentPropertiesOrder, setFieldValue, updatePropertiesOrder]);
192
+ };
191
193
 
192
194
  const onPropertyMove = (propertiesOrder: string[], namespace?: string) => {
193
195
  setFieldValue(namespaceToPropertiesOrderPath(namespace), propertiesOrder, false);
@@ -207,8 +209,8 @@ export function CollectionPropertiesEditorForm({
207
209
  ...(values.properties ?? {}),
208
210
  [id]: property
209
211
  }, false);
210
- const newPropertiesOrder = [...(values.propertiesOrder ?? Object.keys(values.properties)), id];
211
212
 
213
+ const newPropertiesOrder = [...(values.propertiesOrder ?? Object.keys(values.properties)), id];
212
214
  updatePropertiesOrder(newPropertiesOrder);
213
215
 
214
216
  setNewPropertyDialogOpen(false);
@@ -273,7 +275,7 @@ export function CollectionPropertiesEditorForm({
273
275
 
274
276
  };
275
277
 
276
- const onPropertyErrorInternal = useCallback((id: string, namespace?: string, error?: Record<string, any>) => {
278
+ const onPropertyErrorInternal = (id: string, namespace?: string, error?: Record<string, any>) => {
277
279
  const propertyPath = id ? getFullId(id, namespace) : undefined;
278
280
  console.debug("onPropertyErrorInternal", {
279
281
  id,
@@ -286,7 +288,7 @@ export function CollectionPropertiesEditorForm({
286
288
  onPropertyError(id, namespace, hasError ? error : undefined);
287
289
  setFieldError(idToPropertiesPath(propertyPath), hasError ? "Property error" : undefined);
288
290
  }
289
- }, [])
291
+ }
290
292
 
291
293
  const closePropertyDialog = () => {
292
294
  setSelectedPropertyIndex(undefined);
@@ -301,9 +303,9 @@ export function CollectionPropertiesEditorForm({
301
303
  ? values.propertiesOrder
302
304
  : Object.keys(values.properties)) as string[];
303
305
 
304
- const owner = useMemo(() => values.ownerId ? getUser(values.ownerId) : null, [getUser, values.ownerId]);
306
+ const owner = useMemo(() => values.ownerId && getUser ? getUser(values.ownerId) : null, [getUser, values.ownerId]);
305
307
 
306
- const onPropertyClick = useCallback((propertyKey: string, namespace?: string) => {
308
+ const onPropertyClick = (propertyKey: string, namespace?: string) => {
307
309
  console.debug("CollectionEditor: onPropertyClick", {
308
310
  propertyKey,
309
311
  namespace
@@ -311,11 +313,11 @@ export function CollectionPropertiesEditorForm({
311
313
  setSelectedPropertyIndex(usedPropertiesOrder.indexOf(propertyKey));
312
314
  setSelectedPropertyKey(propertyKey);
313
315
  setSelectedPropertyNamespace(namespace);
314
- }, [usedPropertiesOrder]);
316
+ };
315
317
 
316
318
  const body = (
317
319
  <div className={"grid grid-cols-12 gap-2 h-full bg-gray-50 dark:bg-gray-900"}>
318
- <div className={cn(
320
+ <div className={cls(
319
321
  "p-4 md:p-8 pb-20 md:pb-20",
320
322
  "col-span-12 lg:col-span-5 h-full overflow-auto",
321
323
  !asDialog && "border-r " + defaultBorderMixin
@@ -17,7 +17,7 @@ import {
17
17
  } from "@firecms/core";
18
18
  import {
19
19
  Button,
20
- cn,
20
+ cls,
21
21
  DeleteIcon,
22
22
  Dialog,
23
23
  DialogActions,
@@ -228,6 +228,7 @@ export const PropertyForm = React.memo(
228
228
  a.includeIdAndName === b.includeIdAndName &&
229
229
  a.autoOpenTypeSelect === b.autoOpenTypeSelect &&
230
230
  a.autoUpdateId === b.autoUpdateId &&
231
+ a.existingPropertyKeys === b.existingPropertyKeys &&
231
232
  a.existingProperty === b.existingProperty
232
233
  );
233
234
 
@@ -367,13 +368,13 @@ function PropertyEditFormFields({
367
368
  }
368
369
  }
369
370
  }
370
- }, [deferredValues, includeIdAndTitle, onPropertyChanged, propertyNamespace]);
371
+ }, [deferredValues, includeIdAndTitle, propertyNamespace]);
371
372
 
372
373
  useEffect(() => {
373
374
  if (values?.id && onError) {
374
375
  onError(values?.id, propertyNamespace, errors);
375
376
  }
376
- }, [errors, onError, propertyNamespace, values?.id]);
377
+ }, [errors, propertyNamespace, values?.id]);
377
378
 
378
379
  const onWidgetSelectChanged = (newSelectedWidgetId: PropertyConfigId) => {
379
380
  setSelectedFieldConfigId(newSelectedWidgetId);
@@ -508,7 +509,7 @@ function PropertyEditFormFields({
508
509
  e.preventDefault();
509
510
  }
510
511
  }}
511
- className={cn(
512
+ className={cls(
512
513
  "flex items-center",
513
514
  optionDisabled ? "w-full pointer-events-none opacity-50" : "")}>
514
515
  <div className={"mr-8"}>
@@ -11,7 +11,7 @@ import {
11
11
  cardClickableMixin,
12
12
  cardMixin,
13
13
  cardSelectedMixin,
14
- cn,
14
+ cls,
15
15
  FunctionsIcon,
16
16
  Paper,
17
17
  RemoveCircleIcon,
@@ -45,9 +45,6 @@ export function PropertyFieldPreview({
45
45
  ? "border-red-500 dark:border-red-500 border-opacity-100 dark:border-opacity-100 ring-0 dark:ring-0"
46
46
  : (selected ? "border-primary" : "border-transparent");
47
47
 
48
- if(hasError)
49
- console.log("PropertyFieldPreview", property)
50
-
51
48
  return <ErrorBoundary>
52
49
  <div
53
50
  onClick={onClick}
@@ -56,7 +53,7 @@ export function PropertyFieldPreview({
56
53
  <PropertyConfigBadge propertyConfig={propertyConfig}/>
57
54
  </div>
58
55
  <Paper
59
- className={cn(
56
+ className={cls(
60
57
  "border",
61
58
  "pl-2 w-full flex flex-row gap-4 items-center",
62
59
  cardMixin,
@@ -139,7 +136,7 @@ export function NonEditablePropertyPreview({
139
136
  <RemoveCircleIcon color={"disabled"} size={"small"} className={"absolute -right-2 -top-2"}/>
140
137
  </div>
141
138
  <Paper
142
- className={cn(
139
+ className={cls(
143
140
  "pl-2 w-full flex flex-row gap-4 items-center",
144
141
  cardMixin,
145
142
  onClick ? cardClickableMixin : "",
@@ -1,5 +1,5 @@
1
1
  import { PropertyConfigBadge, PropertyConfig } from "@firecms/core";
2
- import { cn, SelectItem, Typography } from "@firecms/ui";
2
+ import { cls, SelectItem, Typography } from "@firecms/ui";
3
3
 
4
4
  export interface PropertySelectItemProps {
5
5
  value: string;
@@ -13,7 +13,7 @@ export function PropertySelectItem({ value, optionDisabled, propertyConfig, exis
13
13
  disabled={optionDisabled}
14
14
  className={"flex flex-row items-center"}>
15
15
  <div
16
- className={cn(
16
+ className={cls(
17
17
  "flex flex-row items-center text-base min-h-[52px]",
18
18
  optionDisabled ? "w-full" : "")}>
19
19
  <div className={"mr-8"}>
@@ -1,4 +1,4 @@
1
- import React, { useCallback } from "react";
1
+ import React from "react";
2
2
  import equal from "react-fast-compare"
3
3
 
4
4
  import {
@@ -48,7 +48,7 @@ export const PropertyTree = React.memo(
48
48
 
49
49
  const propertiesOrder = propertiesOrderProp ?? Object.keys(properties);
50
50
 
51
- const onDragEnd = useCallback((result: any) => {
51
+ const onDragEnd = (result: any) => {
52
52
  // dropped outside the list
53
53
  if (!result.destination) {
54
54
  return;
@@ -61,7 +61,7 @@ export const PropertyTree = React.memo(
61
61
  newPropertiesOrder.splice(endIndex, 0, removed);
62
62
  if (onPropertyMove)
63
63
  onPropertyMove(newPropertiesOrder, namespace);
64
- }, [namespace, onPropertyMove, propertiesOrder])
64
+ }
65
65
 
66
66
  return (
67
67
  <>
@@ -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
 
@@ -1,21 +1,33 @@
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_export";
2
+ import { CircularProgressCenter, EntityCollectionTable, Properties, useSelectionController } from "@firecms/core";
3
+ import { useEffect, useState } from "react";
4
4
  import { Typography } from "@firecms/ui";
5
5
 
6
- export function CollectionEditorImportDataPreview({ importConfig, properties, propertiesOrder }: {
6
+ export function CollectionEditorImportDataPreview({
7
+ importConfig,
8
+ properties,
9
+ propertiesOrder
10
+ }: {
7
11
  importConfig: ImportConfig,
8
12
  properties: Properties,
9
13
  propertiesOrder: string[]
10
14
  }) {
11
15
 
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"));
16
+ const [loading, setLoading] = useState<boolean>(false);
17
+
18
+ async function loadEntities() {
19
+ // const propertiesMapping = getPropertiesMapping(importConfig.originProperties, properties, importConfig.headersMapping);
20
+ const mappedData = importConfig.importData.map(d => convertDataToEntity(d, importConfig.idColumn, importConfig.headersMapping, properties, "TEMP_PATH", importConfig.defaultValues));
15
21
  importConfig.setEntities(mappedData);
22
+ }
23
+
24
+ useEffect(() => {
25
+ loadEntities().finally(() => setLoading(false));
16
26
  }, []);
17
27
 
18
28
  const selectionController = useSelectionController();
29
+ if (loading)
30
+ return <CircularProgressCenter/>
19
31
 
20
32
  return <EntityCollectionTable
21
33
  title={<div>
@@ -31,7 +43,11 @@ export function CollectionEditorImportDataPreview({ importConfig, properties, pr
31
43
  filterable={false}
32
44
  sortable={false}
33
45
  selectionController={selectionController}
34
- displayedColumnIds={propertiesOrder.map(p => ({ key: p, disabled: false }))}
35
- properties={properties}/>
46
+ displayedColumnIds={propertiesOrder.map(p => ({
47
+ key: p,
48
+ disabled: false
49
+ }))}
50
+ properties={properties}
51
+ enablePopupIcon={false}/>
36
52
 
37
53
  }
@@ -6,7 +6,7 @@ import {
6
6
  } from "@firecms/data_import_export";
7
7
  import { getIn, useFormex } from "@firecms/formex";
8
8
 
9
- import { PropertyConfigBadge, getFieldConfig, getFieldId, Properties, Property, PropertyConfig, } from "@firecms/core";
9
+ import { getFieldConfig, getFieldId, Properties, Property, PropertyConfig, PropertyConfigBadge, } from "@firecms/core";
10
10
  import { Container, Select, Tooltip, Typography } from "@firecms/ui";
11
11
  import React, { useState } from "react";
12
12
  import { OnPropertyChangedParams, PropertyFormDialog, PropertyWithId } from "../PropertyEditView";
@@ -143,18 +143,20 @@ export function CollectionEditorImportMapping({
143
143
  <div className={"overflow-auto my-auto"}>
144
144
  <Container maxWidth={"6xl"} className={"flex flex-col gap-4 p-8 m-auto"}>
145
145
 
146
- <Typography variant="h6" className={"mt-4"}>Data property mapping</Typography>
146
+ <Typography variant="h6" className={"my-4 ml-3.5"}>Data property mapping</Typography>
147
147
 
148
- <DataNewPropertiesMapping headersMapping={importConfig.headersMapping}
149
- idColumn={importConfig.idColumn}
150
- originProperties={importConfig.originProperties}
148
+ <DataNewPropertiesMapping importConfig={importConfig}
151
149
  destinationProperties={values.properties as Properties}
152
- onIdPropertyChanged={(value) => importConfig.setIdColumn(value ?? undefined)}
153
150
  buildPropertyView={({
154
151
  property,
155
152
  propertyKey,
156
- importKey
153
+ importKey,
154
+ isIdColumn
157
155
  }) => {
156
+ if (isIdColumn) {
157
+ return <Typography> This column will be used as ID</Typography>
158
+ }
159
+
158
160
  return <ImportNewPropertyFieldPreview
159
161
  property={property}
160
162
  propertyKey={propertyKey}