@firecms/core 3.0.0-beta.7 → 3.0.0-beta.9

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 (216) hide show
  1. package/dist/app/AppBar.d.ts +12 -0
  2. package/dist/app/Drawer.d.ts +17 -0
  3. package/dist/app/Scaffold.d.ts +30 -0
  4. package/dist/app/index.d.ts +4 -0
  5. package/dist/app/useApp.d.ts +16 -0
  6. package/dist/components/ArrayContainer.d.ts +2 -1
  7. package/dist/components/CircularProgressCenter.d.ts +1 -1
  8. package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +0 -1
  9. package/dist/components/EntityCollectionTable/fields/TableReferenceField.d.ts +1 -1
  10. package/dist/components/EntityCollectionTable/internal/popup_field/PopupFormField.d.ts +1 -1
  11. package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +1 -1
  12. package/dist/components/EntityPreview.d.ts +1 -1
  13. package/dist/components/ErrorView.d.ts +1 -1
  14. package/dist/components/HomePage/DefaultHomePage.d.ts +1 -1
  15. package/dist/components/HomePage/NavigationCardBinding.d.ts +1 -1
  16. package/dist/components/PropertyIdCopyTooltip.d.ts +8 -0
  17. package/dist/components/VirtualTable/VirtualTableProps.d.ts +14 -6
  18. package/dist/components/common/useColumnsIds.d.ts +2 -1
  19. package/dist/components/index.d.ts +2 -1
  20. package/dist/{components/FireCMSAppBar.d.ts → core/DefaultAppBar.d.ts} +3 -8
  21. package/dist/core/DefaultDrawer.d.ts +19 -0
  22. package/dist/core/DrawerNavigationItem.d.ts +2 -1
  23. package/dist/core/EntityEditView.d.ts +18 -4
  24. package/dist/core/FireCMS.d.ts +1 -1
  25. package/dist/core/NavigationRoutes.d.ts +2 -2
  26. package/dist/core/index.d.ts +2 -2
  27. package/dist/form/PropertyFieldBinding.d.ts +1 -1
  28. package/dist/form/components/FieldHelperText.d.ts +3 -3
  29. package/dist/form/components/FormikArrayContainer.d.ts +2 -1
  30. package/dist/form/components/LabelWithIcon.d.ts +1 -1
  31. package/dist/form/components/LabelWithIconAndTooltip.d.ts +15 -0
  32. package/dist/form/components/StorageItemPreview.d.ts +4 -4
  33. package/dist/form/components/index.d.ts +1 -0
  34. package/dist/form/field_bindings/ArrayCustomShapedFieldBinding.d.ts +1 -1
  35. package/dist/form/field_bindings/ArrayOfReferencesFieldBinding.d.ts +1 -1
  36. package/dist/form/field_bindings/BlockFieldBinding.d.ts +1 -1
  37. package/dist/form/field_bindings/KeyValueFieldBinding.d.ts +1 -1
  38. package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
  39. package/dist/form/field_bindings/MarkdownEditorFieldBinding.d.ts +11 -0
  40. package/dist/form/field_bindings/{MultiSelectBinding.d.ts → MultiSelectFieldBinding.d.ts} +1 -1
  41. package/dist/form/field_bindings/ReadOnlyFieldBinding.d.ts +1 -1
  42. package/dist/form/field_bindings/RepeatFieldBinding.d.ts +1 -1
  43. package/dist/form/field_bindings/SelectFieldBinding.d.ts +1 -1
  44. package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +3 -5
  45. package/dist/form/field_bindings/TextFieldBinding.d.ts +1 -1
  46. package/dist/form/index.d.ts +3 -5
  47. package/dist/form/useClearRestoreValue.d.ts +2 -2
  48. package/dist/hooks/useProjectLog.d.ts +2 -2
  49. package/dist/index.d.ts +1 -0
  50. package/dist/index.es.js +14434 -11300
  51. package/dist/index.es.js.map +1 -1
  52. package/dist/index.umd.js +19987 -587
  53. package/dist/index.umd.js.map +1 -1
  54. package/dist/preview/PropertyPreviewProps.d.ts +6 -1
  55. package/dist/preview/components/EnumValuesChip.d.ts +1 -1
  56. package/dist/preview/components/ReferencePreview.d.ts +1 -1
  57. package/dist/preview/components/StorageThumbnail.d.ts +2 -1
  58. package/dist/preview/components/UrlComponentPreview.d.ts +2 -1
  59. package/dist/types/auth.d.ts +2 -2
  60. package/dist/types/collections.d.ts +26 -3
  61. package/dist/types/datasource.d.ts +53 -30
  62. package/dist/types/entities.d.ts +1 -0
  63. package/dist/types/entity_overrides.d.ts +2 -2
  64. package/dist/types/fields.d.ts +47 -41
  65. package/dist/types/navigation.d.ts +1 -0
  66. package/dist/types/plugins.d.ts +11 -3
  67. package/dist/types/properties.d.ts +25 -20
  68. package/dist/types/side_dialogs_controller.d.ts +10 -0
  69. package/dist/types/storage.d.ts +75 -0
  70. package/dist/util/entities.d.ts +1 -1
  71. package/dist/util/icon_list.d.ts +5 -1
  72. package/dist/util/icons.d.ts +3 -2
  73. package/dist/util/index.d.ts +1 -0
  74. package/dist/util/plurals.d.ts +0 -2
  75. package/dist/util/property_utils.d.ts +1 -1
  76. package/dist/util/resolutions.d.ts +15 -1
  77. package/dist/util/storage.d.ts +23 -2
  78. package/dist/util/useStorageUploadController.d.ts +3 -3
  79. package/package.json +18 -29
  80. package/src/app/AppBar.tsx +18 -0
  81. package/src/app/Drawer.tsx +25 -0
  82. package/src/{core → app}/Scaffold.tsx +71 -122
  83. package/src/app/index.ts +4 -0
  84. package/src/app/useApp.tsx +32 -0
  85. package/src/components/ArrayContainer.tsx +15 -10
  86. package/src/components/CircularProgressCenter.tsx +1 -1
  87. package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +11 -18
  88. package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +2 -2
  89. package/src/components/EntityCollectionTable/PropertyTableCell.tsx +4 -2
  90. package/src/components/EntityCollectionTable/fields/TableReferenceField.tsx +21 -14
  91. package/src/components/EntityCollectionTable/fields/TableStorageUpload.tsx +12 -4
  92. package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +17 -19
  93. package/src/components/EntityCollectionTable/internal/EntityTableCellActions.tsx +19 -7
  94. package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +5 -6
  95. package/src/components/EntityCollectionView/EntityCollectionView.tsx +33 -29
  96. package/src/components/EntityCollectionView/useSelectionController.tsx +19 -7
  97. package/src/components/EntityPreview.tsx +30 -31
  98. package/src/components/ErrorView.tsx +1 -1
  99. package/src/components/HomePage/DefaultHomePage.tsx +24 -18
  100. package/src/components/HomePage/NavigationCardBinding.tsx +1 -1
  101. package/src/components/HomePage/SmallNavigationCard.tsx +1 -2
  102. package/src/components/PropertyIdCopyTooltip.tsx +48 -0
  103. package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +7 -6
  104. package/src/components/SearchIconsView.tsx +5 -2
  105. package/src/components/SelectableTable/SelectableTable.tsx +2 -4
  106. package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +1 -1
  107. package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +54 -7
  108. package/src/components/VirtualTable/VirtualTable.tsx +36 -10
  109. package/src/components/VirtualTable/VirtualTableCell.tsx +1 -9
  110. package/src/components/VirtualTable/VirtualTableProps.tsx +17 -8
  111. package/src/components/VirtualTable/fields/VirtualTableDateField.tsx +3 -3
  112. package/src/components/VirtualTable/fields/VirtualTableInput.tsx +2 -1
  113. package/src/components/VirtualTable/fields/VirtualTableNumberInput.tsx +2 -1
  114. package/src/components/VirtualTable/fields/VirtualTableSelect.tsx +14 -28
  115. package/src/components/common/useColumnsIds.tsx +13 -0
  116. package/src/components/common/useDataSourceEntityCollectionTableController.tsx +12 -12
  117. package/src/components/common/useTableSearchHelper.ts +53 -12
  118. package/src/components/index.tsx +2 -1
  119. package/src/contexts/DialogsProvider.tsx +2 -2
  120. package/src/{components/FireCMSAppBar.tsx → core/DefaultAppBar.tsx} +28 -30
  121. package/src/core/DefaultDrawer.tsx +183 -0
  122. package/src/core/DrawerNavigationItem.tsx +31 -27
  123. package/src/core/EntityEditView.tsx +712 -145
  124. package/src/core/EntitySidePanel.tsx +0 -1
  125. package/src/core/FireCMS.tsx +2 -2
  126. package/src/core/NavigationRoutes.tsx +4 -4
  127. package/src/core/SideDialogs.tsx +1 -0
  128. package/src/core/field_configs.tsx +5 -5
  129. package/src/core/index.tsx +2 -2
  130. package/src/form/PropertyFieldBinding.tsx +53 -19
  131. package/src/form/components/CustomIdField.tsx +4 -2
  132. package/src/form/components/FieldHelperText.tsx +4 -4
  133. package/src/form/components/FormikArrayContainer.tsx +4 -1
  134. package/src/form/components/LabelWithIcon.tsx +27 -19
  135. package/src/form/components/LabelWithIconAndTooltip.tsx +28 -0
  136. package/src/form/components/StorageItemPreview.tsx +20 -10
  137. package/src/form/components/StorageUploadProgress.tsx +0 -1
  138. package/src/form/components/index.tsx +1 -0
  139. package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +26 -15
  140. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +28 -25
  141. package/src/form/field_bindings/BlockFieldBinding.tsx +13 -11
  142. package/src/form/field_bindings/DateTimeFieldBinding.tsx +17 -14
  143. package/src/form/field_bindings/KeyValueFieldBinding.tsx +48 -42
  144. package/src/form/field_bindings/MapFieldBinding.tsx +17 -17
  145. package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +150 -0
  146. package/src/form/field_bindings/{MultiSelectBinding.tsx → MultiSelectFieldBinding.tsx} +25 -20
  147. package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +9 -14
  148. package/src/form/field_bindings/ReferenceFieldBinding.tsx +27 -18
  149. package/src/form/field_bindings/RepeatFieldBinding.tsx +32 -19
  150. package/src/form/field_bindings/SelectFieldBinding.tsx +17 -10
  151. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +33 -43
  152. package/src/form/field_bindings/SwitchFieldBinding.tsx +9 -5
  153. package/src/form/field_bindings/TextFieldBinding.tsx +26 -23
  154. package/src/form/index.tsx +4 -9
  155. package/src/form/useClearRestoreValue.tsx +2 -2
  156. package/src/form/validation.ts +1 -17
  157. package/src/hooks/data/delete.ts +2 -1
  158. package/src/hooks/data/save.ts +5 -2
  159. package/src/hooks/data/useDataSource.tsx +11 -3
  160. package/src/hooks/useBuildNavigationController.tsx +10 -3
  161. package/src/hooks/useProjectLog.tsx +18 -7
  162. package/src/index.ts +1 -0
  163. package/src/internal/useBuildDataSource.ts +69 -74
  164. package/src/internal/useBuildSideDialogsController.tsx +1 -0
  165. package/src/internal/useBuildSideEntityController.tsx +17 -4
  166. package/src/internal/useUnsavedChangesDialog.tsx +3 -1
  167. package/src/preview/PropertyPreview.tsx +7 -4
  168. package/src/preview/PropertyPreviewProps.tsx +7 -1
  169. package/src/preview/components/BooleanPreview.tsx +1 -1
  170. package/src/preview/components/EnumValuesChip.tsx +1 -1
  171. package/src/preview/components/ImagePreview.tsx +24 -34
  172. package/src/preview/components/ReferencePreview.tsx +2 -12
  173. package/src/preview/components/StorageThumbnail.tsx +5 -1
  174. package/src/preview/components/UrlComponentPreview.tsx +44 -11
  175. package/src/preview/property_previews/ArrayOfMapsPreview.tsx +1 -1
  176. package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +1 -1
  177. package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +1 -1
  178. package/src/preview/property_previews/ArrayOneOfPreview.tsx +2 -2
  179. package/src/preview/property_previews/ArrayPropertyPreview.tsx +1 -1
  180. package/src/preview/property_previews/MapPropertyPreview.tsx +1 -1
  181. package/src/preview/property_previews/SkeletonPropertyComponent.tsx +2 -2
  182. package/src/preview/property_previews/StringPropertyPreview.tsx +2 -2
  183. package/src/preview/util.ts +2 -2
  184. package/src/types/auth.tsx +2 -2
  185. package/src/types/collections.ts +29 -4
  186. package/src/types/customization_controller.tsx +0 -1
  187. package/src/types/datasource.ts +62 -43
  188. package/src/types/entities.ts +2 -0
  189. package/src/types/entity_overrides.tsx +2 -2
  190. package/src/types/fields.tsx +51 -45
  191. package/src/types/navigation.ts +1 -0
  192. package/src/types/plugins.tsx +12 -3
  193. package/src/types/properties.ts +25 -19
  194. package/src/types/side_dialogs_controller.tsx +13 -0
  195. package/src/types/storage.ts +82 -0
  196. package/src/util/entities.ts +5 -4
  197. package/src/util/icon_list.ts +14 -9
  198. package/src/util/icons.tsx +8 -2
  199. package/src/util/index.ts +1 -0
  200. package/src/util/objects.ts +17 -7
  201. package/src/util/permissions.ts +1 -0
  202. package/src/util/plurals.ts +0 -2
  203. package/src/util/property_utils.tsx +1 -1
  204. package/src/util/references.ts +3 -0
  205. package/src/util/resolutions.ts +43 -11
  206. package/src/util/storage.ts +79 -21
  207. package/src/util/useStorageUploadController.tsx +33 -7
  208. package/dist/components/PropertyIdCopyTooltipContent.d.ts +0 -3
  209. package/dist/core/Drawer.d.ts +0 -16
  210. package/dist/core/Scaffold.d.ts +0 -51
  211. package/dist/form/EntityForm.d.ts +0 -77
  212. package/dist/form/field_bindings/MarkdownFieldBinding.d.ts +0 -9
  213. package/src/components/PropertyIdCopyTooltipContent.tsx +0 -27
  214. package/src/core/Drawer.tsx +0 -139
  215. package/src/form/EntityForm.tsx +0 -736
  216. package/src/form/field_bindings/MarkdownFieldBinding.tsx +0 -695
@@ -1,29 +1,27 @@
1
- import React, { useCallback, useEffect, useState } from "react";
1
+ import React, { useCallback, useEffect, useRef, useState } from "react";
2
2
 
3
3
  import { useCustomizationController, useFireCMSContext, useNavigationController } from "../../hooks";
4
- import { CMSAnalyticsEvent, PluginGenericProps, PluginHomePageAdditionalCardsProps } from "../../types";
4
+ import {
5
+ CMSAnalyticsEvent,
6
+ PluginGenericProps,
7
+ PluginHomePageAdditionalCardsProps,
8
+ TopNavigationEntry
9
+ } from "../../types";
5
10
 
6
11
  import { toArray } from "../../util/arrays";
7
12
  import { NavigationGroup } from "./NavigationGroup";
8
13
  import { NavigationCardBinding } from "./NavigationCardBinding";
9
14
 
10
- // @ts-ignore
11
- import * as JsSearch from "js-search";
15
+ import Fuse from "fuse.js"
12
16
 
13
17
  import { Container, SearchBar } from "@firecms/ui";
14
18
  import { FavouritesView } from "./FavouritesView";
15
19
  import { useRestoreScroll } from "../../internal/useRestoreScroll";
16
20
 
17
- const search = new JsSearch.Search("url");
18
- search.addIndex("name");
19
- search.addIndex("description");
20
- search.addIndex("group");
21
- search.addIndex("path");
22
-
23
21
  /**
24
22
  * Default entry view for the CMS. This component renders navigation cards
25
23
  * for each collection defined in the navigation.
26
- * @constructor
24
+
27
25
  * @group Components
28
26
  */
29
27
  export function DefaultHomePage({
@@ -49,6 +47,8 @@ export function DefaultHomePage({
49
47
  const customizationController = useCustomizationController();
50
48
  const navigationController = useNavigationController();
51
49
 
50
+ const fuse = useRef<Fuse<TopNavigationEntry> | null>(null);
51
+
52
52
  if (!navigationController.topLevelNavigation)
53
53
  throw Error("Navigation not ready in FireCMSHomePage");
54
54
 
@@ -64,13 +64,16 @@ export function DefaultHomePage({
64
64
  } = navigationController.topLevelNavigation;
65
65
 
66
66
  const [filteredUrls, setFilteredUrls] = useState<string[] | null>(null);
67
+ const performingSearch = Boolean(filteredUrls);
67
68
 
68
69
  const filteredNavigationEntries = filteredUrls
69
- ? navigationEntries.filter((entry) => filteredUrls.includes(entry.url))
70
+ ? filteredUrls.map(url => navigationEntries.find(e => e.url === url)).filter(Boolean) as TopNavigationEntry[]
70
71
  : navigationEntries;
71
72
 
72
73
  useEffect(() => {
73
- search.addDocuments(navigationEntries);
74
+ fuse.current = new Fuse(navigationEntries, {
75
+ keys: ["name", "description", "group", "path"]
76
+ });
74
77
  }, [navigationEntries]);
75
78
 
76
79
  const updateSearchResults = useCallback(
@@ -78,12 +81,15 @@ export function DefaultHomePage({
78
81
  if (!value || value === "") {
79
82
  setFilteredUrls(null);
80
83
  } else {
81
- const searchResult = search.search(value);
82
- setFilteredUrls(searchResult.map((e: any) => e.url));
84
+ const searchResult = fuse.current?.search(value);
85
+ if (searchResult) {
86
+ setFilteredUrls(searchResult.map((e) => e.item.url));
87
+ }
83
88
  }
84
89
  }, []);
85
90
 
86
- const allGroups: Array<string | undefined> = [...groups];
91
+ const filteredGroups = filteredUrls ? filteredNavigationEntries.map(entry => entry.group) : [];
92
+ const allGroups: Array<string | undefined> = filteredUrls ? filteredGroups.filter((group, index) => filteredGroups.indexOf(group) === index) : [...groups];
87
93
  if (filteredNavigationEntries.filter(e => !e.group).length > 0 || filteredNavigationEntries.length === 0) {
88
94
  allGroups.push(undefined);
89
95
  }
@@ -139,7 +145,7 @@ export function DefaultHomePage({
139
145
  {additionalActions}
140
146
  </div>
141
147
 
142
- <FavouritesView hidden={Boolean(filteredUrls)}/>
148
+ <FavouritesView hidden={performingSearch}/>
143
149
 
144
150
  {additionalChildrenStart}
145
151
 
@@ -163,7 +169,7 @@ export function DefaultHomePage({
163
169
 
164
170
  const thisGroupCollections = filteredNavigationEntries
165
171
  .filter((entry) => entry.group === group || (!entry.group && group === undefined));
166
- if (thisGroupCollections.length === 0 && AdditionalCards.length === 0)
172
+ if (thisGroupCollections.length === 0 && (AdditionalCards.length === 0 || performingSearch))
167
173
  return null;
168
174
  return (
169
175
  <NavigationGroup
@@ -19,7 +19,7 @@ import { SmallNavigationCard } from "./SmallNavigationCard";
19
19
  * @param name
20
20
  * @param description
21
21
  * @param onClick
22
- * @constructor
22
+
23
23
  */
24
24
  export function NavigationCardBinding({
25
25
  path,
@@ -1,4 +1,4 @@
1
- import { ArrowForwardIcon, cardClickableMixin, cardMixin, cls, focusedMixin, Typography, } from "@firecms/ui";
1
+ import { ArrowForwardIcon, cardClickableMixin, cardMixin, cls, Typography, } from "@firecms/ui";
2
2
 
3
3
  import { Link } from "react-router-dom";
4
4
 
@@ -21,7 +21,6 @@ export function SmallNavigationCard({
21
21
  tabIndex={0}
22
22
  className={cls(cardMixin,
23
23
  cardClickableMixin,
24
- focusedMixin,
25
24
  "cursor-pointer flex flex-row items-center px-4 py-2 text-inherit dark:text-inherit visited:text-inherit visited:dark:text-inherit hover:text-inherit hover:dark:text-inherit ")}
26
25
  to={url}
27
26
  >
@@ -0,0 +1,48 @@
1
+ import { ContentCopyIcon, IconButton, Tooltip, Typography } from "@firecms/ui";
2
+ import { useCallback, useState } from "react";
3
+
4
+ export function PropertyIdCopyTooltip({
5
+ propertyKey,
6
+ className,
7
+ children
8
+ }: {
9
+ propertyKey: string,
10
+ className?: string,
11
+ children: React.ReactNode
12
+ }) {
13
+ return <Tooltip title={<PropertyIdCopyTooltipContent propertyKey={propertyKey}/>}
14
+ delayDuration={800}
15
+ side={"top"}
16
+ asChild={false}
17
+ align={"start"}
18
+ sideOffset={8}
19
+ className={className}>
20
+ {children}
21
+ </Tooltip>
22
+
23
+ }
24
+
25
+ export function PropertyIdCopyTooltipContent({ propertyKey }: { propertyKey: string }) {
26
+
27
+ const [copied, setCopied] = useState(false);
28
+
29
+ return (
30
+ <div className={"flex flex-row gap-2 items-center justify-center text-white"}>
31
+ <div>
32
+ <Typography variant={"caption"} className={"min-w-20 text-slate-400"}
33
+ color={"disabled"}>{copied ? "Copied" : "Property ID"}</Typography>
34
+ <Typography variant={"caption"} className={"text-white"}><code>{propertyKey}</code></Typography>
35
+ </div>
36
+ <IconButton size={"small"}>
37
+ <ContentCopyIcon size={"smallest"}
38
+ className={"text-white"}
39
+ onClick={useCallback(() => {
40
+ navigator.clipboard.writeText(propertyKey);
41
+ setCopied(true);
42
+ setTimeout(() => setCopied(false), 2000);
43
+ }, [propertyKey])}
44
+ />
45
+ </IconButton>
46
+ </div>
47
+ );
48
+ }
@@ -16,7 +16,7 @@ import {
16
16
  } from "../../hooks";
17
17
  import { ErrorView } from "../ErrorView";
18
18
  import { AddIcon, Button, DialogActions, Typography } from "@firecms/ui";
19
- import { canCreateEntity, fullPathToCollectionSegments, resolveCollection } from "../../util";
19
+ import { canCreateEntity, IconForView, resolveCollection } from "../../util";
20
20
  import { useSelectionController } from "../EntityCollectionView/useSelectionController";
21
21
  import { useColumnIds, useTableSearchHelper } from "../common";
22
22
  import { useSideDialogContext } from "../../core";
@@ -109,6 +109,7 @@ export function ReferenceSelectionTable<M extends Record<string, any>>(
109
109
 
110
110
  const fullPath = navigation.resolveAliasesFrom(pathInput);
111
111
 
112
+ console.trace("Opening reference dialog for path " + fullPath);
112
113
  const dataSource = useDataSource(collection);
113
114
 
114
115
  const [entitiesDisplayedFirst, setEntitiesDisplayedFirst] = useState<Entity<any>[]>([]);
@@ -247,7 +248,6 @@ export function ReferenceSelectionTable<M extends Record<string, any>>(
247
248
  error={"Could not find collection with id " + collection}/>
248
249
  }
249
250
 
250
- // eslint-disable-next-line react-hooks/rules-of-hooks
251
251
  const resolvedCollection = useMemo(() => resolveCollection({
252
252
  collection: collection,
253
253
  path: fullPath,
@@ -255,10 +255,8 @@ export function ReferenceSelectionTable<M extends Record<string, any>>(
255
255
  fields: customizationController.propertyConfigs
256
256
  }), [collection, customizationController.propertyConfigs, fullPath]);
257
257
 
258
- // eslint-disable-next-line react-hooks/rules-of-hooks
259
258
  const displayedColumnIds = useColumnIds(resolvedCollection, false);
260
259
 
261
- // eslint-disable-next-line react-hooks/rules-of-hooks
262
260
  const tableController = useDataSourceEntityCollectionTableController<M>({
263
261
  fullPath,
264
262
  collection,
@@ -272,7 +270,6 @@ export function ReferenceSelectionTable<M extends Record<string, any>>(
272
270
  onTextSearchClick,
273
271
  textSearchEnabled
274
272
  } =
275
- // eslint-disable-next-line react-hooks/rules-of-hooks
276
273
  useTableSearchHelper({
277
274
  collection,
278
275
  fullPath,
@@ -293,7 +290,11 @@ export function ReferenceSelectionTable<M extends Record<string, any>>(
293
290
  tableController={tableController}
294
291
  enablePopupIcon={false}
295
292
  tableRowActionsBuilder={tableRowActionsBuilder}
296
- title={<Typography variant={"subtitle2"}>
293
+ title={<Typography variant={"subtitle2"} className={"flex flex-row gap-2"}>
294
+ <IconForView
295
+ size={"small"}
296
+ collectionOrView={collection}
297
+ className={"text-gray-300 dark:text-gray-600"}/>
297
298
  {collection.singularName ? `Select ${collection.singularName}` : `Select from ${collection.name}`}
298
299
  </Typography>}
299
300
  defaultSize={collection.defaultSize}
@@ -31,7 +31,9 @@ export function SearchIconsView({
31
31
  setKeys(null);
32
32
  } else {
33
33
  const searchResult = iconsSearch.search(value);
34
- setKeys(searchResult.map((e: any) => e.key));
34
+ const limit = 50;
35
+ const limited = searchResult.slice(0, limit);
36
+ setKeys(limited.map((e) => e.item.key));
35
37
  }
36
38
  }, UPDATE_SEARCH_INDEX_WAIT_MS), []
37
39
  );
@@ -57,7 +59,8 @@ export function SearchIconsView({
57
59
  <div className={"flex max-w-full flex-wrap mt-4"}>
58
60
  {icons.map((icon: string) => {
59
61
  return (
60
- <Tooltip title={icon} key={icon}>
62
+ <Tooltip title={icon} key={icon}
63
+ asChild={true}>
61
64
  <IconButton
62
65
  shape={"square"}
63
66
  toggled={selectedIcon === icon}
@@ -128,8 +128,6 @@ export const SelectableTable = React.memo<SelectableTableProps<any>>(
128
128
  setFilterValues,
129
129
  sortBy,
130
130
  setSortBy,
131
- setSearchString,
132
- clearFilter,
133
131
  itemCount,
134
132
  setItemCount,
135
133
  pageSize = 50,
@@ -223,7 +221,6 @@ export const SelectableTable = React.memo<SelectableTableProps<any>>(
223
221
  onEndReached={loadNextPage}
224
222
  onResetPagination={resetPagination}
225
223
  error={dataLoadingError}
226
- paginationEnabled={paginationEnabled}
227
224
  onColumnResize={onColumnResize}
228
225
  rowHeight={getRowHeight(size)}
229
226
  loading={dataLoading}
@@ -248,7 +245,8 @@ export const SelectableTable = React.memo<SelectableTableProps<any>>(
248
245
  );
249
246
 
250
247
  },
251
- equal
248
+ () => false,
249
+ // equal
252
250
  );
253
251
 
254
252
  function createFilterField({
@@ -95,7 +95,7 @@ export function DateTimeFilterField({
95
95
  size={"medium"}
96
96
  locale={locale}
97
97
  value={internalValue ?? undefined}
98
- onChange={(dateValue: Date | undefined) => {
98
+ onChange={(dateValue: Date | null) => {
99
99
  updateFilter(operation, dateValue === null ? undefined : dateValue);
100
100
  }}
101
101
  clearable={true}
@@ -1,7 +1,17 @@
1
1
  import React, { useState } from "react";
2
2
  import { EnumValuesChip } from "../../../preview";
3
3
  import { VirtualTableWhereFilterOp } from "../../VirtualTable";
4
- import { Checkbox, ClearIcon, IconButton, Label, Select, SelectItem, TextField } from "@firecms/ui";
4
+ import {
5
+ Checkbox,
6
+ ClearIcon,
7
+ IconButton,
8
+ Label,
9
+ MultiSelect,
10
+ MultiSelectItem,
11
+ Select,
12
+ SelectItem,
13
+ TextField
14
+ } from "@firecms/ui";
5
15
  import { EnumValueConfig } from "../../../types";
6
16
 
7
17
  interface StringNumberFilterFieldProps {
@@ -82,6 +92,7 @@ export function StringNumberFilterField({
82
92
  }
83
93
 
84
94
  const multiple = multipleSelectOperations.includes(operation);
95
+
85
96
  return (
86
97
 
87
98
  <div className="flex w-[440px]">
@@ -117,17 +128,14 @@ export function StringNumberFilterField({
117
128
  </IconButton>}
118
129
  />}
119
130
 
120
- {enumValues &&
131
+ {enumValues && !multiple &&
121
132
  <Select
122
133
  position={"item-aligned"}
123
- value={internalValue !== undefined
124
- ? (Array.isArray(internalValue) ? internalValue.map(e => String(e)) : String(internalValue))
125
- : isArray ? [] : ""}
134
+ value={typeof internalValue === "string" ? internalValue : ""}
126
135
  onValueChange={(value) => {
127
136
  if (value !== "")
128
137
  updateFilter(operation, dataType === "number" ? parseInt(value as string) : value as string)
129
138
  }}
130
- multiple={multiple}
131
139
  endAdornment={internalValue && <IconButton
132
140
  className="absolute right-2 top-3"
133
141
  onClick={(e) => updateFilter(operation, undefined)}>
@@ -136,6 +144,8 @@ export function StringNumberFilterField({
136
144
  renderValue={(enumKey) => {
137
145
  if (enumKey === null)
138
146
  return "Filter for null values";
147
+ if (enumKey === undefined)
148
+ return null;
139
149
 
140
150
  return <EnumValuesChip
141
151
  key={`select_value_${name}_${enumKey}`}
@@ -144,7 +154,7 @@ export function StringNumberFilterField({
144
154
  size={"small"}/>;
145
155
  }}>
146
156
  {enumValues.map((enumConfig) => (
147
- <SelectItem key={`select_value_${name}_${enumConfig.id}`}
157
+ <SelectItem key={`select_item_${name}_${enumConfig.id}`}
148
158
  value={String(enumConfig.id)}>
149
159
  <EnumValuesChip
150
160
  enumKey={String(enumConfig.id)}
@@ -155,6 +165,43 @@ export function StringNumberFilterField({
155
165
  </Select>
156
166
  }
157
167
 
168
+ {enumValues && multiple &&
169
+ <MultiSelect
170
+ position={"item-aligned"}
171
+ value={Array.isArray(internalValue) ? internalValue.map(e => String(e)) : []}
172
+ onValueChange={(value) => {
173
+ updateFilter(operation, dataType === "number" ? value.map(v => parseInt(v)) : value)
174
+ }}
175
+ multiple={multiple}
176
+ endAdornment={internalValue && <IconButton
177
+ className="absolute right-2 top-3"
178
+ onClick={(e) => updateFilter(operation, undefined)}>
179
+ <ClearIcon/>
180
+ </IconButton>}
181
+ // renderValues={(enumKeys) => {
182
+ // console.log("renderValues", enumKeys);
183
+ // if (enumKeys === null)
184
+ // return "Filter for null values";
185
+ //
186
+ // return enumKeys.map(key => <EnumValuesChip
187
+ // key={`select_value_${name}_${enumKeys}`}
188
+ // enumKey={key}
189
+ // enumValues={enumValues}
190
+ // size={"small"}/>);
191
+ // }}
192
+ >
193
+ {enumValues.map((enumConfig) => (
194
+ <MultiSelectItem key={`select_value_${name}_${enumConfig.id}`}
195
+ value={String(enumConfig.id)}>
196
+ <EnumValuesChip
197
+ enumKey={String(enumConfig.id)}
198
+ enumValues={enumValues}
199
+ size={"small"}/>
200
+ </MultiSelectItem>
201
+ ))}
202
+ </MultiSelect>
203
+ }
204
+
158
205
  {!isArray && <Label
159
206
  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
207
  htmlFor="null-filter"
@@ -91,6 +91,7 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
91
91
  data,
92
92
  onResetPagination,
93
93
  onEndReached,
94
+ endOffset = 600,
94
95
  rowHeight = 54,
95
96
  columns: columnsProp,
96
97
  onRowClick,
@@ -107,9 +108,11 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
107
108
  hoverRow,
108
109
  createFilterField,
109
110
  rowClassName,
111
+ style,
110
112
  className,
111
113
  endAdornment,
112
- AddColumnComponent
114
+ AddColumnComponent,
115
+ debug
113
116
  }: VirtualTableProps<T>) {
114
117
 
115
118
  const sortByProperty: string | undefined = sortBy ? sortBy[0] : undefined;
@@ -127,10 +130,14 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
127
130
  const [measureRef, bounds] = useMeasure();
128
131
 
129
132
  const onColumnResizeInternal = useCallback((params: OnVirtualTableColumnResizeParams) => {
133
+ if (debug)
134
+ console.log("onColumnResizeInternal", params);
130
135
  setColumns(columns.map((column) => column.key === params.column.key ? params.column : column));
131
136
  }, [columns]);
132
137
 
133
138
  const onColumnResizeEndInternal = useCallback((params: OnVirtualTableColumnResizeParams) => {
139
+ if (debug)
140
+ console.log("onColumnResizeEndInternal", params);
134
141
  setColumns(columns.map((column) => column.key === params.column.key ? params.column : column));
135
142
  if (onColumnResize) {
136
143
  onColumnResize(params);
@@ -141,10 +148,14 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
141
148
  const filterRef = useRef<VirtualTableFilterValues<any> | undefined>();
142
149
 
143
150
  useEffect(() => {
151
+ if (debug)
152
+ console.log("Filter updated", filterInput);
144
153
  filterRef.current = filterInput;
145
154
  }, [filterInput]);
146
155
 
147
156
  const scrollToTop = useCallback(() => {
157
+ if (debug)
158
+ console.log("scrollToTop");
148
159
  endReachCallbackThreshold.current = 0;
149
160
  if (tableRef.current) {
150
161
  // scrollRef.current = [scrollRef.current[0], 0];
@@ -154,6 +165,9 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
154
165
 
155
166
  const onColumnSort = useCallback((key: string) => {
156
167
 
168
+ if (debug)
169
+ console.log("onColumnSort", key);
170
+
157
171
  const isDesc = sortByProperty === key && currentSort === "desc";
158
172
  const isAsc = sortByProperty === key && currentSort === "asc";
159
173
  const newSort = isAsc ? "desc" : (isDesc ? undefined : "asc");
@@ -180,21 +194,21 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
180
194
  scrollToTop();
181
195
  }, [checkFilterCombination, currentSort, onFilterUpdate, onResetPagination, onSortByUpdate, scrollToTop, sortByProperty]);
182
196
 
183
- const resetSort = useCallback(() => {
184
- endReachCallbackThreshold.current = 0;
185
- if (onSortByUpdate)
186
- onSortByUpdate(undefined);
187
- }, [onSortByUpdate]);
188
-
189
197
  const maxScroll = Math.max((data?.length ?? 0) * rowHeight - bounds.height, 0);
198
+ if (debug)
199
+ console.log("maxScroll", maxScroll);
200
+
190
201
  const onEndReachedInternal = useCallback((scrollOffset: number) => {
191
- if (onEndReached && (data?.length ?? 0) > 0 && scrollOffset > endReachCallbackThreshold.current + 600) {
202
+ if (debug)
203
+ console.log("onEndReachedInternal", scrollOffset, endReachCallbackThreshold.current + endOffset);
204
+ if (onEndReached && (data?.length ?? 0) > 0 && scrollOffset > endReachCallbackThreshold.current + endOffset) {
192
205
  endReachCallbackThreshold.current = scrollOffset;
193
206
  onEndReached();
194
207
  }
195
208
  }, [data?.length, onEndReached]);
196
209
 
197
210
  const onScroll = useCallback(({
211
+ scrollDirection,
198
212
  scrollOffset,
199
213
  scrollUpdateWasRequested
200
214
  }: {
@@ -202,11 +216,19 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
202
216
  scrollOffset: number,
203
217
  scrollUpdateWasRequested: boolean;
204
218
  }) => {
205
- if (!scrollUpdateWasRequested && (scrollOffset >= maxScroll - 600))
219
+ if(debug)
220
+ console.log("onScroll", {
221
+ scrollDirection,
222
+ scrollOffset,
223
+ scrollUpdateWasRequested
224
+ });
225
+ if (!scrollUpdateWasRequested && (scrollOffset >= maxScroll - endOffset))
206
226
  onEndReachedInternal(scrollOffset);
207
227
  }, [maxScroll, onEndReachedInternal]);
208
228
 
209
229
  const onFilterUpdateInternal = useCallback((column: VirtualTableColumn, filterForProperty?: [VirtualTableWhereFilterOp, any]) => {
230
+ if(debug)
231
+ console.log("onFilterUpdateInternal", column, filterForProperty);
210
232
 
211
233
  endReachCallbackThreshold.current = 0;
212
234
  const filter = filterRef.current;
@@ -239,7 +261,7 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
239
261
  const empty = !loading && (data?.length ?? 0) === 0;
240
262
  const customView = error
241
263
  ? <CenteredView maxWidth={"2xl"}
242
- className="flex flex-col gap-2">
264
+ className="flex flex-col gap-2">
243
265
 
244
266
  <Typography variant={"h6"}>
245
267
  {"Error fetching data from the data source"}
@@ -271,10 +293,14 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
271
293
  AddColumnComponent
272
294
  };
273
295
 
296
+ if(debug)
297
+ console.log("VirtualTable render", virtualListController);
298
+
274
299
  // useTraceUpdate(virtualListController);
275
300
  return (
276
301
  <div
277
302
  ref={measureRef}
303
+ style={style}
278
304
  className={cls("h-full w-full", className)}>
279
305
  <VirtualListContext.Provider
280
306
  value={virtualListController}>
@@ -16,7 +16,7 @@ type VirtualTableCellProps<T extends any> = {
16
16
  };
17
17
 
18
18
  export const VirtualTableCell = React.memo<VirtualTableCellProps<any>>(
19
- function VirtualTableCell<T extends any>(props: VirtualTableCellProps<T>) {
19
+ function VirtualTableCell<T>(props: VirtualTableCellProps<T>) {
20
20
  // @ts-ignore
21
21
  return props.rowData && props.cellRenderer(
22
22
  {
@@ -30,14 +30,6 @@ export const VirtualTableCell = React.memo<VirtualTableCellProps<any>>(
30
30
  width: props.column.width
31
31
  } as CellRendererParams<T>
32
32
  );
33
- // return props.rowData && <props.cellRenderer
34
- // rowData={props.rowData}
35
- // rowIndex={props.rowIndex}
36
- // isScrolling={false}
37
- // column={props.column}
38
- // columns={props.columns}
39
- // columnIndex={props.columnIndex}
40
- // width={props.column.width}/>
41
33
  },
42
34
  (a, b) => {
43
35
  return equal(a.rowData, b.rowData) &&
@@ -31,11 +31,6 @@ export interface VirtualTableProps<T extends Record<string, any>> {
31
31
  */
32
32
  cellRenderer: React.ComponentType<CellRendererParams<T>>;
33
33
 
34
- /**
35
- * If enabled, content is loaded in batch
36
- */
37
- paginationEnabled?: boolean;
38
-
39
34
  /**
40
35
  * Set this callback if you want to support some combinations
41
36
  * of filter combinations only.
@@ -50,6 +45,11 @@ export interface VirtualTableProps<T extends Record<string, any>> {
50
45
  */
51
46
  onEndReached?: () => void;
52
47
 
48
+ /**
49
+ * Offset in pixels where the onEndReached callback is triggered
50
+ */
51
+ endOffset?: number;
52
+
53
53
  /**
54
54
  * When the pagination should be reset. E.g. the filters or sorting
55
55
  * has been reset.
@@ -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
  */
@@ -142,9 +147,14 @@ export interface VirtualTableProps<T extends Record<string, any>> {
142
147
  */
143
148
  AddColumnComponent?: React.ComponentType;
144
149
 
150
+ /**
151
+ * Debug mode
152
+ */
153
+ debug?: boolean;
154
+
145
155
  }
146
156
 
147
- export type CellRendererParams<T extends any = any> = {
157
+ export type CellRendererParams<T = any> = {
148
158
  column: VirtualTableColumn;
149
159
  columns: VirtualTableColumn[];
150
160
  columnIndex: number;
@@ -158,7 +168,7 @@ export type CellRendererParams<T extends any = any> = {
158
168
  * @see Table
159
169
  * @group Components
160
170
  */
161
- export interface VirtualTableColumn<CustomProps extends any = any> {
171
+ export interface VirtualTableColumn<CustomProps = any> {
162
172
 
163
173
  /**
164
174
  * Data key for the cell value, could be "a.b.c"
@@ -232,7 +242,6 @@ export type OnVirtualTableColumnResizeParams = {
232
242
  column: VirtualTableColumn
233
243
  };
234
244
 
235
-
236
245
  /**
237
246
  * @see Table
238
247
  * @group Components
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
- import { DateTimeField } from "@firecms/ui";
2
+ import { cls, DateTimeField, focusedDisabled } from "@firecms/ui";
3
3
  import { useCustomizationController } from "../../../hooks";
4
4
 
5
5
  export function VirtualTableDateField(props: {
@@ -28,8 +28,8 @@ export function VirtualTableDateField(props: {
28
28
  onChange={(dateValue) => updateValue(dateValue ?? null)}
29
29
  size={"medium"}
30
30
  invisible={true}
31
- className={"w-full h-full"}
32
- inputClassName={"w-full h-full"}
31
+ inputClassName={cls("w-full h-full", focusedDisabled)}
32
+ className={cls("w-full h-full", focusedDisabled)}
33
33
  mode={mode}
34
34
  locale={locale}
35
35
  />
@@ -1,7 +1,7 @@
1
1
  import React, { useEffect, useRef, useState } from "react";
2
2
 
3
3
  import { useDebouncedCallback } from "../../../util";
4
- import { TextareaAutosize } from "@firecms/ui";
4
+ import { focusedDisabled, TextareaAutosize } from "@firecms/ui";
5
5
 
6
6
  export function VirtualTableInput(props: {
7
7
  error: Error | undefined;
@@ -58,6 +58,7 @@ export function VirtualTableInput(props: {
58
58
 
59
59
  return (
60
60
  <TextareaAutosize
61
+ className={focusedDisabled}
61
62
  ref={ref}
62
63
  style={{
63
64
  padding: 0,