@firecms/core 3.1.0-canary.9e89e98 → 3.1.0-canary.a3b8228

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 (216) hide show
  1. package/dist/components/EntityCollectionTable/internal/popup_field/useDraggable.d.ts +2 -2
  2. package/dist/components/EntityCollectionView/CollectionDataErrorBanner.d.ts +4 -0
  3. package/dist/components/ErrorBoundary.d.ts +4 -2
  4. package/dist/components/HomePage/DefaultHomePage.d.ts +0 -1
  5. package/dist/components/LanguageToggle.d.ts +1 -0
  6. package/dist/components/UnsavedChangesDialog.d.ts +1 -0
  7. package/dist/components/VirtualTable/VirtualTableHeader.d.ts +1 -1
  8. package/dist/components/index.d.ts +1 -0
  9. package/dist/core/DrawerNavigationGroup.d.ts +2 -2
  10. package/dist/editor/components/SlashCommandMenu.d.ts +6 -0
  11. package/dist/editor/components/editor-bubble-item.d.ts +8 -0
  12. package/dist/editor/components/editor-bubble.d.ts +8 -0
  13. package/dist/editor/components/image-bubble.d.ts +5 -0
  14. package/dist/editor/components/index.d.ts +16 -0
  15. package/dist/editor/components/table-bubble.d.ts +5 -0
  16. package/dist/editor/editor.d.ts +30 -0
  17. package/dist/editor/extensions/HighlightDecorationExtension.d.ts +24 -0
  18. package/dist/editor/extensions/Image/index.d.ts +6 -0
  19. package/dist/editor/extensions/Image.d.ts +6 -0
  20. package/dist/editor/extensions/TextLoadingDecorationExtension.d.ts +16 -0
  21. package/dist/editor/extensions/clipboard.d.ts +7 -0
  22. package/dist/editor/extensions/custom-keymap.d.ts +1 -0
  23. package/dist/editor/extensions/drag-and-drop.d.ts +9 -0
  24. package/dist/editor/hooks/useProseMirror.d.ts +13 -0
  25. package/dist/editor/hooks/useProseMirrorContext.d.ts +9 -0
  26. package/dist/editor/index.d.ts +2 -0
  27. package/dist/editor/markdown.d.ts +5 -0
  28. package/dist/editor/nodeViews/ImageComponent.d.ts +3 -0
  29. package/dist/editor/nodeViews/ReactNodeView.d.ts +29 -0
  30. package/dist/editor/nodeViews/TaskItemComponent.d.ts +3 -0
  31. package/dist/editor/nodeViews/index.d.ts +6 -0
  32. package/dist/editor/plugins/index.d.ts +2 -0
  33. package/dist/editor/plugins/inputrules.d.ts +6 -0
  34. package/dist/editor/plugins/placeholderPlugin.d.ts +3 -0
  35. package/dist/editor/plugins/slashCommandPlugin.d.ts +12 -0
  36. package/dist/editor/schema.d.ts +2 -0
  37. package/dist/editor/selectors/ai-selector.d.ts +0 -0
  38. package/dist/editor/selectors/color-selector.d.ts +10 -0
  39. package/dist/editor/selectors/link-selector.d.ts +8 -0
  40. package/dist/editor/selectors/node-selector.d.ts +15 -0
  41. package/dist/editor/selectors/text-buttons.d.ts +1 -0
  42. package/dist/editor/types.d.ts +5 -0
  43. package/dist/editor/useProseMirror.d.ts +16 -0
  44. package/dist/editor/utils/prosemirror-utils.d.ts +6 -0
  45. package/dist/editor/utils/remove_classes.d.ts +1 -0
  46. package/dist/editor/utils/useDebouncedCallback.d.ts +1 -0
  47. package/dist/form/components/ErrorFocus.d.ts +1 -1
  48. package/dist/form/field_bindings/MarkdownEditorFieldBinding.d.ts +1 -1
  49. package/dist/hooks/index.d.ts +1 -0
  50. package/dist/hooks/useBuildNavigationController.d.ts +0 -1
  51. package/dist/hooks/useCollapsedGroups.d.ts +3 -3
  52. package/dist/hooks/useTranslation.d.ts +17 -0
  53. package/dist/i18n/FireCMSi18nProvider.d.ts +33 -0
  54. package/dist/index.d.ts +4 -0
  55. package/dist/index.es.js +13009 -2312
  56. package/dist/index.es.js.map +1 -1
  57. package/dist/index.umd.js +12997 -2320
  58. package/dist/index.umd.js.map +1 -1
  59. package/dist/internal/useRestoreScroll.d.ts +1 -1
  60. package/dist/locales/de.d.ts +2 -0
  61. package/dist/locales/en.d.ts +10 -0
  62. package/dist/locales/es.d.ts +10 -0
  63. package/dist/locales/fr.d.ts +2 -0
  64. package/dist/locales/hi.d.ts +2 -0
  65. package/dist/locales/it.d.ts +2 -0
  66. package/dist/locales/pt.d.ts +7 -0
  67. package/dist/types/analytics.d.ts +1 -1
  68. package/dist/types/customization_controller.d.ts +2 -1
  69. package/dist/types/firecms.d.ts +2 -1
  70. package/dist/types/index.d.ts +1 -0
  71. package/dist/types/navigation.d.ts +2 -2
  72. package/dist/types/plugins.d.ts +23 -0
  73. package/dist/types/storage.d.ts +1 -0
  74. package/dist/types/translations.d.ts +646 -0
  75. package/dist/util/entities.d.ts +1 -1
  76. package/dist/util/resolutions.d.ts +2 -2
  77. package/dist/util/useStorageUploadController.d.ts +10 -1
  78. package/package.json +49 -13
  79. package/src/app/Scaffold.tsx +7 -5
  80. package/src/components/AIIcon.tsx +3 -1
  81. package/src/components/ArrayContainer.tsx +6 -4
  82. package/src/components/ClearFilterSortButton.tsx +6 -3
  83. package/src/components/ConfirmationDialog.tsx +4 -2
  84. package/src/components/DeleteEntityDialog.tsx +10 -7
  85. package/src/components/EntityCollectionTable/fields/TableReferenceField.tsx +6 -3
  86. package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +3 -1
  87. package/src/components/EntityCollectionTable/internal/EntityTableCellActions.tsx +1 -1
  88. package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +3 -2
  89. package/src/components/EntityCollectionTable/internal/popup_field/useDraggable.tsx +11 -11
  90. package/src/components/EntityCollectionView/BoardSortableList.tsx +3 -1
  91. package/src/components/EntityCollectionView/CollectionDataErrorBanner.tsx +43 -0
  92. package/src/components/EntityCollectionView/EntityBoardCard.tsx +1 -1
  93. package/src/components/EntityCollectionView/EntityCard.tsx +4 -0
  94. package/src/components/EntityCollectionView/EntityCollectionBoardView.tsx +39 -46
  95. package/src/components/EntityCollectionView/EntityCollectionCardView.tsx +17 -25
  96. package/src/components/EntityCollectionView/EntityCollectionView.tsx +54 -17
  97. package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +4 -3
  98. package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +4 -2
  99. package/src/components/EntityCollectionView/FiltersDialog.tsx +8 -5
  100. package/src/components/EntityCollectionView/ViewModeToggle.tsx +11 -8
  101. package/src/components/EntityView.tsx +3 -2
  102. package/src/components/ErrorBoundary.tsx +27 -15
  103. package/src/components/HomePage/DefaultHomePage.tsx +19 -13
  104. package/src/components/HomePage/HomePageDnD.tsx +3 -1
  105. package/src/components/HomePage/NavigationGroup.tsx +3 -1
  106. package/src/components/HomePage/RenameGroupDialog.tsx +15 -13
  107. package/src/components/LanguageToggle.tsx +66 -0
  108. package/src/components/NotFoundPage.tsx +5 -3
  109. package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +9 -7
  110. package/src/components/ReferenceWidget.tsx +3 -2
  111. package/src/components/SearchIconsView.tsx +3 -1
  112. package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +11 -0
  113. package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +15 -2
  114. package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +11 -0
  115. package/src/components/UnsavedChangesDialog.tsx +6 -4
  116. package/src/components/VirtualTable/VirtualTable.performance.test.tsx +1 -0
  117. package/src/components/VirtualTable/VirtualTable.tsx +116 -113
  118. package/src/components/VirtualTable/VirtualTableHeader.tsx +54 -52
  119. package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +1 -1
  120. package/src/components/VirtualTable/fields/VirtualTableSelect.tsx +3 -3
  121. package/src/components/common/default_entity_actions.tsx +4 -0
  122. package/src/components/common/useDataSourceTableController.tsx +12 -4
  123. package/src/components/index.tsx +1 -0
  124. package/src/core/DefaultAppBar.tsx +15 -11
  125. package/src/core/DefaultDrawer.tsx +8 -2
  126. package/src/core/DrawerNavigationGroup.tsx +5 -3
  127. package/src/core/EntityEditView.tsx +4 -3
  128. package/src/core/EntityEditViewFormActions.tsx +24 -17
  129. package/src/core/EntitySidePanel.tsx +32 -29
  130. package/src/core/FireCMS.tsx +33 -6
  131. package/src/core/field_configs.tsx +14 -9
  132. package/src/editor/components/SlashCommandMenu.tsx +516 -0
  133. package/src/editor/components/editor-bubble-item.tsx +32 -0
  134. package/src/editor/components/editor-bubble.tsx +118 -0
  135. package/src/editor/components/image-bubble.tsx +156 -0
  136. package/src/editor/components/index.ts +14 -0
  137. package/src/editor/components/table-bubble.tsx +165 -0
  138. package/src/editor/editor.tsx +455 -0
  139. package/src/editor/extensions/HighlightDecorationExtension.ts +114 -0
  140. package/src/editor/extensions/Image/index.ts +133 -0
  141. package/src/editor/extensions/Image.ts +159 -0
  142. package/src/editor/extensions/TextLoadingDecorationExtension.tsx +107 -0
  143. package/src/editor/extensions/clipboard.ts +72 -0
  144. package/src/editor/extensions/custom-keymap.ts +24 -0
  145. package/src/editor/extensions/drag-and-drop.tsx +480 -0
  146. package/src/editor/hooks/useProseMirror.ts +124 -0
  147. package/src/editor/hooks/useProseMirrorContext.ts +15 -0
  148. package/src/editor/index.ts +2 -0
  149. package/src/editor/markdown.ts +172 -0
  150. package/src/editor/nodeViews/ImageComponent.tsx +20 -0
  151. package/src/editor/nodeViews/ReactNodeView.tsx +89 -0
  152. package/src/editor/nodeViews/TaskItemComponent.tsx +29 -0
  153. package/src/editor/nodeViews/index.ts +35 -0
  154. package/src/editor/plugins/index.ts +58 -0
  155. package/src/editor/plugins/inputrules.ts +82 -0
  156. package/src/editor/plugins/placeholderPlugin.ts +55 -0
  157. package/src/editor/plugins/slashCommandPlugin.ts +61 -0
  158. package/src/editor/schema.ts +240 -0
  159. package/src/editor/selectors/ai-selector.tsx +111 -0
  160. package/src/editor/selectors/color-selector.tsx +200 -0
  161. package/src/editor/selectors/link-selector.tsx +118 -0
  162. package/src/editor/selectors/node-selector.tsx +157 -0
  163. package/src/editor/selectors/text-buttons.tsx +86 -0
  164. package/src/editor/types.ts +6 -0
  165. package/src/editor/useProseMirror.ts +126 -0
  166. package/src/editor/utils/prosemirror-utils.ts +108 -0
  167. package/src/editor/utils/remove_classes.ts +17 -0
  168. package/src/editor/utils/useDebouncedCallback.ts +25 -0
  169. package/src/form/EntityForm.tsx +85 -63
  170. package/src/form/EntityFormActions.tsx +19 -12
  171. package/src/form/PropertyFieldBinding.tsx +6 -5
  172. package/src/form/components/ErrorFocus.tsx +3 -3
  173. package/src/form/components/LocalChangesMenu.tsx +13 -13
  174. package/src/form/components/StorageItemPreview.tsx +3 -2
  175. package/src/form/components/StorageUploadProgress.tsx +18 -3
  176. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +4 -4
  177. package/src/form/field_bindings/BlockFieldBinding.tsx +5 -2
  178. package/src/form/field_bindings/KeyValueFieldBinding.tsx +23 -18
  179. package/src/form/field_bindings/MapFieldBinding.tsx +4 -3
  180. package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +34 -20
  181. package/src/form/field_bindings/RepeatFieldBinding.tsx +3 -1
  182. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +87 -86
  183. package/src/hooks/index.tsx +1 -0
  184. package/src/hooks/useBuildNavigationController.tsx +49 -22
  185. package/src/hooks/useCollapsedGroups.ts +7 -6
  186. package/src/hooks/useTranslation.ts +31 -0
  187. package/src/hooks/useValidateAuthenticator.tsx +1 -1
  188. package/src/i18n/FireCMSi18nProvider.tsx +160 -0
  189. package/src/index.ts +4 -0
  190. package/src/internal/useBuildDataSource.ts +1 -2
  191. package/src/internal/useBuildSideEntityController.tsx +22 -20
  192. package/src/locales/de.ts +691 -0
  193. package/src/locales/en.ts +703 -0
  194. package/src/locales/es.ts +703 -0
  195. package/src/locales/fr.ts +691 -0
  196. package/src/locales/hi.ts +691 -0
  197. package/src/locales/it.ts +691 -0
  198. package/src/locales/pt.ts +700 -0
  199. package/src/preview/PropertyPreview.tsx +1 -0
  200. package/src/preview/components/UrlComponentPreview.tsx +4 -2
  201. package/src/preview/components/UserPreview.tsx +3 -1
  202. package/src/types/analytics.ts +10 -0
  203. package/src/types/customization_controller.tsx +2 -1
  204. package/src/types/firecms.tsx +2 -1
  205. package/src/types/index.ts +1 -0
  206. package/src/types/navigation.ts +2 -2
  207. package/src/types/plugins.tsx +26 -0
  208. package/src/types/properties.ts +1 -0
  209. package/src/types/storage.ts +2 -1
  210. package/src/types/translations.ts +725 -0
  211. package/src/util/entities.ts +1 -1
  212. package/src/util/join_collections.ts +10 -8
  213. package/src/util/previews.ts +2 -2
  214. package/src/util/property_utils.tsx +1 -1
  215. package/src/util/resolutions.ts +5 -3
  216. package/src/util/useStorageUploadController.tsx +23 -29
@@ -40,7 +40,10 @@ import {
40
40
  useSnackbarController
41
41
  } from "../hooks";
42
42
  import { Alert, CheckIcon, Chip, cls, EditIcon, NotesIcon, paperMixin, Tooltip, Typography } from "@firecms/ui";
43
- import { Formex, FormexController, getIn, setIn, useCreateFormex } from "@firecms/formex";
43
+ import { Formex, FormexController, getIn, setIn, useCreateFormex,
44
+ useFormex
45
+ } from "@firecms/formex";
46
+ import { useTranslation } from "../hooks";
44
47
  import { useAnalyticsController } from "../hooks/useAnalyticsController";
45
48
  import { FormEntry, FormLayout, LabelWithIconAndTooltip, PropertyFieldBinding } from "../form";
46
49
  import { ValidationError } from "yup";
@@ -181,30 +184,30 @@ export function getChanges<T extends object>(source: Partial<T>, comparison: Par
181
184
  }
182
185
 
183
186
  export function EntityForm<M extends Record<string, any>>({
184
- path,
185
- fullIdPath,
186
- entityId: entityIdProp,
187
- collection,
188
- onValuesModified,
189
- onIdChange,
190
- onSaved,
191
- entity,
192
- initialDirtyValues,
193
- onFormContextReady,
194
- forceActionsAtTheBottom,
195
- initialStatus,
196
- className,
197
- onStatusChange,
198
- onEntityChange,
199
- openEntityMode = "full_screen",
200
- formex: formexProp,
201
- disabled: disabledProp,
202
- Builder,
203
- EntityFormActionsComponent = EntityFormActions,
204
- showDefaultActions = true,
205
- showEntityPath = true,
206
- children
207
- }: EntityFormProps<M>) {
187
+ path,
188
+ fullIdPath,
189
+ entityId: entityIdProp,
190
+ collection,
191
+ onValuesModified,
192
+ onIdChange,
193
+ onSaved,
194
+ entity,
195
+ initialDirtyValues,
196
+ onFormContextReady,
197
+ forceActionsAtTheBottom,
198
+ initialStatus,
199
+ className,
200
+ onStatusChange,
201
+ onEntityChange,
202
+ openEntityMode = "full_screen",
203
+ formex: formexProp,
204
+ disabled: disabledProp,
205
+ Builder,
206
+ EntityFormActionsComponent = EntityFormActions,
207
+ showDefaultActions = true,
208
+ showEntityPath = true,
209
+ children
210
+ }: EntityFormProps<M>) {
208
211
 
209
212
  if (collection.customId && collection.formAutoSave) {
210
213
  console.warn(`The collection ${collection.path} has customId and formAutoSave enabled. This is not supported and formAutoSave will be ignored`);
@@ -212,6 +215,7 @@ export function EntityForm<M extends Record<string, any>>({
212
215
 
213
216
  const sideEntityController = useSideEntityController();
214
217
  const navigationController = useNavigationController();
218
+ const { t } = useTranslation();
215
219
 
216
220
  const navigateBack = useCallback(() => {
217
221
  if (openEntityMode === "side_panel") {
@@ -366,6 +370,15 @@ export function EntityForm<M extends Record<string, any>>({
366
370
  useEffect(() => {
367
371
 
368
372
  const handleKeyDown = (e: KeyboardEvent) => {
373
+ if (e.defaultPrevented) return;
374
+ const activeElement = document.activeElement as HTMLElement;
375
+ const isInput = activeElement && (
376
+ activeElement.tagName === "INPUT" ||
377
+ activeElement.tagName === "TEXTAREA" ||
378
+ activeElement.isContentEditable
379
+ );
380
+ if (isInput) return;
381
+
369
382
  const isUndo = (e.metaKey || e.ctrlKey) && !e.shiftKey && e.key.toLowerCase() === "z";
370
383
  const isRedo =
371
384
  ((e.metaKey || e.ctrlKey) && e.shiftKey && e.key.toLowerCase() === "z") ||
@@ -455,12 +468,12 @@ export function EntityForm<M extends Record<string, any>>({
455
468
  }, [entityId, path, snackbarController]);
456
469
 
457
470
  const saveEntity = ({
458
- values,
459
- previousValues,
460
- entityId,
461
- collection,
462
- path
463
- }: {
471
+ values,
472
+ previousValues,
473
+ entityId,
474
+ collection,
475
+ path
476
+ }: {
464
477
  collection: EntityCollection<M>,
465
478
  path: string,
466
479
  entityId: string | undefined,
@@ -493,13 +506,13 @@ export function EntityForm<M extends Record<string, any>>({
493
506
  };
494
507
 
495
508
  const onSaveEntityRequest = async ({
496
- collection,
497
- path,
498
- entityId,
499
- values,
500
- previousValues,
501
- autoSave
502
- }: EntityFormSaveParams<M>): Promise<void> => {
509
+ collection,
510
+ path,
511
+ entityId,
512
+ values,
513
+ previousValues,
514
+ autoSave
515
+ }: EntityFormSaveParams<M>): Promise<void> => {
503
516
  if (!status)
504
517
  return;
505
518
  if (autoSave) {
@@ -567,6 +580,7 @@ export function EntityForm<M extends Record<string, any>>({
567
580
  }, [snackbarController]);
568
581
 
569
582
  const pluginActions: React.ReactNode[] = [];
583
+ const pluginBeforeTitle: React.ReactNode[] = [];
570
584
  const plugins = customizationController.plugins;
571
585
 
572
586
  const actionsDisabled = disabled || formex.isSubmitting || (status === "existing" && !formex.dirty) || Boolean(disabledProp);
@@ -590,6 +604,12 @@ export function EntityForm<M extends Record<string, any>>({
590
604
  key={`actions_${plugin.key}`} {...actionProps} />
591
605
  : null
592
606
  )).filter(Boolean));
607
+ pluginBeforeTitle.push(...plugins.map((plugin) => (
608
+ plugin.form?.BeforeTitle
609
+ ? <plugin.form.BeforeTitle
610
+ key={`before_title_${plugin.key}`} {...actionProps} />
611
+ : null
612
+ )).filter(Boolean));
593
613
  }
594
614
 
595
615
  const titlePropertyKey = getEntityTitlePropertyKey(resolvedCollection, customizationController.propertyConfigs);
@@ -631,17 +651,17 @@ export function EntityForm<M extends Record<string, any>>({
631
651
  const modified = formex.dirty;
632
652
 
633
653
  const uniqueFieldValidator: CustomFieldValidator = useCallback(({
634
- name,
635
- value
636
- }) => dataSource.checkUniqueField(path, name, value, entityId, collection),
654
+ name,
655
+ value
656
+ }) => dataSource.checkUniqueField(path, name, value, entityId, collection),
637
657
  [dataSource, path, entityId]);
638
658
 
639
659
  const validationSchema = useMemo(() => entityId
640
- ? getYupEntitySchema(
641
- entityId,
642
- resolvedCollection.properties,
643
- uniqueFieldValidator)
644
- : undefined,
660
+ ? getYupEntitySchema(
661
+ entityId,
662
+ resolvedCollection.properties,
663
+ uniqueFieldValidator)
664
+ : undefined,
645
665
  [entityId, resolvedCollection.properties, uniqueFieldValidator]);
646
666
 
647
667
  useOnAutoSave(autoSave, formex, lastSavedValues, save);
@@ -699,8 +719,8 @@ export function EntityForm<M extends Record<string, any>>({
699
719
 
700
720
  return (
701
721
  <FormEntry propertyKey={key}
702
- widthPercentage={widthPercentage}
703
- key={`field_${key}`}>
722
+ widthPercentage={widthPercentage}
723
+ key={`field_${key}`}>
704
724
  <PropertyFieldBinding {...cmsFormFieldProps} />
705
725
  </FormEntry>
706
726
  );
@@ -713,7 +733,7 @@ export function EntityForm<M extends Record<string, any>>({
713
733
  throw new Error("When using additional fields you need to provide a Builder or a value");
714
734
  }
715
735
  const child = Builder
716
- ? <Builder entity={entity} context={context}/>
736
+ ? <Builder entity={entity} context={context} />
717
737
  : <div className={"w-full"}>
718
738
  {additionalField.value?.({
719
739
  entity,
@@ -725,9 +745,9 @@ export function EntityForm<M extends Record<string, any>>({
725
745
  <div key={`additional_${key}`} className={"w-full"}>
726
746
  <LabelWithIconAndTooltip
727
747
  propertyKey={key}
728
- icon={<NotesIcon size={"small"}/>}
748
+ icon={<NotesIcon size={"small"} />}
729
749
  title={additionalField.name}
730
- className={"text-text-secondary dark:text-text-secondary-dark ml-3.5"}/>
750
+ className={"text-text-secondary dark:text-text-secondary-dark ml-3.5"} />
731
751
  <div
732
752
  className={cls(paperMixin, "w-full min-h-14 p-4 md:p-6 overflow-x-scroll no-scrollbar")}>
733
753
  <ErrorBoundary>
@@ -749,6 +769,8 @@ export function EntityForm<M extends Record<string, any>>({
749
769
 
750
770
  const formView = <ErrorBoundary>
751
771
  <>
772
+ {pluginBeforeTitle}
773
+
752
774
  {!Builder && <div className={"w-full py-2 flex flex-col items-start my-4 lg:my-6"}>
753
775
  <Typography
754
776
  className={"my-4 flex-grow line-clamp-1 " + (collection.hideIdFromForm ? "mb-6" : "")}
@@ -758,7 +780,7 @@ export function EntityForm<M extends Record<string, any>>({
758
780
 
759
781
  {!entity?.values && initialStatus === "existing" &&
760
782
  <Alert color={"warning"} size={"small"} outerClassName={"w-full mb-4 text-xs"}>
761
- This entity does not exist in the database
783
+ {t("this_entity_not_exist")}
762
784
  </Alert>}
763
785
 
764
786
  {showEntityPath && <Alert color={"base"} outerClassName={"w-full"} size={"small"}>
@@ -772,27 +794,27 @@ export function EntityForm<M extends Record<string, any>>({
772
794
  {children}
773
795
 
774
796
  {initialEntityId && !entity && initialStatus !== "new" && <Alert color={"info"} size={"small"}>
775
- This entity does not exist in the database
797
+ {t("this_entity_not_exist")}
776
798
  </Alert>}
777
799
 
778
800
  {!Builder && !collection.hideIdFromForm &&
779
801
  <CustomIdField customId={collection.customId}
780
- entityId={entityId}
781
- status={status}
782
- onChange={setEntityId}
783
- error={entityIdError}
784
- loading={customIdLoading}
785
- entity={entity}/>
802
+ entityId={entityId}
803
+ status={status}
804
+ onChange={setEntityId}
805
+ error={entityIdError}
806
+ loading={customIdLoading}
807
+ entity={entity} />
786
808
  }
787
809
 
788
810
  {entityId && formContext && <>
789
811
  <div className="mt-12 flex flex-col gap-8" ref={formRef}>
790
812
  {formFields()}
791
- <ErrorFocus containerRef={formRef}/>
813
+ <ErrorFocus containerRef={formRef} />
792
814
  </div>
793
815
  </>}
794
816
 
795
- {forceActionsAtTheBottom && <div className="h-16"/>}
817
+ {forceActionsAtTheBottom && <div className="h-16" />}
796
818
  </>
797
819
  </ErrorBoundary>;
798
820
 
@@ -852,12 +874,12 @@ export function EntityForm<M extends Record<string, any>>({
852
874
  {formex.dirty
853
875
  ? <Tooltip title={"This form has been modified"}>
854
876
  <Chip size={"small"} className={"py-1"} colorScheme={"orangeDarker"}>
855
- <EditIcon size={"smallest"}/>
877
+ <EditIcon size={"smallest"} />
856
878
  </Chip>
857
879
  </Tooltip>
858
880
  : <Tooltip title={"The current form is in sync with the database"}>
859
881
  <Chip size={"small"} className={"py-1"}>
860
- <CheckIcon size={"smallest"}/>
882
+ <CheckIcon size={"smallest"} />
861
883
  </Chip>
862
884
  </Tooltip>}
863
885
  </div>
@@ -19,6 +19,7 @@ import {
19
19
  } from "@firecms/ui";
20
20
  import { FormexController } from "@firecms/formex";
21
21
  import { useFireCMSContext, useSideEntityController } from "../hooks";
22
+ import { useTranslation } from "../hooks/useTranslation";
22
23
 
23
24
  export interface EntityFormActionsProps {
24
25
  fullPath: string;
@@ -56,6 +57,7 @@ export function EntityFormActions({
56
57
 
57
58
  const context = useFireCMSContext();
58
59
  const sideEntityController = useSideEntityController();
60
+ const { t } = useTranslation();
59
61
 
60
62
  return layout === "bottom"
61
63
  ? buildBottomActions({
@@ -72,7 +74,8 @@ export function EntityFormActions({
72
74
  openEntityMode,
73
75
  navigateBack,
74
76
  formContext,
75
- formex
77
+ formex,
78
+ t
76
79
  })
77
80
  : buildSideActions({
78
81
  fullPath,
@@ -88,7 +91,8 @@ export function EntityFormActions({
88
91
  openEntityMode,
89
92
  navigateBack,
90
93
  formContext,
91
- formex
94
+ formex,
95
+ t
92
96
  });
93
97
  }
94
98
 
@@ -108,6 +112,7 @@ type ActionsViewProps<M extends object> = {
108
112
  navigateBack: () => void;
109
113
  formContext: FormContext,
110
114
  formex: FormexController<any>;
115
+ t: (key: any, vars?: Record<string, string>) => string;
111
116
  };
112
117
 
113
118
  function buildBottomActions<M extends object>({
@@ -125,7 +130,8 @@ function buildBottomActions<M extends object>({
125
130
  openEntityMode,
126
131
  navigateBack,
127
132
  formContext,
128
- formex
133
+ formex,
134
+ t
129
135
  }: ActionsViewProps<M>) {
130
136
 
131
137
  const hasErrors = Object.keys(formex.errors).length > 0 && formex.submitCount > 0;
@@ -165,16 +171,16 @@ function buildBottomActions<M extends object>({
165
171
  <Button variant="text" disabled={disabled || formex.isSubmitting}
166
172
  color={"primary"}
167
173
  type="reset">
168
- {status === "existing" ? "Discard" : "Clear"}
174
+ {status === "existing" ? t("discard") : t("clear")}
169
175
  </Button>
170
176
  <Button variant={"filled"}
171
177
  color="primary"
172
178
  type="submit"
173
179
  disabled={disabled || formex.isSubmitting}
174
180
  startIcon={hasErrors ? <ErrorIcon/> : undefined}>
175
- {status === "existing" && "Save"}
176
- {status === "copy" && "Create copy"}
177
- {status === "new" && "Create"}
181
+ {status === "existing" && t("save")}
182
+ {status === "copy" && t("create_copy")}
183
+ {status === "new" && t("create")}
178
184
  </Button>
179
185
 
180
186
  </DialogActions>;
@@ -193,7 +199,8 @@ function buildSideActions<M extends object>({
193
199
  disabled,
194
200
  status,
195
201
  pluginActions,
196
- formex
202
+ formex,
203
+ t
197
204
  }: ActionsViewProps<M>) {
198
205
 
199
206
  const hasErrors = Object.keys(formex.errors).length > 0 && formex.submitCount > 0;
@@ -207,12 +214,12 @@ function buildSideActions<M extends object>({
207
214
  size={"large"}
208
215
  startIcon={hasErrors ? <ErrorIcon/> : undefined}
209
216
  disabled={disabled || formex.isSubmitting}>
210
- {status === "existing" && "Save"}
211
- {status === "copy" && "Create copy"}
212
- {status === "new" && "Create"}
217
+ {status === "existing" && t("save")}
218
+ {status === "copy" && t("create_copy")}
219
+ {status === "new" && t("create")}
213
220
  </LoadingButton>
214
221
  <Button fullWidth={true} variant="text" disabled={disabled || formex.isSubmitting} type="reset">
215
- {status === "existing" ? "Discard" : "Clear"}
222
+ {status === "existing" ? t("discard") : t("clear")}
216
223
  </Button>
217
224
 
218
225
  {pluginActions}
@@ -17,7 +17,7 @@ import {
17
17
  import { ReadOnlyFieldBinding } from "./field_bindings/ReadOnlyFieldBinding";
18
18
 
19
19
  import { isHidden, isPropertyBuilder, isReadOnly, resolveProperty } from "../util";
20
- import { useAuthController, useCustomizationController } from "../hooks";
20
+ import { useAuthController, useCustomizationController, useTranslation } from "../hooks";
21
21
  import { Typography } from "@firecms/ui";
22
22
  import { getFieldConfig, getFieldId } from "../core";
23
23
  import { ErrorBoundary } from "../components";
@@ -137,7 +137,7 @@ function PropertyFieldBindingInternal<T extends CMSType = CMSType, M extends Rec
137
137
  }
138
138
  const configProperty = resolveProperty({
139
139
  propertyKey,
140
- propertyOrBuilder: propertyConfig.property,
140
+ propertyOrBuilder: propertyConfig.property as any,
141
141
  values: fieldProps.form.values,
142
142
  path: context.path,
143
143
  entityId: context.entityId,
@@ -145,7 +145,7 @@ function PropertyFieldBindingInternal<T extends CMSType = CMSType, M extends Rec
145
145
  index,
146
146
  authController
147
147
  });
148
- Component = configProperty.Field as ComponentType<FieldProps<T>>;
148
+ Component = configProperty?.Field as ComponentType<FieldProps<T>> | undefined;
149
149
  }
150
150
  if (!Component) {
151
151
  console.warn(`No field component found for property ${propertyKey}`);
@@ -213,6 +213,7 @@ function FieldInternal<T extends CMSType, CustomProps, M extends Record<string,
213
213
  formexFieldProps: FormexFieldProps<T, any>
214
214
  }) {
215
215
 
216
+ const { t } = useTranslation();
216
217
  const { plugins } = useCustomizationController();
217
218
 
218
219
  const customFieldProps: any = property.customProps;
@@ -291,7 +292,7 @@ function FieldInternal<T extends CMSType, CustomProps, M extends Record<string,
291
292
 
292
293
  {underlyingValueHasChanged && !isSubmitting &&
293
294
  <Typography variant={"caption"} className={"ml-3.5"}>
294
- This value has been updated elsewhere
295
+ {t("value_updated_elsewhere")}
295
296
  </Typography>}
296
297
 
297
298
  </ErrorBoundary>);
@@ -302,7 +303,7 @@ const shouldPropertyReRender = (property: PropertyOrBuilder | ResolvedProperty,
302
303
  if (plugins?.some((plugin) => plugin.form?.fieldBuilder)) {
303
304
  return true;
304
305
  }
305
- if (isPropertyBuilder(property)) {
306
+ if (isPropertyBuilder(property as any)) {
306
307
  return true;
307
308
  }
308
309
  const defAProperty = property as Property | ResolvedProperty;
@@ -2,9 +2,9 @@ import React, { useEffect, useRef } from "react";
2
2
  import { useFormex } from "@firecms/formex";
3
3
 
4
4
  export const ErrorFocus = ({ containerRef }:
5
- {
6
- containerRef?: React.RefObject<HTMLDivElement>
7
- }) => {
5
+ {
6
+ containerRef?: React.RefObject<HTMLDivElement | null>
7
+ }) => {
8
8
  const {
9
9
  isValidating,
10
10
  errors,
@@ -16,7 +16,7 @@ import {
16
16
  WarningIcon
17
17
  } from "@firecms/ui";
18
18
  import { FormexController } from "@firecms/formex";
19
- import { useSnackbarController } from "../../hooks";
19
+ import { useSnackbarController, useTranslation } from "../../hooks";
20
20
  import { mergeDeep } from "../../util";
21
21
  import { flattenKeys, removeEntityFromCache } from "../../util/entity_cache";
22
22
  import { ResolvedProperties } from "../../types";
@@ -39,6 +39,7 @@ export function LocalChangesMenu<M extends object>({
39
39
  }: LocalChangesMenuProps<M>) {
40
40
 
41
41
  const snackbarController = useSnackbarController();
42
+ const { t } = useTranslation();
42
43
  const [previewDialogOpen, setPreviewDialogOpen] = useState(false);
43
44
  const [open, setOpen] = useState(false);
44
45
 
@@ -62,7 +63,7 @@ export function LocalChangesMenu<M extends object>({
62
63
  formex.setValues(mergedValues);
63
64
  snackbarController.open({
64
65
  type: "info",
65
- message: "Local changes applied to the form"
66
+ message: t("local_changes_applied")
66
67
  });
67
68
  handleCloseMenu();
68
69
  onClearLocalChanges?.();
@@ -72,7 +73,7 @@ export function LocalChangesMenu<M extends object>({
72
73
  removeEntityFromCache(cacheKey);
73
74
  snackbarController.open({
74
75
  type: "info",
75
- message: "Local changes discarded"
76
+ message: t("local_changes_discarded")
76
77
  });
77
78
  handleCloseMenu();
78
79
  onClearLocalChanges?.();
@@ -90,7 +91,7 @@ export function LocalChangesMenu<M extends object>({
90
91
  onClick={handleOpenMenu}
91
92
  >
92
93
  <WarningIcon size={"smallest"} className={"mr-1 text-yellow-600 dark:text-yellow-400"}/>
93
- Unsaved Local changes
94
+ {t("unsaved_local_changes")}
94
95
  <KeyboardArrowDownIcon size={"smallest"}/>
95
96
  </Button>
96
97
  }
@@ -98,12 +99,11 @@ export function LocalChangesMenu<M extends object>({
98
99
  onOpenChange={setOpen}
99
100
  >
100
101
  <div className={"max-w-xs px-4 py-4 text-sm text-gray-700 dark:text-gray-300"}>
101
- This document was edited locally and has unsaved changes. These local changes will be lost if you
102
- don't apply them.
102
+ {t("unsaved_local_changes_description")}
103
103
  </div>
104
- <MenuItem dense onClick={handlePreview}><VisibilityIcon size={"small"}/>Preview Changes</MenuItem>
105
- <MenuItem dense onClick={handleApply}><CheckIcon size={"small"}/>Apply Changes</MenuItem>
106
- <MenuItem dense onClick={handleDiscard}><CancelIcon size={"small"}/>Discard Local Changes</MenuItem>
104
+ <MenuItem dense onClick={handlePreview}><VisibilityIcon size={"small"}/>{t("preview_changes")}</MenuItem>
105
+ <MenuItem dense onClick={handleApply}><CheckIcon size={"small"}/>{t("apply_changes")}</MenuItem>
106
+ <MenuItem dense onClick={handleDiscard}><CancelIcon size={"small"}/>{t("discard_local_changes")}</MenuItem>
107
107
  </Menu>
108
108
 
109
109
  <Dialog
@@ -111,10 +111,10 @@ export function LocalChangesMenu<M extends object>({
111
111
  onOpenChange={setPreviewDialogOpen}
112
112
  maxWidth={"4xl"}
113
113
  >
114
- <DialogTitle variant={"h6"}>Preview Local Changes</DialogTitle>
114
+ <DialogTitle variant={"h6"}>{t("preview_local_changes")}</DialogTitle>
115
115
  <DialogContent className={"my-4"}>
116
116
  <Typography variant={"body2"} className={"mb-4"}>
117
- These are the local changes that will be applied to the form.
117
+ {t("preview_local_changes_description")}
118
118
  </Typography>
119
119
  <div className={`border rounded-lg ${defaultBorderMixin}`} style={{
120
120
  maxHeight: 520,
@@ -127,7 +127,7 @@ export function LocalChangesMenu<M extends object>({
127
127
  </div>
128
128
  </DialogContent>
129
129
  <DialogActions>
130
- <Button onClick={() => setPreviewDialogOpen(false)}>Close</Button>
130
+ <Button onClick={() => setPreviewDialogOpen(false)}>{t("close")}</Button>
131
131
  <Button
132
132
  variant={"filled"}
133
133
  onClick={() => {
@@ -135,7 +135,7 @@ export function LocalChangesMenu<M extends object>({
135
135
  setPreviewDialogOpen(false);
136
136
  }}
137
137
  >
138
- Apply changes
138
+ {t("apply_changes")}
139
139
  </Button>
140
140
  </DialogActions>
141
141
  </Dialog>
@@ -5,6 +5,7 @@ import { PreviewSize, PropertyPreview } from "../../preview";
5
5
 
6
6
  import { cls, DescriptionIcon, IconButton, paperMixin, RemoveIcon, Tooltip } from "@firecms/ui";
7
7
  import { ErrorBoundary } from "../../components";
8
+ import { useTranslation } from "../../hooks/useTranslation";
8
9
 
9
10
  interface StorageItemPreviewProps {
10
11
  name: string;
@@ -27,7 +28,7 @@ export function StorageItemPreview({
27
28
  placeholder,
28
29
  className
29
30
  }: StorageItemPreviewProps) {
30
-
31
+ const { t } = useTranslation();
31
32
  return (
32
33
  <div className={cls(
33
34
  "relative border-box flex items-center justify-center",
@@ -41,7 +42,7 @@ export function StorageItemPreview({
41
42
 
42
43
  <Tooltip
43
44
  asChild={true}
44
- title="Remove">
45
+ title={t("remove")}>
45
46
  <IconButton
46
47
  size={"small"}
47
48
  onClick={(event) => {
@@ -32,6 +32,7 @@ export function StorageUploadProgress({
32
32
 
33
33
  const [error, setError] = React.useState<Error | undefined>();
34
34
  const [loading, setLoading] = React.useState<boolean>(false);
35
+ const [progress, setProgress] = React.useState<number>(0);
35
36
  const mounted = React.useRef(false);
36
37
  const uploading = React.useRef(false);
37
38
 
@@ -46,7 +47,10 @@ export function StorageUploadProgress({
46
47
  file,
47
48
  fileName,
48
49
  path: storagePath,
49
- metadata
50
+ metadata,
51
+ onProgress: (p) => {
52
+ if (mounted.current) setProgress(p);
53
+ }
50
54
  })
51
55
  .then(async ({ path, storageUrl }) => {
52
56
  console.debug("Upload successful", path);
@@ -79,22 +83,33 @@ export function StorageUploadProgress({
79
83
  };
80
84
  }, [entry.file, entry.fileName, upload]);
81
85
 
86
+ const isLargeFile = entry.file && entry.file.size > 500 * 1024;
87
+ const renderProgressBar = loading && isLargeFile && progress > 0;
88
+ const progressBar = renderProgressBar && (
89
+ <div className="absolute bottom-0 left-0 h-1 bg-primary w-full origin-left transition-transform duration-200"
90
+ style={{ transform: `scaleX(${progress / 100})` }} />
91
+ );
92
+
82
93
  if (simple) {
83
- return <div className={`w-${imageSize} h-${imageSize}`}>
94
+ return <div className={`relative overflow-hidden w-${imageSize} h-${imageSize}`}>
84
95
 
85
96
  {loading && <Skeleton className={`w-${imageSize} h-${imageSize}`}/>}
86
97
 
98
+ {progressBar}
99
+
87
100
  </div>
88
101
  }
89
102
  return (
90
103
 
91
104
  <div className={cls(paperMixin,
92
- "p-4 relative border-box flex items-center justify-center",
105
+ "p-4 relative overflow-hidden border-box flex items-center justify-center",
93
106
  `min-w-[${imageSize}px] min-h-[${imageSize}px]`)}>
94
107
 
95
108
  {loading &&
96
109
  <Skeleton className="w-full h-full"/>}
97
110
 
111
+ {progressBar}
112
+
98
113
  {error && <ErrorView title={"Error uploading file"}
99
114
  error={error}/>}
100
115
 
@@ -4,8 +4,7 @@ import { ReferencePreview } from "../../preview";
4
4
  import { FieldHelperText, LabelWithIconAndTooltip } from "../components";
5
5
  import { ArrayContainer, ArrayEntryParams, ErrorView } from "../../components";
6
6
  import { getIconForProperty, getReferenceFrom } from "../../util";
7
-
8
- import { useNavigationController, useReferenceDialog } from "../../hooks";
7
+ import { useNavigationController, useReferenceDialog, useTranslation } from "../../hooks";
9
8
  import { Button, cls, EditIcon, ExpandablePanel, fieldBackgroundMixin, Typography } from "@firecms/ui";
10
9
  import { useClearRestoreValue } from "../useClearRestoreValue";
11
10
 
@@ -48,6 +47,7 @@ export function ArrayOfReferencesFieldBinding({
48
47
  setValue
49
48
  });
50
49
 
50
+ const { t } = useTranslation();
51
51
  const navigationController = useNavigationController();
52
52
  const collection: EntityCollection | undefined = useMemo(() => {
53
53
  return ofProperty.path ? navigationController.getCollection(ofProperty.path) : undefined;
@@ -84,7 +84,7 @@ export function ArrayOfReferencesFieldBinding({
84
84
  }: ArrayEntryParams) => {
85
85
  const entryValue = value && value.length > index ? value[index] : undefined;
86
86
  if (!entryValue)
87
- return <div>Internal ERROR</div>;
87
+ return <div>{t("internal_error")}</div>;
88
88
  return (
89
89
  <ReferencePreview
90
90
  key={internalId}
@@ -132,7 +132,7 @@ export function ArrayOfReferencesFieldBinding({
132
132
  disabled={isSubmitting}
133
133
  onClick={onEntryClick}>
134
134
  <EditIcon size={"small"}/>
135
- Edit {property.name}
135
+ {t("edit_name", { name: property.name ?? "" })}
136
136
  </Button>
137
137
  </div>}
138
138
  </>;