@firecms/core 3.0.0-canary.20 → 3.0.0-canary.201

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