@firecms/core 3.0.0-canary.25 → 3.0.0-canary.251

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 (401) hide show
  1. package/README.md +3 -3
  2. package/dist/app/AppBar.d.ts +12 -0
  3. package/dist/app/Drawer.d.ts +16 -0
  4. package/dist/app/Scaffold.d.ts +34 -0
  5. package/dist/app/index.d.ts +4 -0
  6. package/dist/app/useApp.d.ts +16 -0
  7. package/dist/components/ArrayContainer.d.ts +31 -12
  8. package/dist/components/CircularProgressCenter.d.ts +1 -1
  9. package/dist/components/ClearFilterSortButton.d.ts +5 -0
  10. package/dist/components/{DeleteConfirmationDialog.d.ts → ConfirmationDialog.d.ts} +1 -1
  11. package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +13 -13
  12. package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +2 -2
  13. package/dist/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +22 -6
  14. package/dist/components/EntityCollectionTable/PropertyTableCell.d.ts +1 -0
  15. package/dist/components/EntityCollectionTable/column_utils.d.ts +1 -2
  16. package/dist/components/EntityCollectionTable/fields/TableReferenceField.d.ts +3 -1
  17. package/dist/components/EntityCollectionTable/index.d.ts +1 -1
  18. package/dist/components/EntityCollectionTable/internal/CollectionTableToolbar.d.ts +1 -4
  19. package/dist/components/EntityCollectionTable/internal/EntityTableCell.d.ts +2 -2
  20. package/dist/components/EntityCollectionTable/internal/popup_field/PopupFormField.d.ts +7 -4
  21. package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +20 -2
  22. package/dist/components/EntityCollectionView/EntityCollectionViewStartActions.d.ts +11 -0
  23. package/dist/components/EntityCollectionView/utils.d.ts +3 -0
  24. package/dist/components/EntityJsonPreview.d.ts +3 -0
  25. package/dist/components/EntityPreview.d.ts +8 -5
  26. package/dist/components/ErrorView.d.ts +1 -1
  27. package/dist/components/HomePage/DefaultHomePage.d.ts +2 -15
  28. package/dist/components/HomePage/HomePageDnD.d.ts +76 -0
  29. package/dist/components/HomePage/NavigationCard.d.ts +3 -1
  30. package/dist/components/HomePage/NavigationCardBinding.d.ts +4 -3
  31. package/dist/components/HomePage/NavigationGroup.d.ts +7 -1
  32. package/dist/components/HomePage/RenameGroupDialog.d.ts +9 -0
  33. package/dist/components/PropertyConfigBadge.d.ts +2 -1
  34. package/dist/components/PropertyIdCopyTooltip.d.ts +8 -0
  35. package/dist/components/ReferenceWidget.d.ts +3 -1
  36. package/dist/components/SelectableTable/SelectableTable.d.ts +14 -4
  37. package/dist/components/SelectableTable/filters/ReferenceFilterField.d.ts +2 -1
  38. package/dist/components/UnsavedChangesDialog.d.ts +8 -0
  39. package/dist/components/VirtualTable/VirtualTableProps.d.ts +24 -12
  40. package/dist/components/VirtualTable/types.d.ts +3 -3
  41. package/dist/components/{EntityCollectionTable/internal → common}/default_entity_actions.d.ts +1 -3
  42. package/dist/components/common/index.d.ts +2 -1
  43. package/dist/components/common/table_height.d.ts +5 -0
  44. package/dist/components/common/types.d.ts +4 -6
  45. package/dist/components/common/useColumnsIds.d.ts +3 -1
  46. package/dist/components/common/{useDataSourceEntityCollectionTableController.d.ts → useDataSourceTableController.d.ts} +13 -2
  47. package/dist/components/common/useDebouncedCallback.d.ts +1 -0
  48. package/dist/components/common/useScrollRestoration.d.ts +14 -0
  49. package/dist/components/index.d.ts +5 -2
  50. package/dist/contexts/BreacrumbsContext.d.ts +8 -0
  51. package/dist/core/DefaultAppBar.d.ts +29 -0
  52. package/dist/core/DefaultDrawer.d.ts +19 -0
  53. package/dist/core/DrawerNavigationItem.d.ts +10 -0
  54. package/dist/core/EntityEditView.d.ts +40 -11
  55. package/dist/core/EntityEditViewFormActions.d.ts +2 -0
  56. package/dist/core/FireCMS.d.ts +3 -3
  57. package/dist/core/FireCMSRouter.d.ts +4 -0
  58. package/dist/core/NavigationRoutes.d.ts +2 -3
  59. package/dist/core/SideDialogs.d.ts +4 -2
  60. package/dist/core/field_configs.d.ts +1 -1
  61. package/dist/core/index.d.ts +4 -4
  62. package/dist/form/EntityForm.d.ts +36 -64
  63. package/dist/form/EntityFormActions.d.ts +17 -0
  64. package/dist/form/PropertyFieldBinding.d.ts +1 -1
  65. package/dist/form/components/ErrorFocus.d.ts +1 -1
  66. package/dist/form/components/FieldHelperText.d.ts +3 -3
  67. package/dist/form/components/FormEntry.d.ts +6 -0
  68. package/dist/form/components/FormLayout.d.ts +5 -0
  69. package/dist/form/components/LabelWithIcon.d.ts +1 -1
  70. package/dist/form/components/LabelWithIconAndTooltip.d.ts +15 -0
  71. package/dist/form/components/StorageItemPreview.d.ts +4 -4
  72. package/dist/form/components/index.d.ts +3 -1
  73. package/dist/form/field_bindings/ArrayCustomShapedFieldBinding.d.ts +1 -1
  74. package/dist/form/field_bindings/ArrayOfReferencesFieldBinding.d.ts +1 -1
  75. package/dist/form/field_bindings/BlockFieldBinding.d.ts +1 -1
  76. package/dist/form/field_bindings/KeyValueFieldBinding.d.ts +1 -1
  77. package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
  78. package/dist/form/field_bindings/MarkdownEditorFieldBinding.d.ts +11 -0
  79. package/dist/form/field_bindings/{MultiSelectBinding.d.ts → MultiSelectFieldBinding.d.ts} +1 -1
  80. package/dist/form/field_bindings/ReadOnlyFieldBinding.d.ts +1 -1
  81. package/dist/form/field_bindings/ReferenceAsStringFieldBinding.d.ts +9 -0
  82. package/dist/form/field_bindings/ReferenceFieldBinding.d.ts +2 -2
  83. package/dist/form/field_bindings/RepeatFieldBinding.d.ts +1 -1
  84. package/dist/form/field_bindings/SelectFieldBinding.d.ts +1 -1
  85. package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +5 -13
  86. package/dist/form/field_bindings/SwitchFieldBinding.d.ts +1 -2
  87. package/dist/form/field_bindings/TextFieldBinding.d.ts +1 -1
  88. package/dist/form/index.d.ts +17 -18
  89. package/dist/form/useClearRestoreValue.d.ts +2 -2
  90. package/dist/hooks/data/delete.d.ts +4 -4
  91. package/dist/hooks/data/save.d.ts +4 -5
  92. package/dist/hooks/data/useCollectionFetch.d.ts +1 -1
  93. package/dist/hooks/data/useEntityFetch.d.ts +4 -3
  94. package/dist/hooks/index.d.ts +1 -0
  95. package/dist/hooks/useAuthController.d.ts +1 -1
  96. package/dist/hooks/useBreadcrumbsController.d.ts +26 -0
  97. package/dist/hooks/useBuildNavigationController.d.ts +57 -13
  98. package/dist/hooks/useFireCMSContext.d.ts +1 -1
  99. package/dist/hooks/useModeController.d.ts +1 -2
  100. package/dist/hooks/useProjectLog.d.ts +8 -2
  101. package/dist/hooks/useResolvedNavigationFrom.d.ts +3 -3
  102. package/dist/hooks/useValidateAuthenticator.d.ts +4 -8
  103. package/dist/index.d.ts +1 -0
  104. package/dist/index.es.js +22838 -13874
  105. package/dist/index.es.js.map +1 -1
  106. package/dist/index.umd.js +25639 -588
  107. package/dist/index.umd.js.map +1 -1
  108. package/dist/internal/useBuildDataSource.d.ts +3 -17
  109. package/dist/internal/useBuildSideEntityController.d.ts +3 -3
  110. package/dist/internal/useUnsavedChangesDialog.d.ts +7 -9
  111. package/dist/preview/PropertyPreviewProps.d.ts +6 -1
  112. package/dist/preview/components/EnumValuesChip.d.ts +1 -1
  113. package/dist/preview/components/ReferencePreview.d.ts +3 -2
  114. package/dist/preview/components/StorageThumbnail.d.ts +2 -1
  115. package/dist/preview/components/UrlComponentPreview.d.ts +2 -1
  116. package/dist/preview/util.d.ts +3 -3
  117. package/dist/routes/CustomCMSRoute.d.ts +4 -0
  118. package/dist/routes/FireCMSRoute.d.ts +1 -0
  119. package/dist/routes/HomePageRoute.d.ts +3 -0
  120. package/dist/types/analytics.d.ts +1 -1
  121. package/dist/types/auth.d.ts +8 -10
  122. package/dist/types/collections.d.ts +107 -25
  123. package/dist/types/datasource.d.ts +52 -36
  124. package/dist/types/dialogs_controller.d.ts +7 -3
  125. package/dist/types/entities.d.ts +7 -2
  126. package/dist/types/entity_actions.d.ts +28 -4
  127. package/dist/types/entity_callbacks.d.ts +16 -16
  128. package/dist/types/entity_overrides.d.ts +2 -2
  129. package/dist/types/export_import.d.ts +4 -4
  130. package/dist/types/fields.d.ts +74 -42
  131. package/dist/types/firecms.d.ts +8 -3
  132. package/dist/types/firecms_context.d.ts +1 -1
  133. package/dist/types/index.d.ts +0 -1
  134. package/dist/types/navigation.d.ts +62 -19
  135. package/dist/types/permissions.d.ts +4 -4
  136. package/dist/types/plugins.d.ts +48 -12
  137. package/dist/types/properties.d.ts +80 -24
  138. package/dist/types/property_config.d.ts +1 -3
  139. package/dist/types/side_dialogs_controller.d.ts +10 -0
  140. package/dist/types/side_entity_controller.d.ts +10 -1
  141. package/dist/types/storage.d.ts +75 -0
  142. package/dist/types/user.d.ts +1 -0
  143. package/dist/util/builders.d.ts +3 -3
  144. package/dist/util/callbacks.d.ts +2 -0
  145. package/dist/util/createFormexStub.d.ts +2 -0
  146. package/dist/util/entities.d.ts +3 -3
  147. package/dist/util/entity_actions.d.ts +2 -0
  148. package/dist/util/entity_cache.d.ts +23 -0
  149. package/dist/util/icon_list.d.ts +5 -1
  150. package/dist/util/icon_synonyms.d.ts +1 -98
  151. package/dist/util/icons.d.ts +7 -4
  152. package/dist/util/index.d.ts +3 -0
  153. package/dist/util/navigation_from_path.d.ts +6 -1
  154. package/dist/util/navigation_utils.d.ts +15 -3
  155. package/dist/util/objects.d.ts +2 -1
  156. package/dist/util/permissions.d.ts +4 -4
  157. package/dist/util/plurals.d.ts +0 -2
  158. package/dist/util/property_utils.d.ts +4 -4
  159. package/dist/util/references.d.ts +2 -2
  160. package/dist/util/resolutions.d.ts +41 -17
  161. package/dist/util/storage.d.ts +23 -2
  162. package/dist/util/useStorageUploadController.d.ts +3 -3
  163. package/package.json +64 -48
  164. package/src/app/AppBar.tsx +18 -0
  165. package/src/app/Drawer.tsx +24 -0
  166. package/src/app/Scaffold.tsx +253 -0
  167. package/src/app/index.ts +4 -0
  168. package/src/app/useApp.tsx +32 -0
  169. package/src/components/ArrayContainer.tsx +447 -229
  170. package/src/components/CircularProgressCenter.tsx +2 -2
  171. package/src/components/ClearFilterSortButton.tsx +41 -0
  172. package/src/components/{DeleteConfirmationDialog.tsx → ConfirmationDialog.tsx} +11 -11
  173. package/src/components/DeleteEntityDialog.tsx +13 -20
  174. package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +59 -40
  175. package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +38 -31
  176. package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +30 -9
  177. package/src/components/EntityCollectionTable/PropertyTableCell.tsx +72 -42
  178. package/src/components/EntityCollectionTable/column_utils.tsx +3 -3
  179. package/src/components/EntityCollectionTable/fields/TableReferenceField.tsx +30 -16
  180. package/src/components/EntityCollectionTable/fields/TableStorageUpload.tsx +19 -17
  181. package/src/components/EntityCollectionTable/index.tsx +1 -1
  182. package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +32 -37
  183. package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +49 -36
  184. package/src/components/EntityCollectionTable/internal/EntityTableCellActions.tsx +20 -8
  185. package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +135 -105
  186. package/src/components/EntityCollectionTable/internal/popup_field/useDraggable.tsx +9 -9
  187. package/src/components/EntityCollectionView/EntityCollectionView.tsx +231 -117
  188. package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +4 -2
  189. package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +68 -0
  190. package/src/components/EntityCollectionView/useSelectionController.tsx +20 -7
  191. package/src/components/EntityCollectionView/utils.ts +19 -0
  192. package/src/components/EntityJsonPreview.tsx +66 -0
  193. package/src/components/EntityPreview.tsx +80 -59
  194. package/src/components/EntityView.tsx +13 -10
  195. package/src/components/ErrorView.tsx +4 -4
  196. package/src/components/HomePage/DefaultHomePage.tsx +486 -159
  197. package/src/components/HomePage/FavouritesView.tsx +9 -14
  198. package/src/components/HomePage/HomePageDnD.tsx +613 -0
  199. package/src/components/HomePage/NavigationCard.tsx +48 -39
  200. package/src/components/HomePage/NavigationCardBinding.tsx +17 -16
  201. package/src/components/HomePage/NavigationGroup.tsx +63 -29
  202. package/src/components/HomePage/RenameGroupDialog.tsx +113 -0
  203. package/src/components/HomePage/SmallNavigationCard.tsx +5 -6
  204. package/src/components/NotFoundPage.tsx +2 -2
  205. package/src/components/PropertyConfigBadge.tsx +9 -3
  206. package/src/components/PropertyIdCopyTooltip.tsx +47 -0
  207. package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +21 -13
  208. package/src/components/ReferenceWidget.tsx +21 -11
  209. package/src/components/SearchIconsView.tsx +10 -7
  210. package/src/components/SelectableTable/SelectableTable.tsx +157 -145
  211. package/src/components/SelectableTable/filters/BooleanFilterField.tsx +2 -3
  212. package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +25 -8
  213. package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +36 -12
  214. package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +92 -23
  215. package/src/components/UnsavedChangesDialog.tsx +42 -0
  216. package/src/components/VirtualTable/VirtualTable.tsx +105 -51
  217. package/src/components/VirtualTable/VirtualTableCell.tsx +1 -9
  218. package/src/components/VirtualTable/VirtualTableHeader.tsx +10 -10
  219. package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +2 -2
  220. package/src/components/VirtualTable/VirtualTableProps.tsx +28 -14
  221. package/src/components/VirtualTable/VirtualTableRow.tsx +5 -6
  222. package/src/components/VirtualTable/fields/VirtualTableDateField.tsx +5 -5
  223. package/src/components/VirtualTable/fields/VirtualTableInput.tsx +2 -2
  224. package/src/components/VirtualTable/fields/VirtualTableNumberInput.tsx +2 -1
  225. package/src/components/VirtualTable/fields/VirtualTableSelect.tsx +16 -28
  226. package/src/components/VirtualTable/types.tsx +2 -3
  227. package/src/components/{EntityCollectionTable/internal → common}/default_entity_actions.tsx +44 -40
  228. package/src/components/common/index.ts +2 -1
  229. package/src/components/{VirtualTable/common.tsx → common/table_height.tsx} +5 -2
  230. package/src/components/common/types.tsx +4 -6
  231. package/src/components/common/useColumnsIds.tsx +24 -3
  232. package/src/components/common/useDataSourceTableController.tsx +420 -0
  233. package/src/components/common/useDebouncedCallback.tsx +20 -0
  234. package/src/components/common/useScrollRestoration.tsx +68 -0
  235. package/src/components/common/useTableSearchHelper.ts +53 -12
  236. package/src/components/index.tsx +6 -2
  237. package/src/contexts/BreacrumbsContext.tsx +38 -0
  238. package/src/contexts/DialogsProvider.tsx +5 -4
  239. package/src/contexts/ModeController.tsx +1 -3
  240. package/src/contexts/SnackbarProvider.tsx +2 -0
  241. package/src/core/DefaultAppBar.tsx +219 -0
  242. package/src/core/DefaultDrawer.tsx +185 -0
  243. package/src/core/DrawerNavigationItem.tsx +66 -0
  244. package/src/core/EntityEditView.tsx +408 -478
  245. package/src/core/EntityEditViewFormActions.tsx +199 -0
  246. package/src/core/EntitySidePanel.tsx +85 -21
  247. package/src/core/FireCMS.tsx +72 -58
  248. package/src/core/FireCMSRouter.tsx +17 -0
  249. package/src/core/NavigationRoutes.tsx +28 -38
  250. package/src/core/SideDialogs.tsx +22 -12
  251. package/src/core/field_configs.tsx +26 -13
  252. package/src/core/index.tsx +6 -5
  253. package/src/form/EntityForm.tsx +589 -535
  254. package/src/form/EntityFormActions.tsx +169 -0
  255. package/src/form/PropertyFieldBinding.tsx +88 -45
  256. package/src/form/components/CustomIdField.tsx +9 -3
  257. package/src/form/components/FieldHelperText.tsx +4 -4
  258. package/src/form/components/FormEntry.tsx +22 -0
  259. package/src/form/components/FormLayout.tsx +16 -0
  260. package/src/form/components/LabelWithIcon.tsx +30 -19
  261. package/src/form/components/LabelWithIconAndTooltip.tsx +28 -0
  262. package/src/form/components/StorageItemPreview.tsx +23 -13
  263. package/src/form/components/StorageUploadProgress.tsx +5 -6
  264. package/src/form/components/index.tsx +3 -1
  265. package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +34 -19
  266. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +50 -36
  267. package/src/form/field_bindings/BlockFieldBinding.tsx +56 -34
  268. package/src/form/field_bindings/DateTimeFieldBinding.tsx +18 -14
  269. package/src/form/field_bindings/KeyValueFieldBinding.tsx +61 -52
  270. package/src/form/field_bindings/MapFieldBinding.tsx +73 -55
  271. package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +157 -0
  272. package/src/form/field_bindings/{MultiSelectBinding.tsx → MultiSelectFieldBinding.tsx} +26 -21
  273. package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +11 -16
  274. package/src/form/field_bindings/ReferenceAsStringFieldBinding.tsx +135 -0
  275. package/src/form/field_bindings/ReferenceFieldBinding.tsx +42 -31
  276. package/src/form/field_bindings/RepeatFieldBinding.tsx +62 -35
  277. package/src/form/field_bindings/SelectFieldBinding.tsx +24 -15
  278. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +257 -199
  279. package/src/form/field_bindings/SwitchFieldBinding.tsx +29 -24
  280. package/src/form/field_bindings/TextFieldBinding.tsx +28 -24
  281. package/src/form/index.tsx +17 -37
  282. package/src/form/useClearRestoreValue.tsx +2 -2
  283. package/src/form/validation.ts +13 -23
  284. package/src/hooks/data/delete.ts +6 -5
  285. package/src/hooks/data/save.ts +26 -33
  286. package/src/hooks/data/useCollectionFetch.tsx +3 -3
  287. package/src/hooks/data/useDataSource.tsx +11 -3
  288. package/src/hooks/data/useEntityFetch.tsx +10 -6
  289. package/src/hooks/index.tsx +1 -0
  290. package/src/hooks/useAuthController.tsx +1 -1
  291. package/src/hooks/useBreadcrumbsController.tsx +31 -0
  292. package/src/hooks/useBuildLocalConfigurationPersistence.tsx +8 -10
  293. package/src/hooks/useBuildModeController.tsx +22 -29
  294. package/src/hooks/useBuildNavigationController.tsx +440 -119
  295. package/src/hooks/useFireCMSContext.tsx +3 -33
  296. package/src/hooks/useLargeLayout.tsx +0 -35
  297. package/src/hooks/useModeController.tsx +1 -2
  298. package/src/hooks/useProjectLog.tsx +32 -10
  299. package/src/hooks/useResolvedNavigationFrom.tsx +10 -12
  300. package/src/hooks/useValidateAuthenticator.tsx +17 -37
  301. package/src/index.ts +1 -0
  302. package/src/internal/useBuildDataSource.ts +79 -85
  303. package/src/internal/useBuildSideDialogsController.tsx +4 -2
  304. package/src/internal/useBuildSideEntityController.tsx +201 -77
  305. package/src/internal/useUnsavedChangesDialog.tsx +127 -91
  306. package/src/preview/PropertyPreview.tsx +34 -25
  307. package/src/preview/PropertyPreviewProps.tsx +7 -1
  308. package/src/preview/components/BooleanPreview.tsx +2 -2
  309. package/src/preview/components/EmptyValue.tsx +1 -1
  310. package/src/preview/components/EnumValuesChip.tsx +2 -2
  311. package/src/preview/components/ImagePreview.tsx +26 -37
  312. package/src/preview/components/ReferencePreview.tsx +23 -34
  313. package/src/preview/components/StorageThumbnail.tsx +5 -1
  314. package/src/preview/components/UrlComponentPreview.tsx +60 -28
  315. package/src/preview/property_previews/ArrayOfMapsPreview.tsx +6 -6
  316. package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +7 -5
  317. package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +5 -4
  318. package/src/preview/property_previews/ArrayOfStringsPreview.tsx +4 -4
  319. package/src/preview/property_previews/ArrayOneOfPreview.tsx +7 -6
  320. package/src/preview/property_previews/ArrayPropertyPreview.tsx +7 -6
  321. package/src/preview/property_previews/MapPropertyPreview.tsx +12 -11
  322. package/src/preview/property_previews/SkeletonPropertyComponent.tsx +13 -13
  323. package/src/preview/property_previews/StringPropertyPreview.tsx +3 -3
  324. package/src/preview/util.ts +10 -10
  325. package/src/routes/CustomCMSRoute.tsx +21 -0
  326. package/src/routes/FireCMSRoute.tsx +246 -0
  327. package/src/routes/HomePageRoute.tsx +17 -0
  328. package/src/types/analytics.ts +3 -0
  329. package/src/types/auth.tsx +9 -13
  330. package/src/types/collections.ts +129 -30
  331. package/src/types/customization_controller.tsx +0 -1
  332. package/src/types/datasource.ts +61 -43
  333. package/src/types/dialogs_controller.tsx +7 -3
  334. package/src/types/entities.ts +12 -2
  335. package/src/types/entity_actions.tsx +32 -7
  336. package/src/types/entity_callbacks.ts +18 -18
  337. package/src/types/entity_overrides.tsx +2 -2
  338. package/src/types/export_import.ts +4 -4
  339. package/src/types/fields.tsx +85 -46
  340. package/src/types/firecms.tsx +9 -4
  341. package/src/types/firecms_context.tsx +1 -1
  342. package/src/types/index.ts +0 -1
  343. package/src/types/navigation.ts +77 -24
  344. package/src/types/permissions.ts +5 -5
  345. package/src/types/plugins.tsx +57 -14
  346. package/src/types/properties.ts +95 -26
  347. package/src/types/property_config.tsx +1 -2
  348. package/src/types/side_dialogs_controller.tsx +15 -0
  349. package/src/types/side_entity_controller.tsx +11 -1
  350. package/src/types/storage.ts +83 -1
  351. package/src/types/user.ts +2 -0
  352. package/src/util/builders.ts +10 -8
  353. package/src/util/callbacks.ts +119 -0
  354. package/src/util/createFormexStub.tsx +62 -0
  355. package/src/util/entities.ts +9 -6
  356. package/src/util/entity_actions.ts +28 -0
  357. package/src/util/entity_cache.ts +204 -0
  358. package/src/util/enums.ts +1 -1
  359. package/src/util/icon_list.ts +16 -10
  360. package/src/util/icon_synonyms.ts +3 -100
  361. package/src/util/icons.tsx +36 -11
  362. package/src/util/index.ts +3 -0
  363. package/src/util/join_collections.ts +6 -1
  364. package/src/util/make_properties_editable.ts +13 -5
  365. package/src/util/navigation_from_path.ts +18 -7
  366. package/src/util/navigation_utils.ts +141 -25
  367. package/src/util/objects.ts +90 -33
  368. package/src/util/parent_references_from_path.ts +3 -3
  369. package/src/util/permissions.ts +9 -8
  370. package/src/util/plurals.ts +0 -2
  371. package/src/util/property_utils.tsx +17 -6
  372. package/src/util/references.ts +19 -8
  373. package/src/util/resolutions.ts +110 -48
  374. package/src/util/storage.ts +79 -21
  375. package/src/util/strings.ts +2 -2
  376. package/src/util/useStorageUploadController.tsx +91 -28
  377. package/dist/components/EntityCollectionTable/internal/popup_field/ElementResizeListener.d.ts +0 -5
  378. package/dist/components/FireCMSAppBar.d.ts +0 -26
  379. package/dist/components/PropertyIdCopyTooltipContent.d.ts +0 -3
  380. package/dist/components/VirtualTable/common.d.ts +0 -2
  381. package/dist/core/Drawer.d.ts +0 -23
  382. package/dist/core/Scaffold.d.ts +0 -55
  383. package/dist/core/SideEntityView.d.ts +0 -7
  384. package/dist/form/components/FormikArrayContainer.d.ts +0 -18
  385. package/dist/form/field_bindings/MarkdownFieldBinding.d.ts +0 -9
  386. package/dist/internal/useBuildCustomizationController.d.ts +0 -2
  387. package/dist/internal/useLocaleConfig.d.ts +0 -1
  388. package/dist/types/appcheck.d.ts +0 -26
  389. package/src/components/EntityCollectionTable/internal/popup_field/ElementResizeListener.tsx +0 -59
  390. package/src/components/FireCMSAppBar.tsx +0 -165
  391. package/src/components/PropertyIdCopyTooltipContent.tsx +0 -28
  392. package/src/components/common/useDataSourceEntityCollectionTableController.tsx +0 -225
  393. package/src/core/Drawer.tsx +0 -191
  394. package/src/core/Scaffold.tsx +0 -281
  395. package/src/core/SideEntityView.tsx +0 -38
  396. package/src/form/components/FormikArrayContainer.tsx +0 -44
  397. package/src/form/field_bindings/MarkdownFieldBinding.tsx +0 -695
  398. package/src/internal/useBuildCustomizationController.tsx +0 -5
  399. package/src/internal/useLocaleConfig.tsx +0 -18
  400. package/src/types/appcheck.ts +0 -29
  401. /package/src/util/{common.tsx → common.ts} +0 -0
@@ -1,561 +1,491 @@
1
- import React, { useCallback, useEffect, useRef, useState } from "react";
2
- import {
3
- Entity,
4
- EntityCollection,
5
- EntityCustomView,
6
- EntityStatus,
7
- EntityValues,
8
- FireCMSPlugin,
9
- FormContext,
10
- User
11
- } from "../types";
12
- import { CircularProgressCenter, EntityCollectionView, EntityView, ErrorBoundary, } from "../components";
1
+ import React, { useEffect, useMemo, useState } from "react";
2
+ import { Entity, EntityCollection, EntityStatus, FireCMSPlugin, FormContext, User } from "../types";
3
+
4
+ import { CircularProgressCenter, EntityCollectionView, EntityView, ErrorBoundary } from "../components";
13
5
  import {
14
6
  canEditEntity,
15
7
  removeInitialAndTrailingSlashes,
8
+ resolveCollection,
16
9
  resolveDefaultSelectedView,
17
- resolveEntityView,
18
- useDebouncedCallback
10
+ resolvedSelectedEntityView
19
11
  } from "../util";
20
12
 
21
13
  import {
22
- saveEntityWithCallbacks,
23
14
  useAuthController,
24
15
  useCustomizationController,
25
- useDataSource,
26
16
  useEntityFetch,
27
17
  useFireCMSContext,
28
- useSideEntityController,
29
- useSnackbarController
18
+ useLargeLayout
30
19
  } from "../hooks";
31
- import { EntityForm } from "../form";
32
- import { CircularProgress, CloseIcon, cn, defaultBorderMixin, IconButton, Tab, Tabs, Typography } from "@firecms/ui";
33
- import { EntityFormSaveParams } from "../form/EntityForm";
34
- import { FORM_CONTAINER_WIDTH } from "../internal/common";
35
- import { useSideDialogContext } from "./index";
20
+ import { CircularProgress, cls, CodeIcon, defaultBorderMixin, Tab, Tabs, Typography } from "@firecms/ui";
21
+ import { getEntityFromCache } from "../util/entity_cache";
22
+ import { EntityForm, EntityFormProps } from "../form";
23
+ import { EntityEditViewFormActions } from "./EntityEditViewFormActions";
24
+ import { EntityJsonPreview } from "../components/EntityJsonPreview";
25
+ import { createFormexStub } from "../util/createFormexStub";
26
+
27
+ export const MAIN_TAB_VALUE = "__main_##Q$SC^#S6";
28
+ export const JSON_TAB_VALUE = "__json";
29
+
30
+ export type OnUpdateParams = {
31
+ entity: Entity<any>,
32
+ status: EntityStatus,
33
+ path: string,
34
+ entityId?: string;
35
+ selectedTab?: string;
36
+ collection: EntityCollection<any>
37
+ };
36
38
 
37
- const MAIN_TAB_VALUE = "main_##Q$SC^#S6";
39
+ export type OnTabChangeParams<M extends Record<string, any>> = {
40
+ path: string;
41
+ entityId?: string;
42
+ selectedTab?: string;
43
+ collection: EntityCollection<M>;
44
+ };
38
45
 
39
46
  export interface EntityEditViewProps<M extends Record<string, any>> {
40
47
  path: string;
48
+ /**
49
+ * The navigation path to the entity.
50
+ */
51
+ fullIdPath?: string;
41
52
  collection: EntityCollection<M>;
42
53
  entityId?: string;
54
+ databaseId?: string;
43
55
  copy?: boolean;
44
- selectedSubPath?: string;
56
+ selectedTab?: string;
45
57
  parentCollectionIds: string[];
46
- formWidth?: number | string;
47
- onValuesAreModified: (modified: boolean) => void;
48
- onUpdate?: (params: { entity: Entity<any> }) => void;
49
- onClose?: () => void;
58
+ onValuesModified?: (modified: boolean) => void;
59
+ onSaved?: (params: OnUpdateParams) => void;
60
+ onTabChange?: (props: OnTabChangeParams<M>) => void;
61
+ layout?: "side_panel" | "full_screen";
62
+ barActions?: React.ReactNode;
63
+ formProps?: Partial<EntityFormProps<M>>,
50
64
  }
51
65
 
52
66
  /**
53
67
  * This is the default view that is used as the content of a side panel when
54
68
  * an entity is opened.
55
- * You probably don't want to use this view directly since it is bound to the
56
- * side panel. Instead, you might want to use {@link EntityForm} or {@link EntityCollectionView}
57
69
  */
58
- export function EntityEditView<M extends Record<string, any>, UserType extends User>({
59
- path,
60
- entityId,
61
- selectedSubPath,
62
- copy,
63
- collection,
64
- parentCollectionIds,
65
- onValuesAreModified,
66
- formWidth,
67
- onUpdate,
68
- onClose,
69
- }: EntityEditViewProps<M>) {
70
-
71
- if (collection.customId && collection.formAutoSave) {
72
- console.warn(`The collection ${collection.path} has customId and formAutoSave enabled. This is not supported and formAutoSave will be ignored`);
70
+ export function EntityEditView<M extends Record<string, any>, USER extends User>({
71
+ entityId,
72
+ ...props
73
+ }: EntityEditViewProps<M>) {
74
+
75
+ const {
76
+ entity,
77
+ dataLoading,
78
+ // eslint-disable-next-line no-unused-vars
79
+ dataLoadingError
80
+ } = useEntityFetch<M, USER>({
81
+ path: props.path,
82
+ entityId: entityId,
83
+ collection: props.collection,
84
+ databaseId: props.databaseId,
85
+ useCache: false
86
+ });
87
+
88
+ const cachedValues = entityId
89
+ ? getEntityFromCache(props.path + "/" + entityId)
90
+ : getEntityFromCache(props.path + "#new");
91
+
92
+ const authController = useAuthController();
93
+
94
+ const initialStatus = props.copy ? "copy" : (entityId ? "existing" : "new");
95
+ const [status, setStatus] = useState<EntityStatus>(initialStatus);
96
+
97
+ const canEdit = useMemo(() => {
98
+ if (status === "new" || status === "copy") {
99
+ return true;
100
+ } else {
101
+ return entity ? canEditEntity(props.collection, authController, props.path, entity ?? null) : undefined;
102
+ }
103
+ }, [authController, entity, status]);
104
+
105
+ if ((dataLoading && !cachedValues) || (!entity || canEdit === undefined) && (status === "existing" || status === "copy")) {
106
+ return <CircularProgressCenter/>;
73
107
  }
74
108
 
75
- const [saving, setSaving] = useState(false);
76
- /**
77
- * These are the values that are being saved. They are debounced.
78
- * We use this only when autoSave is enabled.
79
- */
80
- const [valuesToBeSaved, setValuesToBeSaved] = useState<EntityValues<M> | undefined>(undefined);
81
- useDebouncedCallback(valuesToBeSaved, () => {
82
- if (valuesToBeSaved)
83
- saveEntity({
84
- entityId: usedEntity?.id,
85
- collection,
86
- path,
87
- values: valuesToBeSaved,
88
- closeAfterSave: false
89
- });
90
- }, false, 2000);
109
+ if (entityId && !entity && !cachedValues) {
110
+ console.error(`Entity with id ${entityId} not found in collection ${props.path}`);
111
+ }
91
112
 
92
- // const largeLayout = useLargeLayout();
93
- // const largeLayoutTabSelected = useRef(!largeLayout);
113
+ return <EntityEditViewInner<M> {...props}
114
+ entityId={entityId}
115
+ entity={entity}
116
+ cachedDirtyValues={cachedValues as Partial<M>}
117
+ dataLoading={dataLoading}
118
+ status={status}
119
+ setStatus={setStatus}
120
+ canEdit={canEdit}
121
+ />;
122
+ }
94
123
 
95
- const resolvedFormWidth: string = typeof formWidth === "number" ? `${formWidth}px` : formWidth ?? FORM_CONTAINER_WIDTH;
124
+ export function EntityEditViewInner<M extends Record<string, any>>({
125
+ path,
126
+ fullIdPath,
127
+ entityId,
128
+ selectedTab: selectedTabProp,
129
+ collection,
130
+ parentCollectionIds,
131
+ onValuesModified,
132
+ onSaved,
133
+ onTabChange,
134
+ entity,
135
+ cachedDirtyValues,
136
+ dataLoading,
137
+ layout = "side_panel",
138
+ barActions,
139
+ status,
140
+ setStatus,
141
+ formProps,
142
+ canEdit
143
+ }: EntityEditViewProps<M> & {
144
+ entity?: Entity<M>,
145
+ cachedDirtyValues?: Partial<M>, // dirty cached entity in memory
146
+ dataLoading: boolean,
147
+ status: EntityStatus,
148
+ setStatus: (status: EntityStatus) => void,
149
+ canEdit?: boolean,
150
+ }) {
96
151
 
97
- const dataSource = useDataSource(collection);
98
- const sideDialogContext = useSideDialogContext();
99
- const sideEntityController = useSideEntityController();
100
- const snackbarController = useSnackbarController();
101
- const customizationController = useCustomizationController();
102
152
  const context = useFireCMSContext();
103
- const authController = useAuthController<UserType>();
104
153
 
105
- const [formContext, setFormContext] = useState<FormContext<M> | undefined>(undefined);
154
+ const [usedEntity, setUsedEntity] = useState<Entity<M> | undefined>(entity);
106
155
 
107
- const [status, setStatus] = useState<EntityStatus>(copy ? "copy" : (entityId ? "existing" : "new"));
156
+ useEffect(() => {
157
+ if (entity)
158
+ setUsedEntity(entity);
159
+ }, [entity]);
108
160
 
109
- const modifiedValuesRef = useRef<EntityValues<M> | undefined>(undefined);
110
- const modifiedValues = modifiedValuesRef.current;
161
+ // Instead of using a ref (which does not trigger re-render), we use state for the form context.
162
+ const [formContext, setFormContext] = useState<FormContext<M> | undefined>(undefined);
111
163
 
112
- const subcollections = (collection.subcollections ?? []).filter(c => !c.hideFromNavigation);
113
- const subcollectionsCount = subcollections?.length ?? 0;
114
- const customViews = collection.entityViews;
115
- const customViewsCount = customViews?.length ?? 0;
116
- const autoSave = collection.formAutoSave && !collection.customId;
164
+ const largeLayout = useLargeLayout();
117
165
 
118
- const hasAdditionalViews = customViewsCount > 0 || subcollectionsCount > 0;
166
+ const customizationController = useCustomizationController();
119
167
 
120
- const defaultSelectedView = selectedSubPath ?? resolveDefaultSelectedView(
168
+ const defaultSelectedView = useMemo(() => resolveDefaultSelectedView(
121
169
  collection ? collection.defaultSelectedView : undefined,
122
170
  {
123
171
  status,
124
172
  entityId
125
173
  }
126
- );
174
+ ), []);
127
175
 
128
- const selectedTabRef = useRef<string>(defaultSelectedView ?? MAIN_TAB_VALUE);
176
+ const [selectedTab, setSelectedTab] = useState<string>(selectedTabProp ?? defaultSelectedView ?? MAIN_TAB_VALUE);
177
+ useEffect(() => {
178
+ if ((selectedTabProp ?? defaultSelectedView ?? MAIN_TAB_VALUE) !== selectedTab) {
179
+ setSelectedTab(selectedTabProp ?? defaultSelectedView ?? MAIN_TAB_VALUE);
180
+ }
181
+ }, [selectedTabProp]);
129
182
 
130
- const mainViewVisible = selectedTabRef.current === MAIN_TAB_VALUE;
183
+ const subcollections = (collection.subcollections ?? []).filter(c => !c.hideFromNavigation);
184
+ const subcollectionsCount = subcollections?.length ?? 0;
185
+ const customViews = collection.entityViews ?? [];
186
+ const customViewsCount = customViews?.length ?? 0;
187
+ const includeJsonView = collection.includeJsonView === undefined ? true : collection.includeJsonView;
188
+ const hasAdditionalViews = customViewsCount > 0 || subcollectionsCount > 0 || includeJsonView;
131
189
 
132
- const {
133
- entity,
134
- dataLoading,
135
- // eslint-disable-next-line no-unused-vars
136
- dataLoadingError
137
- } = useEntityFetch<M, UserType>({
138
- path,
139
- entityId,
140
- collection,
141
- useCache: false
142
- });
190
+ const plugins = customizationController.plugins;
143
191
 
144
- const [usedEntity, setUsedEntity] = useState<Entity<M> | undefined>(entity);
145
- const [readOnly, setReadOnly] = useState<boolean | undefined>(undefined);
192
+ const {
193
+ resolvedEntityViews,
194
+ selectedEntityView,
195
+ selectedSecondaryForm
196
+ } = resolvedSelectedEntityView(customViews, customizationController, selectedTab, canEdit);
146
197
 
147
- useEffect(() => {
148
- if (entity)
149
- setUsedEntity(entity);
150
- }, [entity]);
198
+ const actionsAtTheBottom = !largeLayout || layout === "side_panel" || selectedEntityView?.includeActions === "bottom";
151
199
 
152
- useEffect(() => {
153
- if (status === "new") {
154
- setReadOnly(false);
155
- } else {
156
- const editEnabled = usedEntity ? canEditEntity(collection, authController, path, usedEntity ?? null) : false;
157
- if (usedEntity)
158
- setReadOnly(!editEnabled);
159
- }
160
- }, [authController, usedEntity, status]);
200
+ const mainViewVisible = selectedTab === MAIN_TAB_VALUE || Boolean(selectedSecondaryForm);
161
201
 
162
- const onPreSaveHookError = useCallback((e: Error) => {
163
- setSaving(false);
164
- snackbarController.open({
165
- type: "error",
166
- message: "Error before saving: " + e?.message
167
- });
168
- console.error(e);
169
- }, [snackbarController]);
170
-
171
- const onSaveSuccessHookError = useCallback((e: Error) => {
172
- setSaving(false);
173
- snackbarController.open({
174
- type: "error",
175
- message: "Error after saving (entity is saved): " + e?.message
176
- });
177
- console.error(e);
178
- }, [snackbarController]);
202
+ const authController = useAuthController();
179
203
 
180
- const onSaveSuccess = (updatedEntity: Entity<M>, closeAfterSave: boolean) => {
204
+ const customViewsView: React.ReactNode[] | undefined = customViews && resolvedEntityViews
205
+ .filter(e => !e.includeActions)
206
+ .map((customView) => {
181
207
 
182
- setSaving(false);
183
- if (!autoSave)
184
- snackbarController.open({
185
- type: "success",
186
- message: `${collection.singularName ?? collection.name}: Saved correctly`
187
- });
208
+ if (!customView)
209
+ return null;
210
+ const Builder = customView.Builder;
211
+ if (!Builder) {
212
+ console.error("INTERNAL: customView.Builder is not defined");
213
+ return null;
214
+ }
188
215
 
189
- setUsedEntity(updatedEntity);
190
- setStatus("existing");
216
+ if (!entityId) {
217
+ return null;
218
+ }
191
219
 
192
- onValuesAreModified(false);
220
+ const formexStub = createFormexStub<M>(usedEntity?.values ?? {} as M);
221
+ const usedFormContext: FormContext = formContext ?? {
222
+ entityId,
223
+ disabled: false,
224
+ openEntityMode: layout,
225
+ status: status,
226
+ values: usedEntity?.values ?? {},
227
+ setFieldValue: (key: string, value: any) => {
228
+ throw new Error("You can't update values in read only mode");
229
+ },
230
+ save: () => {
231
+ throw new Error("You can't save in read only mode");
232
+ },
233
+ collection: resolveCollection<M>({
234
+ collection,
235
+ path,
236
+ entityId,
237
+ values: usedEntity?.values ?? {},
238
+ previousValues: usedEntity?.values ?? {},
239
+ propertyConfigs: customizationController.propertyConfigs,
240
+ authController
241
+ }),
242
+ path,
243
+ entity: usedEntity,
244
+ savingError: undefined,
245
+ formex: formexStub
246
+ };
247
+
248
+ return <div
249
+ className={cls(defaultBorderMixin,
250
+ "relative flex-1 w-full h-full overflow-auto",
251
+ { "hidden": selectedTab !== customView.key }
252
+ )}
253
+ key={`custom_view_${customView.key}`}
254
+ role="tabpanel">
255
+ <ErrorBoundary>
256
+ {usedFormContext && <Builder
257
+ collection={collection}
258
+ parentCollectionIds={parentCollectionIds}
259
+ entity={usedEntity}
260
+ modifiedValues={usedFormContext?.formex?.values ?? usedEntity?.values}
261
+ formContext={usedFormContext}
262
+ />}
263
+ </ErrorBoundary>
264
+ </div>;
265
+ }).filter(Boolean);
266
+
267
+ const globalLoading = dataLoading && !usedEntity;
268
+
269
+ const jsonView = <div
270
+ className={cls("relative flex-1 h-full overflow-auto w-full",
271
+ { "hidden": selectedTab !== JSON_TAB_VALUE })}
272
+ key={"json_view"}
273
+ role="tabpanel">
274
+ <ErrorBoundary>
275
+ <EntityJsonPreview
276
+ values={formContext?.values ?? entity?.values ?? {}}/>
277
+ </ErrorBoundary>
278
+ </div>;
279
+
280
+ const subCollectionsViews = subcollections && subcollections.map((subcollection) => {
281
+ const subcollectionId = subcollection.id ?? subcollection.path;
282
+ const newFullPath = usedEntity ? `${path}/${usedEntity?.id}/${removeInitialAndTrailingSlashes(subcollectionId)}` : undefined;
283
+ const newFullIdPath = fullIdPath ? `${fullIdPath}/${usedEntity?.id}/${removeInitialAndTrailingSlashes(subcollectionId)}` : undefined;
284
+
285
+ if (selectedTab !== subcollectionId) return null;
286
+ return (
287
+ <div
288
+ className={"relative flex-1 h-full overflow-auto w-full"}
289
+ key={`subcol_${subcollectionId}`}
290
+ role="tabpanel">
291
+
292
+ {globalLoading && <CircularProgressCenter/>}
293
+
294
+ {!globalLoading &&
295
+ (usedEntity && newFullPath
296
+ ? <EntityCollectionView
297
+ fullPath={newFullPath}
298
+ fullIdPath={newFullIdPath}
299
+ parentCollectionIds={[...parentCollectionIds, collection.id]}
300
+ isSubCollection={true}
301
+ updateUrl={false}
302
+ {...subcollection}
303
+ openEntityMode={layout}/>
304
+ : <div className="flex items-center justify-center w-full h-full p-3">
305
+ <Typography variant={"label"}>
306
+ You need to save your entity before
307
+ adding additional collections
308
+ </Typography>
309
+ </div>)
310
+ }
193
311
 
194
- if (onUpdate)
195
- onUpdate({ entity: updatedEntity });
312
+ </div>
313
+ );
314
+ }).filter(Boolean);
196
315
 
197
- if (closeAfterSave) {
198
- sideDialogContext.setBlocked(false);
199
- sideDialogContext.close(true);
200
- onClose?.();
201
- } else if (status !== "existing") {
202
- sideEntityController.replace({
203
- path,
204
- entityId: updatedEntity.id,
205
- selectedSubPath: selectedTabRef.current,
206
- updateUrl: true,
207
- collection,
316
+ const onSideTabClick = (value: string) => {
317
+ setSelectedTab(value);
318
+ if (status === "existing") {
319
+ onTabChange?.({
320
+ path: fullIdPath ?? path,
321
+ entityId,
322
+ selectedTab: value === MAIN_TAB_VALUE ? undefined : value,
323
+ collection
208
324
  });
209
325
  }
210
-
211
326
  };
212
327
 
213
- const onSaveFailure = useCallback((e: Error) => {
328
+ const entityReadOnlyView = !canEdit && entity ? <div
329
+ className={cls("flex-1 flex flex-row w-full overflow-y-auto justify-center", (canEdit || !mainViewVisible || selectedSecondaryForm) ? "hidden" : "")}>
330
+ <div
331
+ className={cls("relative flex flex-col max-w-4xl lg:max-w-3xl xl:max-w-4xl 2xl:max-w-6xl w-full h-fit")}>
332
+ <Typography className={"mt-16 mb-8 mx-8"} variant={"h4"}>
333
+ {collection.singularName ?? collection.name}
334
+ </Typography>
335
+ <EntityView
336
+ className={"px-8 h-full overflow-auto"}
337
+ entity={entity}
338
+ path={path}
339
+ collection={collection}/>
340
+ <div className="h-16"/>
341
+ </div>
342
+ </div> : null;
343
+
344
+ const entityView = <EntityForm<M>
345
+ collection={collection}
346
+ path={path}
347
+ entityId={entityId ?? usedEntity?.id}
348
+ onValuesModified={onValuesModified}
349
+ entity={entity}
350
+ initialDirtyValues={cachedDirtyValues}
351
+ openEntityMode={layout}
352
+ forceActionsAtTheBottom={actionsAtTheBottom}
353
+ initialStatus={status}
354
+ className={cls((!mainViewVisible || !canEdit) && !selectedSecondaryForm ? "hidden" : "", formProps?.className)}
355
+ EntityFormActionsComponent={EntityEditViewFormActions}
356
+ disabled={!canEdit}
357
+ {...formProps}
358
+ onEntityChange={(entity) => {
359
+ setUsedEntity(entity);
360
+ formProps?.onEntityChange?.(entity);
361
+ }}
362
+ onStatusChange={(status) => {
363
+ setStatus(status);
364
+ formProps?.onStatusChange?.(status);
365
+ }}
366
+ onFormContextReady={(formContext) => {
367
+ setFormContext(formContext);
368
+ formProps?.onFormContextReady?.(formContext);
369
+ }}
370
+ onSaved={(params) => {
371
+ const res = {
372
+ ...params,
373
+ selectedTab: MAIN_TAB_VALUE === selectedTab ? undefined : selectedTab
374
+ };
375
+ onSaved?.(res);
376
+ formProps?.onSaved?.(res);
377
+ }}
378
+ Builder={selectedSecondaryForm?.Builder}
379
+ />;
380
+
381
+ const subcollectionTabs = subcollections && subcollections.map((subcollection) =>
382
+ <Tab
383
+ className="text-sm min-w-[120px]"
384
+ value={subcollection.id}
385
+ key={`entity_detail_collection_tab_${subcollection.name}`}>
386
+ {subcollection.name}
387
+ </Tab>
388
+ );
214
389
 
215
- setSaving(false);
216
- snackbarController.open({
217
- type: "error",
218
- message: "Error saving: " + e?.message
219
- });
390
+ const customViewTabsStart = resolvedEntityViews.filter(view => view.position === "start")
391
+ .map((view) =>
392
+ <Tab
393
+ className={!view.tabComponent ? "text-sm min-w-[120px]" : undefined}
394
+ value={view.key}
395
+ key={`entity_detail_collection_tab_${view.name}`}>
396
+ {view.tabComponent ?? view.name}
397
+ </Tab>
398
+ );
399
+ const customViewTabsEnd = resolvedEntityViews.filter(view => !view.position || view.position === "end")
400
+ .map((view) =>
401
+ <Tab
402
+ className={!view.tabComponent ? "text-sm min-w-[120px]" : undefined}
403
+ value={view.key}
404
+ key={`entity_detail_collection_tab_${view.name}`}>
405
+ {view.tabComponent ?? view.name}
406
+ </Tab>
407
+ );
220
408
 
221
- console.error("Error saving entity", path, entityId);
222
- console.error(e);
223
- }, [entityId, path, snackbarController]);
224
-
225
- const saveEntity = ({
226
- values,
227
- previousValues,
228
- closeAfterSave,
229
- entityId,
230
- collection,
231
- path
232
- }: {
233
- collection: EntityCollection<M>,
234
- path: string,
235
- entityId: string | undefined,
236
- values: M,
237
- previousValues?: M,
238
- closeAfterSave: boolean,
239
- }) => {
240
- setSaving(true);
241
- saveEntityWithCallbacks({
242
- path,
243
- entityId,
244
- values,
245
- previousValues,
246
- collection,
247
- status,
248
- dataSource,
249
- context,
250
- onSaveSuccess: (updatedEntity: Entity<M>) => onSaveSuccess(updatedEntity, closeAfterSave),
251
- onSaveFailure,
252
- onPreSaveHookError,
253
- onSaveSuccessHookError
254
- }).then();
255
- };
409
+ const shouldShowTopBar = Boolean(barActions) || hasAdditionalViews;
256
410
 
257
- const onSaveEntityRequest = async ({
258
- collection,
259
- path,
260
- entityId,
261
- values,
262
- previousValues,
263
- closeAfterSave,
264
- autoSave
265
- }: EntityFormSaveParams<M>): Promise<void> => {
266
- if (!status)
267
- return;
268
-
269
- if (autoSave) {
270
- setValuesToBeSaved(values);
271
- } else {
272
- saveEntity({
273
- collection,
274
- path,
275
- entityId,
276
- values,
277
- previousValues,
278
- closeAfterSave
279
- });
280
- }
281
- };
411
+ let result = <div className="relative flex flex-col h-full w-full bg-white dark:bg-surface-900">
282
412
 
283
- const resolvedEntityViews = customViews ? customViews
284
- .map(e => resolveEntityView(e, customizationController.entityViews))
285
- .filter(Boolean) as EntityCustomView[]
286
- : [];
413
+ {shouldShowTopBar && <div
414
+ className={cls("h-14 flex overflow-visible overflow-x-scroll w-full no-scrollbar h-14 border-b pl-2 pr-2 pt-1 flex items-end bg-surface-50 dark:bg-surface-900", defaultBorderMixin)}>
287
415
 
288
- const customViewsView: React.ReactNode[] | undefined = customViews && resolvedEntityViews
289
- .map(
290
- (customView, colIndex) => {
291
- if (!customView)
292
- return null;
293
- if (selectedTabRef.current !== customView.key)
294
- return null;
295
- const Builder = customView.Builder;
296
- if (!Builder) {
297
- console.error("customView.Builder is not defined");
298
- return null;
299
- }
300
- return <div
301
- className={cn(defaultBorderMixin,
302
- "relative flex-grow w-full h-full overflow-auto ")}
303
- key={`custom_view_${customView.key}`}
304
- role="tabpanel">
305
- <ErrorBoundary>
306
- {formContext && <Builder
307
- collection={collection}
308
- entity={usedEntity}
309
- modifiedValues={modifiedValues ?? usedEntity?.values}
310
- formContext={formContext}
311
- />}
312
- </ErrorBoundary>
313
- </div>;
314
- }
315
- ).filter(Boolean);
416
+ {barActions}
316
417
 
317
- const globalLoading = (dataLoading && !usedEntity) ||
318
- ((!usedEntity || readOnly === undefined) && (status === "existing" || status === "copy"));
418
+ <div className={"flex-grow"}/>
319
419
 
320
- const loading = globalLoading || saving;
420
+ {globalLoading && <div className="self-center">
421
+ <CircularProgress size={"small"}/>
422
+ </div>}
321
423
 
322
- const subCollectionsViews = subcollections && subcollections.map(
323
- (subcollection, colIndex) => {
324
- const subcollectionId = subcollection.id ?? subcollection.path;
325
- const fullPath = usedEntity ? `${path}/${usedEntity?.id}/${removeInitialAndTrailingSlashes(subcollectionId)}` : undefined;
326
- if (selectedTabRef.current !== subcollectionId)
327
- return null;
328
- return (
329
- <div
330
- className={"relative flex-grow h-full overflow-auto w-full"}
331
- key={`subcol_${subcollectionId}`}
332
- role="tabpanel">
333
-
334
- {loading && <CircularProgressCenter/>}
335
-
336
- {!globalLoading &&
337
- (usedEntity && fullPath
338
- ? <EntityCollectionView
339
- fullPath={fullPath}
340
- parentCollectionIds={[...parentCollectionIds, collection.id]}
341
- isSubCollection={true}
342
- {...subcollection}/>
343
- : <div
344
- className="flex items-center justify-center w-full h-full p-3">
345
- <Typography variant={"label"}>
346
- You need to save your entity before
347
- adding additional collections
348
- </Typography>
349
- </div>)
350
- }
351
-
352
- </div>
353
- );
354
- }
355
- ).filter(Boolean);
424
+ {hasAdditionalViews && <Tabs
425
+ value={selectedTab}
426
+ onValueChange={(value) => {
427
+ onSideTabClick(value);
428
+ }}>
356
429
 
357
- const onDiscard = useCallback(() => {
358
- onValuesAreModified(false);
359
- }, []);
430
+ {includeJsonView && <Tab
431
+ disabled={!hasAdditionalViews}
432
+ value={JSON_TAB_VALUE}
433
+ className={"text-sm"}>
434
+ <CodeIcon size={"small"}/>
435
+ </Tab>}
360
436
 
361
- const onSideTabClick = (value: string) => {
362
- selectedTabRef.current = value;
363
- sideEntityController.replace({
364
- path,
365
- entityId,
366
- selectedSubPath: value === MAIN_TAB_VALUE ? undefined : value,
367
- updateUrl: true,
368
- collection,
369
- });
370
- };
437
+ {customViewTabsStart}
371
438
 
372
- const onValuesChanged = useCallback((values?: EntityValues<M>) => {
373
- modifiedValuesRef.current = values;
374
- }, []);
439
+ <Tab
440
+ disabled={!hasAdditionalViews}
441
+ value={MAIN_TAB_VALUE}
442
+ className={"text-sm min-w-[120px]"}>
443
+ {collection.singularName ?? collection.name}
444
+ </Tab>
375
445
 
376
- // eslint-disable-next-line n/handle-callback-err
377
- const onIdUpdateError = useCallback((error: any) => {
378
- snackbarController.open({
379
- type: "error",
380
- message: "Error updating id, check the console"
381
- });
382
- }, []);
383
446
 
384
- const onIdChange = useCallback((id: string) => {
385
- setUsedEntity((prevEntity) => prevEntity
386
- ? {
387
- ...prevEntity,
388
- id
389
- }
390
- : undefined);
391
- }, []);
447
+ {customViewTabsEnd}
392
448
 
393
- const onModified = (dirty: boolean) => {
394
- if (!autoSave)
395
- onValuesAreModified(dirty);
396
- }
449
+ {subcollectionTabs}
450
+ </Tabs>}
451
+ </div>}
397
452
 
398
- function buildForm() {
399
- const plugins = customizationController.plugins;
400
- let form = <EntityForm
401
- status={status}
402
- path={path}
403
- collection={collection}
404
- onEntitySaveRequested={onSaveEntityRequest}
405
- onDiscard={onDiscard}
406
- onValuesChanged={onValuesChanged}
407
- onModified={onModified}
408
- entity={usedEntity}
409
- onIdChange={onIdChange}
410
- onFormContextChange={setFormContext}
411
- hideId={collection.hideIdFromForm}
412
- autoSave={autoSave}
413
- onIdUpdateError={onIdUpdateError}
414
- />;
415
- if (plugins) {
416
- plugins.forEach((plugin: FireCMSPlugin) => {
417
- if (plugin.form?.provider) {
418
- form = (
419
- <plugin.form.provider.Component
420
- status={status}
421
- path={path}
422
- collection={collection}
423
- onDiscard={onDiscard}
424
- onValuesChanged={onValuesChanged}
425
- onModified={onModified}
426
- entity={usedEntity}
427
- context={context}
428
- formContext={formContext}
429
- {...plugin.form.provider.props}>
430
- {form}
431
- </plugin.form.provider.Component>
432
- );
433
- }
434
- });
435
- }
436
- return <ErrorBoundary>{form}</ErrorBoundary>;
437
- }
453
+ {globalLoading
454
+ ? <div className="w-full pt-12 pb-16 px-4 sm:px-8 md:px-10">
455
+ <CircularProgressCenter/>
456
+ </div>
457
+ : <>
458
+ {entityReadOnlyView}
459
+ {entityView}
460
+ </>}
438
461
 
439
- const form = (readOnly === undefined)
440
- ? <></>
441
- : (!readOnly
442
- ? buildForm()
443
- : (
444
- <>
445
- <Typography
446
- className={"mt-16 mb-8 mx-8"}
447
- variant={"h4"}>{collection.singularName ?? collection.name}
448
- </Typography>
449
- <EntityView
450
- className={"px-12"}
451
- entity={usedEntity as Entity<M>}
452
- path={path}
453
- collection={collection}/>
454
- </>
455
- ));
462
+ {jsonView}
456
463
 
457
- const subcollectionTabs = subcollections && subcollections.map(
458
- (subcollection) =>
459
- <Tab
460
- className="text-sm min-w-[140px]"
461
- value={subcollection.id}
462
- key={`entity_detail_collection_tab_${subcollection.name}`}>
463
- {subcollection.name}
464
- </Tab>
465
- );
464
+ {customViewsView}
466
465
 
467
- const customViewTabs = resolvedEntityViews.map(
468
- (view) =>
466
+ {subCollectionsViews}
469
467
 
470
- <Tab
471
- className="text-sm min-w-[140px]"
472
- value={view.key}
473
- key={`entity_detail_collection_tab_${view.name}`}>
474
- {view.name}
475
- </Tab>
476
- );
468
+ </div>;
477
469
 
478
- return (
479
- <div
480
- className="flex flex-col h-full w-full transition-width duration-250 ease-in-out">
481
- {
482
- <>
483
-
484
- <div
485
- className={cn(defaultBorderMixin, "no-scrollbar border-b pl-2 pr-2 pt-1 flex items-end overflow-scroll bg-gray-50 dark:bg-gray-950")}>
486
-
487
- <div
488
- className="pb-1 self-center">
489
- <IconButton
490
- onClick={() => {
491
- onClose?.();
492
- return sideDialogContext.close(false);
493
- }}
494
- size="large">
495
- <CloseIcon/>
496
- </IconButton>
497
- </div>
498
-
499
- <div className={"flex-grow"}/>
500
-
501
- {globalLoading && <div
502
- className="self-center">
503
- <CircularProgress size={"small"}/>
504
- </div>}
505
-
506
- <Tabs
507
- value={selectedTabRef.current}
508
- onValueChange={(value) => {
509
- onSideTabClick(value);
510
- }}
511
- className="pl-4 pr-4 pt-0">
512
-
513
- <Tab
514
- disabled={!hasAdditionalViews}
515
- value={MAIN_TAB_VALUE}
516
- className={`${
517
- !hasAdditionalViews ? "hidden" : ""
518
- } text-sm min-w-[140px]`}
519
- >{collection.singularName ?? collection.name}</Tab>
520
-
521
- {customViewTabs}
522
-
523
- {subcollectionTabs}
524
- </Tabs>
525
-
526
- </div>
527
-
528
- <div
529
- className={"flex-grow h-full flex overflow-auto flex-row w-full "}
530
- style={{
531
- // width: `calc(${ADDITIONAL_TAB_WIDTH} + ${resolvedFormWidth})`,
532
- // maxWidth: "100%",
533
- // [`@media (max-width: ${resolvedFormWidth})`]: {
534
- // width: resolvedFormWidth
535
- // }
536
- }}>
537
-
538
- <div
539
- role="tabpanel"
540
- hidden={!mainViewVisible}
541
- id={`form_${path}`}
542
- className={" w-full"}>
543
-
544
- {globalLoading
545
- ? <CircularProgressCenter/>
546
- : form}
547
-
548
- </div>
549
-
550
- {customViewsView}
551
-
552
- {subCollectionsViews}
553
-
554
- </div>
555
-
556
- </>
470
+ if (plugins) {
471
+ plugins.forEach((plugin: FireCMSPlugin) => {
472
+ if (plugin.form?.provider) {
473
+ result = (
474
+ <plugin.form.provider.Component
475
+ status={status}
476
+ path={path}
477
+ collection={collection}
478
+ entity={usedEntity}
479
+ context={context}
480
+ formContext={formContext}
481
+ {...plugin.form.provider.props}>
482
+ {result}
483
+ </plugin.form.provider.Component>
484
+ );
557
485
  }
486
+ });
487
+ }
558
488
 
559
- </div>
560
- );
489
+ return result;
561
490
  }
491
+