@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,5 +1,6 @@
1
1
  import React, { useEffect, useRef, useState } from "react";
2
2
  import { useDebouncedCallback } from "../../../util";
3
+ import { cls, focusedDisabled } from "@firecms/ui";
3
4
 
4
5
  export function VirtualTableNumberInput(props: {
5
6
  error: Error | undefined;
@@ -65,7 +66,7 @@ export function VirtualTableNumberInput(props: {
65
66
  return (
66
67
  <input
67
68
  ref={ref}
68
- className="w-full text-right p-0 m-0 bg-transparent border-none resize-none outline-none font-normal leading-normal text-unset"
69
+ className={cls("w-full text-right p-0 m-0 bg-transparent border-none resize-none outline-none font-normal leading-normal text-unset", focusedDisabled)}
69
70
  style={{
70
71
  textAlign: align
71
72
  }}
@@ -1,5 +1,5 @@
1
1
  import { EnumValueConfig } from "../../../types";
2
- import { ArrayEnumPreview, EnumValuesChip } from "../../../preview";
2
+ import { EnumValuesChip } from "../../../preview";
3
3
  import React, { useCallback, useEffect } from "react";
4
4
  import { MultiSelect, MultiSelectItem, Select, SelectItem } from "@firecms/ui";
5
5
 
@@ -18,9 +18,7 @@ export function VirtualTableSelect(props: {
18
18
  }) {
19
19
 
20
20
  const {
21
- name,
22
21
  enumValues,
23
- error,
24
22
  internalValue,
25
23
  disabled,
26
24
  small,
@@ -41,6 +39,7 @@ export function VirtualTableSelect(props: {
41
39
  }, [focused, ref]);
42
40
 
43
41
  const onChange = useCallback((updatedValue: string | string[]) => {
42
+ console.trace("onChange");
44
43
  if (valueType === "number") {
45
44
  if (multiple) {
46
45
  const newValue = (updatedValue as string[]).map((v) => parseFloat(v));
@@ -58,37 +57,27 @@ export function VirtualTableSelect(props: {
58
57
  }
59
58
  }, [multiple, updateValue, valueType]);
60
59
 
61
- const renderValue = (enumKey: string | number, index: number) => {
62
- if (multiple && Array.isArray(enumKey)) {
63
- return <ArrayEnumPreview
64
- key={`${enumKey}-${index}`}
65
- value={enumKey}
66
- name={name}
67
- enumValues={enumValues}
68
- size={small ? "small" : "medium"}/>;
69
- } else {
70
- return <EnumValuesChip
71
- key={`${enumKey}-${index}`}
72
- enumKey={enumKey}
73
- enumValues={enumValues}
74
- size={small ? "small" : "medium"}/>;
75
- }
60
+ const renderValue = (enumKey?: string | number) => {
61
+ return <EnumValuesChip
62
+ key={`${enumKey}`}
63
+ enumKey={String(enumKey)}
64
+ enumValues={enumValues}
65
+ size={small ? "small" : "medium"}/>;
76
66
  };
67
+
77
68
  return (
78
69
  multiple
79
70
  ? <MultiSelect
80
71
  inputRef={ref}
81
- containerClassName="w-full h-full"
82
72
  className="w-full h-full p-0 bg-transparent"
83
73
  position={"item-aligned"}
84
74
  disabled={disabled}
85
- padding={false}
86
- includeFocusOutline={false}
75
+ includeClear={false}
76
+ useChips={false}
87
77
  value={validValue
88
78
  ? ((internalValue as any[]).map(v => v.toString()))
89
79
  : ([])}
90
- onMultiValueChange={onChange}
91
- renderValue={renderValue}>
80
+ onValueChange={onChange}>
92
81
  {enumValues?.map((enumConfig) => (
93
82
  <MultiSelectItem
94
83
  key={enumConfig.id}
@@ -105,14 +94,11 @@ export function VirtualTableSelect(props: {
105
94
  className="w-full h-full p-0 bg-transparent"
106
95
  position={"item-aligned"}
107
96
  disabled={disabled}
108
- multiple={multiple}
109
97
  padding={false}
110
- includeFocusOutline={false}
111
98
  value={validValue
112
- ? (multiple ? (internalValue as any[]).map(v => v.toString()) : internalValue?.toString())
113
- : (multiple ? [] : "")}
99
+ ? internalValue?.toString()
100
+ : ""}
114
101
  onValueChange={onChange}
115
- onMultiValueChange={onChange}
116
102
  renderValue={renderValue}>
117
103
  {enumValues?.map((enumConfig) => (
118
104
  <SelectItem
@@ -106,3 +106,16 @@ export function getColumnKeysForProperty(property: ResolvedProperty, key: string
106
106
  disabled: disabled || Boolean(property.disabled) || Boolean(property.readOnly)
107
107
  }];
108
108
  }
109
+
110
+ export function getFormFieldKeys(collection: EntityCollection): string[] {
111
+ const propertyKeys = Object.keys(collection.properties);
112
+ const additionalFields = collection.additionalFields ?? [];
113
+ const allKeys = [
114
+ ...propertyKeys,
115
+ ...additionalFields.map((field) => field.key)
116
+ ];
117
+ if (collection.propertiesOrder) {
118
+ return collection.propertiesOrder.filter(key => allKeys.includes(key));
119
+ }
120
+ return allKeys;
121
+ }
@@ -80,6 +80,18 @@ export function useDataSourceEntityCollectionTableController<M extends Record<st
80
80
  const [searchString, setSearchString] = React.useState<string | undefined>();
81
81
  const [itemCount, setItemCount] = React.useState<number | undefined>(paginationEnabled ? pageSize : undefined);
82
82
 
83
+ const checkFilterCombination = useCallback((filterValues: FilterValues<any>,
84
+ sortBy?: [string, "asc" | "desc"]) => {
85
+ if (!dataSource.isFilterCombinationValid)
86
+ return true;
87
+ return dataSource.isFilterCombinationValid({
88
+ path: resolvedPath,
89
+ collection,
90
+ filterValues,
91
+ sortBy
92
+ })
93
+ }, []);
94
+
83
95
  const initialSortInternal = useMemo(() => {
84
96
  if (initialSort && forceFilter && !checkFilterCombination(forceFilter, initialSort)) {
85
97
  console.warn("Initial sort is not compatible with the force filter. Ignoring initial sort");
@@ -108,18 +120,6 @@ export function useDataSourceEntityCollectionTableController<M extends Record<st
108
120
  const [dataLoadingError, setDataLoadingError] = useState<Error | undefined>();
109
121
  const [noMoreToLoad, setNoMoreToLoad] = useState<boolean>(false);
110
122
 
111
- const checkFilterCombination = useCallback((filterValues: FilterValues<any>,
112
- sortBy?: [string, "asc" | "desc"]) => {
113
- if (!dataSource.isFilterCombinationValid)
114
- return true;
115
- return dataSource.isFilterCombinationValid({
116
- path: resolvedPath,
117
- collection,
118
- filterValues,
119
- sortBy
120
- })
121
- }, []);
122
-
123
123
  const clearFilter = useCallback(() => setFilterValues(forceFilter ?? undefined), [forceFilter]);
124
124
 
125
125
  const updateFilterValues = useCallback((updatedFilter: FilterValues<Extract<keyof M, string>> | undefined) => {
@@ -1,7 +1,7 @@
1
1
  import { useState } from "react";
2
2
 
3
3
  import { EntityCollection } from "../../types";
4
- import { useCustomizationController, useFireCMSContext } from "../../hooks";
4
+ import { useCustomizationController, useDataSource, useFireCMSContext } from "../../hooks";
5
5
 
6
6
  export interface UseTableSearchHelperParams<M extends Record<string, any>> {
7
7
  collection: EntityCollection<M>;
@@ -9,27 +9,58 @@ export interface UseTableSearchHelperParams<M extends Record<string, any>> {
9
9
  parentCollectionIds?: string[];
10
10
  }
11
11
 
12
- export function useTableSearchHelper<M extends Record<string, any>>({ collection, fullPath, parentCollectionIds }: UseTableSearchHelperParams<M>) {
12
+ export function useTableSearchHelper<M extends Record<string, any>>({
13
+ collection,
14
+ fullPath,
15
+ parentCollectionIds
16
+ }: UseTableSearchHelperParams<M>) {
13
17
 
14
18
  const context = useFireCMSContext();
15
19
  const customizationController = useCustomizationController();
20
+ const dataSource = useDataSource();
16
21
 
17
22
  const [textSearchLoading, setTextSearchLoading] = useState<boolean>(false);
18
23
  const [textSearchInitialised, setTextSearchInitialised] = useState<boolean>(false);
24
+
19
25
  let onTextSearchClick: (() => void) | undefined;
20
26
  let textSearchEnabled = Boolean(collection.textSearchEnabled);
21
- if (customizationController?.plugins) {
22
- const addTextSearchClickListener = customizationController.plugins?.find(p => Boolean(p.collectionView?.onTextSearchClick));
27
+
28
+ const props = {
29
+ context,
30
+ path: fullPath,
31
+ databaseId: collection.databaseId,
32
+ collection,
33
+ parentCollectionIds
34
+ };
35
+
36
+ const searchBlocked = customizationController.plugins?.find(p => {
37
+ return p.collectionView?.blockSearch?.(props);
38
+ });
39
+
40
+ const addTextSearchClickListener = Boolean(dataSource?.initTextSearch) || customizationController.plugins?.find(p => Boolean(p.collectionView?.onTextSearchClick));
41
+
42
+ if (addTextSearchClickListener) {
23
43
 
24
44
  onTextSearchClick = addTextSearchClickListener
25
45
  ? () => {
26
46
  setTextSearchLoading(true);
27
- Promise.all(customizationController.plugins?.map(p => {
28
- if (p.collectionView?.onTextSearchClick)
29
- return p.collectionView.onTextSearchClick({ context, path: fullPath, collection, parentCollectionIds });
30
- return Promise.resolve(true);
31
- }) as Promise<boolean>[])
32
- .then((res) => {
47
+ const promises: Promise<boolean>[] = [];
48
+ if (dataSource?.initTextSearch && !searchBlocked) {
49
+ promises.push(dataSource.initTextSearch(props));
50
+ }
51
+ if (searchBlocked) {
52
+ customizationController.plugins?.forEach(p => {
53
+ if (p.collectionView?.onTextSearchClick)
54
+ promises.push(p.collectionView.onTextSearchClick({
55
+ context,
56
+ path: fullPath,
57
+ collection,
58
+ parentCollectionIds
59
+ }));
60
+ })
61
+ }
62
+ return Promise.all(promises)
63
+ .then((res: boolean[]) => {
33
64
  if (res.every(Boolean)) setTextSearchInitialised(true);
34
65
  })
35
66
  .finally(() => setTextSearchLoading(false));
@@ -39,9 +70,19 @@ export function useTableSearchHelper<M extends Record<string, any>>({ collection
39
70
  customizationController.plugins?.forEach(p => {
40
71
  if (!textSearchEnabled)
41
72
  if (p.collectionView?.showTextSearchBar) {
42
- textSearchEnabled = p.collectionView.showTextSearchBar({ context, path: fullPath, collection, parentCollectionIds });
73
+ textSearchEnabled = p.collectionView.showTextSearchBar({
74
+ context,
75
+ path: fullPath,
76
+ collection,
77
+ parentCollectionIds
78
+ });
43
79
  }
44
80
  })
45
81
  }
46
- return { textSearchLoading, textSearchInitialised, onTextSearchClick, textSearchEnabled };
82
+ return {
83
+ textSearchLoading,
84
+ textSearchInitialised,
85
+ onTextSearchClick,
86
+ textSearchEnabled
87
+ };
47
88
  }
@@ -19,6 +19,7 @@ export * from "./EntityCollectionView/EntityCollectionViewActions";
19
19
  export * from "./EntityCollectionView/useSelectionController";
20
20
 
21
21
  export * from "./PropertyConfigBadge";
22
+ export * from "./PropertyIdCopyTooltip";
22
23
 
23
24
  export * from "./EntityCollectionTable";
24
25
  export * from "./NotFoundPage";
@@ -29,7 +30,7 @@ export * from "./DeleteConfirmationDialog";
29
30
 
30
31
  export * from "./FireCMSLogo";
31
32
 
32
- export * from "./FireCMSAppBar";
33
+ export * from "../core/DefaultAppBar";
33
34
 
34
35
  export * from "./ArrayContainer";
35
36
  export * from "./ReferenceWidget";
@@ -18,14 +18,14 @@ export const DialogsProvider: React.FC<PropsWithChildren<{}>> = ({ children }) =
18
18
  if (dialogEntries.length === 0)
19
19
  return;
20
20
 
21
- const updatedPanels = [...dialogEntries.slice(0, -1)];
21
+ const updatedPanels = [...dialogEntriesRef.current.slice(0, -1)];
22
22
  updateDialogEntries(updatedPanels);
23
23
 
24
24
  }, [dialogEntries]);
25
25
 
26
26
  const open = useCallback((dialogEntry: DialogControllerEntryProps) => {
27
27
 
28
- const updatedPanels = [...dialogEntries, dialogEntry];
28
+ const updatedPanels = [...dialogEntriesRef.current, dialogEntry];
29
29
  updateDialogEntries(updatedPanels);
30
30
 
31
31
  return {
@@ -1,6 +1,6 @@
1
1
  import React from "react";
2
2
 
3
- import { Link as ReactLink } from "react-router-dom";
3
+ import { Link as ReactLink, useNavigate } from "react-router-dom";
4
4
  import { ErrorBoundary, FireCMSLogo } from "../components";
5
5
  import {
6
6
  Avatar,
@@ -16,8 +16,9 @@ import {
16
16
  } from "@firecms/ui";
17
17
  import { useAuthController, useLargeLayout, useModeController, useNavigationController } from "../hooks";
18
18
  import { User } from "../types";
19
+ import { useApp } from "../app/useApp";
19
20
 
20
- export type FireCMSAppBarProps<ADDITIONAL_PROPS = object> = {
21
+ export type DefaultAppBarProps<ADDITIONAL_PROPS = object> = {
21
22
 
22
23
  title?: React.ReactNode;
23
24
  /**
@@ -29,12 +30,8 @@ export type FireCMSAppBarProps<ADDITIONAL_PROPS = object> = {
29
30
 
30
31
  dropDownActions?: React.ReactNode;
31
32
 
32
- includeDrawer?: boolean;
33
-
34
33
  includeModeToggle?: boolean;
35
34
 
36
- drawerOpen: boolean;
37
-
38
35
  className?: string;
39
36
 
40
37
  style?: React.CSSProperties;
@@ -48,24 +45,24 @@ export type FireCMSAppBarProps<ADDITIONAL_PROPS = object> = {
48
45
  * This component renders the main app bar of FireCMS.
49
46
  * You will likely not need to use this component directly.
50
47
  *
51
- * @param title
52
- * @param toolbarExtraWidget
53
- * @param drawerOpen
54
- * @constructor
48
+
55
49
  */
56
- export const FireCMSAppBar = function FireCMSAppBar({
50
+ export const DefaultAppBar = function DefaultAppBar({
57
51
  title,
58
52
  endAdornment,
59
53
  startAdornment,
60
- drawerOpen,
61
54
  dropDownActions,
62
- includeDrawer,
63
55
  includeModeToggle = true,
64
56
  className,
65
57
  style,
66
- logo,
67
58
  user: userProp
68
- }: FireCMSAppBarProps) {
59
+ }: DefaultAppBarProps) {
60
+
61
+ const {
62
+ hasDrawer,
63
+ drawerOpen,
64
+ logo
65
+ } = useApp();
69
66
  const navigation = useNavigationController();
70
67
 
71
68
  const authController = useAuthController();
@@ -74,6 +71,8 @@ export const FireCMSAppBar = function FireCMSAppBar({
74
71
  toggleMode
75
72
  } = useModeController();
76
73
 
74
+ const navigate = useNavigate();
75
+
77
76
  const largeLayout = useLargeLayout();
78
77
 
79
78
  const user = userProp ?? authController.user;
@@ -96,20 +95,15 @@ export const FireCMSAppBar = function FireCMSAppBar({
96
95
  return (
97
96
  <div
98
97
  style={style}
99
- className={cls("pr-2",
98
+ className={cls("w-full h-16 transition-all ease-in duration-75 fixed",
100
99
  {
101
- "ml-[17rem]": drawerOpen && largeLayout,
102
- "ml-16": includeDrawer && !(drawerOpen && largeLayout),
103
- "h-16": true,
100
+ "pl-[17rem]": drawerOpen && largeLayout,
101
+ "pl-20": hasDrawer && !(drawerOpen && largeLayout),
104
102
  "z-10": largeLayout,
105
- "transition-all": true,
106
- "ease-in": true,
107
- "duration-75": true,
108
- "w-full": !includeDrawer,
109
- "w-[calc(100%-64px)]": includeDrawer && !(drawerOpen && largeLayout),
110
- "w-[calc(100%-17rem)]": includeDrawer && (drawerOpen && largeLayout),
103
+ // "w-full": !hasDrawer,
104
+ // "w-[calc(100%-64px)]": hasDrawer && !(drawerOpen && largeLayout),
105
+ // "w-[calc(100%-17rem)]": hasDrawer && (drawerOpen && largeLayout),
111
106
  "duration-150": drawerOpen && largeLayout,
112
- fixed: true
113
107
  },
114
108
  className)}>
115
109
 
@@ -121,16 +115,16 @@ export const FireCMSAppBar = function FireCMSAppBar({
121
115
  to={navigation?.basePath ?? "/"}
122
116
  >
123
117
  <div className={"flex flex-row gap-4"}>
124
- {!includeDrawer && (logo
118
+ {!hasDrawer && (logo
125
119
  ? <img src={logo}
126
120
  alt="Logo"
127
- className={cls("w-[32px] h-[32px]")}/>
121
+ className={cls("w-[32px] h-[32px] object-contain")}/>
128
122
  : <FireCMSLogo width={"32px"} height={"32px"}/>)}
129
123
 
130
124
  {typeof title === "string"
131
125
  ? <Typography variant="subtitle1"
132
126
  noWrap
133
- className={"ml-2 !font-medium"}>
127
+ className={cls("transition-all", drawerOpen ? "ml-2" : "")}>
134
128
  {title}
135
129
  </Typography>
136
130
  : title}
@@ -169,7 +163,11 @@ export const FireCMSAppBar = function FireCMSAppBar({
169
163
 
170
164
  {dropDownActions}
171
165
 
172
- {!dropDownActions && <MenuItem onClick={authController.signOut}>
166
+ {!dropDownActions && <MenuItem onClick={async () => {
167
+ await authController.signOut();
168
+ // replace current route with home
169
+ navigate("/");
170
+ }}>
173
171
  <LogoutIcon/>
174
172
  Log Out
175
173
  </MenuItem>}
@@ -0,0 +1,183 @@
1
+ import React, { useCallback } from "react";
2
+
3
+ import { useLargeLayout, useNavigationController } from "../hooks";
4
+
5
+ import { Link, useNavigate } from "react-router-dom";
6
+ import { CMSAnalyticsEvent, TopNavigationEntry, TopNavigationResult } from "../types";
7
+ import { IconForView } from "../util";
8
+ import { cls, IconButton, Menu, MenuItem, MoreVertIcon, Tooltip, Typography } from "@firecms/ui";
9
+ import { useAnalyticsController } from "../hooks/useAnalyticsController";
10
+ import { DrawerNavigationItem } from "./DrawerNavigationItem";
11
+ import { FireCMSLogo } from "../components";
12
+ import { useApp } from "../app/useApp";
13
+
14
+ /**
15
+ * Default drawer used in the CMS
16
+ * @group Core
17
+ */
18
+ export function DefaultDrawer({
19
+ className,
20
+ style,
21
+ }: {
22
+ className?: string
23
+ style?: React.CSSProperties,
24
+ }) {
25
+
26
+ const {
27
+ drawerHovered,
28
+ drawerOpen,
29
+ closeDrawer,
30
+ logo
31
+ } = useApp();
32
+
33
+ const [adminMenuOpen, setAdminMenuOpen] = React.useState(false);
34
+
35
+ const analyticsController = useAnalyticsController();
36
+ const navigation = useNavigationController();
37
+
38
+ const tooltipsOpen = drawerHovered && !drawerOpen && !adminMenuOpen;
39
+ const largeLayout = useLargeLayout();
40
+ const navigate = useNavigate();
41
+
42
+ if (!navigation.topLevelNavigation)
43
+ throw Error("Navigation not ready in Drawer");
44
+
45
+ const {
46
+ navigationEntries,
47
+ groups
48
+ }: TopNavigationResult = navigation.topLevelNavigation;
49
+
50
+ const adminViews = navigationEntries.filter(e => e.type === "admin") ?? [];
51
+ const groupsWithoutAdmin = groups.filter(g => g !== "Admin");
52
+
53
+ const buildGroupHeader = useCallback((group?: string) => {
54
+ if (!drawerOpen) return <div className="w-full"/>;
55
+ return <div
56
+ className="pl-6 pr-8 py-4 flex flex-row items-center">
57
+ <Typography variant={"caption"}
58
+ color={"secondary"}
59
+ className="font-medium flex-grow line-clamp-1">
60
+ {group ? group.toUpperCase() : "Views".toUpperCase()}
61
+ </Typography>
62
+
63
+ </div>;
64
+ }, [drawerOpen]);
65
+
66
+ const onClick = (view: TopNavigationEntry) => {
67
+ const eventName: CMSAnalyticsEvent = view.type === "collection"
68
+ ? "drawer_navigate_to_collection"
69
+ : (view.type === "view" ? "drawer_navigate_to_view" : "unmapped_event");
70
+ analyticsController.onAnalyticsEvent?.(eventName, { url: view.url });
71
+ if (!largeLayout)
72
+ closeDrawer();
73
+ };
74
+
75
+ return (
76
+ <>
77
+ <div className={cls("flex flex-col h-full relative flex-grow w-full", className)} style={style}>
78
+
79
+ <DrawerLogo logo={logo}/>
80
+
81
+ <div className={"mt-4 flex-grow overflow-scroll no-scrollbar"}
82
+ style={{
83
+ maskImage: "linear-gradient(to bottom, transparent 0, black 20px, black calc(100% - 20px), transparent 100%)",
84
+ }}>
85
+
86
+ {groupsWithoutAdmin.map((group) => (
87
+ <div
88
+ className={"bg-gray-50 dark:bg-gray-800 dark:bg-opacity-30 my-4 rounded-lg ml-4"}
89
+ key={`drawer_group_${group}`}>
90
+ {buildGroupHeader(group)}
91
+ {Object.values(navigationEntries)
92
+ .filter(e => e.group === group)
93
+ .map((view, index) =>
94
+ <DrawerNavigationItem
95
+ key={`navigation_${index}`}
96
+ icon={<IconForView collectionOrView={view.collection ?? view.view} size={"small"}/>}
97
+ tooltipsOpen={tooltipsOpen}
98
+ adminMenuOpen={adminMenuOpen}
99
+ drawerOpen={drawerOpen}
100
+ onClick={() => onClick(view)}
101
+ url={view.url}
102
+ name={view.name}/>)}
103
+ </div>
104
+ ))}
105
+
106
+ </div>
107
+
108
+ {adminViews.length > 0 && <Menu
109
+ side={"right"}
110
+ open={adminMenuOpen}
111
+ onOpenChange={setAdminMenuOpen}
112
+ trigger={
113
+ <IconButton
114
+ shape={"square"}
115
+ className={"m-4 text-gray-900 dark:text-white w-fit"}>
116
+ <Tooltip title={"Admin"}
117
+ open={tooltipsOpen}
118
+ side={"right"} sideOffset={28}>
119
+ <MoreVertIcon/>
120
+ </Tooltip>
121
+ {drawerOpen && <div
122
+ className={cls(
123
+ drawerOpen ? "opacity-100" : "opacity-0 hidden",
124
+ "mx-4 font-inherit text-inherit"
125
+ )}>
126
+ ADMIN
127
+ </div>}
128
+ </IconButton>}
129
+ >
130
+ {adminViews.map((entry, index) =>
131
+ <MenuItem
132
+ onClick={(event) => {
133
+ event.preventDefault();
134
+ navigate(entry.path);
135
+ }}
136
+ key={`navigation_${index}`}>
137
+ {<IconForView collectionOrView={entry.view}/>}
138
+ {entry.name}
139
+ </MenuItem>)}
140
+
141
+ </Menu>}
142
+ </div>
143
+
144
+ </>
145
+ );
146
+ }
147
+
148
+ /**
149
+ * This is the logo displayed in the drawer
150
+ * It expands when the drawer is open.
151
+ *
152
+ * @param logo
153
+
154
+ */
155
+ export function DrawerLogo({ logo }: {
156
+ logo?: string;
157
+ }) {
158
+
159
+ const navigation = useNavigationController();
160
+ const { drawerOpen } = useApp();
161
+ return <div
162
+ style={{
163
+ transition: "padding 100ms cubic-bezier(0.4, 0, 0.6, 1) 0ms",
164
+ padding: drawerOpen ? "32px 144px 0px 24px" : "72px 12px 0px 12px"
165
+ }}
166
+ className={cls("cursor-pointer ml-4")}>
167
+
168
+ <Tooltip title={"Home"}
169
+ sideOffset={20}
170
+ side="right">
171
+ <Link
172
+ to={navigation.basePath}>
173
+ {logo
174
+ ? <img src={logo}
175
+ alt="Logo"
176
+ className={cls("max-w-full max-h-full",
177
+ drawerOpen ?? "w-[112px] h-[112px]")}/>
178
+ : <FireCMSLogo/>}
179
+
180
+ </Link>
181
+ </Tooltip>
182
+ </div>;
183
+ }