@firecms/collection_editor 3.0.0-canary.20 → 3.0.0-canary.201

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 (74) hide show
  1. package/LICENSE +114 -21
  2. package/dist/ConfigControllerProvider.d.ts +2 -2
  3. package/dist/index.d.ts +1 -0
  4. package/dist/index.es.js +10061 -4770
  5. package/dist/index.es.js.map +1 -1
  6. package/dist/index.umd.js +10751 -3
  7. package/dist/index.umd.js.map +1 -1
  8. package/dist/types/collection_editor_controller.d.ts +4 -2
  9. package/dist/types/collection_inference.d.ts +1 -1
  10. package/dist/types/config_permissions.d.ts +2 -2
  11. package/dist/types/persisted_collection.d.ts +1 -1
  12. package/dist/ui/CollectionViewHeaderAction.d.ts +3 -2
  13. package/dist/ui/EditorCollectionActionStart.d.ts +2 -0
  14. package/dist/ui/PropertyAddColumnComponent.d.ts +3 -1
  15. package/dist/ui/collection_editor/CollectionDetailsForm.d.ts +3 -1
  16. package/dist/ui/collection_editor/CollectionEditorDialog.d.ts +3 -2
  17. package/dist/ui/collection_editor/CollectionEditorWelcomeView.d.ts +1 -1
  18. package/dist/ui/collection_editor/CollectionPropertiesEditorForm.d.ts +1 -1
  19. package/dist/ui/collection_editor/LayoutModeSwitch.d.ts +5 -0
  20. package/dist/ui/collection_editor/PropertyEditView.d.ts +8 -0
  21. package/dist/ui/collection_editor/PropertyTree.d.ts +9 -9
  22. package/dist/ui/collection_editor/SubcollectionsEditTab.d.ts +1 -1
  23. package/dist/ui/collection_editor/import/CollectionEditorImportMapping.d.ts +7 -0
  24. package/dist/ui/collection_editor/properties/MarkdownPropertyField.d.ts +4 -0
  25. package/dist/ui/collection_editor/properties/StringPropertyField.d.ts +1 -1
  26. package/dist/useCollectionEditorPlugin.d.ts +8 -11
  27. package/dist/utils/collections.d.ts +6 -0
  28. package/package.json +24 -35
  29. package/src/ConfigControllerProvider.tsx +67 -64
  30. package/src/index.ts +1 -0
  31. package/src/types/collection_editor_controller.tsx +7 -4
  32. package/src/types/collection_inference.ts +1 -1
  33. package/src/types/config_permissions.ts +1 -1
  34. package/src/types/persisted_collection.ts +2 -3
  35. package/src/ui/CollectionViewHeaderAction.tsx +10 -5
  36. package/src/ui/EditorCollectionAction.tsx +10 -63
  37. package/src/ui/EditorCollectionActionStart.tsx +88 -0
  38. package/src/ui/HomePageEditorCollectionAction.tsx +19 -13
  39. package/src/ui/NewCollectionButton.tsx +1 -1
  40. package/src/ui/NewCollectionCard.tsx +3 -3
  41. package/src/ui/PropertyAddColumnComponent.tsx +11 -6
  42. package/src/ui/collection_editor/CollectionDetailsForm.tsx +88 -11
  43. package/src/ui/collection_editor/CollectionEditorDialog.tsx +101 -34
  44. package/src/ui/collection_editor/CollectionEditorWelcomeView.tsx +8 -7
  45. package/src/ui/collection_editor/CollectionPropertiesEditorForm.tsx +39 -36
  46. package/src/ui/collection_editor/EntityCustomViewsSelectDialog.tsx +6 -5
  47. package/src/ui/collection_editor/EnumForm.tsx +10 -6
  48. package/src/ui/collection_editor/GetCodeDialog.tsx +56 -26
  49. package/src/ui/collection_editor/LayoutModeSwitch.tsx +54 -0
  50. package/src/ui/collection_editor/PropertyEditView.tsx +257 -79
  51. package/src/ui/collection_editor/PropertyFieldPreview.tsx +7 -10
  52. package/src/ui/collection_editor/PropertyTree.tsx +9 -7
  53. package/src/ui/collection_editor/SubcollectionsEditTab.tsx +26 -19
  54. package/src/ui/collection_editor/UnsavedChangesDialog.tsx +3 -5
  55. package/src/ui/collection_editor/import/CollectionEditorImportDataPreview.tsx +26 -9
  56. package/src/ui/collection_editor/import/CollectionEditorImportMapping.tsx +42 -9
  57. package/src/ui/collection_editor/properties/BlockPropertyField.tsx +32 -20
  58. package/src/ui/collection_editor/properties/DateTimePropertyField.tsx +54 -47
  59. package/src/ui/collection_editor/properties/EnumPropertyField.tsx +3 -1
  60. package/src/ui/collection_editor/properties/MapPropertyField.tsx +7 -6
  61. package/src/ui/collection_editor/properties/MarkdownPropertyField.tsx +139 -0
  62. package/src/ui/collection_editor/properties/ReferencePropertyField.tsx +2 -0
  63. package/src/ui/collection_editor/properties/RepeatPropertyField.tsx +0 -1
  64. package/src/ui/collection_editor/properties/StoragePropertyField.tsx +34 -19
  65. package/src/ui/collection_editor/properties/StringPropertyField.tsx +1 -10
  66. package/src/ui/collection_editor/properties/UrlPropertyField.tsx +1 -0
  67. package/src/ui/collection_editor/properties/validation/ValidationPanel.tsx +2 -2
  68. package/src/ui/collection_editor/templates/pages_template.ts +1 -6
  69. package/src/useCollectionEditorPlugin.tsx +33 -32
  70. package/src/utils/collections.ts +36 -0
  71. package/dist/ui/RootCollectionSuggestions.d.ts +0 -3
  72. package/dist/ui/collection_editor/PropertySelectItem.d.ts +0 -8
  73. package/src/ui/RootCollectionSuggestions.tsx +0 -63
  74. package/src/ui/collection_editor/PropertySelectItem.tsx +0 -32
@@ -3,29 +3,36 @@ import equal from "react-fast-compare"
3
3
 
4
4
  import { Formex, FormexController, getIn, useCreateFormex } from "@firecms/formex";
5
5
  import {
6
+ ConfirmationDialog,
6
7
  DEFAULT_FIELD_CONFIGS,
7
- DeleteConfirmationDialog,
8
- PropertyConfigId,
9
8
  getFieldConfig,
10
9
  getFieldId,
10
+ isEmptyObject,
11
11
  isPropertyBuilder,
12
12
  isValidRegExp,
13
13
  mergeDeep,
14
14
  Property,
15
15
  PropertyConfig,
16
16
  PropertyConfigBadge,
17
+ PropertyConfigId,
17
18
  } from "@firecms/core";
18
19
  import {
19
20
  Button,
20
- cn,
21
+ Card,
22
+ cls,
21
23
  DeleteIcon,
22
24
  Dialog,
23
25
  DialogActions,
24
26
  DialogContent,
27
+ DialogTitle,
28
+ fieldBackgroundDisabledMixin,
29
+ fieldBackgroundHoverMixin,
30
+ fieldBackgroundMixin,
25
31
  IconButton,
26
32
  InfoLabel,
27
- Select,
28
- Typography
33
+ Tooltip,
34
+ Typography,
35
+ WarningIcon
29
36
  } from "@firecms/ui";
30
37
  import { EnumPropertyField } from "./properties/EnumPropertyField";
31
38
  import { StoragePropertyField } from "./properties/StoragePropertyField";
@@ -42,9 +49,9 @@ import { AdvancedPropertyValidation } from "./properties/advanced/AdvancedProper
42
49
  import { editableProperty } from "../../utils/entities";
43
50
  import { KeyValuePropertyField } from "./properties/KeyValuePropertyField";
44
51
  import { updatePropertyFromWidget } from "./utils/update_property_for_widget";
45
- import { PropertySelectItem } from "./PropertySelectItem";
46
52
  import { UrlPropertyField } from "./properties/UrlPropertyField";
47
53
  import { supportedFields } from "./utils/supported_fields";
54
+ import { MarkdownPropertyField } from "./properties/MarkdownPropertyField";
48
55
 
49
56
  export type PropertyWithId = Property & {
50
57
  id?: string
@@ -68,6 +75,7 @@ export type PropertyFormProps = {
68
75
  property?: Property;
69
76
  onPropertyChanged?: (params: OnPropertyChangedParams) => void;
70
77
  onPropertyChangedImmediate?: boolean;
78
+ onDismiss?: () => void;
71
79
  onDelete?: (id?: string, namespace?: string) => void;
72
80
  onError?: (id: string, namespace?: string, error?: Record<string, any>) => void;
73
81
  initialErrors?: Record<string, any>;
@@ -95,6 +103,7 @@ export const PropertyForm = React.memo(
95
103
  property,
96
104
  onPropertyChanged,
97
105
  onPropertyChangedImmediate = true,
106
+ onDismiss,
98
107
  onDelete,
99
108
  onError,
100
109
  initialErrors,
@@ -134,6 +143,7 @@ export const PropertyForm = React.memo(
134
143
  };
135
144
 
136
145
  const formexController = useCreateFormex<PropertyWithId>({
146
+ debugId: "PROPERTY_FORM",
137
147
  initialValues: property
138
148
  ? { id: propertyKey, ...property } as PropertyWithId
139
149
  : initialValue,
@@ -148,7 +158,10 @@ export const PropertyForm = React.memo(
148
158
  } = newPropertyWithId;
149
159
  doOnPropertyChanged({
150
160
  id,
151
- property: { ...property, editable: property.editable ?? true }
161
+ property: {
162
+ ...property,
163
+ editable: property.editable ?? true
164
+ }
152
165
  });
153
166
  if (!existingProperty)
154
167
  controller.resetForm({ values: initialValue });
@@ -209,6 +222,7 @@ export const PropertyForm = React.memo(
209
222
  includeIdAndTitle={includeIdAndName}
210
223
  propertyNamespace={propertyNamespace}
211
224
  onError={onError}
225
+ onDismiss={onDismiss}
212
226
  showErrors={forceShowErrors || formexController.submitCount > 0}
213
227
  existing={existingProperty}
214
228
  autoUpdateId={autoUpdateId}
@@ -228,6 +242,7 @@ export const PropertyForm = React.memo(
228
242
  a.includeIdAndName === b.includeIdAndName &&
229
243
  a.autoOpenTypeSelect === b.autoOpenTypeSelect &&
230
244
  a.autoUpdateId === b.autoUpdateId &&
245
+ a.existingPropertyKeys === b.existingPropertyKeys &&
231
246
  a.existingProperty === b.existingProperty
232
247
  );
233
248
 
@@ -261,8 +276,11 @@ export function PropertyFormDialog({
261
276
  e.stopPropagation();
262
277
  formexRef.current?.handleSubmit(e)
263
278
  }}>
279
+ <DialogTitle hidden>Property edit view</DialogTitle>
264
280
  <DialogContent>
281
+
265
282
  <PropertyForm {...formProps}
283
+ onDismiss={onCancel}
266
284
  onPropertyChanged={(params) => {
267
285
  onPropertyChanged?.(params);
268
286
  onOkClicked?.();
@@ -307,6 +325,7 @@ function PropertyEditFormFields({
307
325
  onPropertyChanged,
308
326
  onDelete,
309
327
  propertyNamespace,
328
+ onDismiss,
310
329
  onError,
311
330
  showErrors,
312
331
  disabled,
@@ -321,6 +340,7 @@ function PropertyEditFormFields({
321
340
  autoUpdateId?: boolean;
322
341
  autoOpenTypeSelect: boolean;
323
342
  propertyNamespace?: string;
343
+ onDismiss?: () => void;
324
344
  onPropertyChanged?: (params: OnPropertyChangedParams) => void;
325
345
  onDelete?: (id?: string, namespace?: string) => void;
326
346
  onError?: (id: string, namespace?: string, error?: Record<string, any>) => void;
@@ -337,12 +357,6 @@ function PropertyEditFormFields({
337
357
  const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
338
358
  const [selectedFieldConfigId, setSelectedFieldConfigId] = useState<string | undefined>(values?.dataType ? getFieldId(values) : undefined);
339
359
 
340
- const allSupportedFields = Object.entries(supportedFields).concat(Object.entries(propertyConfigs));
341
-
342
- const displayedWidgets = inArray
343
- ? allSupportedFields.filter(([_, propertyConfig]) => !isPropertyBuilder(propertyConfig.property) && propertyConfig.property?.dataType !== "array")
344
- : allSupportedFields;
345
-
346
360
  const deferredValues = useDeferredValue(values);
347
361
  const nameFieldRef = useRef<HTMLInputElement>(null);
348
362
 
@@ -367,13 +381,13 @@ function PropertyEditFormFields({
367
381
  }
368
382
  }
369
383
  }
370
- }, [deferredValues, includeIdAndTitle, onPropertyChanged, propertyNamespace]);
384
+ }, [deferredValues, includeIdAndTitle, propertyNamespace]);
371
385
 
372
386
  useEffect(() => {
373
- if (values?.id && onError) {
387
+ if (values?.id && onError && !isEmptyObject(errors)) {
374
388
  onError(values?.id, propertyNamespace, errors);
375
389
  }
376
- }, [errors, onError, propertyNamespace, values?.id]);
390
+ }, [errors, propertyNamespace, values?.id]);
377
391
 
378
392
  const onWidgetSelectChanged = (newSelectedWidgetId: PropertyConfigId) => {
379
393
  setSelectedFieldConfigId(newSelectedWidgetId);
@@ -387,7 +401,6 @@ function PropertyEditFormFields({
387
401
  let childComponent;
388
402
  if (selectedFieldConfigId === "text_field" ||
389
403
  selectedFieldConfigId === "multiline" ||
390
- selectedFieldConfigId === "markdown" ||
391
404
  selectedFieldConfigId === "email") {
392
405
  childComponent =
393
406
  <StringPropertyField widgetId={selectedFieldConfigId}
@@ -397,6 +410,10 @@ function PropertyEditFormFields({
397
410
  childComponent =
398
411
  <UrlPropertyField disabled={disabled}
399
412
  showErrors={showErrors}/>;
413
+ } else if (selectedFieldConfigId === "markdown") {
414
+ childComponent =
415
+ <MarkdownPropertyField disabled={disabled}
416
+ showErrors={showErrors}/>;
400
417
  } else if (selectedFieldConfigId === "select" ||
401
418
  selectedFieldConfigId === "number_select") {
402
419
  childComponent = <EnumPropertyField
@@ -481,62 +498,22 @@ function PropertyEditFormFields({
481
498
 
482
499
  <div className="flex mt-2 justify-between">
483
500
  <div className={"w-full flex flex-col gap-2"}>
484
- <Select
485
- // className={"w-full"}
486
- error={Boolean(selectedWidgetError)}
487
- value={selectedFieldConfigId ?? ""}
488
- placeholder={"Select a property widget"}
501
+ <WidgetSelectView
502
+ initialProperty={values}
503
+ value={selectedFieldConfigId as PropertyConfigId}
504
+ onValueChange={(value) => onWidgetSelectChanged(value as PropertyConfigId)}
489
505
  open={selectOpen}
490
- onOpenChange={setSelectOpen}
491
- position={"item-aligned"}
492
- disabled={disabled}
493
- renderValue={(value) => {
494
- if (!value) {
495
- return <em>Select a property
496
- widget</em>;
506
+ onOpenChange={(open, hasValue) => {
507
+ if (!hasValue) {
508
+ onDismiss?.();
497
509
  }
498
- const key = value as PropertyConfigId;
499
- const propertyConfig = DEFAULT_FIELD_CONFIGS[key] ?? propertyConfigs[key];
500
- const baseProperty = propertyConfig.property;
501
- const baseFieldConfig = baseProperty && !isPropertyBuilder(baseProperty) ? getFieldConfig(baseProperty, propertyConfigs) : undefined;
502
- const optionDisabled = isPropertyBuilder(baseProperty) || (existing && baseProperty.dataType !== values?.dataType);
503
- const computedFieldConfig = baseFieldConfig ? mergeDeep(baseFieldConfig, propertyConfig) : propertyConfig;
504
- return <div
505
- onClick={(e) => {
506
- if (optionDisabled) {
507
- e.stopPropagation();
508
- e.preventDefault();
509
- }
510
- }}
511
- className={cn(
512
- "flex items-center",
513
- optionDisabled ? "w-full pointer-events-none opacity-50" : "")}>
514
- <div className={"mr-8"}>
515
- <PropertyConfigBadge propertyConfig={computedFieldConfig}/>
516
- </div>
517
- <div className={"flex flex-col items-start text-base text-left"}>
518
- <div>{computedFieldConfig.name}</div>
519
- <Typography variant={"caption"}
520
- color={"disabled"}>
521
- {optionDisabled ? "You can only switch to widgets that use the same data type" : computedFieldConfig.description}
522
- </Typography>
523
- </div>
524
- </div>
510
+ setSelectOpen(open);
525
511
  }}
526
- onValueChange={(value) => {
527
- onWidgetSelectChanged(value as PropertyConfigId);
528
- }}>
529
- {displayedWidgets.map(([key, propertyConfig]) => {
530
- const baseProperty = propertyConfig.property;
531
- const optionDisabled = existing && !isPropertyBuilder(baseProperty) && baseProperty.dataType !== values?.dataType;
532
- return <PropertySelectItem
533
- key={key}
534
- value={key}
535
- optionDisabled={optionDisabled}
536
- propertyConfig={propertyConfig}
537
- existing={existing}/>;
538
- })}
539
- </Select>
512
+ disabled={disabled}
513
+ showError={Boolean(selectedWidgetError)}
514
+ existing={existing}
515
+ propertyConfigs={propertyConfigs}
516
+ inArray={inArray}/>
540
517
 
541
518
  {selectedWidgetError &&
542
519
  <Typography variant="caption"
@@ -575,15 +552,15 @@ function PropertyEditFormFields({
575
552
  </div>
576
553
 
577
554
  {onDelete &&
578
- <DeleteConfirmationDialog open={deleteDialogOpen}
579
- onAccept={() => onDelete(values?.id, propertyNamespace)}
580
- onCancel={() => setDeleteDialogOpen(false)}
581
- title={<div>Delete this property?</div>}
582
- body={
583
- <div> This will <b>not delete any
584
- data</b>, only modify the
585
- collection.</div>
586
- }/>}
555
+ <ConfirmationDialog open={deleteDialogOpen}
556
+ onAccept={() => onDelete(values?.id, propertyNamespace)}
557
+ onCancel={() => setDeleteDialogOpen(false)}
558
+ title={<div>Delete this property?</div>}
559
+ body={
560
+ <div> This will <b>not delete any
561
+ data</b>, only modify the
562
+ collection.</div>
563
+ }/>}
587
564
 
588
565
  </>
589
566
  );
@@ -613,3 +590,204 @@ function validateName(value: string) {
613
590
  }
614
591
  return error;
615
592
  }
593
+
594
+ const WIDGET_TYPE_MAP: Record<PropertyConfigId, string> = {
595
+ text_field: "Text",
596
+ multiline: "Text",
597
+ markdown: "Text",
598
+ url: "Text",
599
+ email: "Text",
600
+ switch: "Boolean",
601
+ select: "Select",
602
+ multi_select: "Select",
603
+ number_input: "Number",
604
+ number_select: "Select",
605
+ multi_number_select: "Select",
606
+ file_upload: "File",
607
+ multi_file_upload: "File",
608
+ reference: "Reference",
609
+ multi_references: "Reference",
610
+ date_time: "Date",
611
+ group: "Group",
612
+ key_value: "Group",
613
+ repeat: "Array",
614
+ custom_array: "Array",
615
+ block: "Group"
616
+ };
617
+
618
+ function WidgetSelectView({
619
+ initialProperty,
620
+ value,
621
+ onValueChange,
622
+ open,
623
+ onOpenChange,
624
+ disabled,
625
+ showError,
626
+ existing,
627
+ propertyConfigs,
628
+ inArray
629
+ }: {
630
+ initialProperty?: PropertyWithId,
631
+ value?: PropertyConfigId,
632
+ onValueChange: (value: string) => void,
633
+ showError: boolean,
634
+ open: boolean,
635
+ onOpenChange: (open: boolean, hasValue: boolean) => void,
636
+ disabled: boolean,
637
+ existing: boolean,
638
+ propertyConfigs: Record<string, PropertyConfig>,
639
+ inArray?: boolean
640
+ }) {
641
+
642
+ const allSupportedFields = Object.entries(supportedFields).concat(Object.entries(propertyConfigs));
643
+
644
+ const displayedWidgets = (inArray
645
+ ? allSupportedFields.filter(([_, propertyConfig]) => !isPropertyBuilder(propertyConfig.property) && propertyConfig.property?.dataType !== "array")
646
+ : allSupportedFields)
647
+ .map(([key, propertyConfig]) => ({
648
+ [key]: propertyConfig
649
+ }))
650
+ .reduce((a, b) => {
651
+ return {
652
+ ...a,
653
+ ...b
654
+ }
655
+ }, {});
656
+
657
+ const key = value;
658
+ const propertyConfig = key ? (DEFAULT_FIELD_CONFIGS[key] ?? propertyConfigs[key]) : undefined;
659
+ const baseProperty = propertyConfig?.property;
660
+ const baseFieldConfig = baseProperty && !isPropertyBuilder(baseProperty) ? getFieldConfig(baseProperty, propertyConfigs) : undefined;
661
+ const computedFieldConfig = baseFieldConfig && propertyConfig ? mergeDeep(baseFieldConfig, propertyConfig) : propertyConfig;
662
+
663
+ const groups: string[] = [...new Set(Object.keys(displayedWidgets).map(key => {
664
+ const group = WIDGET_TYPE_MAP[key as PropertyConfigId];
665
+ if (group) {
666
+ return group;
667
+ }
668
+ return "Custom/Other"
669
+ }))];
670
+
671
+ return <>
672
+ <div
673
+ onClick={() => {
674
+ if (!disabled) {
675
+ onOpenChange(!open, Boolean(value));
676
+ }
677
+ }}
678
+ className={cls(
679
+ "select-none rounded-md text-sm p-4",
680
+ fieldBackgroundMixin,
681
+ disabled ? fieldBackgroundDisabledMixin : fieldBackgroundHoverMixin,
682
+ "relative flex items-center",
683
+ )}>
684
+ {!value && <em>Select a property widget</em>}
685
+ {value && computedFieldConfig && <div
686
+ className={cls(
687
+ "flex items-center")}>
688
+ <div className={"mr-8"}>
689
+ <PropertyConfigBadge propertyConfig={computedFieldConfig}/>
690
+ </div>
691
+ <div className={"flex flex-col items-start text-base text-left"}>
692
+ <div>{computedFieldConfig.name}</div>
693
+ <Typography variant={"caption"}
694
+ color={"secondary"}>
695
+ {computedFieldConfig.description}
696
+ </Typography>
697
+ </div>
698
+ </div>}
699
+ </div>
700
+ <Dialog open={open}
701
+ onOpenChange={(open) => onOpenChange(open, Boolean(value))}
702
+ maxWidth={"4xl"}>
703
+ <DialogTitle>
704
+ Select a property widget
705
+ </DialogTitle>
706
+ <DialogContent>
707
+ <div>
708
+ {groups.map(group => {
709
+ return <div key={group} className={"mt-4"}>
710
+ <Typography variant={"label"}>{group}</Typography>
711
+ <div className={"grid grid-cols-1 md:grid-cols-2 gap-x-4 gap-y-2 mt-4"}>
712
+ {Object.entries(displayedWidgets).map(([key, propertyConfig]) => {
713
+ const groupKey = WIDGET_TYPE_MAP[key as PropertyConfigId];
714
+ if (groupKey === group) {
715
+ return <WidgetSelectViewItem
716
+ key={key}
717
+ initialProperty={initialProperty}
718
+ onClick={() => {
719
+ onValueChange(key);
720
+ onOpenChange(false, true);
721
+ }}
722
+ propertyConfig={propertyConfig}
723
+ existing={existing}/>;
724
+ }
725
+ return null;
726
+ })}
727
+ </div>
728
+ </div>;
729
+ })}
730
+ {/*{displayedWidgets.map(([key, propertyConfig]) => {*/}
731
+ {/* return <WidgetSelectViewItem*/}
732
+ {/* key={key}*/}
733
+ {/* initialProperty={initialProperty}*/}
734
+ {/* onClick={() => {*/}
735
+ {/* onValueChange(key);*/}
736
+ {/* onOpenChange(false);*/}
737
+ {/* }}*/}
738
+ {/* propertyConfig={propertyConfig}*/}
739
+ {/* existing={existing}/>;*/}
740
+ {/*})}*/}
741
+ </div>
742
+ </DialogContent>
743
+ </Dialog>
744
+ </>;
745
+ }
746
+
747
+ export interface PropertySelectItemProps {
748
+ onClick?: () => void;
749
+ initialProperty?: PropertyWithId;
750
+ propertyConfig: PropertyConfig;
751
+ existing: boolean;
752
+ }
753
+
754
+ export function WidgetSelectViewItem({
755
+ onClick,
756
+ initialProperty,
757
+ // optionDisabled,
758
+ propertyConfig,
759
+ existing
760
+ }: PropertySelectItemProps) {
761
+ const baseProperty = propertyConfig.property;
762
+ const shouldWarnChangingDataType = existing && !isPropertyBuilder(baseProperty) && baseProperty.dataType !== initialProperty?.dataType;
763
+
764
+ return <Card
765
+ onClick={onClick}
766
+ className={"flex flex-row items-center px-4 py-2"}>
767
+ <div
768
+ className={cls(
769
+ "flex flex-row items-center text-base min-h-[48px]",
770
+ )}>
771
+ <div className={"mr-8"}>
772
+ <PropertyConfigBadge propertyConfig={propertyConfig} disabled={shouldWarnChangingDataType}/>
773
+ </div>
774
+ <div>
775
+ <div className={"flex flex-row gap-2 items-center"}>
776
+ {shouldWarnChangingDataType && <Tooltip
777
+ title={"This widget uses a different data type than the initially selected widget. This can cause errors with existing data."}>
778
+ <WarningIcon size="smallest" className={"w-4"}/>
779
+ </Tooltip>}
780
+ <Typography
781
+ color={shouldWarnChangingDataType ? "secondary" : undefined}>{propertyConfig.name}</Typography>
782
+ </div>
783
+
784
+ <Typography variant={"caption"}
785
+ color={"secondary"}
786
+ className={"max-w-sm"}>
787
+ {propertyConfig.description}
788
+ </Typography>
789
+
790
+ </div>
791
+ </div>
792
+ </Card>
793
+ }
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  ErrorBoundary,
3
- PropertyConfigBadge,
4
3
  getFieldConfig,
5
4
  isPropertyBuilder,
6
5
  Property,
6
+ PropertyConfigBadge,
7
7
  PropertyOrBuilder,
8
8
  useCustomizationController,
9
9
  } from "@firecms/core";
@@ -11,10 +11,10 @@ import {
11
11
  cardClickableMixin,
12
12
  cardMixin,
13
13
  cardSelectedMixin,
14
- cn,
14
+ cls,
15
+ DoNotDisturbOnIcon,
15
16
  FunctionsIcon,
16
17
  Paper,
17
- RemoveCircleIcon,
18
18
  Typography,
19
19
  } from "@firecms/ui";
20
20
 
@@ -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,
@@ -133,13 +130,13 @@ export function NonEditablePropertyPreview({
133
130
  <div className={"relative m-4"}>
134
131
  {propertyConfig && <PropertyConfigBadge propertyConfig={propertyConfig}/>}
135
132
  {!propertyConfig && <div
136
- className={"h-8 w-8 p-1 rounded-full shadow text-white bg-gray-500"}>
133
+ className={"h-8 w-8 p-1 rounded-full shadow text-white bg-surface-500"}>
137
134
  <FunctionsIcon color={"inherit"} size={"medium"}/>
138
135
  </div>}
139
- <RemoveCircleIcon color={"disabled"} size={"small"} className={"absolute -right-2 -top-2"}/>
136
+ <DoNotDisturbOnIcon 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,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 {
@@ -9,7 +9,7 @@ import {
9
9
  PropertiesOrBuilders,
10
10
  PropertyOrBuilder
11
11
  } from "@firecms/core";
12
- import { AutoAwesomeIcon, defaultBorderMixin, DragHandleIcon, IconButton, RemoveIcon, Tooltip } from "@firecms/ui";
12
+ import { AutorenewIcon, defaultBorderMixin, DragHandleIcon, IconButton, RemoveIcon, Tooltip } from "@firecms/ui";
13
13
  import { NonEditablePropertyPreview, PropertyFieldPreview } from "./PropertyFieldPreview";
14
14
  import { DragDropContext, Draggable, DraggableProvided, Droppable } from "@hello-pangea/dnd";
15
15
  import { getFullId, getFullIdPath } from "./util";
@@ -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
  <>
@@ -224,10 +224,11 @@ export function PropertyTreeEntry({
224
224
  <div className="absolute top-2 right-2 flex flex-row ">
225
225
 
226
226
  {isPropertyInferred && <Tooltip title={"Inferred property"}>
227
- <AutoAwesomeIcon size="small" className={"p-2"}/>
227
+ <AutorenewIcon size="small" className={"p-2"}/>
228
228
  </Tooltip>}
229
229
 
230
- {onPropertyRemove && <Tooltip title={"Remove"}>
230
+ {onPropertyRemove && <Tooltip title={"Remove"}
231
+ asChild={true}>
231
232
  <IconButton size="small"
232
233
  color="inherit"
233
234
  onClick={() => onPropertyRemove(propertyKey, namespace)}>
@@ -235,7 +236,8 @@ export function PropertyTreeEntry({
235
236
  </IconButton>
236
237
  </Tooltip>}
237
238
 
238
- {onPropertyMove && <Tooltip title={"Move"}>
239
+ {onPropertyMove && <Tooltip title={"Move"}
240
+ asChild={true}>
239
241
  <IconButton
240
242
  component={"span"}
241
243
  size="small"