@firecms/core 3.0.0-canary.9 → 3.0.0-canary.90

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 (246) hide show
  1. package/README.md +1 -1
  2. package/dist/app/AppBar.d.ts +12 -0
  3. package/dist/app/Drawer.d.ts +17 -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/CircularProgressCenter.d.ts +1 -1
  8. package/dist/components/ClearFilterSortButton.d.ts +5 -0
  9. package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +11 -12
  10. package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +1 -1
  11. package/dist/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +5 -3
  12. package/dist/components/EntityCollectionTable/PropertyTableCell.d.ts +1 -0
  13. package/dist/components/EntityCollectionTable/column_utils.d.ts +1 -2
  14. package/dist/components/EntityCollectionTable/fields/TableReferenceField.d.ts +2 -0
  15. package/dist/components/EntityCollectionTable/internal/CollectionTableToolbar.d.ts +1 -4
  16. package/dist/components/EntityCollectionTable/internal/EntityTableCell.d.ts +2 -2
  17. package/dist/components/EntityCollectionTable/internal/popup_field/PopupFormField.d.ts +1 -1
  18. package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +12 -2
  19. package/dist/components/EntityCollectionView/EntityCollectionViewStartActions.d.ts +11 -0
  20. package/dist/components/EntityPreview.d.ts +5 -4
  21. package/dist/components/ErrorView.d.ts +1 -1
  22. package/dist/components/HomePage/DefaultHomePage.d.ts +1 -1
  23. package/dist/components/HomePage/NavigationCardBinding.d.ts +1 -1
  24. package/dist/components/ReferenceWidget.d.ts +3 -1
  25. package/dist/components/SelectableTable/SelectableTable.d.ts +1 -1
  26. package/dist/components/SelectableTable/filters/ReferenceFilterField.d.ts +2 -1
  27. package/dist/components/VirtualTable/VirtualTableProps.d.ts +15 -12
  28. package/dist/components/VirtualTable/types.d.ts +3 -3
  29. package/dist/components/{EntityCollectionTable/internal → common}/default_entity_actions.d.ts +1 -1
  30. package/dist/components/common/index.d.ts +1 -0
  31. package/dist/components/common/table_height.d.ts +5 -0
  32. package/dist/components/common/types.d.ts +4 -6
  33. package/dist/components/common/useDataSourceEntityCollectionTableController.d.ts +3 -0
  34. package/dist/components/index.d.ts +2 -1
  35. package/dist/contexts/AuthControllerContext.d.ts +1 -1
  36. package/dist/{components/FireCMSAppBar.d.ts → core/DefaultAppBar.d.ts} +6 -9
  37. package/dist/core/DefaultDrawer.d.ts +19 -0
  38. package/dist/core/DrawerNavigationItem.d.ts +9 -0
  39. package/dist/core/EntityEditView.d.ts +17 -3
  40. package/dist/core/FireCMS.d.ts +1 -1
  41. package/dist/core/NavigationRoutes.d.ts +3 -3
  42. package/dist/core/index.d.ts +3 -4
  43. package/dist/form/PropertiesForm.d.ts +8 -0
  44. package/dist/form/components/ErrorFocus.d.ts +1 -1
  45. package/dist/form/components/FieldHelperText.d.ts +3 -3
  46. package/dist/form/components/StorageItemPreview.d.ts +4 -4
  47. package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
  48. package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +2 -4
  49. package/dist/form/index.d.ts +0 -2
  50. package/dist/hooks/data/delete.d.ts +2 -2
  51. package/dist/hooks/data/save.d.ts +2 -3
  52. package/dist/hooks/data/useDataSource.d.ts +1 -1
  53. package/dist/hooks/data/useEntityFetch.d.ts +3 -3
  54. package/dist/hooks/index.d.ts +2 -0
  55. package/dist/hooks/useBuildNavigationController.d.ts +1 -2
  56. package/dist/hooks/useProjectLog.d.ts +2 -2
  57. package/dist/hooks/useValidateAuthenticator.d.ts +21 -0
  58. package/dist/index.d.ts +1 -0
  59. package/dist/index.es.js +15552 -11933
  60. package/dist/index.es.js.map +1 -1
  61. package/dist/index.umd.js +19643 -7
  62. package/dist/index.umd.js.map +1 -1
  63. package/dist/internal/useBuildDataSource.d.ts +1 -16
  64. package/dist/internal/useRestoreScroll.d.ts +1 -1
  65. package/dist/preview/PropertyPreviewProps.d.ts +6 -4
  66. package/dist/preview/components/ReferencePreview.d.ts +2 -1
  67. package/dist/preview/components/StorageThumbnail.d.ts +2 -1
  68. package/dist/preview/components/UrlComponentPreview.d.ts +2 -1
  69. package/dist/types/auth.d.ts +26 -2
  70. package/dist/types/collections.d.ts +31 -7
  71. package/dist/types/datasource.d.ts +34 -20
  72. package/dist/types/entities.d.ts +5 -1
  73. package/dist/types/entity_actions.d.ts +14 -0
  74. package/dist/types/entity_callbacks.d.ts +2 -2
  75. package/dist/types/fields.d.ts +31 -30
  76. package/dist/types/index.d.ts +0 -1
  77. package/dist/types/navigation.d.ts +5 -5
  78. package/dist/types/plugins.d.ts +16 -6
  79. package/dist/types/properties.d.ts +17 -4
  80. package/dist/types/storage.d.ts +11 -3
  81. package/dist/util/collections.d.ts +1 -1
  82. package/dist/util/entities.d.ts +1 -1
  83. package/dist/util/icon_synonyms.d.ts +1 -97
  84. package/dist/util/icons.d.ts +2 -2
  85. package/dist/util/navigation_utils.d.ts +2 -2
  86. package/dist/util/objects.d.ts +1 -1
  87. package/dist/util/plurals.d.ts +0 -2
  88. package/dist/util/resolutions.d.ts +13 -13
  89. package/dist/util/storage.d.ts +23 -2
  90. package/dist/util/useStorageUploadController.d.ts +1 -1
  91. package/dist/util/useTraceUpdate.d.ts +1 -0
  92. package/package.json +130 -119
  93. package/src/app/AppBar.tsx +18 -0
  94. package/src/app/Drawer.tsx +25 -0
  95. package/src/app/Scaffold.tsx +249 -0
  96. package/src/app/index.ts +4 -0
  97. package/src/app/useApp.tsx +32 -0
  98. package/src/components/CircularProgressCenter.tsx +1 -1
  99. package/src/components/ClearFilterSortButton.tsx +41 -0
  100. package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +9 -18
  101. package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +21 -20
  102. package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +10 -6
  103. package/src/components/EntityCollectionTable/PropertyTableCell.tsx +38 -34
  104. package/src/components/EntityCollectionTable/column_utils.tsx +3 -3
  105. package/src/components/EntityCollectionTable/fields/TableReferenceField.tsx +11 -2
  106. package/src/components/EntityCollectionTable/fields/TableStorageUpload.tsx +14 -6
  107. package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +29 -34
  108. package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +16 -12
  109. package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +4 -5
  110. package/src/components/EntityCollectionView/EntityCollectionView.tsx +69 -45
  111. package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +68 -0
  112. package/src/components/EntityCollectionView/useSelectionController.tsx +19 -7
  113. package/src/components/EntityPreview.tsx +15 -9
  114. package/src/components/EntityView.tsx +5 -5
  115. package/src/components/ErrorView.tsx +1 -1
  116. package/src/components/HomePage/DefaultHomePage.tsx +3 -3
  117. package/src/components/HomePage/NavigationCard.tsx +3 -3
  118. package/src/components/HomePage/NavigationCardBinding.tsx +1 -1
  119. package/src/components/HomePage/SmallNavigationCard.tsx +5 -5
  120. package/src/components/PropertyIdCopyTooltipContent.tsx +2 -3
  121. package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +1 -0
  122. package/src/components/ReferenceWidget.tsx +22 -12
  123. package/src/components/SearchIconsView.tsx +5 -5
  124. package/src/components/SelectableTable/SelectableTable.tsx +7 -7
  125. package/src/components/SelectableTable/filters/BooleanFilterField.tsx +2 -3
  126. package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +22 -7
  127. package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +28 -6
  128. package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +35 -15
  129. package/src/components/VirtualTable/VirtualTable.tsx +70 -37
  130. package/src/components/VirtualTable/VirtualTableCell.tsx +1 -1
  131. package/src/components/VirtualTable/VirtualTableHeader.tsx +4 -4
  132. package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +2 -2
  133. package/src/components/VirtualTable/VirtualTableProps.tsx +18 -14
  134. package/src/components/VirtualTable/VirtualTableRow.tsx +4 -5
  135. package/src/components/VirtualTable/fields/VirtualTableDateField.tsx +1 -1
  136. package/src/components/VirtualTable/types.tsx +2 -3
  137. package/src/components/{EntityCollectionTable/internal → common}/default_entity_actions.tsx +2 -2
  138. package/src/components/common/index.ts +1 -0
  139. package/src/components/{VirtualTable/common.tsx → common/table_height.tsx} +5 -2
  140. package/src/components/common/types.tsx +4 -6
  141. package/src/components/common/useColumnsIds.tsx +10 -2
  142. package/src/components/common/useDataSourceEntityCollectionTableController.tsx +11 -0
  143. package/src/components/common/useTableSearchHelper.ts +52 -12
  144. package/src/components/index.tsx +2 -1
  145. package/src/contexts/AuthControllerContext.tsx +1 -1
  146. package/src/contexts/DialogsProvider.tsx +2 -2
  147. package/src/{components/FireCMSAppBar.tsx → core/DefaultAppBar.tsx} +52 -37
  148. package/src/core/DefaultDrawer.tsx +177 -0
  149. package/src/core/DrawerNavigationItem.tsx +62 -0
  150. package/src/core/EntityEditView.tsx +676 -133
  151. package/src/core/EntitySidePanel.tsx +1 -2
  152. package/src/core/FireCMS.tsx +39 -44
  153. package/src/core/NavigationRoutes.tsx +7 -8
  154. package/src/core/field_configs.tsx +2 -3
  155. package/src/core/index.tsx +3 -4
  156. package/src/form/PropertiesForm.tsx +81 -0
  157. package/src/form/PropertyFieldBinding.tsx +29 -7
  158. package/src/form/components/FieldHelperText.tsx +3 -3
  159. package/src/form/components/StorageItemPreview.tsx +20 -11
  160. package/src/form/components/StorageUploadProgress.tsx +3 -3
  161. package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +8 -5
  162. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +8 -5
  163. package/src/form/field_bindings/BlockFieldBinding.tsx +2 -2
  164. package/src/form/field_bindings/KeyValueFieldBinding.tsx +44 -39
  165. package/src/form/field_bindings/MapFieldBinding.tsx +11 -3
  166. package/src/form/field_bindings/MarkdownFieldBinding.tsx +2 -2
  167. package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +2 -9
  168. package/src/form/field_bindings/ReferenceFieldBinding.tsx +15 -13
  169. package/src/form/field_bindings/RepeatFieldBinding.tsx +10 -7
  170. package/src/form/field_bindings/SelectFieldBinding.tsx +3 -3
  171. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +22 -43
  172. package/src/form/field_bindings/SwitchFieldBinding.tsx +1 -1
  173. package/src/form/index.tsx +4 -4
  174. package/src/form/validation.ts +1 -17
  175. package/src/hooks/data/delete.ts +3 -3
  176. package/src/hooks/data/save.ts +4 -2
  177. package/src/hooks/data/useDataSource.tsx +2 -2
  178. package/src/hooks/data/useEntityFetch.tsx +3 -3
  179. package/src/hooks/index.tsx +3 -0
  180. package/src/hooks/useBuildLocalConfigurationPersistence.tsx +8 -10
  181. package/src/hooks/useBuildModeController.tsx +11 -5
  182. package/src/hooks/useBuildNavigationController.tsx +137 -61
  183. package/src/hooks/useProjectLog.tsx +21 -8
  184. package/src/hooks/useResolvedNavigationFrom.tsx +1 -1
  185. package/src/hooks/useValidateAuthenticator.tsx +115 -0
  186. package/src/index.ts +1 -0
  187. package/src/internal/useBuildDataSource.ts +56 -49
  188. package/src/internal/useBuildSideEntityController.tsx +88 -21
  189. package/src/preview/PropertyPreview.tsx +9 -16
  190. package/src/preview/PropertyPreviewProps.tsx +4 -8
  191. package/src/preview/components/BooleanPreview.tsx +4 -2
  192. package/src/preview/components/EnumValuesChip.tsx +1 -1
  193. package/src/preview/components/ImagePreview.tsx +21 -33
  194. package/src/preview/components/ReferencePreview.tsx +23 -23
  195. package/src/preview/components/StorageThumbnail.tsx +5 -1
  196. package/src/preview/components/UrlComponentPreview.tsx +44 -11
  197. package/src/preview/property_previews/ArrayOfMapsPreview.tsx +0 -1
  198. package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +2 -1
  199. package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +0 -1
  200. package/src/preview/property_previews/ArrayOfStringsPreview.tsx +0 -1
  201. package/src/preview/property_previews/ArrayOneOfPreview.tsx +2 -3
  202. package/src/preview/property_previews/ArrayPropertyPreview.tsx +2 -3
  203. package/src/preview/property_previews/MapPropertyPreview.tsx +5 -5
  204. package/src/preview/property_previews/StringPropertyPreview.tsx +2 -2
  205. package/src/types/auth.tsx +35 -2
  206. package/src/types/collections.ts +37 -8
  207. package/src/types/customization_controller.tsx +0 -1
  208. package/src/types/datasource.ts +41 -24
  209. package/src/types/entities.ts +9 -1
  210. package/src/types/entity_actions.tsx +16 -3
  211. package/src/types/entity_callbacks.ts +2 -2
  212. package/src/types/fields.tsx +33 -33
  213. package/src/types/index.ts +0 -1
  214. package/src/types/navigation.ts +6 -7
  215. package/src/types/plugins.tsx +18 -8
  216. package/src/types/properties.ts +22 -6
  217. package/src/types/storage.ts +12 -3
  218. package/src/util/collections.ts +1 -1
  219. package/src/util/entities.ts +5 -4
  220. package/src/util/enums.ts +1 -1
  221. package/src/util/icon_list.ts +2 -2
  222. package/src/util/icon_synonyms.ts +3 -99
  223. package/src/util/navigation_utils.ts +6 -6
  224. package/src/util/objects.ts +25 -28
  225. package/src/util/permissions.ts +1 -0
  226. package/src/util/plurals.ts +0 -2
  227. package/src/util/resolutions.ts +32 -31
  228. package/src/util/storage.ts +75 -21
  229. package/src/util/strings.ts +2 -2
  230. package/src/util/useStorageUploadController.tsx +21 -3
  231. package/src/util/useTraceUpdate.tsx +2 -1
  232. package/dist/components/VirtualTable/common.d.ts +0 -2
  233. package/dist/core/Drawer.d.ts +0 -23
  234. package/dist/core/Scaffold.d.ts +0 -55
  235. package/dist/core/SideEntityView.d.ts +0 -7
  236. package/dist/form/EntityForm.d.ts +0 -77
  237. package/dist/internal/useBuildCustomizationController.d.ts +0 -2
  238. package/dist/internal/useLocaleConfig.d.ts +0 -1
  239. package/dist/types/appcheck.d.ts +0 -26
  240. package/src/core/Drawer.tsx +0 -191
  241. package/src/core/Scaffold.tsx +0 -281
  242. package/src/core/SideEntityView.tsx +0 -38
  243. package/src/form/EntityForm.tsx +0 -728
  244. package/src/internal/useBuildCustomizationController.tsx +0 -5
  245. package/src/internal/useLocaleConfig.tsx +0 -18
  246. package/src/types/appcheck.ts +0 -29
@@ -3,7 +3,7 @@ import React, { useEffect } from "react";
3
3
  import {
4
4
  Button,
5
5
  CircularProgress,
6
- cn,
6
+ cls,
7
7
  defaultBorderMixin,
8
8
  FilterListOffIcon,
9
9
  SearchBar,
@@ -16,20 +16,27 @@ import { useLargeLayout } from "../../../hooks";
16
16
 
17
17
  interface CollectionTableToolbarProps {
18
18
  size: CollectionSize;
19
- filterIsSet: boolean;
20
19
  loading: boolean;
21
- forceFilter?: boolean;
22
20
  actionsStart?: React.ReactNode;
23
21
  actions?: React.ReactNode;
24
22
  title?: React.ReactNode,
25
23
  onTextSearchClick?: () => void;
26
24
  onTextSearch?: (searchString?: string) => void;
27
25
  onSizeChanged: (size: CollectionSize) => void;
28
- clearFilter?: () => void;
29
26
  textSearchLoading?: boolean;
30
27
  }
31
28
 
32
- export function CollectionTableToolbar(props: CollectionTableToolbarProps) {
29
+ export function CollectionTableToolbar({
30
+ actions,
31
+ actionsStart,
32
+ loading,
33
+ onSizeChanged,
34
+ onTextSearch,
35
+ onTextSearchClick,
36
+ size,
37
+ textSearchLoading,
38
+ title
39
+ }: CollectionTableToolbarProps) {
33
40
 
34
41
  const searchInputRef = React.useRef<HTMLInputElement>(null);
35
42
  const largeLayout = useLargeLayout();
@@ -37,30 +44,20 @@ export function CollectionTableToolbar(props: CollectionTableToolbarProps) {
37
44
  const searchLoading = React.useRef<boolean>(false);
38
45
 
39
46
  useEffect(() => {
40
- if (searchInputRef.current && searchLoading.current && !props.textSearchLoading) {
47
+ if (searchInputRef.current && searchLoading.current && !textSearchLoading) {
41
48
  searchInputRef.current.focus();
42
49
  }
43
- searchLoading.current = props.textSearchLoading ?? false;
44
- }, [props.textSearchLoading]);
45
-
46
- const clearFilterButton = !props.forceFilter && props.filterIsSet && props.clearFilter &&
47
- <Button
48
- variant={"outlined"}
49
- className="h-fit-content"
50
- aria-label="filter clear"
51
- onClick={props.clearFilter}
52
- size={"small"}>
53
- <FilterListOffIcon/>
54
- Clear filter
55
- </Button>;
50
+ searchLoading.current = textSearchLoading ?? false;
51
+ }, [textSearchLoading]);
52
+
56
53
 
57
54
  const sizeSelect = (
58
55
  <Tooltip title={"Table row size"} side={"right"} sideOffset={4}>
59
56
  <Select
60
- value={props.size as string}
57
+ value={size as string}
61
58
  className="w-16 h-10"
62
59
  size={"small"}
63
- onValueChange={(v) => props.onSizeChanged(v as CollectionSize)}
60
+ onValueChange={(v) => onSizeChanged(v as CollectionSize)}
64
61
  renderValue={(v) => <div className={"font-medium"}>{v.toUpperCase()}</div>}
65
62
  >
66
63
  {["xs", "s", "m", "l", "xl"].map((size) => (
@@ -74,40 +71,38 @@ export function CollectionTableToolbar(props: CollectionTableToolbarProps) {
74
71
 
75
72
  return (
76
73
  <div
77
- className={cn(defaultBorderMixin, "no-scrollbar min-h-[56px] overflow-x-auto px-2 md:px-4 bg-gray-50 dark:bg-gray-900 border-b flex flex-row justify-between items-center w-full")}>
74
+ className={cls(defaultBorderMixin, "no-scrollbar min-h-[56px] overflow-x-auto px-2 md:px-4 bg-gray-50 dark:bg-gray-900 border-b flex flex-row justify-between items-center w-full")}>
78
75
 
79
76
  <div className="flex items-center gap-2 md:mr-4 mr-2">
80
77
 
81
- {props.title && <div className={"hidden lg:block"}>
82
- {props.title}
78
+ {title && <div className={"hidden lg:block"}>
79
+ {title}
83
80
  </div>}
84
81
 
85
82
  {sizeSelect}
86
83
 
87
- {props.actionsStart}
88
-
89
- {clearFilterButton}
84
+ {actionsStart}
90
85
 
91
86
  </div>
92
87
 
93
88
  <div className="flex items-center gap-2">
94
89
 
95
90
  {largeLayout && <div className="w-[22px]">
96
- {props.loading &&
91
+ {loading &&
97
92
  <CircularProgress size={"small"}/>}
98
93
  </div>}
99
94
 
100
- {(props.onTextSearch || props.onTextSearchClick) &&
95
+ {(onTextSearch || onTextSearchClick) &&
101
96
  <SearchBar
102
97
  key={"search-bar"}
103
98
  inputRef={searchInputRef}
104
- loading={props.textSearchLoading}
105
- disabled={Boolean(props.onTextSearchClick)}
106
- onClick={props.onTextSearchClick}
107
- onTextSearch={props.onTextSearchClick ? undefined : props.onTextSearch}
99
+ loading={textSearchLoading}
100
+ disabled={Boolean(onTextSearchClick)}
101
+ onClick={onTextSearchClick}
102
+ onTextSearch={onTextSearchClick ? undefined : onTextSearch}
108
103
  expandable={true}/>}
109
104
 
110
- {props.actions}
105
+ {actions}
111
106
 
112
107
  </div>
113
108
 
@@ -2,10 +2,9 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"
2
2
 
3
3
  import useMeasure from "react-use-measure";
4
4
 
5
- import { VirtualTableSize } from "../../VirtualTable";
6
- import { getRowHeight } from "../../VirtualTable/common";
7
- import { cn, RemoveCircleIcon, Tooltip } from "@firecms/ui";
5
+ import { cls, RemoveCircleIcon, Tooltip } from "@firecms/ui";
8
6
  import { ErrorBoundary } from "../../../components";
7
+ import { getRowHeight, TableSize } from "../../common/table_height";
9
8
 
10
9
  interface EntityTableCellProps {
11
10
  children: React.ReactNode;
@@ -19,7 +18,7 @@ interface EntityTableCellProps {
19
18
  error?: Error;
20
19
  allowScroll?: boolean;
21
20
  align: "right" | "left" | "center";
22
- size: VirtualTableSize;
21
+ size: TableSize;
23
22
  disabledTooltip?: string;
24
23
  width: number;
25
24
  showExpandIcon?: boolean;
@@ -47,7 +46,7 @@ const TableCellInner = ({
47
46
  }: TableCellInnerProps) => {
48
47
  return (
49
48
  <div
50
- className={cn("flex flex-col max-h-full w-full",
49
+ className={cls("flex flex-col max-h-full w-full",
51
50
  {
52
51
  "items-start": faded || scrollable
53
52
  })}
@@ -96,7 +95,7 @@ export const EntityTableCell = React.memo<EntityTableCellProps>(
96
95
  const [onHover, setOnHover] = useState(false);
97
96
  const [internalSaved, setInternalSaved] = useState(saved);
98
97
 
99
- const showError = !disabled && error;
98
+ const showError = !disabled && Boolean(error);
100
99
 
101
100
  useEffect(() => {
102
101
  if (saved) {
@@ -176,21 +175,26 @@ export const EntityTableCell = React.memo<EntityTableCellProps>(
176
175
  const setOnHoverTrue = useCallback(() => setOnHover(true), []);
177
176
  const setOnHoverFalse = useCallback(() => setOnHover(false), []);
178
177
 
178
+ const borderClass = showError
179
+ ? "border-red-500"
180
+ : internalSaved
181
+ ? "border-green-500"
182
+ : isSelected
183
+ ? "border-primary"
184
+ : "border-transparent";
185
+
179
186
  return (
180
187
  <div
181
- ref={ref}
182
- className={cn(
188
+ className={cls(
183
189
  "transition-colors duration-100 ease-in-out",
184
190
  `flex relative h-full rounded-md p-${p} border border-4 border-opacity-75`,
185
191
  onHover && !disabled ? "bg-gray-50 dark:bg-gray-900" : "",
186
192
  saved ? "bg-gray-100 bg-opacity-75 dark:bg-gray-800 dark:bg-opacity-75" : "",
187
- !isSelected && !internalSaved && !showError ? "border-transparent" : "",
188
193
  hideOverflow ? "overflow-hidden" : "",
189
194
  isSelected ? "bg-gray-50 dark:bg-gray-900" : "",
190
- isSelected && !internalSaved ? "border-primary" : "",
191
- internalSaved ? "border-green-500 " : "",
192
- showError ? "border-red-500" : ""
195
+ borderClass
193
196
  )}
197
+ ref={ref}
194
198
  style={{
195
199
  justifyContent,
196
200
  alignItems: disabled || !isOverflowing ? "center" : undefined,
@@ -41,7 +41,7 @@ interface PopupFormFieldProps<M extends Record<string, any>> {
41
41
  * Callback when the value of a cell has been edited
42
42
  * @param params
43
43
  */
44
- onCellValueChange?: (params: OnCellValueChangeParams<any, M>) => Promise<void> | void;
44
+ onCellValueChange?: (params: OnCellValueChangeParams<any, any>) => Promise<void> | void;
45
45
  }
46
46
 
47
47
  export function PopupFormField<M extends Record<string, any>>(props: PopupFormFieldProps<M>) {
@@ -205,12 +205,10 @@ export function PopupFormFieldInternal<M extends Record<string, any>>({
205
205
  return onCellValueChange({
206
206
  value: values[propertyKey as string],
207
207
  propertyKey: propertyKey as string,
208
- entity,
208
+ data: entity,
209
209
  setError: setSavingError,
210
210
  onValueUpdated: () => {
211
211
  },
212
- fullPath: path,
213
- context: fireCMSContext
214
212
  });
215
213
  }
216
214
  return Promise.resolve();
@@ -266,7 +264,8 @@ export function PopupFormFieldInternal<M extends Record<string, any>>({
266
264
  values,
267
265
  path,
268
266
  setFieldValue,
269
- save: saveValue
267
+ save: saveValue,
268
+ formex
270
269
  };
271
270
 
272
271
  const property: ResolvedProperty<any> | undefined = propertyKey && getPropertyInPath(collection.properties, propertyKey as string);
@@ -7,7 +7,7 @@ import {
7
7
  CollectionSize,
8
8
  Entity,
9
9
  EntityAction,
10
- EntityCollection,
10
+ EntityCollection, EntityTableController,
11
11
  FilterValues,
12
12
  PartialEntityCollection,
13
13
  PropertyOrBuilder,
@@ -35,6 +35,7 @@ import {
35
35
  useAuthController,
36
36
  useCustomizationController,
37
37
  useDataSource,
38
+ useFireCMSContext,
38
39
  useLargeLayout,
39
40
  useNavigationController,
40
41
  useSideEntityController
@@ -44,7 +45,7 @@ import { EntityCollectionViewActions } from "./EntityCollectionViewActions";
44
45
  import {
45
46
  AddIcon,
46
47
  Button,
47
- cn,
48
+ cls,
48
49
  IconButton,
49
50
  KeyboardTabIcon,
50
51
  Markdown,
@@ -65,14 +66,11 @@ import {
65
66
  } from "../common";
66
67
  import { PopupFormField } from "../EntityCollectionTable/internal/popup_field/PopupFormField";
67
68
  import { GetPropertyForProps } from "../EntityCollectionTable/EntityCollectionTableProps";
68
- import {
69
- copyEntityAction,
70
- deleteEntityAction,
71
- editEntityAction
72
- } from "../EntityCollectionTable/internal/default_entity_actions";
69
+ import { copyEntityAction, deleteEntityAction, editEntityAction } from "../common/default_entity_actions";
73
70
  import { DeleteEntityDialog } from "../DeleteEntityDialog";
74
71
  import { useAnalyticsController } from "../../hooks/useAnalyticsController";
75
72
  import { useSelectionController } from "./useSelectionController";
73
+ import { EntityCollectionViewStartActions } from "./EntityCollectionViewStartActions";
76
74
 
77
75
  const COLLECTION_GROUP_PARENT_ID = "collectionGroupParent";
78
76
 
@@ -80,10 +78,22 @@ const COLLECTION_GROUP_PARENT_ID = "collectionGroupParent";
80
78
  * @group Components
81
79
  */
82
80
  export type EntityCollectionViewProps<M extends Record<string, any>> = {
83
- fullPath: string;
81
+ /**
82
+ * Complete path where this collection is located.
83
+ * It defaults to the collection path if not provided.
84
+ */
85
+ fullPath?: string;
86
+ /**
87
+ * If this is a subcollection, specify the parent collection ids.
88
+ */
84
89
  parentCollectionIds?: string[];
90
+ /**
91
+ * Whether this is a subcollection or not.
92
+ */
85
93
  isSubCollection?: boolean;
94
+
86
95
  className?: string;
96
+
87
97
  } & EntityCollection<M>;
88
98
 
89
99
  /**
@@ -107,12 +117,12 @@ export type EntityCollectionViewProps<M extends Record<string, any>> = {
107
117
  *
108
118
  * @param fullPath
109
119
  * @param collection
110
- * @constructor
120
+
111
121
  * @group Components
112
122
  */
113
123
  export const EntityCollectionView = React.memo(
114
124
  function EntityCollectionView<M extends Record<string, any>>({
115
- fullPath,
125
+ fullPath: fullPathProp,
116
126
  parentCollectionIds,
117
127
  isSubCollection,
118
128
  className,
@@ -120,6 +130,8 @@ export const EntityCollectionView = React.memo(
120
130
  }: EntityCollectionViewProps<M>
121
131
  ) {
122
132
 
133
+ const context = useFireCMSContext();
134
+ const fullPath = fullPathProp ?? collectionProp.path;
123
135
  const dataSource = useDataSource(collectionProp);
124
136
  const navigation = useNavigationController();
125
137
  const sideEntityController = useSideEntityController();
@@ -128,7 +140,6 @@ export const EntityCollectionView = React.memo(
128
140
  const analyticsController = useAnalyticsController();
129
141
  const customizationController = useCustomizationController();
130
142
 
131
-
132
143
  const containerRef = React.useRef<HTMLDivElement>(null);
133
144
 
134
145
  const collection = useMemo(() => {
@@ -142,7 +153,7 @@ export const EntityCollectionView = React.memo(
142
153
  }, [collection]);
143
154
 
144
155
  const canCreateEntities = canCreateEntity(collection, authController, fullPath, null);
145
- const [selectedNavigationEntity, setSelectedNavigationEntity] = useState<Entity<M> | undefined>(undefined);
156
+ const [highlightedEntity, setHighlightedEntity] = useState<Entity<M> | undefined>(undefined);
146
157
  const [deleteEntityClicked, setDeleteEntityClicked] = React.useState<Entity<M> | Entity<M>[] | undefined>(undefined);
147
158
 
148
159
  const [lastDeleteTimestamp, setLastDeleteTimestamp] = React.useState<number>(0);
@@ -151,12 +162,12 @@ export const EntityCollectionView = React.memo(
151
162
  const [docsCount, setDocsCount] = useState<number>(0);
152
163
 
153
164
  const unselectNavigatedEntity = useCallback(() => {
154
- const currentSelection = selectedNavigationEntity;
165
+ const currentSelection = highlightedEntity;
155
166
  setTimeout(() => {
156
- if (currentSelection === selectedNavigationEntity)
157
- setSelectedNavigationEntity(undefined);
167
+ if (currentSelection === highlightedEntity)
168
+ setHighlightedEntity(undefined);
158
169
  }, 2400);
159
- }, [selectedNavigationEntity]);
170
+ }, [highlightedEntity]);
160
171
 
161
172
  const checkInlineEditing = useCallback((entity?: Entity<any>): boolean => {
162
173
  const collection = collectionRef.current;
@@ -175,19 +186,16 @@ export const EntityCollectionView = React.memo(
175
186
  const usedSelectionController = collection.selectionController ?? selectionController;
176
187
  const {
177
188
  selectedEntities,
178
- toggleEntitySelection,
179
- isEntitySelected,
180
189
  setSelectedEntities
181
190
  } = usedSelectionController;
182
191
 
183
- useEffect(() => {
184
- setDeleteEntityClicked(undefined);
185
- }, [selectedEntities]);
192
+ // useEffect(() => {
193
+ // setDeleteEntityClicked(undefined);
194
+ // }, [selectedEntities]);
186
195
 
187
196
  const tableController = useDataSourceEntityCollectionTableController<M>({
188
197
  fullPath,
189
- collection: collectionRef.current,
190
- entitiesDisplayedFirst: [],
198
+ collection,
191
199
  lastDeleteTimestamp
192
200
  });
193
201
 
@@ -201,7 +209,7 @@ export const EntityCollectionView = React.memo(
201
209
  const onEntityClick = useCallback((clickedEntity: Entity<M>) => {
202
210
  console.log("Entity clicked", clickedEntity)
203
211
  const collection = collectionRef.current;
204
- setSelectedNavigationEntity(clickedEntity);
212
+ setHighlightedEntity(clickedEntity);
205
213
  analyticsController.onAnalyticsEvent?.("edit_entity_clicked", {
206
214
  path: clickedEntity.path,
207
215
  entityId: clickedEntity.id
@@ -257,6 +265,7 @@ export const EntityCollectionView = React.memo(
257
265
  fullPath: string,
258
266
  parentCollectionIds: string[],
259
267
  collection: EntityCollection;
268
+ tableController: EntityTableController;
260
269
  }> | undefined
261
270
 
262
271
  // we are only using the first plugin that implements this
@@ -301,13 +310,11 @@ export const EntityCollectionView = React.memo(
301
310
  [fullPath]);
302
311
 
303
312
  const onValueChange: OnCellValueChange<any, any> = ({
304
- fullPath,
305
- context,
306
313
  value,
307
314
  propertyKey,
308
315
  onValueUpdated,
309
316
  setError,
310
- entity,
317
+ data: entity,
311
318
  }) => {
312
319
 
313
320
  const updatedValues = setIn({ ...entity.values }, propertyKey, value);
@@ -324,10 +331,12 @@ export const EntityCollectionView = React.memo(
324
331
  return saveEntityWithCallbacks({
325
332
  ...saveProps,
326
333
  collection,
327
- callbacks: collection.callbacks,
328
334
  dataSource,
329
335
  context,
330
- onSaveSuccess: () => onValueUpdated(),
336
+ onSaveSuccess: () => {
337
+ setError(undefined);
338
+ onValueUpdated();
339
+ },
331
340
  onSaveFailure: (e: Error) => {
332
341
  console.error("Save failure");
333
342
  console.error(e);
@@ -346,7 +355,6 @@ export const EntityCollectionView = React.memo(
346
355
 
347
356
  const getPropertyFor = useCallback(({
348
357
  propertyKey,
349
- propertyValue,
350
358
  entity
351
359
  }: GetPropertyForProps<M>) => {
352
360
  let propertyOrBuilder: PropertyOrBuilder<any, M> | undefined = getPropertyInPath<M>(collection.properties, propertyKey);
@@ -360,13 +368,12 @@ export const EntityCollectionView = React.memo(
360
368
  return resolveProperty({
361
369
  propertyKey,
362
370
  propertyOrBuilder,
363
- path: fullPath,
364
- propertyValue,
371
+ path: entity.path,
365
372
  values: entity.values,
366
373
  entityId: entity.id,
367
374
  fields: customizationController.propertyConfigs
368
375
  });
369
- }, [collection.properties, customizationController.propertyConfigs, fullPath, resolvedCollection.properties]);
376
+ }, [collection.properties, customizationController.propertyConfigs, resolvedCollection.properties]);
370
377
 
371
378
  const displayedColumnIds = useColumnIds(resolvedCollection, true);
372
379
 
@@ -406,7 +413,7 @@ export const EntityCollectionView = React.memo(
406
413
  Builder: ({ entity }) => {
407
414
  const collectionsWithPath = navigation.getParentReferencesFromPath(entity.path);
408
415
  return (
409
- <>
416
+ <div className={"flex flex-col gap-2 w-full"}>
410
417
  {collectionsWithPath.map((reference) => {
411
418
  return (
412
419
  <ReferencePreview
@@ -415,7 +422,7 @@ export const EntityCollectionView = React.memo(
415
422
  size={"tiny"}/>
416
423
  );
417
424
  })}
418
- </>
425
+ </div>
419
426
  );
420
427
  }
421
428
  }]
@@ -460,7 +467,7 @@ export const EntityCollectionView = React.memo(
460
467
  return (largeLayout ? (80 + actionsWidth) : (70 + actionsWidth)) + (collapsedActions.length > 0 ? (largeLayout ? 40 : 30) : 0);
461
468
  };
462
469
 
463
- const tableRowActionsBuilder = ({
470
+ const tableRowActionsBuilder = useCallback(({
464
471
  entity,
465
472
  size,
466
473
  width,
@@ -472,7 +479,7 @@ export const EntityCollectionView = React.memo(
472
479
  frozen?: boolean
473
480
  }) => {
474
481
 
475
- const isSelected = isEntitySelected(entity);
482
+ const isSelected = usedSelectionController.selectedEntities.map(e => e.id).includes(entity.id);
476
483
 
477
484
  const actions = getActionsForEntity({
478
485
  entity,
@@ -487,7 +494,7 @@ export const EntityCollectionView = React.memo(
487
494
  isSelected={isSelected}
488
495
  selectionEnabled={selectionEnabled}
489
496
  size={size}
490
- highlightEntity={setSelectedNavigationEntity}
497
+ highlightEntity={setHighlightedEntity}
491
498
  unhighlightEntity={unselectNavigatedEntity}
492
499
  collection={collection}
493
500
  fullPath={fullPath}
@@ -498,7 +505,7 @@ export const EntityCollectionView = React.memo(
498
505
  />
499
506
  );
500
507
 
501
- };
508
+ }, [updateLastDeleteTimestamp, usedSelectionController]);
502
509
 
503
510
  const title = <Popover
504
511
  open={popOverOpen}
@@ -557,6 +564,7 @@ export const EntityCollectionView = React.memo(
557
564
  property={property}
558
565
  fullPath={fullPath}
559
566
  collection={collection}
567
+ tableController={tableController}
560
568
  parentCollectionIds={parentCollectionIds ?? []}/>;
561
569
  })}
562
570
  </>;
@@ -567,7 +575,8 @@ export const EntityCollectionView = React.memo(
567
575
  if (typeof AddColumnComponent === "function")
568
576
  return <AddColumnComponent fullPath={fullPath}
569
577
  parentCollectionIds={parentCollectionIds ?? []}
570
- collection={collection}/>;
578
+ collection={collection}
579
+ tableController={tableController}/>;
571
580
  return null;
572
581
  }
573
582
  : undefined;
@@ -584,12 +593,13 @@ export const EntityCollectionView = React.memo(
584
593
  });
585
594
 
586
595
  return (
587
- <div className={cn("overflow-hidden h-full w-full rounded-md", className)}
596
+ <div className={cls("overflow-hidden h-full w-full rounded-md", className)}
588
597
  ref={containerRef}>
589
598
  <EntityCollectionTable
590
599
  key={`collection_table_${fullPath}`}
591
600
  additionalFields={additionalFields}
592
601
  tableController={tableController}
602
+ enablePopupIcon={true}
593
603
  displayedColumnIds={displayedColumnIds}
594
604
  onSizeChanged={onSizeChanged}
595
605
  onEntityClick={onEntityClick}
@@ -599,13 +609,21 @@ export const EntityCollectionView = React.memo(
599
609
  uniqueFieldValidator={uniqueFieldValidator}
600
610
  title={title}
601
611
  selectionController={usedSelectionController}
602
- highlightedEntities={selectedNavigationEntity ? [selectedNavigationEntity] : []}
612
+ highlightedEntities={highlightedEntity ? [highlightedEntity] : []}
603
613
  defaultSize={collection.defaultSize}
604
614
  properties={resolvedCollection.properties}
605
615
  getPropertyFor={getPropertyFor}
606
616
  onTextSearchClick={textSearchInitialised ? undefined : onTextSearchClick}
607
617
  textSearchLoading={textSearchLoading}
608
618
  textSearchEnabled={textSearchEnabled}
619
+ actionsStart={<EntityCollectionViewStartActions
620
+ parentCollectionIds={parentCollectionIds ?? []}
621
+ collection={collection}
622
+ tableController={tableController}
623
+ path={fullPath}
624
+ relativePath={collection.path}
625
+ selectionController={usedSelectionController}
626
+ collectionEntitiesCount={docsCount}/>}
609
627
  actions={<EntityCollectionViewActions
610
628
  parentCollectionIds={parentCollectionIds ?? []}
611
629
  collection={collection}
@@ -683,8 +701,11 @@ export const EntityCollectionView = React.memo(
683
701
  equal(a.selectionController, b.selectionController) &&
684
702
  equal(a.Actions, b.Actions) &&
685
703
  equal(a.defaultSize, b.defaultSize) &&
704
+ equal(a.initialFilter, b.initialFilter) &&
705
+ equal(a.initialSort, b.initialSort) &&
686
706
  equal(a.textSearchEnabled, b.textSearchEnabled) &&
687
707
  equal(a.additionalFields, b.additionalFields) &&
708
+ equal(a.sideDialogWidth, b.sideDialogWidth) &&
688
709
  equal(a.forceFilter, b.forceFilter);
689
710
  }) as React.FunctionComponent<EntityCollectionViewProps<any>>
690
711
 
@@ -724,6 +745,7 @@ function EntitiesCount({
724
745
 
725
746
  useEffect(() => {
726
747
  if (onCountChange) {
748
+ setError(undefined);
727
749
  onCountChange(count ?? 0);
728
750
  }
729
751
  }, [onCountChange, count]);
@@ -775,7 +797,7 @@ function EntityIdHeaderWidget({
775
797
  if (!searchString) return;
776
798
  setOpenPopup(false);
777
799
  return sideEntityController.open({
778
- entityId: searchString,
800
+ entityId: searchString.trim(),
779
801
  path,
780
802
  collection,
781
803
  updateUrl: true,
@@ -788,11 +810,13 @@ function EntityIdHeaderWidget({
788
810
  autoFocus={openPopup}
789
811
  placeholder={"Find entity by ID"}
790
812
  // size={"small"}
791
- onChange={(e) => setSearchString(e.target.value)}
813
+ onChange={(e) => {
814
+ setSearchString(e.target.value);
815
+ }}
792
816
  value={searchString}
793
817
  className={"flex-grow bg-transparent outline-none p-1"}/>
794
818
  <Button variant={"outlined"}
795
- disabled={!searchString}
819
+ disabled={!(searchString.trim())}
796
820
  type={"submit"}
797
821
  >Go</Button>
798
822
  </div>
@@ -0,0 +1,68 @@
1
+ import React from "react";
2
+ import { useCustomizationController, useFireCMSContext } from "../../hooks";
3
+ import { CollectionActionsProps, EntityCollection, EntityTableController, SelectionController } from "../../types";
4
+ import { toArray } from "../../util/arrays";
5
+ import { ErrorBoundary } from "../ErrorBoundary";
6
+ import { ClearFilterSortButton } from "../ClearFilterSortButton";
7
+
8
+ export type EntityCollectionViewStartActionsProps<M extends Record<string, any>> = {
9
+ collection: EntityCollection<M>;
10
+ path: string;
11
+ relativePath: string;
12
+ parentCollectionIds: string[];
13
+ selectionController: SelectionController<M>;
14
+ tableController: EntityTableController<M>;
15
+ collectionEntitiesCount: number;
16
+ }
17
+
18
+ export function EntityCollectionViewStartActions<M extends Record<string, any>>({
19
+ collection,
20
+ relativePath,
21
+ parentCollectionIds,
22
+ path,
23
+ selectionController,
24
+ tableController,
25
+ collectionEntitiesCount
26
+ }: EntityCollectionViewStartActionsProps<M>) {
27
+
28
+ const context = useFireCMSContext();
29
+
30
+ const customizationController = useCustomizationController();
31
+ const plugins = customizationController.plugins ?? [];
32
+
33
+ const actionProps: CollectionActionsProps = {
34
+ path,
35
+ relativePath,
36
+ parentCollectionIds,
37
+ collection,
38
+ selectionController,
39
+ context,
40
+ tableController,
41
+ collectionEntitiesCount
42
+ };
43
+ const actions: React.ReactNode[] = [
44
+ <ClearFilterSortButton
45
+ key={"clear_filter"}
46
+ tableController={tableController}
47
+ enabled={!collection.forceFilter}/>
48
+ ];
49
+
50
+ if (plugins) {
51
+ plugins.forEach((plugin, i) => {
52
+ if (plugin.collectionView?.CollectionActionsStart) {
53
+ actions.push(...toArray(plugin.collectionView?.CollectionActionsStart)
54
+ .map((Action, j) => (
55
+ <ErrorBoundary key={`plugin_actions_${i}_${j}`}>
56
+ <Action {...actionProps} {...plugin.collectionView?.collectionActionsStartProps}/>
57
+ </ErrorBoundary>
58
+ )));
59
+ }
60
+ });
61
+ }
62
+
63
+ return (
64
+ <>
65
+ {actions}
66
+ </>
67
+ );
68
+ }