@firecms/core 3.0.0-canary.29 → 3.0.0-canary.292

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