@firecms/collection_editor 3.0.0-canary.15 → 3.0.0-canary.151

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