@firecms/core 3.0.0-canary.6 → 3.0.0-canary.61

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 (242) hide show
  1. package/README.md +2 -2
  2. package/dist/components/ClearFilterSortButton.d.ts +5 -0
  3. package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +11 -11
  4. package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +2 -2
  5. package/dist/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +5 -3
  6. package/dist/components/EntityCollectionTable/PropertyTableCell.d.ts +3 -2
  7. package/dist/components/EntityCollectionTable/column_utils.d.ts +1 -2
  8. package/dist/components/EntityCollectionTable/fields/TableReferenceField.d.ts +2 -0
  9. package/dist/components/EntityCollectionTable/internal/CollectionTableToolbar.d.ts +1 -4
  10. package/dist/components/EntityCollectionTable/internal/EntityTableCell.d.ts +2 -2
  11. package/dist/components/EntityCollectionTable/internal/popup_field/PopupFormField.d.ts +1 -1
  12. package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +12 -3
  13. package/dist/components/EntityCollectionView/EntityCollectionViewStartActions.d.ts +11 -0
  14. package/dist/components/EntityCollectionView/useSelectionController.d.ts +2 -0
  15. package/dist/components/EntityPreview.d.ts +26 -7
  16. package/dist/components/EntityView.d.ts +11 -0
  17. package/dist/components/FieldCaption.d.ts +5 -0
  18. package/dist/components/FireCMSAppBar.d.ts +4 -2
  19. package/dist/components/HomePage/NavigationCard.d.ts +8 -0
  20. package/dist/components/HomePage/{NavigationCollectionCard.d.ts → NavigationCardBinding.d.ts} +2 -2
  21. package/dist/components/HomePage/SmallNavigationCard.d.ts +6 -0
  22. package/dist/components/HomePage/index.d.ts +3 -1
  23. package/dist/components/ReferenceWidget.d.ts +3 -1
  24. package/dist/components/SelectableTable/SelectableTable.d.ts +1 -1
  25. package/dist/components/SelectableTable/filters/ReferenceFilterField.d.ts +2 -1
  26. package/dist/components/VirtualTable/VirtualTableProps.d.ts +6 -7
  27. package/dist/components/VirtualTable/types.d.ts +3 -3
  28. package/dist/components/{EntityCollectionTable/internal → common}/default_entity_actions.d.ts +1 -1
  29. package/dist/components/common/index.d.ts +1 -0
  30. package/dist/components/common/table_height.d.ts +5 -0
  31. package/dist/components/common/types.d.ts +4 -6
  32. package/dist/components/common/useDataSourceEntityCollectionTableController.d.ts +3 -0
  33. package/dist/components/index.d.ts +5 -2
  34. package/dist/contexts/AuthControllerContext.d.ts +1 -1
  35. package/dist/core/Drawer.d.ts +5 -12
  36. package/dist/core/DrawerNavigationItem.d.ts +9 -0
  37. package/dist/core/{EntityView.d.ts → EntityEditView.d.ts} +2 -2
  38. package/dist/core/NavigationRoutes.d.ts +1 -1
  39. package/dist/core/Scaffold.d.ts +8 -12
  40. package/dist/core/index.d.ts +3 -4
  41. package/dist/form/EntityForm.d.ts +1 -1
  42. package/dist/form/components/ErrorFocus.d.ts +1 -1
  43. package/dist/form/components/StorageItemPreview.d.ts +3 -2
  44. package/dist/form/components/StorageUploadProgress.d.ts +1 -1
  45. package/dist/form/field_bindings/KeyValueFieldBinding.d.ts +1 -1
  46. package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
  47. package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +4 -3
  48. package/dist/form/field_bindings/TextFieldBinding.d.ts +2 -2
  49. package/dist/form/validation.d.ts +1 -1
  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 +2 -2
  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 +6 -4
  56. package/dist/hooks/useProjectLog.d.ts +6 -2
  57. package/dist/hooks/useStorageSource.d.ts +2 -2
  58. package/dist/hooks/useValidateAuthenticator.d.ts +21 -0
  59. package/dist/index.es.js +10498 -9944
  60. package/dist/index.es.js.map +1 -1
  61. package/dist/index.umd.js +5 -5
  62. package/dist/index.umd.js.map +1 -1
  63. package/dist/internal/useBuildDataSource.d.ts +1 -16
  64. package/dist/preview/PropertyPreview.d.ts +1 -1
  65. package/dist/preview/PropertyPreviewProps.d.ts +1 -4
  66. package/dist/preview/components/BooleanPreview.d.ts +5 -1
  67. package/dist/preview/components/EnumValuesChip.d.ts +1 -1
  68. package/dist/preview/components/ReferencePreview.d.ts +3 -8
  69. package/dist/types/analytics.d.ts +1 -1
  70. package/dist/types/auth.d.ts +37 -1
  71. package/dist/types/collections.d.ts +30 -6
  72. package/dist/types/datasource.d.ts +21 -14
  73. package/dist/types/entities.d.ts +5 -1
  74. package/dist/types/entity_actions.d.ts +14 -0
  75. package/dist/types/entity_callbacks.d.ts +2 -2
  76. package/dist/types/entity_overrides.d.ts +6 -0
  77. package/dist/types/index.d.ts +2 -1
  78. package/dist/types/navigation.d.ts +15 -14
  79. package/dist/types/permissions.d.ts +5 -1
  80. package/dist/types/plugins.d.ts +20 -20
  81. package/dist/types/properties.d.ts +12 -4
  82. package/dist/types/property_config.d.ts +2 -2
  83. package/dist/types/roles.d.ts +31 -0
  84. package/dist/types/storage.d.ts +11 -3
  85. package/dist/types/user.d.ts +5 -0
  86. package/dist/util/collections.d.ts +9 -1
  87. package/dist/util/entities.d.ts +1 -1
  88. package/dist/util/icon_synonyms.d.ts +1 -97
  89. package/dist/util/icons.d.ts +8 -2
  90. package/dist/util/navigation_utils.d.ts +2 -2
  91. package/dist/util/objects.d.ts +1 -1
  92. package/dist/util/permissions.d.ts +4 -4
  93. package/dist/util/references.d.ts +4 -2
  94. package/dist/util/resolutions.d.ts +14 -14
  95. package/dist/util/useTraceUpdate.d.ts +1 -0
  96. package/package.json +139 -119
  97. package/src/components/ClearFilterSortButton.tsx +41 -0
  98. package/src/components/DeleteEntityDialog.tsx +4 -4
  99. package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +4 -4
  100. package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +276 -279
  101. package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +9 -5
  102. package/src/components/EntityCollectionTable/PropertyTableCell.tsx +48 -45
  103. package/src/components/EntityCollectionTable/column_utils.tsx +3 -3
  104. package/src/components/EntityCollectionTable/fields/TableReferenceField.tsx +18 -17
  105. package/src/components/EntityCollectionTable/fields/TableStorageUpload.tsx +5 -5
  106. package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +29 -34
  107. package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +16 -12
  108. package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +2 -4
  109. package/src/components/EntityCollectionView/EntityCollectionView.tsx +73 -72
  110. package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +5 -6
  111. package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +68 -0
  112. package/src/components/EntityCollectionView/useSelectionController.tsx +30 -0
  113. package/src/components/EntityPreview.tsx +209 -70
  114. package/src/components/EntityView.tsx +84 -0
  115. package/src/components/FieldCaption.tsx +14 -0
  116. package/src/components/FireCMSAppBar.tsx +40 -15
  117. package/src/components/HomePage/DefaultHomePage.tsx +15 -11
  118. package/src/components/HomePage/NavigationCard.tsx +69 -0
  119. package/src/components/HomePage/NavigationCardBinding.tsx +116 -0
  120. package/src/components/HomePage/SmallNavigationCard.tsx +45 -0
  121. package/src/components/HomePage/index.tsx +3 -1
  122. package/src/components/PropertyIdCopyTooltipContent.tsx +2 -3
  123. package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +4 -4
  124. package/src/components/ReferenceWidget.tsx +22 -12
  125. package/src/components/SearchIconsView.tsx +5 -5
  126. package/src/components/SelectableTable/SelectableTable.tsx +5 -3
  127. package/src/components/SelectableTable/filters/BooleanFilterField.tsx +2 -3
  128. package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +23 -8
  129. package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +38 -24
  130. package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +35 -15
  131. package/src/components/VirtualTable/VirtualTable.tsx +38 -29
  132. package/src/components/VirtualTable/VirtualTableHeader.tsx +4 -4
  133. package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +2 -2
  134. package/src/components/VirtualTable/VirtualTableProps.tsx +7 -7
  135. package/src/components/VirtualTable/VirtualTableRow.tsx +4 -5
  136. package/src/components/VirtualTable/fields/VirtualTableDateField.tsx +1 -1
  137. package/src/components/VirtualTable/types.tsx +2 -3
  138. package/src/components/{EntityCollectionTable/internal → common}/default_entity_actions.tsx +11 -7
  139. package/src/components/common/index.ts +1 -0
  140. package/src/components/{VirtualTable/common.tsx → common/table_height.tsx} +5 -2
  141. package/src/components/common/types.tsx +4 -6
  142. package/src/components/common/useColumnsIds.tsx +10 -2
  143. package/src/components/common/useDataSourceEntityCollectionTableController.tsx +12 -1
  144. package/src/components/common/useTableSearchHelper.ts +39 -9
  145. package/src/components/index.tsx +5 -2
  146. package/src/contexts/AuthControllerContext.tsx +1 -1
  147. package/src/core/Drawer.tsx +78 -103
  148. package/src/core/DrawerNavigationItem.tsx +62 -0
  149. package/src/core/{EntityView.tsx → EntityEditView.tsx} +27 -45
  150. package/src/core/EntitySidePanel.tsx +3 -3
  151. package/src/core/FireCMS.tsx +54 -43
  152. package/src/core/NavigationRoutes.tsx +11 -4
  153. package/src/core/Scaffold.tsx +80 -66
  154. package/src/core/field_configs.tsx +2 -3
  155. package/src/core/index.tsx +3 -4
  156. package/src/form/EntityForm.tsx +42 -27
  157. package/src/form/PropertyFieldBinding.tsx +0 -2
  158. package/src/form/components/StorageItemPreview.tsx +7 -5
  159. package/src/form/components/StorageUploadProgress.tsx +9 -8
  160. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +10 -12
  161. package/src/form/field_bindings/BlockFieldBinding.tsx +2 -2
  162. package/src/form/field_bindings/DateTimeFieldBinding.tsx +1 -1
  163. package/src/form/field_bindings/KeyValueFieldBinding.tsx +19 -19
  164. package/src/form/field_bindings/MapFieldBinding.tsx +15 -15
  165. package/src/form/field_bindings/MarkdownFieldBinding.tsx +2 -2
  166. package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +3 -3
  167. package/src/form/field_bindings/ReferenceFieldBinding.tsx +16 -13
  168. package/src/form/field_bindings/SelectFieldBinding.tsx +3 -3
  169. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +18 -9
  170. package/src/form/field_bindings/TextFieldBinding.tsx +7 -5
  171. package/src/form/validation.ts +3 -4
  172. package/src/hooks/data/delete.ts +3 -3
  173. package/src/hooks/data/save.ts +4 -2
  174. package/src/hooks/data/useCollectionFetch.tsx +1 -1
  175. package/src/hooks/data/useDataSource.tsx +8 -3
  176. package/src/hooks/data/useEntityFetch.tsx +4 -4
  177. package/src/hooks/index.tsx +3 -0
  178. package/src/hooks/useBuildLocalConfigurationPersistence.tsx +8 -10
  179. package/src/hooks/useBuildModeController.tsx +11 -5
  180. package/src/hooks/useBuildNavigationController.tsx +200 -83
  181. package/src/hooks/useProjectLog.tsx +17 -7
  182. package/src/hooks/useReferenceDialog.tsx +2 -2
  183. package/src/hooks/useResolvedNavigationFrom.tsx +1 -1
  184. package/src/hooks/useStorageSource.tsx +7 -2
  185. package/src/hooks/useValidateAuthenticator.tsx +115 -0
  186. package/src/internal/useBuildDataSource.ts +54 -47
  187. package/src/internal/useBuildSideEntityController.tsx +88 -21
  188. package/src/preview/PropertyPreview.tsx +5 -15
  189. package/src/preview/PropertyPreviewProps.tsx +1 -11
  190. package/src/preview/components/BooleanPreview.tsx +19 -4
  191. package/src/preview/components/EnumValuesChip.tsx +2 -2
  192. package/src/preview/components/ReferencePreview.tsx +72 -165
  193. package/src/preview/property_previews/ArrayOfMapsPreview.tsx +0 -1
  194. package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +2 -1
  195. package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +0 -1
  196. package/src/preview/property_previews/ArrayOfStringsPreview.tsx +0 -1
  197. package/src/preview/property_previews/ArrayOneOfPreview.tsx +2 -3
  198. package/src/preview/property_previews/ArrayPropertyPreview.tsx +2 -3
  199. package/src/preview/property_previews/MapPropertyPreview.tsx +5 -5
  200. package/src/preview/property_previews/StringPropertyPreview.tsx +8 -7
  201. package/src/types/analytics.ts +1 -0
  202. package/src/types/auth.tsx +50 -1
  203. package/src/types/collections.ts +37 -6
  204. package/src/types/datasource.ts +24 -17
  205. package/src/types/entities.ts +9 -1
  206. package/src/types/entity_actions.tsx +17 -0
  207. package/src/types/entity_callbacks.ts +2 -2
  208. package/src/types/entity_overrides.tsx +7 -0
  209. package/src/types/firecms.tsx +0 -1
  210. package/src/types/index.ts +2 -1
  211. package/src/types/navigation.ts +17 -17
  212. package/src/types/permissions.ts +6 -1
  213. package/src/types/plugins.tsx +26 -28
  214. package/src/types/properties.ts +18 -6
  215. package/src/types/property_config.tsx +2 -2
  216. package/src/types/roles.ts +41 -0
  217. package/src/types/side_entity_controller.tsx +1 -0
  218. package/src/types/storage.ts +12 -3
  219. package/src/types/user.ts +7 -0
  220. package/src/util/collections.ts +22 -0
  221. package/src/util/entities.ts +1 -1
  222. package/src/util/enums.ts +1 -1
  223. package/src/util/icon_list.ts +2 -2
  224. package/src/util/icon_synonyms.ts +3 -99
  225. package/src/util/icons.tsx +11 -3
  226. package/src/util/navigation_utils.ts +6 -6
  227. package/src/util/objects.ts +8 -21
  228. package/src/util/permissions.ts +11 -8
  229. package/src/util/references.ts +36 -5
  230. package/src/util/resolutions.ts +32 -31
  231. package/src/util/strings.ts +2 -2
  232. package/src/util/useTraceUpdate.tsx +2 -1
  233. package/dist/components/VirtualTable/common.d.ts +0 -2
  234. package/dist/core/SideEntityView.d.ts +0 -7
  235. package/dist/internal/useBuildCustomizationController.d.ts +0 -2
  236. package/dist/internal/useLocaleConfig.d.ts +0 -1
  237. package/dist/types/appcheck.d.ts +0 -26
  238. package/src/components/HomePage/NavigationCollectionCard.tsx +0 -146
  239. package/src/core/SideEntityView.tsx +0 -38
  240. package/src/internal/useBuildCustomizationController.tsx +0 -5
  241. package/src/internal/useLocaleConfig.tsx +0 -18
  242. package/src/types/appcheck.ts +0 -29
@@ -1,7 +1,7 @@
1
1
  import React, { useState } from "react";
2
2
  import { EnumValuesChip } from "../../../preview";
3
3
  import { VirtualTableWhereFilterOp } from "../../VirtualTable";
4
- import { ClearIcon, IconButton, Select, SelectItem, TextField } from "@firecms/ui";
4
+ import { Checkbox, ClearIcon, IconButton, Label, Select, SelectItem, TextField } from "@firecms/ui";
5
5
  import { EnumValueConfig } from "../../../types";
6
6
 
7
7
  interface StringNumberFilterFieldProps {
@@ -50,15 +50,15 @@ export function StringNumberFilterField({
50
50
 
51
51
  const [fieldOperation, fieldValue] = value || [possibleOperations[0], undefined];
52
52
  const [operation, setOperation] = useState<VirtualTableWhereFilterOp>(fieldOperation);
53
- const [internalValue, setInternalValue] = useState<string | number | string[] | number[] | undefined>(fieldValue);
53
+ const [internalValue, setInternalValue] = useState<string | number | string[] | number[] | null | undefined>(fieldValue);
54
54
 
55
- function updateFilter(op: VirtualTableWhereFilterOp, val: string | number | string[] | number[] | undefined) {
55
+ function updateFilter(op: VirtualTableWhereFilterOp, val: string | number | string[] | number[] | null | undefined) {
56
56
  let newValue = val;
57
57
  const prevOpIsArray = multipleSelectOperations.includes(operation);
58
58
  const newOpIsArray = multipleSelectOperations.includes(op);
59
59
  if (prevOpIsArray !== newOpIsArray) {
60
60
  // @ts-ignore
61
- newValue = newOpIsArray ? (typeof val === "string" || typeof val === "number" ? [val] : []) : "";
61
+ newValue = newOpIsArray ? (typeof val === "string" || typeof val === "number" ? [val] : []) : undefined;
62
62
  }
63
63
 
64
64
  if (typeof newValue === "number" && isNaN(newValue))
@@ -84,7 +84,7 @@ export function StringNumberFilterField({
84
84
  const multiple = multipleSelectOperations.includes(operation);
85
85
  return (
86
86
 
87
- <div className="flex w-[440px] items-center">
87
+ <div className="flex w-[440px]">
88
88
  <div className={"w-[80px]"}>
89
89
  <Select value={operation}
90
90
  position={"item-aligned"}
@@ -100,11 +100,11 @@ export function StringNumberFilterField({
100
100
  </Select>
101
101
  </div>
102
102
 
103
- <div className="flex-grow ml-2">
103
+ <div className="flex-grow ml-2 flex flex-col gap-2">
104
104
 
105
105
  {!enumValues && <TextField
106
106
  type={dataType === "number" ? "number" : undefined}
107
- value={internalValue !== undefined ? String(internalValue) : ""}
107
+ value={internalValue !== undefined && internalValue != null ? String(internalValue) : ""}
108
108
  onChange={(evt) => {
109
109
  const val = dataType === "number"
110
110
  ? parseFloat(evt.target.value)
@@ -118,26 +118,31 @@ export function StringNumberFilterField({
118
118
  />}
119
119
 
120
120
  {enumValues &&
121
-
122
121
  <Select
123
122
  position={"item-aligned"}
124
123
  value={internalValue !== undefined
125
124
  ? (Array.isArray(internalValue) ? internalValue.map(e => String(e)) : String(internalValue))
126
125
  : isArray ? [] : ""}
127
126
  onValueChange={(value) => {
128
- updateFilter(operation, dataType === "number" ? parseInt(value as string) : value as string)
127
+ if (value !== "")
128
+ updateFilter(operation, dataType === "number" ? parseInt(value as string) : value as string)
129
129
  }}
130
130
  multiple={multiple}
131
131
  endAdornment={internalValue && <IconButton
132
- className="absolute right-3 top-2"
132
+ className="absolute right-2 top-3"
133
133
  onClick={(e) => updateFilter(operation, undefined)}>
134
134
  <ClearIcon/>
135
135
  </IconButton>}
136
- renderValue={(enumKey) => <EnumValuesChip
137
- key={`select_value_${name}_${enumKey}`}
138
- enumKey={enumKey}
139
- enumValues={enumValues}
140
- size={"small"}/>}>
136
+ renderValue={(enumKey) => {
137
+ if (enumKey === null)
138
+ return "Filter for null values";
139
+
140
+ return <EnumValuesChip
141
+ key={`select_value_${name}_${enumKey}`}
142
+ enumKey={enumKey}
143
+ enumValues={enumValues}
144
+ size={"small"}/>;
145
+ }}>
141
146
  {enumValues.map((enumConfig) => (
142
147
  <SelectItem key={`select_value_${name}_${enumConfig.id}`}
143
148
  value={String(enumConfig.id)}>
@@ -150,6 +155,21 @@ export function StringNumberFilterField({
150
155
  </Select>
151
156
  }
152
157
 
158
+ {!isArray && <Label
159
+ className="border cursor-pointer rounded-md p-2 flex items-center gap-2 [&:has(:checked)]:bg-gray-100 dark:[&:has(:checked)]:bg-gray-800"
160
+ htmlFor="null-filter"
161
+ >
162
+ <Checkbox id="null-filter"
163
+ checked={internalValue === null}
164
+ size={"small"}
165
+ onCheckedChange={(checked) => {
166
+ if (internalValue !== null)
167
+ updateFilter(operation, null);
168
+ else updateFilter(operation, undefined);
169
+ }}/>
170
+ Filter for null values
171
+ </Label>}
172
+
153
173
  </div>
154
174
 
155
175
  </div>
@@ -15,12 +15,11 @@ import {
15
15
  VirtualTableWhereFilterOp
16
16
  } from "./VirtualTableProps";
17
17
 
18
- import { getRowHeight } from "./common";
19
18
  import { VirtualTableContextProps } from "./types";
20
19
  import { VirtualTableHeaderRow } from "./VirtualTableHeaderRow";
21
20
  import { VirtualTableRow } from "./VirtualTableRow";
22
21
  import { VirtualTableCell } from "./VirtualTableCell";
23
- import { AssignmentIcon, cn, Markdown, Typography } from "@firecms/ui";
22
+ import { AssignmentIcon, CenteredView, cls, Typography } from "@firecms/ui";
24
23
 
25
24
  const VirtualListContext = createContext<VirtualTableContextProps<any>>({} as any);
26
25
  VirtualListContext.displayName = "VirtualListContext";
@@ -92,7 +91,7 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
92
91
  data,
93
92
  onResetPagination,
94
93
  onEndReached,
95
- size = "m",
94
+ rowHeight = 54,
96
95
  columns: columnsProp,
97
96
  onRowClick,
98
97
  onColumnResize,
@@ -108,6 +107,7 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
108
107
  hoverRow,
109
108
  createFilterField,
110
109
  rowClassName,
110
+ style,
111
111
  className,
112
112
  endAdornment,
113
113
  AddColumnComponent
@@ -187,7 +187,7 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
187
187
  onSortByUpdate(undefined);
188
188
  }, [onSortByUpdate]);
189
189
 
190
- const maxScroll = Math.max((data?.length ?? 0) * getRowHeight(size) - bounds.height, 0);
190
+ const maxScroll = Math.max((data?.length ?? 0) * rowHeight - bounds.height, 0);
191
191
  const onEndReachedInternal = useCallback((scrollOffset: number) => {
192
192
  if (onEndReached && (data?.length ?? 0) > 0 && scrollOffset > endReachCallbackThreshold.current + 600) {
193
193
  endReachCallbackThreshold.current = scrollOffset;
@@ -225,24 +225,7 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
225
225
  }
226
226
 
227
227
  if (onFilterUpdate) onFilterUpdate(newFilterValue);
228
-
229
- if (column.key !== sortByProperty) {
230
- resetSort();
231
- }
232
- }, [checkFilterCombination, currentSort, onFilterUpdate, resetSort, sortByProperty]);
233
-
234
- const buildErrorView = useCallback(() => (
235
- <div
236
- className="h-full flex flex-col items-center justify-center sticky left-0">
237
-
238
- <Typography variant={"h6"}>
239
- {"Error fetching data from the data source"}
240
- </Typography>
241
-
242
- {error?.message && <Markdown className={"px-4 break-all"} source={error.message}/>}
243
-
244
- </div>
245
- ), [error?.message]);
228
+ }, [checkFilterCombination, currentSort, onFilterUpdate, sortByProperty]);
246
229
 
247
230
  const buildEmptyView = useCallback(() => {
248
231
  if (loading)
@@ -255,11 +238,22 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
255
238
  }, [emptyComponent, loading]);
256
239
 
257
240
  const empty = !loading && (data?.length ?? 0) === 0;
258
- const customView = error ? buildErrorView() : (empty ? buildEmptyView() : undefined);
241
+ const customView = error
242
+ ? <CenteredView maxWidth={"2xl"}
243
+ className="flex flex-col gap-2">
244
+
245
+ <Typography variant={"h6"}>
246
+ {"Error fetching data from the data source"}
247
+ </Typography>
248
+
249
+ {error?.message && <SafeLinkRenderer text={error.message}/>}
250
+
251
+ </CenteredView>
252
+ : (empty ? buildEmptyView() : undefined);
259
253
 
260
254
  const virtualListController = {
261
255
  data,
262
- size,
256
+ rowHeight: rowHeight,
263
257
  cellRenderer,
264
258
  columns,
265
259
  currentSort,
@@ -282,19 +276,20 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
282
276
  return (
283
277
  <div
284
278
  ref={measureRef}
285
- className={cn("h-full w-full", className)}>
279
+ style={style}
280
+ className={cls("h-full w-full", className)}>
286
281
  <VirtualListContext.Provider
287
282
  value={virtualListController}>
288
283
 
289
284
  <MemoizedList
290
285
  outerRef={tableRef}
291
- key={size}
286
+ key={rowHeight}
292
287
  width={bounds.width}
293
288
  height={bounds.height}
294
289
  itemCount={(data?.length ?? 0) + (endAdornment ? 1 : 0)}
295
290
  onScroll={onScroll}
296
291
  includeAddColumn={Boolean(AddColumnComponent)}
297
- itemSize={getRowHeight(size)}/>
292
+ itemSize={rowHeight}/>
298
293
 
299
294
  </VirtualListContext.Provider>
300
295
  </div>
@@ -334,7 +329,7 @@ function MemoizedList({
334
329
  onRowClick,
335
330
  data,
336
331
  columns,
337
- size = "m",
332
+ rowHeight = 54,
338
333
  cellRenderer,
339
334
  hoverRow,
340
335
  rowClassName,
@@ -367,7 +362,7 @@ function MemoizedList({
367
362
  ...style,
368
363
  top: `calc(${style.top}px + 48px)`
369
364
  }}
370
- size={size}>
365
+ rowHeight={rowHeight}>
371
366
 
372
367
  {columns.map((column: VirtualTableColumn, columnIndex: number) => {
373
368
  const cellData = rowData && rowData[column.key];
@@ -403,3 +398,17 @@ function MemoizedList({
403
398
  {Row}
404
399
  </List>;
405
400
  }
401
+
402
+ const SafeLinkRenderer: React.FC<{
403
+ text: string;
404
+ }> = ({ text }) => {
405
+ const urlRegex = /https?:\/\/[^\s]+/g;
406
+ const htmlContent = text.replace(urlRegex, (url) => {
407
+ // For each URL found, replace it with an HTML <a> tag
408
+ return `<a href="${url}" class="underline" target="_blank">Link</a><br/>`;
409
+ });
410
+
411
+ return (
412
+ <div className={"break-all"} dangerouslySetInnerHTML={{ __html: htmlContent }}/>
413
+ );
414
+ };
@@ -7,7 +7,7 @@ import {
7
7
  ArrowUpwardIcon,
8
8
  Badge,
9
9
  Button,
10
- cn,
10
+ cls,
11
11
  defaultBorderMixin,
12
12
  FilterListIcon,
13
13
  IconButton,
@@ -85,7 +85,7 @@ export const VirtualTableHeader = React.memo<VirtualTableHeaderProps<any>>(
85
85
  return (
86
86
  <ErrorBoundary>
87
87
  <div
88
- className={cn("flex py-0 px-3 h-full text-xs uppercase font-semibold relative select-none items-center bg-gray-50 dark:bg-gray-900",
88
+ className={cls("flex py-0 px-3 h-full text-xs uppercase font-semibold relative select-none items-center bg-gray-50 dark:bg-gray-900",
89
89
  "text-gray-600 hover:text-gray-800 dark:text-gray-400 dark:hover:text-gray-200 ",
90
90
  "hover:bg-gray-100 dark:hover:bg-gray-800 hover:bg-opacity-50 dark:hover:bg-opacity-50",
91
91
  column.frozen ? "sticky left-0 z-10" : "relative z-0"
@@ -179,7 +179,7 @@ export const VirtualTableHeader = React.memo<VirtualTableHeaderProps<any>>(
179
179
 
180
180
  {column.resizable && <div
181
181
  ref={resizeHandleRef}
182
- className={cn(
182
+ className={cls(
183
183
  "absolute h-full w-[6px] top-0 right-0 cursor-col-resize",
184
184
  hovered && "bg-gray-300 dark:bg-gray-700"
185
185
  )}
@@ -240,7 +240,7 @@ function FilterForm<M>({
240
240
  }}
241
241
  className={"text-gray-900 dark:text-white"}>
242
242
  <div
243
- className={cn(defaultBorderMixin, "py-4 px-6 text-xs font-semibold uppercase border-b")}>
243
+ className={cls(defaultBorderMixin, "py-4 px-6 text-xs font-semibold uppercase border-b")}>
244
244
  {column.title ?? id}
245
245
  </div>
246
246
  {filterField && <div className="m-4">
@@ -4,7 +4,7 @@ import { VirtualTableColumn, VirtualTableWhereFilterOp } from "./VirtualTablePro
4
4
  import { ErrorBoundary } from "../ErrorBoundary";
5
5
  import { VirtualTableHeader } from "./VirtualTableHeader";
6
6
  import { VirtualTableContextProps } from "./types";
7
- import { cn, defaultBorderMixin } from "@firecms/ui";
7
+ import { cls, defaultBorderMixin } from "@firecms/ui";
8
8
 
9
9
  export const VirtualTableHeaderRow = ({
10
10
  columns,
@@ -100,7 +100,7 @@ export const VirtualTableHeaderRow = ({
100
100
 
101
101
  return (
102
102
  <div
103
- className={cn(defaultBorderMixin, "z-20 sticky min-w-full flex w-fit flex-row top-0 left-0 h-12 border-b bg-gray-50 dark:bg-gray-900")}>
103
+ className={cls(defaultBorderMixin, "z-20 sticky min-w-full flex w-fit flex-row top-0 left-0 h-12 border-b bg-gray-50 dark:bg-gray-900")}>
104
104
  {columns.map((c, columnIndex) => {
105
105
  const column = columns[columnIndex];
106
106
 
@@ -69,7 +69,7 @@ export interface VirtualTableProps<T extends Record<string, any>> {
69
69
  /**
70
70
  * Size of the table
71
71
  */
72
- size?: VirtualTableSize,
72
+ rowHeight?: number,
73
73
 
74
74
  /**
75
75
  * In case this table should have some filters set by default
@@ -131,6 +131,11 @@ export interface VirtualTableProps<T extends Record<string, any>> {
131
131
  */
132
132
  className?: string;
133
133
 
134
+ /**
135
+ * Style applied to the table
136
+ */
137
+ style?: React.CSSProperties;
138
+
134
139
  /**
135
140
  * Component rendered at the end of the table, after scroll
136
141
  */
@@ -232,11 +237,6 @@ export type OnVirtualTableColumnResizeParams = {
232
237
  column: VirtualTableColumn
233
238
  };
234
239
 
235
- /**
236
- * @see Table
237
- * @group Components
238
- */
239
- export type VirtualTableSize = "xs" | "s" | "m" | "l" | "xl";
240
240
 
241
241
  /**
242
242
  * @see Table
@@ -252,7 +252,7 @@ export type VirtualTableFilterValues<Key extends string> = Partial<Record<Key, [
252
252
 
253
253
  /**
254
254
  * Filter conditions in a `Query.where()` clause are specified using the
255
- * strings '<', '<=', '==', '>=', '>', 'array-contains', 'in', 'not-in', and 'array-contains-any'.
255
+ * strings `<`, `<=`, `==`, `>=`, `>`, `array-contains`, `in`, and `array-contains-any`.
256
256
  * @see Table
257
257
  * @group Models
258
258
  */
@@ -2,9 +2,8 @@ import React, { useCallback } from "react";
2
2
 
3
3
  import equal from "react-fast-compare"
4
4
 
5
- import { getRowHeight } from "./common";
6
5
  import { VirtualTableRowProps } from "./types";
7
- import { cn } from "@firecms/ui";
6
+ import { cls } from "@firecms/ui";
8
7
 
9
8
  export const VirtualTableRow = React.memo<VirtualTableRowProps<any>>(
10
9
  function VirtualTableRow<T>({
@@ -12,7 +11,7 @@ export const VirtualTableRow = React.memo<VirtualTableRowProps<any>>(
12
11
  rowIndex,
13
12
  children,
14
13
  onRowClick,
15
- size,
14
+ rowHeight,
16
15
  style,
17
16
  hoverRow,
18
17
  rowClassName
@@ -29,7 +28,7 @@ export const VirtualTableRow = React.memo<VirtualTableRowProps<any>>(
29
28
 
30
29
  return (
31
30
  <div
32
- className={cn(
31
+ className={cls(
33
32
  "flex min-w-full text-sm border-b border-gray-200 dark:border-gray-800 border-opacity-40 dark:border-opacity-40",
34
33
  rowClassName ? rowClassName(rowData) : "",
35
34
  {
@@ -40,7 +39,7 @@ export const VirtualTableRow = React.memo<VirtualTableRowProps<any>>(
40
39
  onClick={onClick}
41
40
  style={{
42
41
  ...(style),
43
- height: getRowHeight(size),
42
+ height: rowHeight,
44
43
  width: "fit-content"
45
44
  }}
46
45
  >
@@ -25,7 +25,7 @@ export function VirtualTableDateField(props: {
25
25
  return (
26
26
  <DateTimeField
27
27
  value={internalValue ?? undefined}
28
- onChange={(dateValue) => updateValue(dateValue)}
28
+ onChange={(dateValue) => updateValue(dateValue ?? null)}
29
29
  size={"medium"}
30
30
  invisible={true}
31
31
  className={"w-full h-full"}
@@ -5,14 +5,13 @@ import {
5
5
  OnVirtualTableColumnResizeParams,
6
6
  VirtualTableColumn,
7
7
  VirtualTableFilterValues,
8
- VirtualTableSize,
9
8
  VirtualTableWhereFilterOp
10
9
  } from "./VirtualTableProps";
11
10
  import { FilterFormFieldProps } from "./VirtualTableHeader";
12
11
 
13
12
  export type VirtualTableRowProps<T> = {
14
13
  style: any,
15
- size: VirtualTableSize,
14
+ rowHeight: number,
16
15
  rowData: T;
17
16
  rowIndex: number;
18
17
  onRowClick?: (props: OnRowClickParams<any>) => void;
@@ -24,7 +23,7 @@ export type VirtualTableRowProps<T> = {
24
23
 
25
24
  export type VirtualTableContextProps<T extends any> = {
26
25
  data?: T[];
27
- size?: VirtualTableSize,
26
+ rowHeight?: number,
28
27
  columns: VirtualTableColumn[];
29
28
  cellRenderer: React.ComponentType<CellRendererParams<T>>;
30
29
  currentSort: "asc" | "desc" | undefined;
@@ -1,6 +1,6 @@
1
- import { EntityAction } from "../../../types";
2
1
  import { ArchiveIcon, DeleteIcon, FileCopyIcon, KeyboardTabIcon, OpenInNewIcon } from "@firecms/ui";
3
- import { DeleteEntityDialog } from "../../DeleteEntityDialog";
2
+ import { EntityAction } from "../../types";
3
+ import { DeleteEntityDialog } from "../DeleteEntityDialog";
4
4
 
5
5
  export const editEntityAction: EntityAction = {
6
6
  icon: <KeyboardTabIcon/>,
@@ -9,21 +9,23 @@ export const editEntityAction: EntityAction = {
9
9
  onClick({
10
10
  entity,
11
11
  collection,
12
+ fullPath,
12
13
  context,
13
14
  highlightEntity,
14
- unhighlightEntity
15
+ unhighlightEntity,
15
16
  }): Promise<void> {
16
17
  highlightEntity?.(entity);
17
18
  context.analyticsController?.onAnalyticsEvent?.("entity_click", {
18
19
  path: entity.path,
19
20
  entityId: entity.id
20
21
  });
22
+ const path = collection?.collectionGroup ? entity.path : (fullPath ?? entity.path);
21
23
  context.sideEntityController.open({
22
24
  entityId: entity.id,
23
- path: entity.path,
25
+ path,
24
26
  collection,
25
27
  updateUrl: true,
26
- onClose: () => unhighlightEntity?.(entity)
28
+ onClose: () => unhighlightEntity?.(entity),
27
29
  });
28
30
  return Promise.resolve(undefined);
29
31
  }
@@ -37,7 +39,7 @@ export const copyEntityAction: EntityAction = {
37
39
  collection,
38
40
  context,
39
41
  highlightEntity,
40
- unhighlightEntity
42
+ unhighlightEntity,
41
43
  }): Promise<void> {
42
44
  highlightEntity?.(entity);
43
45
  context.analyticsController?.onAnalyticsEvent?.("copy_entity_click", {
@@ -50,11 +52,12 @@ export const copyEntityAction: EntityAction = {
50
52
  copy: true,
51
53
  collection,
52
54
  updateUrl: true,
53
- onClose: () => unhighlightEntity?.(entity)
55
+ onClose: () => unhighlightEntity?.(entity),
54
56
  });
55
57
  return Promise.resolve(undefined);
56
58
  }
57
59
  }
60
+
58
61
  export const archiveEntityAction: EntityAction = {
59
62
  icon: <ArchiveIcon/>,
60
63
  name: "Archive",
@@ -69,6 +72,7 @@ export const archiveEntityAction: EntityAction = {
69
72
  return Promise.resolve(undefined);
70
73
  }
71
74
  }
75
+
72
76
  export const openWebsiteAction: EntityAction = {
73
77
  icon: <OpenInNewIcon/>,
74
78
  name: "See in website",
@@ -3,3 +3,4 @@ export * from "./useDebouncedData";
3
3
  export * from "./useColumnsIds";
4
4
  export * from "./useDataSourceEntityCollectionTableController";
5
5
  export * from "./useTableSearchHelper";
6
+ export * from "./default_entity_actions";
@@ -1,6 +1,9 @@
1
- import { VirtualTableSize } from "./VirtualTableProps";
1
+ /**
2
+ * @group Components
3
+ */
4
+ export type TableSize = "xs" | "s" | "m" | "l" | "xl";
2
5
 
3
- export function getRowHeight(size: VirtualTableSize): number {
6
+ export function getRowHeight(size: TableSize): number {
4
7
  switch (size) {
5
8
  case "xl":
6
9
  return 400;
@@ -1,4 +1,4 @@
1
- import { CollectionSize, Entity, FireCMSContext, ResolvedProperty, SelectedCellProps } from "../../types";
1
+ import { CollectionSize, ResolvedProperty, SelectedCellProps } from "../../types";
2
2
 
3
3
  export type EntityCollectionTableController<M extends Record<string, any>> = {
4
4
 
@@ -31,14 +31,12 @@ export type EntityCollectionTableController<M extends Record<string, any>> = {
31
31
  * Props passed in a callback when the content of a cell in a table has been edited
32
32
  * @group Collection components
33
33
  */
34
- export interface OnCellValueChangeParams<T = any, M extends Record<string, any> = any> {
34
+ export interface OnCellValueChangeParams<T = any, D = any> {
35
35
  value: T,
36
36
  propertyKey: string,
37
- entity: Entity<M>,
37
+ data?: D,
38
38
  onValueUpdated: () => void
39
- setError: (e: Error) => void
40
- fullPath: string
41
- context: FireCMSContext
39
+ setError: (e: Error | undefined) => void
42
40
  }
43
41
 
44
42
  /**
@@ -7,8 +7,16 @@ const COLLECTION_GROUP_PARENT_ID = "collectionGroupParent";
7
7
 
8
8
  export function useColumnIds<M extends Record<string, any>>(collection: ResolvedEntityCollection<M>, includeSubcollections: boolean): PropertyColumnConfig[] {
9
9
  return useMemo(() => {
10
- if (collection.propertiesOrder)
11
- return hideAndExpandKeys(collection, collection.propertiesOrder);
10
+ if (collection.propertiesOrder) {
11
+ const propertyColumnConfigs = hideAndExpandKeys(collection, collection.propertiesOrder);
12
+ if (collection.collectionGroup) {
13
+ propertyColumnConfigs.push({
14
+ key: COLLECTION_GROUP_PARENT_ID,
15
+ disabled: true
16
+ });
17
+ }
18
+ return propertyColumnConfigs;
19
+ }
12
20
  return getDefaultColumnKeys(collection, includeSubcollections);
13
21
  }, [collection, includeSubcollections]);
14
22
  }
@@ -12,6 +12,7 @@ import {
12
12
  User
13
13
  } from "../../types";
14
14
  import { useDebouncedData } from "./useDebouncedData";
15
+ import equal from "react-fast-compare"
15
16
 
16
17
  const DEFAULT_PAGE_SIZE = 50;
17
18
 
@@ -31,6 +32,10 @@ export type DataSourceEntityCollectionTableControllerProps<M extends Record<stri
31
32
  entitiesDisplayedFirst?: Entity<M>[];
32
33
 
33
34
  lastDeleteTimestamp?: number;
35
+
36
+ /**
37
+ * Force filter to be applied to the table.
38
+ */
34
39
  forceFilter?: FilterValues<string>;
35
40
  }
36
41
 
@@ -65,7 +70,7 @@ export function useDataSourceEntityCollectionTableController<M extends Record<st
65
70
 
66
71
  const [popupCell, setPopupCell] = React.useState<SelectedCellProps<M> | undefined>(undefined);
67
72
  const navigation = useNavigationController();
68
- const dataSource = useDataSource();
73
+ const dataSource = useDataSource(collection);
69
74
  const resolvedPath = useMemo(() => navigation.resolveAliasesFrom(fullPath), [fullPath, navigation.resolveAliasesFrom]);
70
75
 
71
76
  const forceFilter = forceFilterFromProps ?? forceFilterFromCollection;
@@ -83,6 +88,12 @@ export function useDataSourceEntityCollectionTableController<M extends Record<st
83
88
  return initialSort;
84
89
  }, [initialSort, forceFilter]);
85
90
 
91
+ useEffect(() => {
92
+ if (!equal(forceFilter, filterValues)) {
93
+ setFilterValues(forceFilter)
94
+ }
95
+ }, [forceFilter]);
96
+
86
97
  const [filterValues, setFilterValues] = React.useState<FilterValues<Extract<keyof M, string>> | undefined>(forceFilter ?? initialFilter ?? undefined);
87
98
  const [sortBy, setSortBy] = React.useState<[Extract<keyof M, string>, "asc" | "desc"] | undefined>(initialSortInternal);
88
99