@firecms/core 3.2.0 → 3.3.0-canary.102f274

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 (195) hide show
  1. package/dist/app/AppBar.d.ts +1 -1
  2. package/dist/app/Drawer.d.ts +1 -1
  3. package/dist/components/AIIcon.d.ts +3 -2
  4. package/dist/components/ArrayContainer.d.ts +3 -3
  5. package/dist/components/CircularProgressCenter.d.ts +2 -1
  6. package/dist/components/ClearFilterSortButton.d.ts +1 -1
  7. package/dist/components/ConfirmationDialog.d.ts +1 -1
  8. package/dist/components/DeleteEntityDialog.d.ts +2 -1
  9. package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +1 -1
  10. package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +2 -1
  11. package/dist/components/EntityCollectionTable/fields/TableReferenceField.d.ts +1 -1
  12. package/dist/components/EntityCollectionTable/fields/TableStorageUpload.d.ts +2 -2
  13. package/dist/components/EntityCollectionTable/internal/CollectionTableToolbar.d.ts +1 -1
  14. package/dist/components/EntityCollectionTable/internal/EntityTableCellActions.d.ts +1 -1
  15. package/dist/components/EntityCollectionTable/internal/popup_field/PopupFormField.d.ts +4 -3
  16. package/dist/components/EntityCollectionView/Board.d.ts +2 -1
  17. package/dist/components/EntityCollectionView/BoardColumnTitle.d.ts +1 -1
  18. package/dist/components/EntityCollectionView/BoardSortableList.d.ts +1 -1
  19. package/dist/components/EntityCollectionView/CollectionDataErrorBanner.d.ts +2 -1
  20. package/dist/components/EntityCollectionView/EntityBoardCard.d.ts +1 -1
  21. package/dist/components/EntityCollectionView/EntityCard.d.ts +2 -1
  22. package/dist/components/EntityCollectionView/EntityCollectionBoardView.d.ts +1 -1
  23. package/dist/components/EntityCollectionView/EntityCollectionCardView.d.ts +1 -1
  24. package/dist/components/EntityCollectionView/EntityCollectionViewActions.d.ts +2 -1
  25. package/dist/components/EntityCollectionView/EntityCollectionViewStartActions.d.ts +2 -1
  26. package/dist/components/EntityCollectionView/FiltersDialog.d.ts +2 -1
  27. package/dist/components/EntityCollectionView/ViewModeToggle.d.ts +2 -1
  28. package/dist/components/EntityJsonPreview.d.ts +2 -1
  29. package/dist/components/EntityPreview.d.ts +1 -1
  30. package/dist/components/EntityView.d.ts +2 -1
  31. package/dist/components/ErrorBoundary.d.ts +1 -1
  32. package/dist/components/ErrorTooltip.d.ts +2 -1
  33. package/dist/components/FieldCaption.d.ts +1 -1
  34. package/dist/components/FireCMSLogo.d.ts +1 -1
  35. package/dist/components/HomePage/DefaultHomePage.d.ts +1 -1
  36. package/dist/components/HomePage/FavouritesView.d.ts +1 -1
  37. package/dist/components/HomePage/HomePageDnD.d.ts +4 -4
  38. package/dist/components/HomePage/NavigationCardBinding.d.ts +2 -1
  39. package/dist/components/HomePage/NavigationGroup.d.ts +2 -2
  40. package/dist/components/HomePage/RenameGroupDialog.d.ts +2 -1
  41. package/dist/components/HomePage/SmallNavigationCard.d.ts +1 -1
  42. package/dist/components/LanguageToggle.d.ts +2 -1
  43. package/dist/components/NotFoundPage.d.ts +2 -1
  44. package/dist/components/PropertyCollectionView.d.ts +2 -1
  45. package/dist/components/PropertyIdCopyTooltip.d.ts +2 -2
  46. package/dist/components/ReferenceTable/ReferenceSelectionTable.d.ts +1 -1
  47. package/dist/components/ReferenceWidget.d.ts +2 -1
  48. package/dist/components/SearchIconsView.d.ts +2 -1
  49. package/dist/components/SelectableTable/SelectableTable.d.ts +1 -1
  50. package/dist/components/SelectableTable/filters/BooleanFilterField.d.ts +2 -1
  51. package/dist/components/SelectableTable/filters/DateTimeFilterField.d.ts +2 -1
  52. package/dist/components/SelectableTable/filters/ReferenceFilterField.d.ts +2 -1
  53. package/dist/components/SelectableTable/filters/StringNumberFilterField.d.ts +2 -1
  54. package/dist/components/UnsavedChangesDialog.d.ts +1 -1
  55. package/dist/components/UserDisplay.d.ts +1 -1
  56. package/dist/components/VirtualTable/VirtualTableHeader.d.ts +1 -0
  57. package/dist/components/VirtualTable/VirtualTableHeaderRow.d.ts +2 -1
  58. package/dist/components/VirtualTable/VirtualTableProps.d.ts +6 -1
  59. package/dist/components/VirtualTable/fields/VirtualTableDateField.d.ts +1 -1
  60. package/dist/components/VirtualTable/fields/VirtualTableInput.d.ts +2 -1
  61. package/dist/components/VirtualTable/fields/VirtualTableNumberInput.d.ts +2 -1
  62. package/dist/components/VirtualTable/fields/VirtualTableSelect.d.ts +1 -1
  63. package/dist/components/VirtualTable/fields/VirtualTableSwitch.d.ts +2 -1
  64. package/dist/components/VirtualTable/fields/VirtualTableUserSelect.d.ts +1 -1
  65. package/dist/components/VirtualTable/types.d.ts +1 -0
  66. package/dist/core/DefaultAppBar.d.ts +1 -1
  67. package/dist/core/DefaultDrawer.d.ts +2 -2
  68. package/dist/core/DrawerNavigationGroup.d.ts +1 -1
  69. package/dist/core/DrawerNavigationItem.d.ts +1 -1
  70. package/dist/core/EntityEditView.d.ts +2 -2
  71. package/dist/core/EntityEditViewFormActions.d.ts +2 -1
  72. package/dist/core/EntitySidePanel.d.ts +2 -1
  73. package/dist/core/FireCMS.d.ts +2 -1
  74. package/dist/core/FireCMSRouter.d.ts +1 -1
  75. package/dist/core/SideDialogs.d.ts +1 -1
  76. package/dist/editor/components/SlashCommandMenu.d.ts +2 -1
  77. package/dist/editor/editor.d.ts +1 -1
  78. package/dist/editor/selectors/color-selector.d.ts +1 -1
  79. package/dist/editor/selectors/link-selector.d.ts +1 -1
  80. package/dist/editor/selectors/node-selector.d.ts +1 -1
  81. package/dist/editor/selectors/text-buttons.d.ts +1 -1
  82. package/dist/form/EntityForm.d.ts +1 -1
  83. package/dist/form/EntityFormActions.d.ts +1 -1
  84. package/dist/form/components/CustomIdField.d.ts +2 -1
  85. package/dist/form/components/FieldHelperText.d.ts +1 -1
  86. package/dist/form/components/FormEntry.d.ts +1 -1
  87. package/dist/form/components/FormLayout.d.ts +1 -1
  88. package/dist/form/components/LabelWithIconAndTooltip.d.ts +1 -1
  89. package/dist/form/components/LocalChangesMenu.d.ts +2 -1
  90. package/dist/form/components/StorageItemPreview.d.ts +2 -1
  91. package/dist/form/components/StorageUploadProgress.d.ts +2 -1
  92. package/dist/form/field_bindings/ArrayCustomShapedFieldBinding.d.ts +2 -1
  93. package/dist/form/field_bindings/ArrayOfReferencesFieldBinding.d.ts +2 -1
  94. package/dist/form/field_bindings/BlockFieldBinding.d.ts +2 -1
  95. package/dist/form/field_bindings/DateTimeFieldBinding.d.ts +2 -1
  96. package/dist/form/field_bindings/KeyValueFieldBinding.d.ts +2 -1
  97. package/dist/form/field_bindings/MapFieldBinding.d.ts +2 -1
  98. package/dist/form/field_bindings/MarkdownEditorFieldBinding.d.ts +3 -2
  99. package/dist/form/field_bindings/MultiSelectFieldBinding.d.ts +2 -1
  100. package/dist/form/field_bindings/ReadOnlyFieldBinding.d.ts +2 -1
  101. package/dist/form/field_bindings/ReferenceAsStringFieldBinding.d.ts +2 -1
  102. package/dist/form/field_bindings/ReferenceFieldBinding.d.ts +2 -1
  103. package/dist/form/field_bindings/RepeatFieldBinding.d.ts +2 -1
  104. package/dist/form/field_bindings/SelectFieldBinding.d.ts +2 -1
  105. package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +3 -2
  106. package/dist/form/field_bindings/SwitchFieldBinding.d.ts +2 -1
  107. package/dist/form/field_bindings/TextFieldBinding.d.ts +2 -1
  108. package/dist/form/field_bindings/UserSelectFieldBinding.d.ts +2 -1
  109. package/dist/i18n/FireCMSi18nProvider.d.ts +2 -2
  110. package/dist/index.d.ts +1 -0
  111. package/dist/index.es.js +24392 -23648
  112. package/dist/index.es.js.map +1 -1
  113. package/dist/index.umd.js +23301 -22557
  114. package/dist/index.umd.js.map +1 -1
  115. package/dist/preview/components/ArrayEnumPreview.d.ts +2 -1
  116. package/dist/preview/components/AsyncPreviewComponent.d.ts +1 -1
  117. package/dist/preview/components/EmptyValue.d.ts +2 -1
  118. package/dist/preview/components/EnumValuesChip.d.ts +1 -1
  119. package/dist/preview/components/ImagePreview.d.ts +2 -1
  120. package/dist/preview/components/ReferencePreview.d.ts +1 -1
  121. package/dist/preview/components/StorageThumbnail.d.ts +1 -1
  122. package/dist/preview/components/UserPreview.d.ts +2 -1
  123. package/dist/preview/property_previews/ArrayOfMapsPreview.d.ts +2 -1
  124. package/dist/preview/property_previews/ArrayOfReferencesPreview.d.ts +1 -1
  125. package/dist/preview/property_previews/ArrayOfStorageComponentsPreview.d.ts +2 -1
  126. package/dist/preview/property_previews/ArrayOfStringsPreview.d.ts +2 -1
  127. package/dist/preview/property_previews/ArrayOneOfPreview.d.ts +2 -1
  128. package/dist/preview/property_previews/ArrayPropertyEnumPreview.d.ts +1 -1
  129. package/dist/preview/property_previews/ArrayPropertyPreview.d.ts +2 -1
  130. package/dist/preview/property_previews/MapPropertyPreview.d.ts +3 -2
  131. package/dist/preview/property_previews/SkeletonPropertyComponent.d.ts +5 -4
  132. package/dist/routes/FireCMSRoute.d.ts +2 -1
  133. package/dist/types/collections.d.ts +38 -0
  134. package/dist/types/properties.d.ts +9 -8
  135. package/dist/types/translations.d.ts +23 -0
  136. package/dist/util/index.d.ts +1 -0
  137. package/dist/util/lazy_eager.d.ts +7 -0
  138. package/dist/util/objects.d.ts +1 -0
  139. package/dist/util/property_utils.d.ts +1 -1
  140. package/package.json +5 -5
  141. package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +9 -3
  142. package/src/components/EntityCollectionTable/internal/common.tsx +2 -2
  143. package/src/components/EntityCollectionView/EntityCollectionView.tsx +3 -5
  144. package/src/components/EntityJsonPreview.tsx +2 -1
  145. package/src/components/ErrorBoundary.tsx +3 -3
  146. package/src/components/HomePage/NavigationCardBinding.tsx +6 -3
  147. package/src/components/VirtualTable/VirtualTable.tsx +5 -3
  148. package/src/components/VirtualTable/VirtualTableHeader.tsx +9 -8
  149. package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +8 -3
  150. package/src/components/VirtualTable/VirtualTableProps.tsx +7 -1
  151. package/src/components/VirtualTable/types.tsx +1 -0
  152. package/src/core/DefaultDrawer.tsx +1 -1
  153. package/src/core/DrawerNavigationGroup.tsx +1 -1
  154. package/src/core/EntityEditView.tsx +50 -5
  155. package/src/core/EntitySidePanel.tsx +2 -1
  156. package/src/core/field_configs.tsx +4 -2
  157. package/src/editor/editor.tsx +20 -1
  158. package/src/editor/markdown.ts +89 -1
  159. package/src/form/EntityForm.tsx +64 -4
  160. package/src/form/PropertyFieldBinding.tsx +4 -3
  161. package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +18 -5
  162. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +18 -5
  163. package/src/form/field_bindings/BlockFieldBinding.tsx +21 -7
  164. package/src/form/field_bindings/DateTimeFieldBinding.tsx +1 -1
  165. package/src/form/field_bindings/KeyValueFieldBinding.tsx +23 -6
  166. package/src/form/field_bindings/MapFieldBinding.tsx +23 -8
  167. package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +43 -20
  168. package/src/form/field_bindings/MultiSelectFieldBinding.tsx +15 -1
  169. package/src/form/field_bindings/ReferenceAsStringFieldBinding.tsx +25 -11
  170. package/src/form/field_bindings/ReferenceFieldBinding.tsx +25 -11
  171. package/src/form/field_bindings/RepeatFieldBinding.tsx +18 -5
  172. package/src/form/field_bindings/SelectFieldBinding.tsx +7 -5
  173. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +24 -7
  174. package/src/form/field_bindings/SwitchFieldBinding.tsx +31 -14
  175. package/src/form/field_bindings/TextFieldBinding.tsx +10 -7
  176. package/src/form/field_bindings/UserSelectFieldBinding.tsx +7 -5
  177. package/src/index.ts +1 -0
  178. package/src/internal/useBuildSideEntityController.tsx +1 -1
  179. package/src/locales/de.ts +28 -1
  180. package/src/locales/en.ts +27 -0
  181. package/src/locales/es.ts +28 -1
  182. package/src/locales/fr.ts +28 -1
  183. package/src/locales/hi.ts +28 -1
  184. package/src/locales/it.ts +28 -1
  185. package/src/locales/pt.ts +28 -1
  186. package/src/preview/PropertyPreview.tsx +6 -5
  187. package/src/preview/components/ReferencePreview.tsx +2 -1
  188. package/src/preview/property_previews/MapPropertyPreview.tsx +49 -27
  189. package/src/routes/FireCMSRoute.tsx +63 -54
  190. package/src/types/collections.ts +40 -0
  191. package/src/types/properties.ts +11 -10
  192. package/src/types/translations.ts +27 -0
  193. package/src/util/index.ts +1 -0
  194. package/src/util/lazy_eager.tsx +33 -0
  195. package/src/util/objects.ts +15 -0
@@ -6,7 +6,7 @@ import { getIconForProperty, isHidden, isReadOnly, pick } from "../../util";
6
6
  import { FieldHelperText, LabelWithIconAndTooltip } from "../components";
7
7
  import { FormEntry } from "../components/FormEntry";
8
8
  import { PropertyFieldBinding } from "../PropertyFieldBinding";
9
- import { cls, ExpandablePanel, InputLabel, Select, SelectItem } from "@firecms/ui";
9
+ import { cls, ExpandablePanel, InputLabel, Select, SelectItem, IconButton, CloseIcon } from "@firecms/ui";
10
10
  import { useTranslation } from "../../hooks";
11
11
 
12
12
  /**
@@ -28,7 +28,8 @@ export function MapFieldBinding({
28
28
  includeDescription,
29
29
  autoFocus,
30
30
  context,
31
- onPropertyChange
31
+ onPropertyChange,
32
+ setValue
32
33
  }: FieldProps<Record<string, any>>) {
33
34
 
34
35
  const pickOnlySomeKeys = property.pickOnlySomeKeys || false;
@@ -108,12 +109,26 @@ export function MapFieldBinding({
108
109
  }}
109
110
  className={property.widthPercentage !== undefined ? "mt-8" : undefined}
110
111
  innerClassName={"px-2 md:px-4 pb-2 md:pb-4 pt-1 md:pt-2 bg-white dark:bg-surface-900"}
111
- title={<LabelWithIconAndTooltip
112
- propertyKey={propertyKey}
113
- icon={getIconForProperty(property, "small")}
114
- required={property.validation?.required}
115
- title={property.name}
116
- className={"text-text-secondary dark:text-text-secondary-dark"} />}>
112
+ title={<div className="flex items-center w-full">
113
+ <LabelWithIconAndTooltip
114
+ propertyKey={propertyKey}
115
+ icon={getIconForProperty(property, "small")}
116
+ required={property.validation?.required}
117
+ title={property.name}
118
+ className={"text-text-secondary dark:text-text-secondary-dark flex-grow"} />
119
+ {(property.nullable || property.clearable) && !disabled && (
120
+ <IconButton
121
+ size="small"
122
+ onClick={(e) => {
123
+ e.stopPropagation();
124
+ e.preventDefault();
125
+ setValue(null);
126
+ }}
127
+ >
128
+ <CloseIcon size={"small"}/>
129
+ </IconButton>
130
+ )}
131
+ </div>}>
117
132
  {mapFormView}
118
133
  </ExpandablePanel>}
119
134
 
@@ -11,10 +11,14 @@ import {
11
11
  useAuthController,
12
12
  useStorageSource
13
13
  } from "../../index";
14
- import { cls, fieldBackgroundDisabledMixin, fieldBackgroundHoverMixin, fieldBackgroundMixin } from "@firecms/ui";
15
- import { FireCMSEditor, FireCMSEditorProps } from "../../editor";
14
+ import { cls, fieldBackgroundDisabledMixin, fieldBackgroundHoverMixin, fieldBackgroundMixin, IconButton, CloseIcon } from "@firecms/ui";
15
+ import type { FireCMSEditorProps } from "../../editor";
16
16
  import { resolveProperty, resolveStorageFilenameString, resolveStoragePathString } from "../../util";
17
17
  import { isImageFile, resizeImage } from "../../util/useStorageUploadController";
18
+ import { lazyEager } from "../../util/lazy_eager";
19
+ import { CircularProgressCenter } from "../../components/CircularProgressCenter";
20
+
21
+ const FireCMSEditor = lazyEager<typeof import("../../editor/editor")["FireCMSEditor"]>(() => import("../../editor/editor"), "FireCMSEditor");
18
22
 
19
23
  interface MarkdownEditorFieldProps {
20
24
  highlight?: { from: number, to: number };
@@ -51,7 +55,7 @@ export function MarkdownEditorFieldBinding({
51
55
  const internalValue = useRef<string | null>(value);
52
56
 
53
57
  const onContentChange = useCallback((content: string) => {
54
- if (content === value || (value === null && content === "")) {
58
+ if (content === value || ((value === null || value === undefined) && content === "")) {
55
59
  return;
56
60
  }
57
61
  internalValue.current = content;
@@ -135,17 +139,21 @@ export function MarkdownEditorFieldBinding({
135
139
  return url;
136
140
  };
137
141
 
138
- const editor = <FireCMSEditor
139
- key={context.formex.version + fieldVersion}
140
- content={value}
141
- onMarkdownContentChange={onContentChange}
142
- version={context.formex.version + fieldVersion}
143
- highlight={highlight}
144
- disabled={disabled}
145
- markdownConfig={markdownConfig}
146
- handleImageUpload={handleImageUpload}
147
- {...editorProps}
148
- />;
142
+ const editor = (
143
+ <React.Suspense fallback={<CircularProgressCenter />}>
144
+ <FireCMSEditor
145
+ key={context.formex.version + fieldVersion}
146
+ content={value}
147
+ onMarkdownContentChange={onContentChange}
148
+ version={context.formex.version + fieldVersion}
149
+ highlight={highlight}
150
+ disabled={disabled}
151
+ markdownConfig={markdownConfig}
152
+ handleImageUpload={handleImageUpload}
153
+ {...editorProps}
154
+ />
155
+ </React.Suspense>
156
+ );
149
157
 
150
158
  if (minimalistView)
151
159
  return (
@@ -156,12 +164,27 @@ export function MarkdownEditorFieldBinding({
156
164
 
157
165
  return (
158
166
  <>
159
- <LabelWithIconAndTooltip
160
- propertyKey={propertyKey}
161
- icon={getIconForProperty(property, "small")}
162
- required={property.validation?.required}
163
- title={property.name}
164
- className={"h-8 text-text-secondary dark:text-text-secondary-dark ml-3.5"} />
167
+ <div className="flex items-center w-full">
168
+ <LabelWithIconAndTooltip
169
+ propertyKey={propertyKey}
170
+ icon={getIconForProperty(property, "small")}
171
+ required={property.validation?.required}
172
+ title={property.name}
173
+ className={"h-8 text-text-secondary dark:text-text-secondary-dark ml-3.5"} />
174
+ <div className="flex-grow"/>
175
+ {(property.nullable || property.clearable) && !disabled && (
176
+ <IconButton
177
+ size="small"
178
+ onClick={(e) => {
179
+ e.stopPropagation();
180
+ e.preventDefault();
181
+ setValue(null);
182
+ }}
183
+ >
184
+ <CloseIcon size={"small"}/>
185
+ </IconButton>
186
+ )}
187
+ </div>
165
188
  <div
166
189
  className={cls("rounded-md", fieldBackgroundMixin, disabled ? fieldBackgroundDisabledMixin : fieldBackgroundHoverMixin)}>
167
190
  {editor}
@@ -4,7 +4,7 @@ import { EnumType, FieldProps, ResolvedProperty } from "../../types";
4
4
  import { FieldHelperText, LabelWithIconAndTooltip } from "../components";
5
5
  import { EnumValuesChip } from "../../preview";
6
6
  import { enumToObjectEntries, getIconForProperty, getLabelOrConfigFrom } from "../../util";
7
- import { CloseIcon, MultiSelect, MultiSelectItem } from "@firecms/ui";
7
+ import { CloseIcon, MultiSelect, MultiSelectItem, IconButton } from "@firecms/ui";
8
8
  import { useClearRestoreValue } from "../useClearRestoreValue";
9
9
 
10
10
  /**
@@ -93,6 +93,20 @@ export function MultiSelectFieldBinding({
93
93
  required={property.validation?.required}
94
94
  title={property.name}
95
95
  className={"h-8 text-text-secondary dark:text-text-secondary-dark ml-3.5"}/>}
96
+ endAdornment={
97
+ (property.nullable || property.clearable) && !disabled && value !== null && value !== undefined ? (
98
+ <IconButton
99
+ size="small"
100
+ onClick={(e) => {
101
+ e.stopPropagation();
102
+ e.preventDefault();
103
+ setValue(null);
104
+ }}
105
+ >
106
+ <CloseIcon size={"small"}/>
107
+ </IconButton>
108
+ ) : undefined
109
+ }
96
110
  onValueChange={(updatedValue: string[]) => {
97
111
  let newValue: EnumType[] | null;
98
112
  if (of && (of as ResolvedProperty)?.dataType === "number") {
@@ -8,7 +8,7 @@ import { ReferencePreview } from "../../preview";
8
8
  import { getIconForProperty, IconForView } from "../../util";
9
9
  import { useClearRestoreValue } from "../useClearRestoreValue";
10
10
  import { EntityPreviewContainer } from "../../components/EntityPreview";
11
- import { cls } from "@firecms/ui";
11
+ import { cls, IconButton, CloseIcon } from "@firecms/ui";
12
12
 
13
13
  /**
14
14
  * Field that opens a reference selection dialog and stores the entity ID as a string.
@@ -98,16 +98,30 @@ function ReferenceAsStringFieldBindingInternal({
98
98
 
99
99
  {collection && <>
100
100
 
101
- {referenceValue && <ReferencePreview
102
- disabled={!path}
103
- previewProperties={property.reference?.previewProperties}
104
- hover={!disabled}
105
- size={size}
106
- onClick={disabled || isSubmitting ? undefined : onEntryClick}
107
- reference={referenceValue}
108
- includeEntityLink={property.reference?.includeEntityLink}
109
- includeId={property.reference?.includeId}
110
- />}
101
+ {referenceValue && <div className="flex items-center gap-2">
102
+ <ReferencePreview
103
+ disabled={!path}
104
+ previewProperties={property.reference?.previewProperties}
105
+ hover={!disabled}
106
+ size={size}
107
+ onClick={disabled || isSubmitting ? undefined : onEntryClick}
108
+ reference={referenceValue}
109
+ includeEntityLink={property.reference?.includeEntityLink}
110
+ includeId={property.reference?.includeId}
111
+ />
112
+ {(property.nullable || property.clearable) && !disabled && (
113
+ <IconButton
114
+ size="small"
115
+ onClick={(e) => {
116
+ e.stopPropagation();
117
+ e.preventDefault();
118
+ setValue(null);
119
+ }}
120
+ >
121
+ <CloseIcon size={"small"}/>
122
+ </IconButton>
123
+ )}
124
+ </div>}
111
125
 
112
126
  {!value && <div className="justify-center text-left">
113
127
  <EntityPreviewContainer
@@ -9,7 +9,7 @@ import { EmptyValue, ReferencePreview } from "../../preview";
9
9
  import { getIconForProperty, getReferenceFrom, IconForView } from "../../util";
10
10
  import { useClearRestoreValue } from "../useClearRestoreValue";
11
11
  import { EntityPreviewContainer } from "../../components/EntityPreview";
12
- import { cls } from "@firecms/ui";
12
+ import { cls, IconButton, CloseIcon } from "@firecms/ui";
13
13
 
14
14
  /**
15
15
  * Field that opens a reference selection dialog.
@@ -97,16 +97,30 @@ function ReferenceFieldBindingInternal({
97
97
 
98
98
  {collection && <>
99
99
 
100
- {value && <ReferencePreview
101
- disabled={!property.path}
102
- previewProperties={property.previewProperties}
103
- hover={!disabled}
104
- size={size}
105
- onClick={disabled || isSubmitting ? undefined : onEntryClick}
106
- reference={value}
107
- includeEntityLink={property.includeEntityLink}
108
- includeId={property.includeId}
109
- />}
100
+ {value && <div className="flex items-center gap-2">
101
+ <ReferencePreview
102
+ disabled={!property.path}
103
+ previewProperties={property.previewProperties}
104
+ hover={!disabled}
105
+ size={size}
106
+ onClick={disabled || isSubmitting ? undefined : onEntryClick}
107
+ reference={value}
108
+ includeEntityLink={property.includeEntityLink}
109
+ includeId={property.includeId}
110
+ />
111
+ {(property.nullable || property.clearable) && !disabled && (
112
+ <IconButton
113
+ size="small"
114
+ onClick={(e) => {
115
+ e.stopPropagation();
116
+ e.preventDefault();
117
+ setValue(null);
118
+ }}
119
+ >
120
+ <CloseIcon size={"small"}/>
121
+ </IconButton>
122
+ )}
123
+ </div>}
110
124
 
111
125
  {!value && <div className="justify-center text-left">
112
126
  <EntityPreviewContainer className={cls("px-6 h-16 text-sm font-medium flex items-center gap-6",
@@ -4,7 +4,7 @@ import { FieldHelperText, LabelWithIconAndTooltip } from "../components";
4
4
  import { ArrayContainer, ArrayEntryParams, ErrorBoundary } from "../../components";
5
5
  import { getArrayResolvedProperties, getDefaultValueFor, getIconForProperty, mergeDeep } from "../../util";
6
6
  import { PropertyFieldBinding } from "../PropertyFieldBinding";
7
- import { ExpandablePanel, Typography } from "@firecms/ui";
7
+ import { ExpandablePanel, Typography, IconButton, CloseIcon } from "@firecms/ui";
8
8
  import { useClearRestoreValue } from "../useClearRestoreValue";
9
9
  import { useAuthController } from "../../hooks";
10
10
  import { useTranslation } from "../../hooks/useTranslation";
@@ -101,15 +101,28 @@ export function RepeatFieldBinding<T extends Array<any>>({
101
101
  className={property.widthPercentage !== undefined ? "mt-8" : undefined}
102
102
  />;
103
103
 
104
- const title = (<>
104
+ const title = (<div className="flex items-center w-full">
105
105
  <LabelWithIconAndTooltip
106
106
  propertyKey={propertyKey}
107
107
  icon={getIconForProperty(property, "small")}
108
108
  required={property.validation?.required}
109
109
  title={property.name}
110
- className={"h-8 flex flex-grow text-text-secondary dark:text-text-secondary-dark"}/>
111
- {Array.isArray(value) && <Typography variant={"caption"} className={"px-4"}>({value.length})</Typography>}
112
- </>);
110
+ className={"text-text-secondary dark:text-text-secondary-dark"}/>
111
+ {Array.isArray(value) && <span className={"text-sm text-text-secondary dark:text-text-secondary-dark ml-1"}>({value.length})</span>}
112
+ <div className="flex-grow"/>
113
+ {(property.nullable || property.clearable) && !disabled && (
114
+ <IconButton
115
+ size="small"
116
+ onClick={(e) => {
117
+ e.stopPropagation();
118
+ e.preventDefault();
119
+ setValue(null);
120
+ }}
121
+ >
122
+ <CloseIcon size={"small"}/>
123
+ </IconButton>
124
+ )}
125
+ </div>);
113
126
 
114
127
  return (
115
128
 
@@ -66,11 +66,13 @@ export function SelectFieldBinding<T extends EnumType>({
66
66
  />
67
67
  </PropertyIdCopyTooltip>}
68
68
  endAdornment={
69
- property.clearable && !disabled && <IconButton
70
- size="small"
71
- onClick={handleClearClick}>
72
- <CloseIcon size={"small"}/>
73
- </IconButton>
69
+ (property.nullable || property.clearable) && !disabled && value !== null && value !== undefined ? (
70
+ <IconButton
71
+ size="small"
72
+ onClick={handleClearClick}>
73
+ <CloseIcon size={"small"}/>
74
+ </IconButton>
75
+ ) : undefined
74
76
  }
75
77
  onValueChange={(updatedValue: string) => {
76
78
  const newValue = updatedValue
@@ -38,7 +38,9 @@ import {
38
38
  fieldBackgroundDisabledMixin,
39
39
  fieldBackgroundHoverMixin,
40
40
  fieldBackgroundMixin,
41
- Typography
41
+ Typography,
42
+ IconButton,
43
+ CloseIcon
42
44
  } from "@firecms/ui";
43
45
  import { useClearRestoreValue } from "../useClearRestoreValue";
44
46
  import { useTranslation } from "../../hooks/useTranslation";
@@ -110,12 +112,27 @@ export function StorageUploadFieldBinding({
110
112
  <>
111
113
 
112
114
  {!minimalistView &&
113
- <LabelWithIconAndTooltip
114
- propertyKey={propertyKey}
115
- icon={getIconForProperty(property, "small")}
116
- required={property.validation?.required}
117
- title={property.name}
118
- className={"h-8 text-text-secondary dark:text-text-secondary-dark ml-3.5"} />}
115
+ <div className="flex items-center w-full">
116
+ <LabelWithIconAndTooltip
117
+ propertyKey={propertyKey}
118
+ icon={getIconForProperty(property, "small")}
119
+ required={property.validation?.required}
120
+ title={property.name}
121
+ className={"h-8 text-text-secondary dark:text-text-secondary-dark ml-3.5"} />
122
+ <div className="flex-grow"/>
123
+ {(property.nullable || property.clearable) && !disabled && (
124
+ <IconButton
125
+ size="small"
126
+ onClick={(e) => {
127
+ e.stopPropagation();
128
+ e.preventDefault();
129
+ setValue(null);
130
+ }}
131
+ >
132
+ <CloseIcon size={"small"}/>
133
+ </IconButton>
134
+ )}
135
+ </div>}
119
136
 
120
137
  <StorageUpload
121
138
  value={internalValue}
@@ -3,7 +3,7 @@ import React from "react";
3
3
  import { FieldProps } from "../../types";
4
4
  import { getIconForProperty } from "../../util";
5
5
  import { FieldHelperText, LabelWithIcon } from "../components";
6
- import { BooleanSwitchWithLabel } from "@firecms/ui";
6
+ import { BooleanSwitchWithLabel, IconButton, CloseIcon } from "@firecms/ui";
7
7
  import { useClearRestoreValue } from "../useClearRestoreValue";
8
8
  import { PropertyIdCopyTooltip } from "../../components";
9
9
 
@@ -39,19 +39,36 @@ export const SwitchFieldBinding = function SwitchFieldBinding({
39
39
  <>
40
40
 
41
41
  <PropertyIdCopyTooltip propertyKey={propertyKey}>
42
- <BooleanSwitchWithLabel
43
- value={value}
44
- onValueChange={(v) => setValue(v)}
45
- error={showError}
46
- className={property.widthPercentage !== undefined ? "mt-8" : undefined}
47
- label={<LabelWithIcon
48
- icon={getIconForProperty(property, "small")}
49
- required={property.validation?.required}
50
- title={property.name}/>}
51
- disabled={disabled}
52
- autoFocus={autoFocus}
53
- size={size}
54
- />
42
+ <div className="flex items-center">
43
+ <BooleanSwitchWithLabel
44
+ value={value}
45
+ onValueChange={(v) => setValue(v)}
46
+ error={showError}
47
+ className={property.widthPercentage !== undefined ? "mt-8" : undefined}
48
+ label={<LabelWithIcon
49
+ icon={getIconForProperty(property, "small")}
50
+ required={property.validation?.required}
51
+ title={property.name}/>}
52
+ disabled={disabled}
53
+ autoFocus={autoFocus}
54
+ size={size}
55
+ switchAdornment={
56
+ (property.nullable || property.clearable) && !disabled && value !== null && (
57
+ <IconButton
58
+ size="small"
59
+ onClick={(e) => {
60
+ e.stopPropagation();
61
+ e.preventDefault();
62
+ setValue(null);
63
+ }}
64
+ className="mr-2"
65
+ >
66
+ <CloseIcon size={"small"}/>
67
+ </IconButton>
68
+ )
69
+ }
70
+ />
71
+ </div>
55
72
  </PropertyIdCopyTooltip>
56
73
 
57
74
  <FieldHelperText includeDescription={includeDescription}
@@ -100,10 +100,10 @@ export function TextFieldBinding<T extends string | number>({
100
100
  showError && error ? "text-red-500 dark:text-red-600" : ""
101
101
  )}
102
102
  />
103
- {property.clearable && (
103
+ {(property.nullable || property.clearable) && value !== null && value !== undefined && (
104
104
  <div className="flex flex-row justify-center items-center absolute h-full right-0 top-0 mr-4">
105
- <IconButton onClick={handleClearClick}>
106
- <CloseIcon />
105
+ <IconButton size="small" onClick={handleClearClick}>
106
+ <CloseIcon size="small" />
107
107
  </IconButton>
108
108
  </div>
109
109
  )}
@@ -119,10 +119,13 @@ export function TextFieldBinding<T extends string | number>({
119
119
  type={inputType}
120
120
  disabled={disabled}
121
121
  endAdornment={
122
- property.clearable && <IconButton
123
- onClick={handleClearClick}>
124
- <CloseIcon />
125
- </IconButton>
122
+ (property.nullable || property.clearable) && value !== null && value !== undefined ? (
123
+ <IconButton
124
+ size="small"
125
+ onClick={handleClearClick}>
126
+ <CloseIcon size="small" />
127
+ </IconButton>
128
+ ) : undefined
126
129
  }
127
130
  error={showError ? error : undefined}
128
131
  inputClassName={error ? "text-red-500 dark:text-red-600" : ""} />
@@ -59,11 +59,13 @@ export function UserSelectFieldBinding({
59
59
  />
60
60
  </PropertyIdCopyTooltip>}
61
61
  endAdornment={
62
- property.clearable && !disabled && value && <IconButton
63
- size="small"
64
- onClick={handleClearClick}>
65
- <CloseIcon size={"small"}/>
66
- </IconButton>
62
+ (property.nullable || property.clearable) && !disabled && value !== null && value !== undefined ? (
63
+ <IconButton
64
+ size="small"
65
+ onClick={handleClearClick}>
66
+ <CloseIcon size={"small"}/>
67
+ </IconButton>
68
+ ) : undefined
67
69
  }
68
70
  onValueChange={(updatedValue: string) => {
69
71
  const newValue = updatedValue || null;
package/src/index.ts CHANGED
@@ -11,3 +11,4 @@ export * from "./i18n/FireCMSi18nProvider";
11
11
  export * from "./locales/en";
12
12
  export * from "./locales/es";
13
13
  export * from "./editor";
14
+ export * from "./util/objects";
@@ -32,7 +32,7 @@ export function getEntityViewWidth(props: EntitySidePanelProps<any>, small: bool
32
32
  selectedSecondaryForm
33
33
  } = resolvedSelectedEntityView(props.collection?.entityViews, customizationController, props.selectedTab);
34
34
 
35
- const shouldUseSmallLayout = !props.selectedTab || props.selectedTab === JSON_TAB_VALUE || props.selectedTab === "__history" || Boolean(selectedSecondaryForm);
35
+ const shouldUseSmallLayout = !props.selectedTab || props.selectedTab === JSON_TAB_VALUE || props.selectedTab === "__history" || props.selectedTab === "__raw_data" || Boolean(selectedSecondaryForm);
36
36
 
37
37
  let resolvedWidth: string | undefined;
38
38
  if (props.width) {
package/src/locales/de.ts CHANGED
@@ -437,6 +437,8 @@ export const de: FireCMSTranslations = {
437
437
  cms_users: "CMS-Benutzer",
438
438
  roles_menu: "Rollen",
439
439
  project_settings: "Projekteinstellungen",
440
+ firestore_manager: "Firestore-Manager",
441
+ manage_your_firestore_data: "Deine Firestore-Daten verwalten",
440
442
 
441
443
  // ─── FireCMS Cloud Login ──────────────────────────────────────
442
444
  build_admin_panel_in_minutes: "Erstellen Sie Ihr Firebase Admin Panel in wenigen Minuten",
@@ -678,6 +680,17 @@ export const de: FireCMSTranslations = {
678
680
  settings_appcheck_updated: "AppCheck aktualisiert",
679
681
  settings_appcheck_error: "Fehler beim Aktualisieren von AppCheck",
680
682
 
683
+ // --- Permission Error View ---
684
+ missing_firestore_security_rules: "Fehlende Firestore-Sicherheitsregeln",
685
+ firecms_cloud_requires_security_rule: "FireCMS Cloud erfordert eine spezifische Sicherheitsregel in Ihrem Firestore, um authentifizierten Benutzern Zugriff zu gewähren. Auf die Sammlung",
686
+ cannot_be_accessed_without_it: "kann ohne sie nicht zugegriffen werden.",
687
+ required_security_rule: "Erforderliche Sicherheitsregel",
688
+ fix_automatically: "Automatisch beheben",
689
+ open_firebase_rules: "Firebase-Regeln öffnen",
690
+ security_rules_updated_successfully: "Sicherheitsregeln erfolgreich aktualisiert! Bitte laden Sie die Seite neu, um Ihre Daten zu laden.",
691
+ sec_rules_fixing: "Beheben...",
692
+ sec_rules_fixed: "Behoben!",
693
+
681
694
  // ─── Text Search Dialog ─────────────────────────────────────
682
695
  text_search_dialog_title: "Textsuche aktivieren",
683
696
  text_search_local_not_recommended: "Die lokale Textsuche wird für große Sammlungen nicht empfohlen.",
@@ -687,5 +700,19 @@ export const de: FireCMSTranslations = {
687
700
  text_search_own_implementation: "Sie haben Ihren eigenen Textsuch-Controller implementiert. Sie können die Textsuche für Ihre Sammlung aktivieren.",
688
701
  text_search_enable_for_collection: "Für diese Sammlung aktivieren",
689
702
  text_search_enable_for_project: "Für das Projekt aktivieren",
690
- text_search_enabled_snackbar: "Lokale Textsuche aktiviert"
703
+ text_search_enabled_snackbar: "Lokale Textsuche aktiviert",
704
+
705
+ // ─── GCP Marketplace ─────────────────────────────────────────
706
+ marketplace_managed_by_gcp: "Verwaltet über GCP Marketplace",
707
+ marketplace_billing_note: "Ihr Abonnement wird über den Google Cloud Marketplace verwaltet. Planänderungen, Abrechnung und Kündigung werden in der GCP-Konsole durchgeführt.",
708
+ marketplace_manage_in_gcp_console: "In der GCP-Konsole verwalten",
709
+ marketplace_plan_changes_note: "Um Ihren Plan zu ändern oder zu kündigen, besuchen Sie Ihre GCP Marketplace-Bestellungen.",
710
+ marketplace_welcome_title: "Willkommen vom GCP Marketplace!",
711
+ marketplace_welcome_subtitle: "Ihr Google Cloud Marketplace-Abonnement ist aktiv. Wählen Sie ein vorhandenes Projekt aus oder erstellen Sie ein neues, um es zu verknüpfen.",
712
+ marketplace_select_or_create_project: "Projekt auswählen oder erstellen",
713
+ marketplace_link_project: "Projekt verknüpfen",
714
+ marketplace_linking: "Projekt wird verknüpft…",
715
+ marketplace_link_success: "Projekt erfolgreich verknüpft! Weiterleitung…",
716
+ marketplace_link_error: "Fehler beim Verknüpfen des Projekts. Bitte versuchen Sie es erneut.",
717
+ marketplace_no_account_id: "Keine GCP Marketplace-Konto-ID gefunden. Bitte starten Sie vom GCP Marketplace.",
691
718
  };
package/src/locales/en.ts CHANGED
@@ -445,6 +445,8 @@ export const en: FireCMSTranslations = {
445
445
  cms_users: "CMS Users",
446
446
  roles_menu: "Roles",
447
447
  project_settings: "Project settings",
448
+ firestore_manager: "Firestore Manager",
449
+ manage_your_firestore_data: "Manage your Firestore data",
448
450
 
449
451
  // ─── FireCMS Cloud Login ──────────────────────────────────────
450
452
  build_admin_panel_in_minutes: "Build Your Firebase Admin Panel in Minutes",
@@ -700,4 +702,29 @@ export const en: FireCMSTranslations = {
700
702
  settings_appcheck_refresh_note: "You might need to refresh the page to see the changes, after saving.",
701
703
  settings_appcheck_updated: "AppCheck updated",
702
704
  settings_appcheck_error: "Error updating AppCheck",
705
+
706
+ // --- Permission Error View ---
707
+ missing_firestore_security_rules: "Missing Firestore Security Rules",
708
+ firecms_cloud_requires_security_rule: "FireCMS Cloud requires a specific security rule in your Firestore to grant access to authenticated users. The collection",
709
+ cannot_be_accessed_without_it: "cannot be accessed without it.",
710
+ required_security_rule: "Required security rule",
711
+ fix_automatically: "Fix automatically",
712
+ open_firebase_rules: "Open Firebase Rules",
713
+ security_rules_updated_successfully: "Security rules updated successfully! Please refresh the page to load your data.",
714
+ sec_rules_fixing: "Fixing...",
715
+ sec_rules_fixed: "Fixed!",
716
+
717
+ // ─── GCP Marketplace ─────────────────────────────────────────
718
+ marketplace_managed_by_gcp: "Managed via GCP Marketplace",
719
+ marketplace_billing_note: "Your subscription is managed through Google Cloud Marketplace. Plan changes, billing, and cancellation are handled in the GCP Console.",
720
+ marketplace_manage_in_gcp_console: "Manage in GCP Console",
721
+ marketplace_plan_changes_note: "To change your plan or cancel, visit your GCP Marketplace orders.",
722
+ marketplace_welcome_title: "Welcome from GCP Marketplace!",
723
+ marketplace_welcome_subtitle: "Your Google Cloud Marketplace subscription is active. Select an existing project or create a new one to link it.",
724
+ marketplace_select_or_create_project: "Select or create a project",
725
+ marketplace_link_project: "Link project",
726
+ marketplace_linking: "Linking project…",
727
+ marketplace_link_success: "Project linked successfully! Redirecting…",
728
+ marketplace_link_error: "Error linking project. Please try again.",
729
+ marketplace_no_account_id: "No GCP Marketplace account ID found. Please start from the GCP Marketplace.",
703
730
  };