@firecms/core 3.0.0-canary.21 → 3.0.0-canary.210

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 (380) hide show
  1. package/README.md +3 -3
  2. package/dist/app/AppBar.d.ts +12 -0
  3. package/dist/app/Drawer.d.ts +16 -0
  4. package/dist/app/Scaffold.d.ts +34 -0
  5. package/dist/app/index.d.ts +4 -0
  6. package/dist/app/useApp.d.ts +16 -0
  7. package/dist/components/ArrayContainer.d.ts +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/core/DefaultAppBar.d.ts +29 -0
  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 +3 -3
  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 +37 -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 +21823 -14330
  98. package/dist/index.es.js.map +1 -1
  99. package/dist/index.umd.js +24174 -588
  100. package/dist/index.umd.js.map +1 -1
  101. package/dist/internal/useBuildDataSource.d.ts +1 -16
  102. package/dist/internal/useBuildSideEntityController.d.ts +2 -2
  103. package/dist/internal/useUnsavedChangesDialog.d.ts +7 -9
  104. package/dist/preview/PropertyPreviewProps.d.ts +6 -1
  105. package/dist/preview/components/EnumValuesChip.d.ts +1 -1
  106. package/dist/preview/components/ReferencePreview.d.ts +3 -2
  107. package/dist/preview/components/StorageThumbnail.d.ts +2 -1
  108. package/dist/preview/components/UrlComponentPreview.d.ts +2 -1
  109. package/dist/preview/util.d.ts +3 -3
  110. package/dist/routes/CustomCMSRoute.d.ts +4 -0
  111. package/dist/routes/FireCMSRoute.d.ts +1 -0
  112. package/dist/routes/HomePageRoute.d.ts +3 -0
  113. package/dist/types/auth.d.ts +8 -10
  114. package/dist/types/collections.d.ts +77 -22
  115. package/dist/types/datasource.d.ts +52 -36
  116. package/dist/types/dialogs_controller.d.ts +7 -3
  117. package/dist/types/entities.d.ts +7 -2
  118. package/dist/types/entity_actions.d.ts +28 -4
  119. package/dist/types/entity_callbacks.d.ts +16 -16
  120. package/dist/types/entity_overrides.d.ts +2 -2
  121. package/dist/types/export_import.d.ts +4 -4
  122. package/dist/types/fields.d.ts +71 -42
  123. package/dist/types/firecms.d.ts +6 -2
  124. package/dist/types/firecms_context.d.ts +1 -1
  125. package/dist/types/index.d.ts +0 -1
  126. package/dist/types/navigation.d.ts +32 -14
  127. package/dist/types/permissions.d.ts +4 -4
  128. package/dist/types/plugins.d.ts +23 -12
  129. package/dist/types/properties.d.ts +52 -24
  130. package/dist/types/property_config.d.ts +0 -2
  131. package/dist/types/side_dialogs_controller.d.ts +10 -0
  132. package/dist/types/side_entity_controller.d.ts +6 -1
  133. package/dist/types/storage.d.ts +86 -3
  134. package/dist/types/user.d.ts +1 -0
  135. package/dist/util/builders.d.ts +3 -3
  136. package/dist/util/entities.d.ts +3 -3
  137. package/dist/util/entity_actions.d.ts +2 -0
  138. package/dist/util/entity_cache.d.ts +23 -0
  139. package/dist/util/icon_list.d.ts +5 -1
  140. package/dist/util/icon_synonyms.d.ts +1 -98
  141. package/dist/util/icons.d.ts +6 -3
  142. package/dist/util/index.d.ts +2 -0
  143. package/dist/util/navigation_from_path.d.ts +6 -1
  144. package/dist/util/navigation_utils.d.ts +14 -3
  145. package/dist/util/objects.d.ts +2 -1
  146. package/dist/util/permissions.d.ts +4 -4
  147. package/dist/util/plurals.d.ts +0 -2
  148. package/dist/util/property_utils.d.ts +3 -3
  149. package/dist/util/resolutions.d.ts +36 -17
  150. package/dist/util/storage.d.ts +23 -2
  151. package/dist/util/useStorageUploadController.d.ts +3 -3
  152. package/package.json +61 -48
  153. package/src/app/AppBar.tsx +18 -0
  154. package/src/app/Drawer.tsx +24 -0
  155. package/src/app/Scaffold.tsx +253 -0
  156. package/src/app/index.ts +4 -0
  157. package/src/app/useApp.tsx +32 -0
  158. package/src/components/ArrayContainer.tsx +127 -41
  159. package/src/components/CircularProgressCenter.tsx +2 -2
  160. package/src/components/ClearFilterSortButton.tsx +41 -0
  161. package/src/components/{DeleteConfirmationDialog.tsx → ConfirmationDialog.tsx} +3 -3
  162. package/src/components/DeleteEntityDialog.tsx +10 -19
  163. package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +54 -37
  164. package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +38 -31
  165. package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +30 -9
  166. package/src/components/EntityCollectionTable/PropertyTableCell.tsx +47 -39
  167. package/src/components/EntityCollectionTable/column_utils.tsx +3 -3
  168. package/src/components/EntityCollectionTable/fields/TableReferenceField.tsx +30 -16
  169. package/src/components/EntityCollectionTable/fields/TableStorageUpload.tsx +19 -17
  170. package/src/components/EntityCollectionTable/index.tsx +1 -1
  171. package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +31 -36
  172. package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +36 -34
  173. package/src/components/EntityCollectionTable/internal/EntityTableCellActions.tsx +20 -8
  174. package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +81 -80
  175. package/src/components/EntityCollectionView/EntityCollectionView.tsx +207 -113
  176. package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +4 -2
  177. package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +68 -0
  178. package/src/components/EntityCollectionView/useSelectionController.tsx +20 -7
  179. package/src/components/EntityCollectionView/utils.ts +19 -0
  180. package/src/components/EntityPreview.tsx +62 -52
  181. package/src/components/EntityView.tsx +10 -10
  182. package/src/components/ErrorView.tsx +4 -4
  183. package/src/components/HomePage/DefaultHomePage.tsx +26 -19
  184. package/src/components/HomePage/FavouritesView.tsx +6 -11
  185. package/src/components/HomePage/NavigationCard.tsx +3 -3
  186. package/src/components/HomePage/NavigationCardBinding.tsx +5 -10
  187. package/src/components/HomePage/NavigationGroup.tsx +2 -2
  188. package/src/components/HomePage/SmallNavigationCard.tsx +5 -6
  189. package/src/components/NotFoundPage.tsx +2 -2
  190. package/src/components/PropertyConfigBadge.tsx +9 -3
  191. package/src/components/PropertyIdCopyTooltip.tsx +47 -0
  192. package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +19 -13
  193. package/src/components/ReferenceWidget.tsx +21 -11
  194. package/src/components/SearchIconsView.tsx +10 -7
  195. package/src/components/SelectableTable/SelectableTable.tsx +27 -12
  196. package/src/components/SelectableTable/filters/BooleanFilterField.tsx +2 -3
  197. package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +25 -8
  198. package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +36 -12
  199. package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +92 -23
  200. package/src/components/UnsavedChangesDialog.tsx +42 -0
  201. package/src/components/VirtualTable/VirtualTable.tsx +96 -48
  202. package/src/components/VirtualTable/VirtualTableCell.tsx +1 -9
  203. package/src/components/VirtualTable/VirtualTableHeader.tsx +10 -10
  204. package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +2 -2
  205. package/src/components/VirtualTable/VirtualTableProps.tsx +33 -14
  206. package/src/components/VirtualTable/VirtualTableRow.tsx +5 -6
  207. package/src/components/VirtualTable/fields/VirtualTableDateField.tsx +5 -5
  208. package/src/components/VirtualTable/fields/VirtualTableInput.tsx +3 -2
  209. package/src/components/VirtualTable/fields/VirtualTableNumberInput.tsx +2 -1
  210. package/src/components/VirtualTable/fields/VirtualTableSelect.tsx +16 -28
  211. package/src/components/VirtualTable/types.tsx +2 -3
  212. package/src/components/{EntityCollectionTable/internal → common}/default_entity_actions.tsx +33 -40
  213. package/src/components/common/index.ts +2 -1
  214. package/src/components/{VirtualTable/common.tsx → common/table_height.tsx} +5 -2
  215. package/src/components/common/types.tsx +4 -6
  216. package/src/components/common/useColumnsIds.tsx +24 -3
  217. package/src/components/common/useDataSourceTableController.tsx +420 -0
  218. package/src/components/common/useDebouncedCallback.tsx +20 -0
  219. package/src/components/common/useScrollRestoration.tsx +68 -0
  220. package/src/components/common/useTableSearchHelper.ts +53 -12
  221. package/src/components/index.tsx +4 -2
  222. package/src/contexts/BreacrumbsContext.tsx +38 -0
  223. package/src/contexts/DialogsProvider.tsx +5 -4
  224. package/src/contexts/ModeController.tsx +1 -3
  225. package/src/contexts/SnackbarProvider.tsx +2 -0
  226. package/src/core/DefaultAppBar.tsx +219 -0
  227. package/src/core/DefaultDrawer.tsx +185 -0
  228. package/src/core/DrawerNavigationItem.tsx +66 -0
  229. package/src/core/EntityEditView.tsx +321 -479
  230. package/src/core/EntityEditViewFormActions.tsx +199 -0
  231. package/src/core/EntitySidePanel.tsx +86 -17
  232. package/src/core/FireCMS.tsx +56 -49
  233. package/src/core/FireCMSRouter.tsx +17 -0
  234. package/src/core/NavigationRoutes.tsx +28 -38
  235. package/src/core/SideDialogs.tsx +22 -12
  236. package/src/core/field_configs.tsx +11 -12
  237. package/src/core/index.tsx +6 -5
  238. package/src/form/EntityForm.tsx +585 -539
  239. package/src/form/EntityFormActions.tsx +169 -0
  240. package/src/form/PropertyFieldBinding.tsx +85 -44
  241. package/src/form/components/CustomIdField.tsx +6 -2
  242. package/src/form/components/FieldHelperText.tsx +4 -4
  243. package/src/form/components/FormEntry.tsx +22 -0
  244. package/src/form/components/FormLayout.tsx +16 -0
  245. package/src/form/components/LabelWithIcon.tsx +30 -19
  246. package/src/form/components/LabelWithIconAndTooltip.tsx +28 -0
  247. package/src/form/components/StorageItemPreview.tsx +22 -12
  248. package/src/form/components/StorageUploadProgress.tsx +4 -5
  249. package/src/form/components/index.tsx +3 -1
  250. package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +31 -19
  251. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +47 -35
  252. package/src/form/field_bindings/BlockFieldBinding.tsx +56 -34
  253. package/src/form/field_bindings/DateTimeFieldBinding.tsx +18 -14
  254. package/src/form/field_bindings/KeyValueFieldBinding.tsx +60 -51
  255. package/src/form/field_bindings/MapFieldBinding.tsx +71 -54
  256. package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +153 -0
  257. package/src/form/field_bindings/{MultiSelectBinding.tsx → MultiSelectFieldBinding.tsx} +25 -20
  258. package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +11 -16
  259. package/src/form/field_bindings/ReferenceFieldBinding.tsx +42 -31
  260. package/src/form/field_bindings/RepeatFieldBinding.tsx +56 -35
  261. package/src/form/field_bindings/SelectFieldBinding.tsx +22 -14
  262. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +42 -50
  263. package/src/form/field_bindings/SwitchFieldBinding.tsx +29 -24
  264. package/src/form/field_bindings/TextFieldBinding.tsx +28 -24
  265. package/src/form/index.tsx +16 -37
  266. package/src/form/useClearRestoreValue.tsx +2 -2
  267. package/src/form/validation.ts +13 -23
  268. package/src/hooks/data/delete.ts +6 -5
  269. package/src/hooks/data/save.ts +13 -9
  270. package/src/hooks/data/useCollectionFetch.tsx +3 -3
  271. package/src/hooks/data/useDataSource.tsx +11 -3
  272. package/src/hooks/data/useEntityFetch.tsx +10 -6
  273. package/src/hooks/index.tsx +1 -0
  274. package/src/hooks/useAuthController.tsx +1 -1
  275. package/src/hooks/useBreadcrumbsController.tsx +31 -0
  276. package/src/hooks/useBuildLocalConfigurationPersistence.tsx +8 -10
  277. package/src/hooks/useBuildModeController.tsx +22 -29
  278. package/src/hooks/useBuildNavigationController.tsx +159 -54
  279. package/src/hooks/useFireCMSContext.tsx +5 -5
  280. package/src/hooks/useLargeLayout.tsx +0 -35
  281. package/src/hooks/useModeController.tsx +1 -2
  282. package/src/hooks/useProjectLog.tsx +32 -10
  283. package/src/hooks/useResolvedNavigationFrom.tsx +10 -12
  284. package/src/hooks/useValidateAuthenticator.tsx +17 -37
  285. package/src/index.ts +1 -0
  286. package/src/internal/useBuildDataSource.ts +72 -82
  287. package/src/internal/useBuildSideDialogsController.tsx +4 -2
  288. package/src/internal/useBuildSideEntityController.tsx +193 -73
  289. package/src/internal/useUnsavedChangesDialog.tsx +127 -91
  290. package/src/preview/PropertyPreview.tsx +17 -24
  291. package/src/preview/PropertyPreviewProps.tsx +7 -1
  292. package/src/preview/components/BooleanPreview.tsx +2 -2
  293. package/src/preview/components/EmptyValue.tsx +1 -1
  294. package/src/preview/components/EnumValuesChip.tsx +2 -2
  295. package/src/preview/components/ImagePreview.tsx +25 -36
  296. package/src/preview/components/ReferencePreview.tsx +22 -33
  297. package/src/preview/components/StorageThumbnail.tsx +5 -1
  298. package/src/preview/components/UrlComponentPreview.tsx +60 -28
  299. package/src/preview/property_previews/ArrayOfMapsPreview.tsx +2 -3
  300. package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +4 -3
  301. package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +2 -3
  302. package/src/preview/property_previews/ArrayOfStringsPreview.tsx +1 -2
  303. package/src/preview/property_previews/ArrayOneOfPreview.tsx +4 -5
  304. package/src/preview/property_previews/ArrayPropertyPreview.tsx +4 -5
  305. package/src/preview/property_previews/MapPropertyPreview.tsx +12 -11
  306. package/src/preview/property_previews/SkeletonPropertyComponent.tsx +12 -12
  307. package/src/preview/property_previews/StringPropertyPreview.tsx +3 -3
  308. package/src/preview/util.ts +10 -10
  309. package/src/routes/CustomCMSRoute.tsx +21 -0
  310. package/src/routes/FireCMSRoute.tsx +235 -0
  311. package/src/routes/HomePageRoute.tsx +17 -0
  312. package/src/types/auth.tsx +9 -13
  313. package/src/types/collections.ts +94 -27
  314. package/src/types/customization_controller.tsx +0 -1
  315. package/src/types/datasource.ts +61 -43
  316. package/src/types/dialogs_controller.tsx +7 -3
  317. package/src/types/entities.ts +12 -2
  318. package/src/types/entity_actions.tsx +32 -7
  319. package/src/types/entity_callbacks.ts +18 -18
  320. package/src/types/entity_overrides.tsx +2 -2
  321. package/src/types/export_import.ts +4 -4
  322. package/src/types/fields.tsx +81 -46
  323. package/src/types/firecms.tsx +7 -2
  324. package/src/types/firecms_context.tsx +1 -1
  325. package/src/types/index.ts +0 -1
  326. package/src/types/navigation.ts +38 -18
  327. package/src/types/permissions.ts +5 -5
  328. package/src/types/plugins.tsx +25 -14
  329. package/src/types/properties.ts +60 -25
  330. package/src/types/property_config.tsx +0 -2
  331. package/src/types/side_dialogs_controller.tsx +15 -0
  332. package/src/types/side_entity_controller.tsx +6 -1
  333. package/src/types/storage.ts +94 -3
  334. package/src/types/user.ts +2 -0
  335. package/src/util/builders.ts +10 -8
  336. package/src/util/entities.ts +9 -6
  337. package/src/util/entity_actions.ts +28 -0
  338. package/src/util/entity_cache.ts +204 -0
  339. package/src/util/enums.ts +1 -1
  340. package/src/util/icon_list.ts +16 -10
  341. package/src/util/icon_synonyms.ts +3 -100
  342. package/src/util/icons.tsx +17 -7
  343. package/src/util/index.ts +2 -0
  344. package/src/util/join_collections.ts +3 -0
  345. package/src/util/make_properties_editable.ts +13 -5
  346. package/src/util/navigation_from_path.ts +13 -6
  347. package/src/util/navigation_utils.ts +59 -7
  348. package/src/util/objects.ts +48 -28
  349. package/src/util/parent_references_from_path.ts +3 -3
  350. package/src/util/permissions.ts +9 -8
  351. package/src/util/plurals.ts +0 -2
  352. package/src/util/property_utils.tsx +11 -4
  353. package/src/util/references.ts +11 -2
  354. package/src/util/resolutions.ts +100 -46
  355. package/src/util/storage.ts +79 -21
  356. package/src/util/strings.ts +2 -2
  357. package/src/util/useStorageUploadController.tsx +71 -27
  358. package/dist/components/FireCMSAppBar.d.ts +0 -26
  359. package/dist/components/PropertyIdCopyTooltipContent.d.ts +0 -3
  360. package/dist/components/VirtualTable/common.d.ts +0 -2
  361. package/dist/core/Drawer.d.ts +0 -23
  362. package/dist/core/Scaffold.d.ts +0 -55
  363. package/dist/core/SideEntityView.d.ts +0 -7
  364. package/dist/form/components/FormikArrayContainer.d.ts +0 -18
  365. package/dist/form/field_bindings/MarkdownFieldBinding.d.ts +0 -9
  366. package/dist/internal/useBuildCustomizationController.d.ts +0 -2
  367. package/dist/internal/useLocaleConfig.d.ts +0 -1
  368. package/dist/types/appcheck.d.ts +0 -26
  369. package/src/components/FireCMSAppBar.tsx +0 -165
  370. package/src/components/PropertyIdCopyTooltipContent.tsx +0 -28
  371. package/src/components/common/useDataSourceEntityCollectionTableController.tsx +0 -225
  372. package/src/core/Drawer.tsx +0 -191
  373. package/src/core/Scaffold.tsx +0 -281
  374. package/src/core/SideEntityView.tsx +0 -38
  375. package/src/form/components/FormikArrayContainer.tsx +0 -44
  376. package/src/form/field_bindings/MarkdownFieldBinding.tsx +0 -695
  377. package/src/internal/useBuildCustomizationController.tsx +0 -5
  378. package/src/internal/useLocaleConfig.tsx +0 -18
  379. package/src/types/appcheck.ts +0 -29
  380. /package/src/util/{common.tsx → common.ts} +0 -0
@@ -1,26 +1,99 @@
1
1
  import { useCallback, useEffect, useRef } from "react";
2
2
  import {
3
+ CustomizationController,
3
4
  EntityCollection,
4
5
  EntitySidePanelProps,
5
6
  NavigationController,
7
+ ResolvedProperty,
6
8
  SideDialogPanelProps,
7
9
  SideDialogsController,
8
10
  SideEntityController
9
11
  } from "../types";
10
- import { getNavigationEntriesFromPathInternal, NavigationViewInternal } from "../util/navigation_from_path";
12
+ import { getNavigationEntriesFromPath, NavigationViewInternal } from "../util/navigation_from_path";
11
13
  import { useLocation } from "react-router-dom";
12
- import { removeInitialAndTrailingSlashes, resolveDefaultSelectedView } from "../util";
14
+ import {
15
+ removeInitialAndTrailingSlashes,
16
+ resolveCollection,
17
+ resolveDefaultSelectedView,
18
+ resolvedSelectedEntityView
19
+ } from "../util";
13
20
  import { ADDITIONAL_TAB_WIDTH, CONTAINER_FULL_WIDTH, FORM_CONTAINER_WIDTH } from "./common";
14
- import { useLargeLayout } from "../hooks";
21
+ import { useCustomizationController, useLargeLayout } from "../hooks";
15
22
  import { EntitySidePanel } from "../core/EntitySidePanel";
16
23
 
17
- const NEW_URL_HASH = "new";
24
+ const NEW_URL_HASH = "new_side";
25
+ const SIDE_URL_HASH = "side";
18
26
 
19
- export function getEntityViewWidth(props: EntitySidePanelProps<any>, small: boolean): string {
27
+ export function getEntityViewWidth(props: EntitySidePanelProps<any>, small: boolean, customizationController: CustomizationController): string {
20
28
  if (small) return CONTAINER_FULL_WIDTH;
21
- const mainViewSelected = !props.selectedSubPath;
22
- const resolvedWidth: string | undefined = typeof props.width === "number" ? `${props.width}px` : props.width;
23
- return !mainViewSelected ? `calc(${ADDITIONAL_TAB_WIDTH} + ${resolvedWidth ?? FORM_CONTAINER_WIDTH})` : resolvedWidth ?? FORM_CONTAINER_WIDTH
29
+
30
+ const {
31
+ selectedSecondaryForm
32
+ } = resolvedSelectedEntityView(props.collection?.entityViews, customizationController, props.selectedTab);
33
+
34
+ const shouldUseSmallLayout = !props.selectedTab || Boolean(selectedSecondaryForm);
35
+
36
+ let resolvedWidth: string | undefined;
37
+ if (props.width) {
38
+ resolvedWidth = typeof props.width === "number" ? `${props.width}px` : props.width;
39
+ } else if (props.collection?.sideDialogWidth) {
40
+ resolvedWidth = typeof props.collection.sideDialogWidth === "number" ? `${props.collection.sideDialogWidth}px` : props.collection.sideDialogWidth;
41
+ }
42
+
43
+ if (!shouldUseSmallLayout) {
44
+ return `calc(${ADDITIONAL_TAB_WIDTH} + ${resolvedWidth ?? FORM_CONTAINER_WIDTH})`
45
+ } else {
46
+ if (resolvedWidth) {
47
+ return resolvedWidth
48
+ } else if (!props.collection) {
49
+ return FORM_CONTAINER_WIDTH;
50
+ } else {
51
+ return calculateCollectionDesiredWidth(props.collection);
52
+ }
53
+ }
54
+ }
55
+
56
+ const collectionViewWidthCache: { [key: string]: string } = {};
57
+
58
+ function calculateCollectionDesiredWidth(collection: EntityCollection<any>): string {
59
+ if (collectionViewWidthCache[collection.id]) {
60
+ return collectionViewWidthCache[collection.id];
61
+ }
62
+ const resolvedCollection = resolveCollection({
63
+ collection,
64
+ path: "__ignored",
65
+ ignoreMissingFields: true
66
+ });
67
+
68
+ let result = FORM_CONTAINER_WIDTH
69
+ if (resolvedCollection?.properties) {
70
+ const values = Object.values(resolvedCollection.properties).map((p: ResolvedProperty) => getNestedPropertiesDepth(p));
71
+ const maxDepth = Math.max(...values);
72
+ if (maxDepth < 3) {
73
+ result = FORM_CONTAINER_WIDTH;
74
+ } else {
75
+ result = 768 + 32 * (maxDepth - 2) + "px";
76
+ }
77
+ }
78
+ collectionViewWidthCache[collection.id] = result;
79
+ return result;
80
+ }
81
+
82
+ function getNestedPropertiesDepth(property: ResolvedProperty, accumulator: number = 0): number {
83
+ if (property.dataType === "map" && property.properties) {
84
+ const values = Object.values(property.properties).flatMap((property) => getNestedPropertiesDepth(property, accumulator + 1));
85
+ return Math.max(...values);
86
+ } else if (property.dataType === "array" && property.oneOf) {
87
+ return accumulator + 3;
88
+ } else if (property.dataType === "array" && property.of) {
89
+ if (Array.isArray(property.of)) {
90
+ return Math.max(...property.of.map((p) => getNestedPropertiesDepth(p, accumulator + 1)));
91
+ } else {
92
+ return getNestedPropertiesDepth(property.of, accumulator + 1);
93
+ }
94
+ } else {
95
+ return accumulator + 1;
96
+ }
24
97
  }
25
98
 
26
99
  export const useBuildSideEntityController = (navigation: NavigationController,
@@ -28,30 +101,64 @@ export const useBuildSideEntityController = (navigation: NavigationController,
28
101
 
29
102
  const location = useLocation();
30
103
  const initialised = useRef<boolean>(false);
104
+ const customizationController = useCustomizationController();
31
105
 
32
106
  const smallLayout = !useLargeLayout();
33
107
 
34
108
  // only on initialisation, create panels from URL
35
109
  useEffect(() => {
36
- if (!navigation.loading && !initialised.current) {
37
- console.debug("Initialising side entity controller");
38
- if (navigation.isUrlCollectionPath(location.pathname)) {
39
- const newFlag = location.hash === `#${NEW_URL_HASH}`;
110
+
111
+ const newFlag = location.hash === `#${NEW_URL_HASH}`;
112
+ const sideFlag = location.hash === `#${SIDE_URL_HASH}`;
113
+
114
+ if (!navigation.loading) {
115
+ if ((newFlag || sideFlag) && navigation.isUrlCollectionPath(location.pathname)) {
40
116
  const entityOrCollectionPath = navigation.urlPathToDataPath(location.pathname);
41
117
  const panelsFromUrl = buildSidePanelsFromUrl(entityOrCollectionPath, navigation.collections ?? [], newFlag);
42
118
  for (let i = 0; i < panelsFromUrl.length; i++) {
43
- const panel = panelsFromUrl[i];
44
- setTimeout(() => {
45
- if (i === 0)
46
- sideDialogsController.replace(propsToSidePanel(panel, navigation, smallLayout));
47
- else
48
- sideDialogsController.open(propsToSidePanel(panel, navigation, smallLayout))
49
- }, 1);
119
+ const props = panelsFromUrl[i];
120
+ if (i === 0)
121
+ sideDialogsController.replace(propsToSidePanel(props, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, customizationController));
122
+ else
123
+ sideDialogsController.open(propsToSidePanel(props, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, customizationController))
50
124
  }
51
125
  }
52
126
  initialised.current = true;
53
127
  }
54
- }, [location, navigation, sideDialogsController, smallLayout]);
128
+ }, [navigation.loading]);
129
+
130
+ // sync panels if URL changes with #side
131
+ const currentPanelKeys = sideDialogsController.sidePanels.map(p => p.key);
132
+ useEffect(() => {
133
+ if (initialised.current) {
134
+ const sideFlag = location.hash === `#${SIDE_URL_HASH}`;
135
+ if (sideFlag) {
136
+ const entityOrCollectionPath = navigation.urlPathToDataPath(location.pathname);
137
+ const panelsFromUrl = buildSidePanelsFromUrl(entityOrCollectionPath, navigation.collections ?? [], false);
138
+ // if we have more panels than determined by the url, we ignore the url. We might have references open
139
+ if (panelsFromUrl.length <= currentPanelKeys.length) {
140
+ return;
141
+ }
142
+ const lastPanel = panelsFromUrl[panelsFromUrl.length - 1];
143
+ const panelProps = propsToSidePanel(lastPanel, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, customizationController);
144
+ const lastCurrentPanel = currentPanelKeys.length > 0 ? currentPanelKeys[currentPanelKeys.length - 1] : undefined;
145
+ if (!lastCurrentPanel || lastCurrentPanel !== panelProps.key) {
146
+ sideDialogsController.replace(panelProps);
147
+ }
148
+ }
149
+ }
150
+ }, [location.pathname, location.hash, currentPanelKeys]);
151
+
152
+ // update side panels to match browser size
153
+ useEffect(() => {
154
+ const updatedSidePanels = sideDialogsController.sidePanels.map(sidePanelProps => {
155
+ if (sidePanelProps.additional) {
156
+ return propsToSidePanel(sidePanelProps.additional, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, customizationController);
157
+ }
158
+ return sidePanelProps;
159
+ });
160
+ sideDialogsController.setSidePanels(updatedSidePanels);
161
+ }, [smallLayout]);
55
162
 
56
163
  const close = useCallback(() => {
57
164
  sideDialogsController.close();
@@ -71,12 +178,18 @@ export const useBuildSideEntityController = (navigation: NavigationController,
71
178
  }
72
179
  );
73
180
 
74
- sideDialogsController.open(propsToSidePanel({
75
- selectedSubPath: defaultSelectedView,
76
- ...props,
77
- }, navigation, smallLayout));
181
+ sideDialogsController.open(
182
+ propsToSidePanel({
183
+ selectedTab: defaultSelectedView,
184
+ ...props
185
+ },
186
+ navigation.buildUrlCollectionPath,
187
+ navigation.resolveIdsFrom,
188
+ smallLayout,
189
+ customizationController
190
+ ));
78
191
 
79
- }, [sideDialogsController, navigation, smallLayout]);
192
+ }, [sideDialogsController, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout]);
80
193
 
81
194
  const replace = useCallback((props: EntitySidePanelProps<any>) => {
82
195
 
@@ -84,9 +197,9 @@ export const useBuildSideEntityController = (navigation: NavigationController,
84
197
  throw Error("If you want to copy an entity you need to provide an entityId");
85
198
  }
86
199
 
87
- sideDialogsController.replace(propsToSidePanel(props, navigation, smallLayout));
200
+ sideDialogsController.replace(propsToSidePanel(props, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, customizationController));
88
201
 
89
- }, [navigation, sideDialogsController, smallLayout]);
202
+ }, [navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, sideDialogsController, smallLayout]);
90
203
 
91
204
  return {
92
205
  close,
@@ -97,12 +210,12 @@ export const useBuildSideEntityController = (navigation: NavigationController,
97
210
 
98
211
  export function buildSidePanelsFromUrl(path: string, collections: EntityCollection[], newFlag: boolean): EntitySidePanelProps<any>[] {
99
212
 
100
- const navigationViewsForPath: NavigationViewInternal<any>[] = getNavigationEntriesFromPathInternal({
213
+ const navigationViewsForPath: NavigationViewInternal<any>[] = getNavigationEntriesFromPath({
101
214
  path,
102
215
  collections
103
216
  });
104
217
 
105
- const sidePanels: EntitySidePanelProps<any>[] = [];
218
+ let sidePanel: EntitySidePanelProps<any> | undefined = undefined;
106
219
  let lastCollectionPath = "";
107
220
  for (let i = 0; i < navigationViewsForPath.length; i++) {
108
221
  const navigationEntry = navigationViewsForPath[i];
@@ -111,63 +224,70 @@ export function buildSidePanelsFromUrl(path: string, collections: EntityCollecti
111
224
  lastCollectionPath = navigationEntry.path;
112
225
  }
113
226
 
114
- if (i > 0) { // the first collection is handled by the main navigation
115
- const previousEntry = navigationViewsForPath[i - 1];
116
- if (navigationEntry.type === "entity") {
117
- sidePanels.push({
118
- path: navigationEntry.path,
119
- entityId: navigationEntry.entityId,
120
- copy: false
121
- }
122
- );
123
- } else if (navigationEntry.type === "custom_view") {
124
- if (previousEntry.type === "entity") {
125
- const lastSidePanel: EntitySidePanelProps<any> = sidePanels[sidePanels.length - 1];
126
- if (lastSidePanel)
127
- lastSidePanel.selectedSubPath = navigationEntry.view.key;
128
- }
129
- } else if (navigationEntry.type === "collection") {
130
- if (previousEntry.type === "entity") {
131
- const lastSidePanel: EntitySidePanelProps<any> = sidePanels[sidePanels.length - 1];
132
- if (lastSidePanel)
133
- lastSidePanel.selectedSubPath = navigationEntry.collection.id ?? navigationEntry.collection.path;
134
- }
227
+ const previousEntry = navigationViewsForPath[i - 1];
228
+ if (navigationEntry.type === "entity") {
229
+ sidePanel = {
230
+ path: navigationEntry.path,
231
+ entityId: navigationEntry.entityId,
232
+ copy: false,
233
+ width: navigationEntry.parentCollection?.sideDialogWidth
234
+ };
235
+ } else if (navigationEntry.type === "custom_view") {
236
+ if (previousEntry?.type === "entity") {
237
+ if (sidePanel)
238
+ sidePanel.selectedTab = navigationEntry.view.key;
239
+ }
240
+ } else if (navigationEntry.type === "collection") {
241
+ if (previousEntry?.type === "entity") {
242
+ if (sidePanel)
243
+ sidePanel.selectedTab = navigationEntry.collection.id ?? navigationEntry.collection.path;
135
244
  }
136
245
  }
137
246
 
138
247
  }
139
248
 
140
249
  if (newFlag) {
141
- sidePanels.push({
250
+ sidePanel = {
142
251
  path: lastCollectionPath,
143
252
  copy: false
144
- });
253
+ }
145
254
  }
146
255
 
147
- return sidePanels;
256
+ return sidePanel ? [sidePanel] : [];
148
257
  }
149
258
 
150
- const propsToSidePanel = (props: EntitySidePanelProps<any>, navigation: NavigationController, smallLayout: boolean): SideDialogPanelProps => {
259
+ const propsToSidePanel = (props: EntitySidePanelProps,
260
+ buildUrlCollectionPath: (path: string) => string,
261
+ resolveIdsFrom: (pathWithAliases: string) => string,
262
+ smallLayout: boolean,
263
+ customizationController: CustomizationController): SideDialogPanelProps => {
264
+
265
+ const collectionPath = removeInitialAndTrailingSlashes(props.path);
151
266
 
152
- const collectionPath = removeInitialAndTrailingSlashes(props.path);
267
+ const newPath = props.entityId
268
+ ? buildUrlCollectionPath(`${collectionPath}/${props.entityId}${props.selectedTab ? "/" + props.selectedTab : ""}#${SIDE_URL_HASH}`)
269
+ : buildUrlCollectionPath(`${collectionPath}#${NEW_URL_HASH}`);
270
+ const resolvedPath = resolveIdsFrom(props.path);
153
271
 
154
- const newPath = props.entityId
155
- ? navigation.buildUrlCollectionPath(`${collectionPath}/${props.entityId}/${props.selectedSubPath || ""}`)
156
- : navigation.buildUrlCollectionPath(`${collectionPath}#${NEW_URL_HASH}`);
157
- const resolvedPath = navigation.resolveAliasesFrom(props.path);
272
+ const resolvedPanelProps: EntitySidePanelProps<any> = {
273
+ ...props,
274
+ path: resolvedPath,
275
+ formProps: props.formProps
276
+ };
158
277
 
159
- const resolvedPanelProps: EntitySidePanelProps<any> = {
160
- ...props,
161
- path: resolvedPath
162
- };
278
+ const entityViewWidth = getEntityViewWidth(props, smallLayout, customizationController);
163
279
 
164
- return ({
165
- key: `${props.path}/${props.entityId}`,
166
- component: <EntitySidePanel {...resolvedPanelProps}/>,
167
- urlPath: newPath,
168
- parentUrlPath: navigation.buildUrlCollectionPath(collectionPath),
169
- width: getEntityViewWidth(props, smallLayout),
170
- onClose: props.onClose
171
- });
172
- }
173
- ;
280
+ return {
281
+ key: `${props.path}/${props.entityId}`,
282
+ component: <EntitySidePanel {...resolvedPanelProps}/>,
283
+ urlPath: newPath,
284
+ parentUrlPath: buildUrlCollectionPath(collectionPath),
285
+ width: entityViewWidth,
286
+ onClose: props.onClose,
287
+ additional: props
288
+ };
289
+ }
290
+
291
+ function isSideUrl(url: string): boolean {
292
+ return url.endsWith("#" + SIDE_URL_HASH) || url.endsWith("#" + NEW_URL_HASH);
293
+ }
@@ -1,106 +1,142 @@
1
- import React, { useCallback } from "react";
2
- import { Blocker, Transition } from "history";
3
- import { UNSAFE_NavigationContext, useNavigate } from "react-router-dom";
4
- import { Button, Dialog, DialogActions, DialogContent, Typography } from "@firecms/ui";
1
+ import React, { useCallback, useEffect, useState } from "react";
2
+ import { Button, Dialog, DialogActions, DialogContent, DialogTitle, Typography } from "@firecms/ui";
5
3
 
6
- export function useNavigationUnsavedChangesDialog(when: boolean, onSuccess: () => void):
7
- {
8
- navigationWasBlocked: boolean,
9
- handleCancel: () => void,
10
- handleOk: () => void
11
- } {
12
-
13
- const [nextLocation, setNextLocation] = React.useState<any | undefined>();
14
- const { navigator } = React.useContext(UNSAFE_NavigationContext);
4
+ /**
5
+ * Type representing a pending navigation action.
6
+ */
7
+ type PendingNavigation =
8
+ | {
9
+ type: "popstate";
10
+ delta: number;
11
+ }
12
+ | {
13
+ type: "link";
14
+ href: string;
15
+ }
16
+ | null;
15
17
 
16
- const navigate = useNavigate();
18
+ /**
19
+ * Custom hook to handle navigation blocking when there are unsaved changes.
20
+ *
21
+ * @param when - Indicates whether to block navigation.
22
+ * @param onSuccess - Callback invoked when navigation is confirmed.
23
+ * @returns An object containing the state of navigation blocking and handlers.
24
+ */
25
+ export function useNavigationUnsavedChangesDialog(
26
+ when: boolean,
27
+ onSuccess: () => void
28
+ ): {
29
+ navigationWasBlocked: boolean;
30
+ handleCancel: () => void;
31
+ handleOk: () => void;
32
+ } {
33
+ const [isDialogOpen, setIsDialogOpen] = useState<boolean>(false);
34
+ const [pendingNavigation, setPendingNavigation] = useState<PendingNavigation>(null);
17
35
 
18
- const handleCancel = () => {
19
- setNextLocation(undefined);
20
- };
36
+ /**
37
+ * Handler to cancel the navigation attempt.
38
+ */
39
+ const handleCancel = useCallback(() => {
40
+ setIsDialogOpen(false);
41
+ setPendingNavigation(null);
42
+ }, []);
21
43
 
22
- const handleOk = () => {
23
- onSuccess();
24
- setNextLocation(undefined);
25
- navigate(-1);
26
- };
44
+ /**
45
+ * Handler to confirm and proceed with the navigation.
46
+ */
47
+ const handleOk = useCallback(() => {
48
+ setIsDialogOpen(false);
49
+ if (pendingNavigation) {
50
+ onSuccess();
51
+ if (pendingNavigation.type === "popstate") {
52
+ window.history.go(pendingNavigation.delta);
53
+ } else if (pendingNavigation.type === "link") {
54
+ window.location.href = pendingNavigation.href;
55
+ }
56
+ setPendingNavigation(null);
57
+ }
58
+ }, [onSuccess, pendingNavigation]);
27
59
 
28
- const blocker: Blocker = useCallback(({
29
- action,
30
- location: nextLocation,
31
- retry
32
- }) => {
33
- switch (action) {
34
- case "REPLACE": {
35
- retry();
36
- return;
60
+ /**
61
+ * Event handler for beforeunload to handle page refresh or tab close.
62
+ */
63
+ const handleBeforeUnload = useCallback(
64
+ (e: BeforeUnloadEvent) => {
65
+ if (when) {
66
+ e.preventDefault();
67
+ e.returnValue = "";
37
68
  }
38
- case "POP": {
39
- setNextLocation(nextLocation);
69
+ },
70
+ [when]
71
+ );
72
+
73
+ /**
74
+ * Event handler for popstate to handle back and forward browser buttons.
75
+ */
76
+ const handlePopState = useCallback(
77
+ (e: PopStateEvent) => {
78
+ if (when) {
79
+ e.preventDefault();
80
+ // Assuming backward navigation; adjust delta as needed
81
+ setPendingNavigation({
82
+ type: "popstate",
83
+ delta: -1
84
+ });
85
+ setIsDialogOpen(true);
40
86
  }
41
- }
42
- }, []);
87
+ },
88
+ [when]
89
+ );
90
+
91
+ /**
92
+ * Event handler to intercept link clicks within the application.
93
+ */
94
+ const handleLinkClick = useCallback(
95
+ (e: MouseEvent) => {
96
+ if (!when) return;
43
97
 
44
- React.useEffect(() => {
45
- if (!when) return;
46
- if (nextLocation) return;
47
- if (!("block" in navigator)) return;
48
- const unblock = (navigator as any).block((tx: Transition) => {
49
- const autoUnblockingTx = {
50
- ...tx,
51
- retry() {
52
- unblock();
53
- tx.retry();
98
+ const target = e.target as HTMLElement;
99
+ const anchor = target.closest("a[href]") as HTMLAnchorElement | null;
100
+ if (anchor && anchor.host === window.location.host) {
101
+ e.preventDefault();
102
+ const href = anchor.getAttribute("href");
103
+ if (href) {
104
+ setPendingNavigation({
105
+ type: "link",
106
+ href
107
+ });
108
+ setIsDialogOpen(true);
54
109
  }
55
- };
56
- blocker(autoUnblockingTx);
57
- });
110
+ }
111
+ },
112
+ [when]
113
+ );
114
+
115
+ /**
116
+ * Effect hook to add and clean up event listeners based on the `when` condition.
117
+ */
118
+ useEffect(() => {
119
+ if (when) {
120
+ window.addEventListener("beforeunload", handleBeforeUnload);
121
+ window.addEventListener("popstate", handlePopState);
122
+ document.addEventListener("click", handleLinkClick);
123
+ } else {
124
+ window.removeEventListener("beforeunload", handleBeforeUnload);
125
+ window.removeEventListener("popstate", handlePopState);
126
+ document.removeEventListener("click", handleLinkClick);
127
+ }
58
128
 
59
- return unblock;
60
- }, [navigator, blocker, when, nextLocation]);
129
+ // Cleanup on unmount or when `when` changes
130
+ return () => {
131
+ window.removeEventListener("beforeunload", handleBeforeUnload);
132
+ window.removeEventListener("popstate", handlePopState);
133
+ document.removeEventListener("click", handleLinkClick);
134
+ };
135
+ }, [when, handleBeforeUnload, handlePopState, handleLinkClick]);
61
136
 
62
137
  return {
63
- navigationWasBlocked: Boolean(nextLocation),
138
+ navigationWasBlocked: isDialogOpen,
64
139
  handleCancel,
65
- handleOk
140
+ handleOk,
66
141
  };
67
142
  }
68
-
69
- export interface UnsavedChangesDialogProps {
70
- open: boolean;
71
- body?: React.ReactNode;
72
- title?: string;
73
- handleOk: () => void;
74
- handleCancel: () => void;
75
- }
76
-
77
- export function UnsavedChangesDialog({
78
- open,
79
- handleOk,
80
- handleCancel,
81
- body,
82
- title
83
- }: UnsavedChangesDialogProps) {
84
-
85
- return (
86
- <Dialog
87
- open={open}
88
- onOpenChange={(open) => open ? handleCancel() : handleOk()}
89
- >
90
- <DialogContent>
91
- <Typography variant={"h6"}>{title}</Typography>
92
-
93
- {body}
94
-
95
- <Typography>
96
- Are you sure you want to leave this page?
97
- </Typography>
98
-
99
- </DialogContent>
100
- <DialogActions>
101
- <Button variant="text" onClick={handleCancel} autoFocus> Cancel </Button>
102
- <Button onClick={handleOk}> Ok </Button>
103
- </DialogActions>
104
- </Dialog>
105
- );
106
- }
@@ -47,17 +47,16 @@ export const PropertyPreview = React.memo(function PropertyPreview<T extends CMS
47
47
  size,
48
48
  height,
49
49
  width,
50
- // entity
50
+ interactive
51
51
  } = props;
52
52
 
53
53
  const property = resolveProperty({
54
54
  propertyKey,
55
55
  propertyOrBuilder: inputProperty,
56
- propertyValue: value,
57
- fields: customizationController.propertyConfigs
56
+ propertyConfigs: customizationController.propertyConfigs
58
57
  });
59
58
 
60
- if (value === undefined || property === null) {
59
+ if (property === null) {
61
60
  content = <EmptyValue/>;
62
61
  } else if (property.Preview) {
63
62
  content = createElement(property.Preview as React.ComponentType<PropertyPreviewProps>,
@@ -71,12 +70,19 @@ export const PropertyPreview = React.memo(function PropertyPreview<T extends CMS
71
70
  // entity,
72
71
  customProps: property.customProps
73
72
  });
74
- } else if (value === null) {
73
+ } else if (value === undefined || value === null) {
75
74
  content = <EmptyValue/>;
76
75
  } else if (property.dataType === "string") {
77
76
  const stringProperty = property as ResolvedStringProperty;
78
77
  if (typeof value === "string") {
79
- if (stringProperty.url) {
78
+ if (stringProperty.storage) {
79
+ const filePath = stringProperty.storage.previewUrl ? stringProperty.storage.previewUrl(value) : value;
80
+ content = <StorageThumbnail
81
+ interactive={interactive}
82
+ storeUrl={property.storage?.storeUrl ?? false}
83
+ size={props.size}
84
+ storagePathOrDownloadUrl={filePath}/>;
85
+ } else if (stringProperty.url) {
80
86
  if (typeof stringProperty.url === "boolean")
81
87
  content =
82
88
  <UrlComponentPreview size={props.size}
@@ -85,14 +91,10 @@ export const PropertyPreview = React.memo(function PropertyPreview<T extends CMS
85
91
  content =
86
92
  <UrlComponentPreview size={props.size}
87
93
  url={value}
94
+ interactive={interactive}
88
95
  previewType={stringProperty.url}/>;
89
- } else if (stringProperty.storage) {
90
- content = <StorageThumbnail
91
- storeUrl={property.storage?.storeUrl ?? false}
92
- size={props.size}
93
- storagePathOrDownloadUrl={value}/>;
94
96
  } else if (stringProperty.markdown) {
95
- content = <Markdown source={value}/>;
97
+ content = <Markdown source={value} size={"small"}/>;
96
98
  } else {
97
99
  content = <StringPropertyPreview {...props}
98
100
  property={stringProperty}
@@ -113,17 +115,7 @@ export const PropertyPreview = React.memo(function PropertyPreview<T extends CMS
113
115
  content = <ArrayPropertyPreview {...props}
114
116
  value={value}
115
117
  property={property as ResolvedArrayProperty}/>;
116
- }
117
- // else if (arrayProperty.of.dataType === "map") {
118
- // content =
119
- // <ArrayOfMapsPreview propertyKey={propertyKey}
120
- // property={property as ResolvedArrayProperty}
121
- // value={value as Record<string, any>[]} // This might be wrong
122
- // entity={entity}
123
- // size={size}
124
- // />;
125
- // }
126
- else if (arrayProperty.of.dataType === "reference") {
118
+ } else if (arrayProperty.of.dataType === "reference") {
127
119
  content = <ArrayOfReferencesPreview {...props}
128
120
  value={value}
129
121
  property={property as ResolvedArrayProperty}/>;
@@ -182,8 +174,9 @@ export const PropertyPreview = React.memo(function PropertyPreview<T extends CMS
182
174
  content = <ReferencePreview
183
175
  disabled={!property.path}
184
176
  previewProperties={property.previewProperties}
177
+ includeId={property.includeId}
178
+ includeEntityLink={property.includeEntityLink}
185
179
  size={props.size}
186
- // onClick={props.onClick}
187
180
  reference={value as EntityReference}
188
181
  />;
189
182
  } else {