@firecms/core 3.0.0-canary.22 → 3.0.0-canary.221

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