@firecms/core 3.0.0-canary.19 → 3.0.0-canary.191

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 +31 -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 +36 -68
  57. package/dist/form/EntityFormActions.d.ts +16 -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 +22037 -14330
  98. package/dist/index.es.js.map +1 -1
  99. package/dist/index.umd.js +24386 -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 +71 -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 +1 -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 +5 -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 +206 -112
  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 +358 -480
  229. package/src/core/EntityEditViewFormActions.tsx +198 -0
  230. package/src/core/EntitySidePanel.tsx +87 -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 +568 -546
  238. package/src/form/EntityFormActions.tsx +168 -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 +178 -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 +223 -0
  310. package/src/routes/HomePageRoute.tsx +17 -0
  311. package/src/types/auth.tsx +9 -13
  312. package/src/types/collections.ts +87 -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 +13 -0
  331. package/src/types/side_entity_controller.tsx +1 -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 +10 -2
  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,439 @@
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, 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
50
  }
51
51
 
52
52
  /**
53
53
  * This is the default view that is used as the content of a side panel when
54
54
  * 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
55
  */
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
- }
56
+ export function EntityEditView<M extends Record<string, any>, USER extends User>({
57
+ entityId,
58
+ ...props
59
+ }: EntityEditViewProps<M>) {
74
60
 
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);
61
+ const {
62
+ entity,
63
+ dataLoading,
64
+ // eslint-disable-next-line no-unused-vars
65
+ dataLoadingError
66
+ } = useEntityFetch<M, USER>({
67
+ path: props.path,
68
+ entityId: entityId,
69
+ collection: props.collection,
70
+ databaseId: props.databaseId,
71
+ useCache: false
72
+ });
91
73
 
92
- // const largeLayout = useLargeLayout();
93
- // const largeLayoutTabSelected = useRef(!largeLayout);
74
+ const cachedValues = entityId
75
+ ? getEntityFromCache(props.path + "/" + entityId)
76
+ : getEntityFromCache(props.path + "#new");
94
77
 
95
- const resolvedFormWidth: string = typeof formWidth === "number" ? `${formWidth}px` : formWidth ?? FORM_CONTAINER_WIDTH;
78
+ const authController = useAuthController();
96
79
 
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>();
80
+ const initialStatus = props.copy ? "copy" : (entityId ? "existing" : "new");
81
+ const [status, setStatus] = useState<EntityStatus>(initialStatus);
104
82
 
105
- const [formContext, setFormContext] = useState<FormContext<M> | undefined>(undefined);
83
+ const canEdit = useMemo(() => {
84
+ if (status === "new" || status === "copy") {
85
+ return true;
86
+ } else {
87
+ return entity ? canEditEntity(props.collection, authController, props.path, entity ?? null) : undefined;
88
+ }
89
+ }, [authController, entity, status]);
106
90
 
107
- const [status, setStatus] = useState<EntityStatus>(copy ? "copy" : (entityId ? "existing" : "new"));
91
+ if ((dataLoading && !cachedValues) || (!entity || canEdit === undefined) && (status === "existing" || status === "copy")) {
92
+ return <CircularProgressCenter/>;
93
+ }
108
94
 
109
- const modifiedValuesRef = useRef<EntityValues<M> | undefined>(undefined);
110
- const modifiedValues = modifiedValuesRef.current;
95
+ if (entityId && !entity && !cachedValues) {
96
+ console.error(`Entity with id ${entityId} not found in collection ${props.path}`);
97
+ }
111
98
 
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;
99
+ if (!canEdit) {
100
+ return <div className={"flex flex-col"}>
101
+ <Typography className={"mt-16 mb-8 mx-8"} variant={"h4"}>
102
+ {props.collection.singularName ?? props.collection.name}
103
+ </Typography>
104
+ <EntityView
105
+ className={"px-8"}
106
+ entity={entity as Entity<M>}
107
+ path={props.path}
108
+ collection={props.collection}/>
109
+ </div>
110
+ }
117
111
 
118
- const hasAdditionalViews = customViewsCount > 0 || subcollectionsCount > 0;
112
+ return <EntityEditViewInner<M> {...props}
113
+ entityId={entityId}
114
+ entity={entity}
115
+ cachedDirtyValues={cachedValues as Partial<M>}
116
+ dataLoading={dataLoading}
117
+ status={status}
118
+ setStatus={setStatus}
119
+ />;
120
+ }
119
121
 
120
- const defaultSelectedView = selectedSubPath ?? resolveDefaultSelectedView(
121
- collection ? collection.defaultSelectedView : undefined,
122
- {
123
- status,
124
- entityId
125
- }
126
- );
122
+ function SecondaryForm<M extends object>({
123
+ collection,
124
+ className,
125
+ customView,
126
+ entity,
127
+ formContext,
128
+ forceActionsAtTheBottom,
129
+ }: {
130
+ className?: string,
131
+ customView: EntityCustomView,
132
+ formContext: FormContext<M>,
133
+ collection: EntityCollection<M>,
134
+ forceActionsAtTheBottom?: boolean,
135
+ entity: Entity<M> | undefined,
136
+ }) {
137
+
138
+ if (!customView.Builder) {
139
+ console.error("customView.Builder is not defined");
140
+ return null;
141
+ }
127
142
 
128
- const selectedTabRef = useRef<string>(defaultSelectedView ?? MAIN_TAB_VALUE);
143
+ return <FormLayoutInner
144
+ className={className}
145
+ forceActionsAtTheBottom={forceActionsAtTheBottom}
146
+ formContext={formContext}
147
+ EntityFormActionsComponent={EntityEditViewFormActions}>
148
+ <ErrorBoundary>
149
+ {formContext && <customView.Builder
150
+ collection={collection}
151
+ entity={entity}
152
+ modifiedValues={formContext.formex.values ?? entity?.values}
153
+ formContext={formContext}
154
+ />}
155
+ </ErrorBoundary>
156
+ </FormLayoutInner>;
157
+ }
129
158
 
130
- const mainViewVisible = selectedTabRef.current === MAIN_TAB_VALUE;
159
+ export function EntityEditViewInner<M extends Record<string, any>>({
160
+ path,
161
+ entityId,
162
+ selectedTab: selectedTabProp,
163
+ collection,
164
+ parentCollectionIds,
165
+ onValuesModified,
166
+ onSaved,
167
+ onTabChange,
168
+ entity,
169
+ cachedDirtyValues,
170
+ dataLoading,
171
+ layout = "side_panel",
172
+ barActions,
173
+ status,
174
+ setStatus,
175
+ }: EntityEditViewProps<M> & {
176
+ entity?: Entity<M>,
177
+ cachedDirtyValues?: Partial<M>, // dirty cached entity in memory
178
+ dataLoading: boolean,
179
+ status: EntityStatus,
180
+ setStatus: (status: EntityStatus) => void,
181
+ }) {
131
182
 
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
- });
183
+ const context = useFireCMSContext();
143
184
 
144
185
  const [usedEntity, setUsedEntity] = useState<Entity<M> | undefined>(entity);
145
- const [readOnly, setReadOnly] = useState<boolean | undefined>(undefined);
146
186
 
147
187
  useEffect(() => {
148
188
  if (entity)
149
189
  setUsedEntity(entity);
150
190
  }, [entity]);
151
191
 
192
+ // Instead of using a ref (which does not trigger re-render), we use state for the form context.
193
+ const [formContext, setFormContext] = useState<FormContext<M> | undefined>(undefined);
194
+
195
+ const largeLayout = useLargeLayout();
196
+
197
+ const customizationController = useCustomizationController();
198
+
199
+ const defaultSelectedView = useMemo(() => resolveDefaultSelectedView(
200
+ collection ? collection.defaultSelectedView : undefined,
201
+ {
202
+ status,
203
+ entityId
204
+ }
205
+ ), []);
206
+
207
+ const [selectedTab, setSelectedTab] = useState<string>(selectedTabProp ?? defaultSelectedView ?? MAIN_TAB_VALUE);
208
+
152
209
  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);
210
+ if ((selectedTabProp ?? MAIN_TAB_VALUE) !== selectedTab) {
211
+ setSelectedTab(selectedTabProp ?? MAIN_TAB_VALUE);
159
212
  }
160
- }, [authController, usedEntity, status]);
213
+ }, [selectedTabProp]);
161
214
 
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]);
215
+ const mainViewVisible = selectedTab === MAIN_TAB_VALUE;
179
216
 
180
- const onSaveSuccess = (updatedEntity: Entity<M>, closeAfterSave: boolean) => {
217
+ const subcollections = (collection.subcollections ?? []).filter(c => !c.hideFromNavigation);
218
+ const subcollectionsCount = subcollections?.length ?? 0;
219
+ const customViews = collection.entityViews;
220
+ const customViewsCount = customViews?.length ?? 0;
221
+ const hasAdditionalViews = customViewsCount > 0 || subcollectionsCount > 0;
181
222
 
182
- setSaving(false);
183
- if (!autoSave)
184
- snackbarController.open({
185
- type: "success",
186
- message: `${collection.singularName ?? collection.name}: Saved correctly`
187
- });
223
+ const resolvedEntityViews = customViews ? customViews
224
+ .map(e => resolveEntityView(e, customizationController.entityViews))
225
+ .filter(Boolean) as EntityCustomView[]
226
+ : [];
188
227
 
189
- setUsedEntity(updatedEntity);
190
- setStatus("existing");
228
+ const selectedEntityView = resolvedEntityViews.find(e => e.key === selectedTab);
229
+ const actionsAtTheBottom = !largeLayout || layout === "side_panel" || selectedEntityView?.includeActions === "bottom";
191
230
 
192
- onValuesAreModified(false);
231
+ const secondaryForms: React.ReactNode[] | undefined = formContext && customViews && resolvedEntityViews
232
+ .filter(e => e.includeActions)
233
+ .map((customView) => {
234
+ if (!customView || !formContext)
235
+ return null;
193
236
 
194
- if (onUpdate)
195
- onUpdate({ entity: updatedEntity });
237
+ if (!customView.Builder) {
238
+ console.error("customView.Builder is not defined");
239
+ return null;
240
+ }
196
241
 
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
- }
242
+ return <SecondaryForm key={`custom_view_${customView.key}`}
243
+ className={selectedTab !== customView.key ? "hidden" : ""}
244
+ customView={customView}
245
+ formContext={formContext}
246
+ collection={collection}
247
+ forceActionsAtTheBottom={!largeLayout || layout === "side_panel" || customView.includeActions === "bottom"}
248
+ entity={usedEntity}/>;
210
249
 
211
- };
250
+ }).filter(Boolean);
212
251
 
213
- const onSaveFailure = useCallback((e: Error) => {
252
+ const customViewsView: React.ReactNode[] | undefined = customViews && resolvedEntityViews
253
+ .filter(e => !e.includeActions)
254
+ .map((customView) => {
255
+ if (!customView)
256
+ return null;
257
+ const Builder = customView.Builder;
258
+ if (!Builder) {
259
+ console.error("customView.Builder is not defined");
260
+ return null;
261
+ }
214
262
 
215
- setSaving(false);
216
- snackbarController.open({
217
- type: "error",
218
- message: "Error saving: " + e?.message
219
- });
263
+ return <div
264
+ className={cls(defaultBorderMixin,
265
+ "relative flex-1 w-full h-full overflow-auto",
266
+ { "hidden": selectedTab !== customView.key }
267
+ )}
268
+ key={`custom_view_${customView.key}`}
269
+ role="tabpanel">
270
+ <ErrorBoundary>
271
+ {formContext && <Builder
272
+ collection={collection}
273
+ entity={usedEntity}
274
+ modifiedValues={formContext.formex.values ?? usedEntity?.values}
275
+ formContext={formContext}
276
+ />}
277
+ </ErrorBoundary>
278
+ </div>;
279
+ }).filter(Boolean);
280
+
281
+ const globalLoading = dataLoading && !usedEntity;
282
+
283
+ const subCollectionsViews = subcollections && subcollections.map((subcollection) => {
284
+ const subcollectionId = subcollection.id ?? subcollection.path;
285
+ const fullPath = usedEntity ? `${path}/${usedEntity?.id}/${removeInitialAndTrailingSlashes(subcollectionId)}` : undefined;
286
+ if (selectedTab !== subcollectionId) return null;
287
+ return (
288
+ <div
289
+ className={"relative flex-1 h-full overflow-auto w-full"}
290
+ key={`subcol_${subcollectionId}`}
291
+ role="tabpanel">
292
+
293
+ {globalLoading && <CircularProgressCenter/>}
294
+
295
+ {!globalLoading &&
296
+ (usedEntity && fullPath
297
+ ? <EntityCollectionView
298
+ fullPath={fullPath}
299
+ parentCollectionIds={[...parentCollectionIds, collection.id]}
300
+ isSubCollection={true}
301
+ updateUrl={false}
302
+ {...subcollection}
303
+ openEntityMode={layout}/>
304
+ : <div className="flex items-center justify-center w-full h-full p-3">
305
+ <Typography variant={"label"}>
306
+ You need to save your entity before
307
+ adding additional collections
308
+ </Typography>
309
+ </div>)
310
+ }
220
311
 
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
- };
312
+ </div>
313
+ );
314
+ }).filter(Boolean);
256
315
 
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,
316
+ const onSideTabClick = (value: string) => {
317
+ setSelectedTab(value);
318
+ if (status === "existing") {
319
+ onTabChange?.({
274
320
  path,
275
321
  entityId,
276
- values,
277
- previousValues,
278
- closeAfterSave
322
+ selectedTab: value === MAIN_TAB_VALUE ? undefined : value,
323
+ collection
279
324
  });
280
325
  }
281
326
  };
282
327
 
283
- const resolvedEntityViews = customViews ? customViews
284
- .map(e => resolveEntityView(e, customizationController.entityViews))
285
- .filter(Boolean) as EntityCustomView[]
286
- : [];
328
+ // Render the main entity form view (or a read-only view if the user cannot edit)
329
+ const entityView = <EntityForm<M>
330
+ collection={collection}
331
+ path={path}
332
+ entityId={entityId ?? usedEntity?.id}
333
+ onValuesModified={onValuesModified}
334
+ onSaved={onSaved ? (params) => onSaved({
335
+ ...params,
336
+ selectedTab: MAIN_TAB_VALUE === selectedTab ? undefined : selectedTab,
337
+ }) : undefined}
338
+ entity={entity}
339
+ cachedDirtyValues={cachedDirtyValues}
340
+ openEntityMode={layout}
341
+ onFormContextReady={setFormContext}
342
+ forceActionsAtTheBottom={actionsAtTheBottom}
343
+ initialStatus={status}
344
+ onStatusChange={setStatus}
345
+ className={!mainViewVisible ? "hidden" : ""}
346
+ EntityFormActionsComponent={EntityEditViewFormActions}
347
+ onEntityChange={setUsedEntity}
348
+ />;
349
+
350
+ const subcollectionTabs = subcollections && subcollections.map((subcollection) =>
351
+ <Tab
352
+ className="text-sm min-w-[120px]"
353
+ value={subcollection.id}
354
+ key={`entity_detail_collection_tab_${subcollection.name}`}>
355
+ {subcollection.name}
356
+ </Tab>
357
+ );
287
358
 
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);
359
+ const customViewTabs = resolvedEntityViews.map((view) =>
360
+ <Tab
361
+ className="text-sm min-w-[120px]"
362
+ value={view.key}
363
+ key={`entity_detail_collection_tab_${view.name}`}>
364
+ {view.name}
365
+ </Tab>
366
+ );
316
367
 
317
- const globalLoading = (dataLoading && !usedEntity) ||
318
- ((!usedEntity || readOnly === undefined) && (status === "existing" || status === "copy"));
368
+ const shouldShowTopBar = Boolean(barActions) || hasAdditionalViews;
319
369
 
320
- const loading = globalLoading || saving;
370
+ let result = <div className="relative flex flex-col h-full w-full bg-white dark:bg-surface-900">
321
371
 
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);
372
+ {shouldShowTopBar && <div
373
+ 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
374
 
357
- const onDiscard = useCallback(() => {
358
- onValuesAreModified(false);
359
- }, []);
375
+ {barActions}
360
376
 
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
- };
377
+ <div className={"flex-grow"}/>
371
378
 
372
- const onValuesChanged = useCallback((values?: EntityValues<M>) => {
373
- modifiedValuesRef.current = values;
374
- }, []);
379
+ {globalLoading && <div className="self-center">
380
+ <CircularProgress size={"small"}/>
381
+ </div>}
375
382
 
376
- // eslint-disable-next-line n/handle-callback-err
377
- const onIdUpdateError = useCallback((error: any) => {
378
- snackbarController.open({
379
- type: "error",
380
- message: "Error updating id, check the console"
381
- });
382
- }, []);
383
+ {hasAdditionalViews && <Tabs
384
+ value={selectedTab}
385
+ onValueChange={(value) => {
386
+ onSideTabClick(value);
387
+ }}>
383
388
 
384
- const onIdChange = useCallback((id: string) => {
385
- setUsedEntity((prevEntity) => prevEntity
386
- ? {
387
- ...prevEntity,
388
- id
389
- }
390
- : undefined);
391
- }, []);
389
+ <Tab
390
+ disabled={!hasAdditionalViews}
391
+ value={MAIN_TAB_VALUE}
392
+ className={"text-sm min-w-[120px]"}>
393
+ {collection.singularName ?? collection.name}
394
+ </Tab>
392
395
 
393
- const onModified = (dirty: boolean) => {
394
- if (!autoSave)
395
- onValuesAreModified(dirty);
396
- }
396
+ {customViewTabs}
397
397
 
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
- }
398
+ {subcollectionTabs}
399
+ </Tabs>}
400
+ </div>}
438
401
 
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
- );
402
+ {globalLoading
403
+ ? <div className="w-full pt-12 pb-16 px-4 sm:px-8 md:px-10">
404
+ <CircularProgressCenter/>
405
+ </div>
406
+ : entityView}
466
407
 
467
- const customViewTabs = resolvedEntityViews.map(
468
- (view) =>
408
+ {secondaryForms}
469
409
 
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
- );
410
+ {customViewsView}
411
+
412
+ {subCollectionsViews}
413
+
414
+ </div>;
477
415
 
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
- </>
416
+ const plugins = customizationController.plugins;
417
+
418
+ if (plugins) {
419
+ plugins.forEach((plugin: FireCMSPlugin) => {
420
+ if (plugin.form?.provider) {
421
+ result = (
422
+ <plugin.form.provider.Component
423
+ status={status}
424
+ path={path}
425
+ collection={collection}
426
+ entity={usedEntity}
427
+ context={context}
428
+ formContext={formContext}
429
+ {...plugin.form.provider.props}>
430
+ {result}
431
+ </plugin.form.provider.Component>
432
+ );
557
433
  }
434
+ });
435
+ }
558
436
 
559
- </div>
560
- );
437
+ return result;
561
438
  }
439
+