@firecms/core 3.0.0-canary.24 → 3.0.0-canary.241

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