@firecms/core 3.0.0-canary.8 → 3.0.0-canary.81

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 (239) 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/ClearFilterSortButton.d.ts +5 -0
  8. package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +11 -11
  9. package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +1 -1
  10. package/dist/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +5 -3
  11. package/dist/components/EntityCollectionTable/PropertyTableCell.d.ts +1 -0
  12. package/dist/components/EntityCollectionTable/column_utils.d.ts +1 -2
  13. package/dist/components/EntityCollectionTable/fields/TableReferenceField.d.ts +2 -0
  14. package/dist/components/EntityCollectionTable/internal/CollectionTableToolbar.d.ts +1 -4
  15. package/dist/components/EntityCollectionTable/internal/EntityTableCell.d.ts +2 -2
  16. package/dist/components/EntityCollectionTable/internal/popup_field/PopupFormField.d.ts +1 -1
  17. package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +11 -1
  18. package/dist/components/EntityCollectionView/EntityCollectionViewStartActions.d.ts +11 -0
  19. package/dist/components/EntityPreview.d.ts +5 -4
  20. package/dist/components/ReferenceWidget.d.ts +3 -1
  21. package/dist/components/SelectableTable/SelectableTable.d.ts +1 -1
  22. package/dist/components/SelectableTable/filters/ReferenceFilterField.d.ts +2 -1
  23. package/dist/components/VirtualTable/VirtualTableProps.d.ts +5 -6
  24. package/dist/components/VirtualTable/types.d.ts +3 -3
  25. package/dist/components/{EntityCollectionTable/internal → common}/default_entity_actions.d.ts +1 -1
  26. package/dist/components/common/index.d.ts +1 -0
  27. package/dist/components/common/table_height.d.ts +5 -0
  28. package/dist/components/common/types.d.ts +4 -6
  29. package/dist/components/common/useDataSourceEntityCollectionTableController.d.ts +3 -0
  30. package/dist/components/index.d.ts +2 -1
  31. package/dist/contexts/AuthControllerContext.d.ts +1 -1
  32. package/dist/{components/FireCMSAppBar.d.ts → core/DefaultAppBar.d.ts} +5 -8
  33. package/dist/core/DefaultDrawer.d.ts +19 -0
  34. package/dist/core/DrawerNavigationItem.d.ts +9 -0
  35. package/dist/core/EntityEditView.d.ts +17 -3
  36. package/dist/core/NavigationRoutes.d.ts +2 -2
  37. package/dist/core/index.d.ts +3 -4
  38. package/dist/form/PropertiesForm.d.ts +8 -0
  39. package/dist/form/components/ErrorFocus.d.ts +1 -1
  40. package/dist/form/components/FieldHelperText.d.ts +3 -3
  41. package/dist/form/components/StorageItemPreview.d.ts +4 -4
  42. package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
  43. package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +2 -4
  44. package/dist/form/index.d.ts +0 -2
  45. package/dist/hooks/data/delete.d.ts +2 -2
  46. package/dist/hooks/data/save.d.ts +2 -3
  47. package/dist/hooks/data/useDataSource.d.ts +1 -1
  48. package/dist/hooks/data/useEntityFetch.d.ts +3 -3
  49. package/dist/hooks/index.d.ts +2 -0
  50. package/dist/hooks/useBuildNavigationController.d.ts +1 -2
  51. package/dist/hooks/useProjectLog.d.ts +2 -2
  52. package/dist/hooks/useValidateAuthenticator.d.ts +21 -0
  53. package/dist/index.d.ts +1 -0
  54. package/dist/index.es.js +9816 -9546
  55. package/dist/index.es.js.map +1 -1
  56. package/dist/index.umd.js +5 -5
  57. package/dist/index.umd.js.map +1 -1
  58. package/dist/internal/useBuildDataSource.d.ts +1 -16
  59. package/dist/internal/useRestoreScroll.d.ts +1 -1
  60. package/dist/preview/PropertyPreviewProps.d.ts +6 -4
  61. package/dist/preview/components/ReferencePreview.d.ts +2 -1
  62. package/dist/preview/components/StorageThumbnail.d.ts +2 -1
  63. package/dist/preview/components/UrlComponentPreview.d.ts +2 -1
  64. package/dist/types/auth.d.ts +31 -2
  65. package/dist/types/collections.d.ts +30 -5
  66. package/dist/types/datasource.d.ts +21 -14
  67. package/dist/types/entities.d.ts +5 -1
  68. package/dist/types/entity_actions.d.ts +14 -0
  69. package/dist/types/entity_callbacks.d.ts +2 -2
  70. package/dist/types/fields.d.ts +31 -30
  71. package/dist/types/index.d.ts +1 -1
  72. package/dist/types/navigation.d.ts +5 -5
  73. package/dist/types/plugins.d.ts +16 -6
  74. package/dist/types/properties.d.ts +17 -4
  75. package/dist/types/roles.d.ts +31 -0
  76. package/dist/types/storage.d.ts +11 -3
  77. package/dist/types/user.d.ts +5 -0
  78. package/dist/util/collections.d.ts +1 -1
  79. package/dist/util/entities.d.ts +1 -1
  80. package/dist/util/icon_synonyms.d.ts +1 -97
  81. package/dist/util/icons.d.ts +2 -2
  82. package/dist/util/navigation_utils.d.ts +2 -2
  83. package/dist/util/objects.d.ts +1 -1
  84. package/dist/util/resolutions.d.ts +13 -13
  85. package/dist/util/storage.d.ts +23 -2
  86. package/dist/util/useStorageUploadController.d.ts +1 -1
  87. package/dist/util/useTraceUpdate.d.ts +1 -0
  88. package/package.json +130 -119
  89. package/src/app/AppBar.tsx +18 -0
  90. package/src/app/Drawer.tsx +25 -0
  91. package/src/app/Scaffold.tsx +249 -0
  92. package/src/app/index.ts +4 -0
  93. package/src/app/useApp.tsx +32 -0
  94. package/src/components/ClearFilterSortButton.tsx +41 -0
  95. package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +8 -10
  96. package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +19 -18
  97. package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +10 -6
  98. package/src/components/EntityCollectionTable/PropertyTableCell.tsx +38 -34
  99. package/src/components/EntityCollectionTable/column_utils.tsx +3 -3
  100. package/src/components/EntityCollectionTable/fields/TableReferenceField.tsx +10 -2
  101. package/src/components/EntityCollectionTable/fields/TableStorageUpload.tsx +2 -2
  102. package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +29 -34
  103. package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +16 -12
  104. package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +4 -5
  105. package/src/components/EntityCollectionView/EntityCollectionView.tsx +54 -29
  106. package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +68 -0
  107. package/src/components/EntityPreview.tsx +14 -9
  108. package/src/components/EntityView.tsx +5 -5
  109. package/src/components/HomePage/DefaultHomePage.tsx +2 -2
  110. package/src/components/HomePage/NavigationCard.tsx +3 -3
  111. package/src/components/HomePage/SmallNavigationCard.tsx +5 -5
  112. package/src/components/PropertyIdCopyTooltipContent.tsx +2 -3
  113. package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +1 -0
  114. package/src/components/ReferenceWidget.tsx +22 -12
  115. package/src/components/SearchIconsView.tsx +5 -5
  116. package/src/components/SelectableTable/SelectableTable.tsx +5 -3
  117. package/src/components/SelectableTable/filters/BooleanFilterField.tsx +2 -3
  118. package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +23 -8
  119. package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +28 -6
  120. package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +35 -15
  121. package/src/components/VirtualTable/VirtualTable.tsx +38 -29
  122. package/src/components/VirtualTable/VirtualTableHeader.tsx +4 -4
  123. package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +2 -2
  124. package/src/components/VirtualTable/VirtualTableProps.tsx +6 -6
  125. package/src/components/VirtualTable/VirtualTableRow.tsx +4 -5
  126. package/src/components/VirtualTable/fields/VirtualTableDateField.tsx +1 -1
  127. package/src/components/VirtualTable/types.tsx +2 -3
  128. package/src/components/{EntityCollectionTable/internal → common}/default_entity_actions.tsx +2 -2
  129. package/src/components/common/index.ts +1 -0
  130. package/src/components/{VirtualTable/common.tsx → common/table_height.tsx} +5 -2
  131. package/src/components/common/types.tsx +4 -6
  132. package/src/components/common/useColumnsIds.tsx +10 -2
  133. package/src/components/common/useDataSourceEntityCollectionTableController.tsx +11 -0
  134. package/src/components/common/useTableSearchHelper.ts +52 -12
  135. package/src/components/index.tsx +2 -1
  136. package/src/contexts/AuthControllerContext.tsx +1 -1
  137. package/src/contexts/DialogsProvider.tsx +2 -2
  138. package/src/{components/FireCMSAppBar.tsx → core/DefaultAppBar.tsx} +51 -36
  139. package/src/core/DefaultDrawer.tsx +177 -0
  140. package/src/core/DrawerNavigationItem.tsx +62 -0
  141. package/src/core/EntityEditView.tsx +673 -134
  142. package/src/core/EntitySidePanel.tsx +1 -2
  143. package/src/core/FireCMS.tsx +38 -43
  144. package/src/core/NavigationRoutes.tsx +6 -7
  145. package/src/core/field_configs.tsx +2 -3
  146. package/src/core/index.tsx +3 -4
  147. package/src/form/PropertiesForm.tsx +81 -0
  148. package/src/form/PropertyFieldBinding.tsx +29 -7
  149. package/src/form/components/FieldHelperText.tsx +3 -3
  150. package/src/form/components/StorageItemPreview.tsx +20 -11
  151. package/src/form/components/StorageUploadProgress.tsx +3 -3
  152. package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +8 -5
  153. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +8 -5
  154. package/src/form/field_bindings/BlockFieldBinding.tsx +2 -2
  155. package/src/form/field_bindings/DateTimeFieldBinding.tsx +1 -1
  156. package/src/form/field_bindings/KeyValueFieldBinding.tsx +44 -39
  157. package/src/form/field_bindings/MapFieldBinding.tsx +11 -3
  158. package/src/form/field_bindings/MarkdownFieldBinding.tsx +2 -2
  159. package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +2 -9
  160. package/src/form/field_bindings/ReferenceFieldBinding.tsx +15 -13
  161. package/src/form/field_bindings/RepeatFieldBinding.tsx +10 -7
  162. package/src/form/field_bindings/SelectFieldBinding.tsx +3 -3
  163. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +10 -39
  164. package/src/form/field_bindings/SwitchFieldBinding.tsx +1 -1
  165. package/src/form/index.tsx +4 -4
  166. package/src/form/validation.ts +1 -17
  167. package/src/hooks/data/delete.ts +3 -3
  168. package/src/hooks/data/save.ts +4 -2
  169. package/src/hooks/data/useDataSource.tsx +1 -1
  170. package/src/hooks/data/useEntityFetch.tsx +3 -3
  171. package/src/hooks/index.tsx +3 -0
  172. package/src/hooks/useBuildLocalConfigurationPersistence.tsx +8 -10
  173. package/src/hooks/useBuildModeController.tsx +11 -5
  174. package/src/hooks/useBuildNavigationController.tsx +137 -61
  175. package/src/hooks/useProjectLog.tsx +8 -6
  176. package/src/hooks/useResolvedNavigationFrom.tsx +1 -1
  177. package/src/hooks/useValidateAuthenticator.tsx +115 -0
  178. package/src/index.ts +1 -0
  179. package/src/internal/useBuildDataSource.ts +54 -47
  180. package/src/internal/useBuildSideEntityController.tsx +88 -21
  181. package/src/preview/PropertyPreview.tsx +9 -16
  182. package/src/preview/PropertyPreviewProps.tsx +4 -8
  183. package/src/preview/components/BooleanPreview.tsx +4 -2
  184. package/src/preview/components/EnumValuesChip.tsx +1 -1
  185. package/src/preview/components/ImagePreview.tsx +21 -33
  186. package/src/preview/components/ReferencePreview.tsx +23 -23
  187. package/src/preview/components/StorageThumbnail.tsx +5 -1
  188. package/src/preview/components/UrlComponentPreview.tsx +44 -11
  189. package/src/preview/property_previews/ArrayOfMapsPreview.tsx +0 -1
  190. package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +2 -1
  191. package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +0 -1
  192. package/src/preview/property_previews/ArrayOfStringsPreview.tsx +0 -1
  193. package/src/preview/property_previews/ArrayOneOfPreview.tsx +2 -3
  194. package/src/preview/property_previews/ArrayPropertyPreview.tsx +2 -3
  195. package/src/preview/property_previews/MapPropertyPreview.tsx +5 -5
  196. package/src/preview/property_previews/StringPropertyPreview.tsx +2 -2
  197. package/src/types/auth.tsx +41 -2
  198. package/src/types/collections.ts +35 -5
  199. package/src/types/customization_controller.tsx +0 -1
  200. package/src/types/datasource.ts +24 -17
  201. package/src/types/entities.ts +9 -1
  202. package/src/types/entity_actions.tsx +16 -3
  203. package/src/types/entity_callbacks.ts +2 -2
  204. package/src/types/fields.tsx +33 -33
  205. package/src/types/index.ts +1 -1
  206. package/src/types/navigation.ts +6 -7
  207. package/src/types/plugins.tsx +18 -8
  208. package/src/types/properties.ts +22 -6
  209. package/src/types/roles.ts +41 -0
  210. package/src/types/storage.ts +12 -3
  211. package/src/types/user.ts +7 -0
  212. package/src/util/collections.ts +1 -1
  213. package/src/util/entities.ts +5 -4
  214. package/src/util/enums.ts +1 -1
  215. package/src/util/icon_list.ts +2 -2
  216. package/src/util/icon_synonyms.ts +3 -99
  217. package/src/util/navigation_utils.ts +6 -6
  218. package/src/util/objects.ts +25 -28
  219. package/src/util/permissions.ts +1 -0
  220. package/src/util/resolutions.ts +32 -31
  221. package/src/util/storage.ts +75 -21
  222. package/src/util/strings.ts +2 -2
  223. package/src/util/useStorageUploadController.tsx +21 -3
  224. package/src/util/useTraceUpdate.tsx +2 -1
  225. package/dist/components/VirtualTable/common.d.ts +0 -2
  226. package/dist/core/Drawer.d.ts +0 -23
  227. package/dist/core/Scaffold.d.ts +0 -55
  228. package/dist/core/SideEntityView.d.ts +0 -7
  229. package/dist/form/EntityForm.d.ts +0 -77
  230. package/dist/internal/useBuildCustomizationController.d.ts +0 -2
  231. package/dist/internal/useLocaleConfig.d.ts +0 -1
  232. package/dist/types/appcheck.d.ts +0 -26
  233. package/src/core/Drawer.tsx +0 -191
  234. package/src/core/Scaffold.tsx +0 -281
  235. package/src/core/SideEntityView.tsx +0 -38
  236. package/src/form/EntityForm.tsx +0 -728
  237. package/src/internal/useBuildCustomizationController.tsx +0 -5
  238. package/src/internal/useLocaleConfig.tsx +0 -18
  239. package/src/types/appcheck.ts +0 -29
@@ -1,4 +1,4 @@
1
- import { ContentPasteIcon, IconButton, Typography } from "@firecms/ui";
1
+ import { ContentCopyIcon, IconButton, Typography } from "@firecms/ui";
2
2
  import { useCallback, useState } from "react";
3
3
 
4
4
  export function PropertyIdCopyTooltipContent({ propertyId }: { propertyId: string }) {
@@ -12,9 +12,8 @@ export function PropertyIdCopyTooltipContent({ propertyId }: { propertyId: strin
12
12
  color={"disabled"}>{copied ? "Copied" : "Property ID"}</Typography>
13
13
  <Typography variant={"caption"} className={"text-white"}><code>{propertyId}</code></Typography>
14
14
  </div>
15
- {/* Copy to clipboard button*/}
16
15
  <IconButton size={"small"}>
17
- <ContentPasteIcon size={"smallest"}
16
+ <ContentCopyIcon size={"smallest"}
18
17
  className={"text-white"}
19
18
  onClick={useCallback(() => {
20
19
  navigator.clipboard.writeText(propertyId);
@@ -291,6 +291,7 @@ export function ReferenceSelectionTable<M extends Record<string, any>>(
291
291
  displayedColumnIds={displayedColumnIds}
292
292
  onEntityClick={onEntityClick}
293
293
  tableController={tableController}
294
+ enablePopupIcon={false}
294
295
  tableRowActionsBuilder={tableRowActionsBuilder}
295
296
  title={<Typography variant={"subtitle2"}>
296
297
  {collection.singularName ? `Select ${collection.singularName}` : `Select from ${collection.name}`}
@@ -4,7 +4,7 @@ import { Entity, EntityCollection, EntityReference, FilterValues } from "../type
4
4
  import { getReferenceFrom } from "../util";
5
5
  import { PreviewSize, ReferencePreview } from "../preview";
6
6
  import { useNavigationController, useReferenceDialog } from "../hooks";
7
- import { Button, cn } from "@firecms/ui";
7
+ import { Button, cls } from "@firecms/ui";
8
8
 
9
9
  export type ReferenceWidgetProps<M extends Record<string, any>> = {
10
10
  name?: string,
@@ -27,6 +27,8 @@ export type ReferenceWidgetProps<M extends Record<string, any>> = {
27
27
  forceFilter?: FilterValues<string>;
28
28
  size: PreviewSize;
29
29
  className?: string;
30
+ includeId?: boolean;
31
+ includeEntityLink?: boolean;
30
32
  };
31
33
 
32
34
  /**
@@ -43,25 +45,26 @@ export function ReferenceWidget<M extends Record<string, any>>({
43
45
  previewProperties,
44
46
  forceFilter,
45
47
  size,
46
- className
48
+ className,
49
+ includeId,
50
+ includeEntityLink
47
51
  }: ReferenceWidgetProps<M>) {
48
52
 
49
53
  const navigationController = useNavigationController();
50
54
 
51
55
  const collection: EntityCollection | undefined = useMemo(() => {
52
56
  return navigationController.getCollection(path);
53
- }, [path, navigationController]);
54
-
55
- // if (!collection) {
56
- // throw Error(`Couldn't find the corresponding collection for the path: ${path}`);
57
- // }
57
+ }, [path, navigationController.getCollection]);
58
58
 
59
59
  const onSingleEntitySelected = useCallback((entity: Entity<M> | null) => {
60
60
  if (disabled)
61
61
  return;
62
62
  if (onReferenceSelected) {
63
63
  const reference = entity ? getReferenceFrom(entity) : null;
64
- onReferenceSelected?.({ reference, entity });
64
+ onReferenceSelected?.({
65
+ reference,
66
+ entity
67
+ });
65
68
  }
66
69
  }, [disabled, onReferenceSelected]);
67
70
 
@@ -70,7 +73,10 @@ export function ReferenceWidget<M extends Record<string, any>>({
70
73
  return;
71
74
  if (onMultipleReferenceSelected) {
72
75
  const references = entities ? entities.map(e => getReferenceFrom(e)) : null;
73
- onMultipleReferenceSelected({ references, entities });
76
+ onMultipleReferenceSelected({
77
+ references,
78
+ entities
79
+ });
74
80
  }
75
81
  }, [disabled, onReferenceSelected]);
76
82
 
@@ -110,7 +116,9 @@ export function ReferenceWidget<M extends Record<string, any>>({
110
116
  reference={ref}
111
117
  disabled={disabled}
112
118
  previewProperties={previewProperties}
113
- size={size}/>
119
+ size={size}
120
+ includeId={includeId}
121
+ includeEntityLink={includeEntityLink}/>
114
122
  })}
115
123
  </div>
116
124
  } else if (value?.isEntityReference && value?.isEntityReference()) {
@@ -119,10 +127,12 @@ export function ReferenceWidget<M extends Record<string, any>>({
119
127
  onClick={onEntryClick}
120
128
  disabled={disabled}
121
129
  previewProperties={previewProperties}
122
- size={size}/>
130
+ size={size}
131
+ includeId={includeId}
132
+ includeEntityLink={includeEntityLink}/>
123
133
 
124
134
  }
125
- return <div className={cn("text-sm font-medium text-gray-500",
135
+ return <div className={cls("text-sm font-medium",
126
136
  "min-w-80 flex flex-col gap-4",
127
137
  "relative transition-colors duration-200 ease-in rounded font-medium",
128
138
  disabled ? "bg-opacity-50" : "hover:bg-opacity-75",
@@ -1,14 +1,14 @@
1
1
  import React from "react";
2
2
 
3
3
  import { coolIconKeys, debounce, Icon, IconButton, iconKeys, SearchBar, Tooltip } from "@firecms/ui";
4
- import { icon_synonyms, iconsSearch } from "../util";
4
+ import { iconSynonyms, iconsSearch } from "../util";
5
5
 
6
6
  const UPDATE_SEARCH_INDEX_WAIT_MS = 220;
7
7
 
8
- if (process.env.NODE_ENV !== "production") {
9
- Object.keys(icon_synonyms).forEach((icon: string) => {
8
+ if (iconSynonyms && process.env.NODE_ENV !== "production") {
9
+ Object.keys(iconSynonyms).forEach((icon: string) => {
10
10
  if (!iconKeys.includes(icon)) {
11
- console.warn(`The icon ${icon} no longer exists. Remove it from \`icon_synonyms\``);
11
+ console.warn(`The icon ${icon} no longer exists. Remove it from \`iconSynonyms\``);
12
12
  }
13
13
  });
14
14
  }
@@ -48,7 +48,7 @@ export function SearchIconsView({
48
48
  return (
49
49
  <>
50
50
  <SearchBar
51
- autoFocus
51
+ autoFocus={false}
52
52
  innerClassName={"w-full sticky top-0 z-10"}
53
53
  onTextSearch={(value?: string) => setQuery(value ?? "")}
54
54
  placeholder="Search for more icons…"
@@ -10,7 +10,7 @@ import {
10
10
  } from "../../types";
11
11
  import { CellRendererParams, VirtualTable, VirtualTableColumn } from "../VirtualTable";
12
12
  import { enumToObjectEntries } from "../../util";
13
- import { OnCellValueChange, OnColumnResizeParams } from "../common/types";
13
+ import { OnCellValueChange, OnColumnResizeParams } from "../common";
14
14
  import { FilterFormFieldProps } from "../VirtualTable/VirtualTableHeader";
15
15
  import { ReferenceFilterField } from "./filters/ReferenceFilterField";
16
16
  import { StringNumberFilterField } from "./filters/StringNumberFilterField";
@@ -18,6 +18,7 @@ import { BooleanFilterField } from "./filters/BooleanFilterField";
18
18
  import { DateTimeFilterField } from "./filters/DateTimeFilterField";
19
19
  import { useOutsideAlerter } from "@firecms/ui";
20
20
  import { SelectableTableContext } from "./SelectableTableContext";
21
+ import { getRowHeight } from "../common/table_height";
21
22
 
22
23
  export type SelectableTableProps<M extends Record<string, any>> = {
23
24
 
@@ -115,7 +116,7 @@ export const SelectableTable = React.memo<SelectableTableProps<any>>(
115
116
  onEntityClick,
116
117
  onColumnResize,
117
118
  hoverRow = true,
118
- size,
119
+ size = "m",
119
120
  inlineEditing = false,
120
121
  tableController:
121
122
  {
@@ -224,7 +225,7 @@ export const SelectableTable = React.memo<SelectableTableProps<any>>(
224
225
  error={dataLoadingError}
225
226
  paginationEnabled={paginationEnabled}
226
227
  onColumnResize={onColumnResize}
227
- size={size}
228
+ rowHeight={getRowHeight(size)}
228
229
  loading={dataLoading}
229
230
  filter={filterValues}
230
231
  onFilterUpdate={setFilterValues ? onFilterUpdate : undefined}
@@ -280,6 +281,7 @@ function createFilterField({
280
281
  isArray={isArray}
281
282
  path={baseProperty.path}
282
283
  title={resolvedProperty?.name}
284
+ includeId={baseProperty.includeId}
283
285
  previewProperties={baseProperty?.previewProperties}
284
286
  hidden={hidden}
285
287
  setHidden={setHidden}/>;
@@ -32,7 +32,7 @@ export function BooleanFilterField({
32
32
  const valueSet = !!value;
33
33
 
34
34
  return (
35
- <div className="w-[200px]">
35
+ <div className="w-[300px]">
36
36
  <BooleanSwitchWithLabel
37
37
  value={valueSetToTrue}
38
38
  allowIndeterminate={true}
@@ -44,6 +44,5 @@ export function BooleanFilterField({
44
44
  : `${title} is false`}
45
45
  />
46
46
  </div>
47
- )
48
- ;
47
+ );
49
48
  }
@@ -1,6 +1,6 @@
1
1
  import React, { useState } from "react";
2
2
  import { VirtualTableWhereFilterOp } from "../../VirtualTable";
3
- import { DateTimeField, Select, SelectItem } from "@firecms/ui";
3
+ import { Checkbox, DateTimeField, Label, Select, SelectItem } from "@firecms/ui";
4
4
  import { useCustomizationController } from "../../../hooks";
5
5
 
6
6
  interface DateTimeFilterFieldProps {
@@ -43,10 +43,10 @@ export function DateTimeFilterField({
43
43
 
44
44
  const [fieldOperation, fieldValue] = value || [possibleOperations[0], undefined];
45
45
  const [operation, setOperation] = useState<VirtualTableWhereFilterOp>(fieldOperation);
46
- const [internalValue, setInternalValue] = useState<Date | undefined>(fieldValue);
46
+ const [internalValue, setInternalValue] = useState<Date | null | undefined>(fieldValue);
47
47
 
48
- function updateFilter(op: VirtualTableWhereFilterOp, val: Date | undefined) {
49
- let newValue: Date | undefined = val;
48
+ function updateFilter(op: VirtualTableWhereFilterOp, val: Date | undefined | null) {
49
+ let newValue: Date | null | undefined = val;
50
50
  const prevOpIsArray = multipleSelectOperations.includes(operation);
51
51
  const newOpIsArray = multipleSelectOperations.includes(op);
52
52
  if (prevOpIsArray !== newOpIsArray) {
@@ -73,7 +73,7 @@ export function DateTimeFilterField({
73
73
 
74
74
  return (
75
75
 
76
- <div className="flex w-[440px] items-center">
76
+ <div className="flex w-[440px]">
77
77
  <div className="w-[80px]">
78
78
  <Select value={operation}
79
79
  onValueChange={(value) => {
@@ -88,19 +88,34 @@ export function DateTimeFilterField({
88
88
  </Select>
89
89
  </div>
90
90
 
91
- <div className="flex-grow ml-2">
91
+ <div className="flex-grow ml-2 flex flex-col gap-2">
92
92
 
93
93
  <DateTimeField
94
94
  mode={mode}
95
95
  size={"medium"}
96
96
  locale={locale}
97
- value={internalValue}
98
- onChange={(dateValue: Date | null) => {
97
+ value={internalValue ?? undefined}
98
+ onChange={(dateValue: Date | undefined) => {
99
99
  updateFilter(operation, dateValue === null ? undefined : dateValue);
100
100
  }}
101
101
  clearable={true}
102
102
  />
103
103
 
104
+ <Label
105
+ className="border cursor-pointer rounded-md p-2 flex items-center gap-2 [&:has(:checked)]:bg-gray-100 dark:[&:has(:checked)]:bg-gray-800"
106
+ htmlFor="null-filter"
107
+ >
108
+ <Checkbox id="null-filter"
109
+ checked={internalValue === null}
110
+ size={"small"}
111
+ onCheckedChange={(checked) => {
112
+ if (internalValue !== null)
113
+ updateFilter(operation, null);
114
+ else updateFilter(operation, undefined);
115
+ }}/>
116
+ Filter for null values
117
+ </Label>
118
+
104
119
  </div>
105
120
 
106
121
  </div>
@@ -4,7 +4,7 @@ import { Entity, EntityCollection, EntityReference } from "../../../types";
4
4
  import { ReferencePreview } from "../../../preview";
5
5
  import { getReferenceFrom } from "../../../util";
6
6
  import { useNavigationController, useReferenceDialog } from "../../../hooks";
7
- import { Button, Select, SelectItem } from "@firecms/ui";
7
+ import { Button, Checkbox, Label, Select, SelectItem } from "@firecms/ui";
8
8
 
9
9
  interface ReferenceFilterFieldProps {
10
10
  name: string,
@@ -13,6 +13,7 @@ interface ReferenceFilterFieldProps {
13
13
  isArray?: boolean;
14
14
  path?: string;
15
15
  title?: string;
16
+ includeId?: boolean;
16
17
  previewProperties?: string[];
17
18
  hidden: boolean;
18
19
  setHidden: (hidden: boolean) => void;
@@ -40,6 +41,7 @@ export function ReferenceFilterField({
40
41
  isArray,
41
42
  path,
42
43
  title,
44
+ includeId = true,
43
45
  previewProperties,
44
46
  setHidden
45
47
  }: ReferenceFilterFieldProps) {
@@ -54,7 +56,7 @@ export function ReferenceFilterField({
54
56
 
55
57
  const [fieldOperation, fieldValue] = value || [possibleOperations[0], undefined];
56
58
  const [operation, setOperation] = useState<VirtualTableWhereFilterOp>(fieldOperation);
57
- const [internalValue, setInternalValue] = useState<EntityReference | EntityReference[] | undefined>(fieldValue);
59
+ const [internalValue, setInternalValue] = useState<EntityReference | EntityReference[] | undefined | null>(fieldValue);
58
60
 
59
61
  const selectedEntityIds = internalValue
60
62
  ? (Array.isArray(internalValue) ? internalValue.map((ref) => {
@@ -65,7 +67,7 @@ export function ReferenceFilterField({
65
67
  }).filter(Boolean) as string[] : [internalValue.id])
66
68
  : [];
67
69
 
68
- function updateFilter(op: VirtualTableWhereFilterOp, val?: EntityReference | EntityReference[]) {
70
+ function updateFilter(op: VirtualTableWhereFilterOp, val?: EntityReference | EntityReference[] | null) {
69
71
 
70
72
  const prevOpIsArray = multipleSelectOperations.includes(operation);
71
73
  const newOpIsArray = multipleSelectOperations.includes(op);
@@ -134,7 +136,8 @@ export function ReferenceFilterField({
134
136
  onClick={doOpenDialog}
135
137
  reference={reference}
136
138
  hover={true}
137
- allowEntityNavigation={false}
139
+ includeId={includeId}
140
+ includeEntityLink={false}
138
141
  />
139
142
  );
140
143
  };
@@ -142,7 +145,7 @@ export function ReferenceFilterField({
142
145
  return (
143
146
 
144
147
  <div className="flex w-[440px] flex-row">
145
- <div className="w-[120px]">
148
+ <div className="w-[140px]">
146
149
  <Select value={operation}
147
150
  onValueChange={(value) => {
148
151
  updateFilter(value as VirtualTableWhereFilterOp, internalValue);
@@ -156,21 +159,40 @@ export function ReferenceFilterField({
156
159
  </Select>
157
160
  </div>
158
161
 
159
- <div className="flex-grow ml-2 h-full">
162
+ <div className="flex-grow ml-2 h-full gap-2 flex flex-col">
160
163
 
161
164
  {internalValue && Array.isArray(internalValue) && <div>
162
165
  {internalValue.map((ref, index) => buildEntry(ref))}
163
166
  </div>}
167
+
164
168
  {internalValue && !Array.isArray(internalValue) && <div>
165
169
  {buildEntry(internalValue)}
166
170
  </div>}
171
+
167
172
  {(!internalValue || (Array.isArray(internalValue) && internalValue.length === 0)) &&
168
173
  <Button onClick={doOpenDialog}
169
174
  variant={"outlined"}
175
+ size={"large"}
170
176
  className="h-full w-full">
171
177
  {multiple ? "Select references" : "Select reference"}
172
178
  </Button>
173
179
  }
180
+
181
+ {!isArray && <Label
182
+ className="border cursor-pointer rounded-md p-2 flex items-center gap-2 [&:has(:checked)]:bg-gray-100 dark:[&:has(:checked)]:bg-gray-800"
183
+ htmlFor="null-filter"
184
+ >
185
+ <Checkbox id="null-filter"
186
+ checked={internalValue === null}
187
+ size={"small"}
188
+ onCheckedChange={(checked) => {
189
+ if (internalValue !== null)
190
+ updateFilter(operation, null);
191
+ else updateFilter(operation, undefined);
192
+ }}/>
193
+ Filter for null values
194
+ </Label>}
195
+
174
196
  </div>
175
197
 
176
198
  </div>
@@ -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
+ };