@firecms/core 3.0.0-beta.4.pre.2 → 3.0.0-beta.6

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 (109) hide show
  1. package/README.md +1 -1
  2. package/dist/components/ClearFilterSortButton.d.ts +5 -0
  3. package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +11 -11
  4. package/dist/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +1 -1
  5. package/dist/components/EntityCollectionTable/internal/CollectionTableToolbar.d.ts +1 -4
  6. package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +11 -1
  7. package/dist/components/EntityCollectionView/EntityCollectionViewStartActions.d.ts +11 -0
  8. package/dist/components/EntityPreview.d.ts +2 -2
  9. package/dist/components/SelectableTable/SelectableTable.d.ts +1 -1
  10. package/dist/components/common/types.d.ts +1 -1
  11. package/dist/contexts/AuthControllerContext.d.ts +1 -1
  12. package/dist/form/components/ErrorFocus.d.ts +1 -1
  13. package/dist/hooks/data/delete.d.ts +2 -2
  14. package/dist/hooks/data/save.d.ts +1 -1
  15. package/dist/hooks/data/useDataSource.d.ts +1 -1
  16. package/dist/hooks/data/useEntityFetch.d.ts +3 -3
  17. package/dist/hooks/index.d.ts +1 -0
  18. package/dist/hooks/useBuildNavigationController.d.ts +1 -2
  19. package/dist/hooks/useProjectLog.d.ts +2 -2
  20. package/dist/hooks/useValidateAuthenticator.d.ts +21 -0
  21. package/dist/index.es.js +3948 -3737
  22. package/dist/index.es.js.map +1 -1
  23. package/dist/index.umd.js +5 -5
  24. package/dist/index.umd.js.map +1 -1
  25. package/dist/internal/useBuildDataSource.d.ts +1 -16
  26. package/dist/internal/useRestoreScroll.d.ts +1 -1
  27. package/dist/preview/PropertyPreviewProps.d.ts +1 -4
  28. package/dist/types/auth.d.ts +30 -1
  29. package/dist/types/collections.d.ts +8 -4
  30. package/dist/types/datasource.d.ts +3 -6
  31. package/dist/types/entities.d.ts +5 -1
  32. package/dist/types/entity_callbacks.d.ts +2 -2
  33. package/dist/types/index.d.ts +1 -1
  34. package/dist/types/navigation.d.ts +4 -4
  35. package/dist/types/plugins.d.ts +5 -3
  36. package/dist/types/properties.d.ts +2 -2
  37. package/dist/types/roles.d.ts +31 -0
  38. package/dist/types/storage.d.ts +11 -3
  39. package/dist/types/user.d.ts +5 -0
  40. package/dist/util/collections.d.ts +1 -1
  41. package/dist/util/entities.d.ts +1 -1
  42. package/dist/util/navigation_utils.d.ts +2 -2
  43. package/dist/util/resolutions.d.ts +5 -5
  44. package/dist/util/useTraceUpdate.d.ts +1 -0
  45. package/package.json +23 -20
  46. package/src/components/ClearFilterSortButton.tsx +41 -0
  47. package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +10 -11
  48. package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +1 -1
  49. package/src/components/EntityCollectionTable/PropertyTableCell.tsx +16 -19
  50. package/src/components/EntityCollectionTable/fields/TableReferenceField.tsx +1 -1
  51. package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +27 -32
  52. package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +11 -6
  53. package/src/components/EntityCollectionView/EntityCollectionView.tsx +28 -5
  54. package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +68 -0
  55. package/src/components/EntityPreview.tsx +5 -2
  56. package/src/components/EntityView.tsx +1 -1
  57. package/src/components/HomePage/DefaultHomePage.tsx +2 -2
  58. package/src/components/HomePage/NavigationCard.tsx +1 -1
  59. package/src/components/ReferenceWidget.tsx +1 -1
  60. package/src/components/SelectableTable/SelectableTable.tsx +1 -1
  61. package/src/components/SelectableTable/filters/BooleanFilterField.tsx +2 -3
  62. package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +23 -8
  63. package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +24 -5
  64. package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +35 -15
  65. package/src/components/VirtualTable/VirtualTable.tsx +28 -20
  66. package/src/components/VirtualTable/fields/VirtualTableDateField.tsx +1 -1
  67. package/src/components/common/types.tsx +1 -1
  68. package/src/contexts/AuthControllerContext.tsx +1 -1
  69. package/src/core/FireCMS.tsx +2 -3
  70. package/src/core/field_configs.tsx +1 -2
  71. package/src/form/EntityForm.tsx +1 -1
  72. package/src/form/field_bindings/DateTimeFieldBinding.tsx +1 -1
  73. package/src/hooks/data/delete.ts +3 -3
  74. package/src/hooks/data/save.ts +2 -1
  75. package/src/hooks/data/useDataSource.tsx +1 -1
  76. package/src/hooks/data/useEntityFetch.tsx +3 -3
  77. package/src/hooks/index.tsx +2 -0
  78. package/src/hooks/useBuildLocalConfigurationPersistence.tsx +9 -10
  79. package/src/hooks/useBuildModeController.tsx +11 -5
  80. package/src/hooks/useBuildNavigationController.tsx +136 -59
  81. package/src/hooks/useProjectLog.tsx +8 -6
  82. package/src/hooks/useValidateAuthenticator.tsx +115 -0
  83. package/src/internal/useBuildDataSource.ts +42 -47
  84. package/src/internal/useBuildSideEntityController.tsx +18 -12
  85. package/src/preview/PropertyPreview.tsx +2 -12
  86. package/src/preview/PropertyPreviewProps.tsx +1 -11
  87. package/src/preview/components/BooleanPreview.tsx +4 -2
  88. package/src/preview/components/ReferencePreview.tsx +1 -1
  89. package/src/types/auth.tsx +40 -1
  90. package/src/types/collections.ts +8 -4
  91. package/src/types/datasource.ts +8 -5
  92. package/src/types/entities.ts +9 -1
  93. package/src/types/entity_callbacks.ts +2 -2
  94. package/src/types/index.ts +1 -1
  95. package/src/types/navigation.ts +6 -6
  96. package/src/types/plugins.tsx +6 -5
  97. package/src/types/properties.ts +5 -4
  98. package/src/types/roles.ts +41 -0
  99. package/src/types/storage.ts +12 -3
  100. package/src/types/user.ts +7 -0
  101. package/src/util/collections.ts +1 -1
  102. package/src/util/entities.ts +1 -1
  103. package/src/util/navigation_utils.ts +6 -6
  104. package/src/util/strings.ts +2 -2
  105. package/src/util/useTraceUpdate.tsx +2 -1
  106. package/dist/internal/useLocaleConfig.d.ts +0 -1
  107. package/dist/types/appcheck.d.ts +0 -26
  108. package/src/internal/useLocaleConfig.tsx +0 -18
  109. package/src/types/appcheck.ts +0 -29
@@ -92,7 +92,7 @@ export type EntityCollectionTableProps<M extends Record<string, any>,
92
92
  */
93
93
  tableController: EntityTableController<M>;
94
94
 
95
- displayedColumnIds: PropertyColumnConfig[];
95
+ displayedColumnIds?: PropertyColumnConfig[];
96
96
 
97
97
  forceFilter?: FilterValues<Extract<keyof M, string>>;
98
98
 
@@ -95,6 +95,7 @@ export const PropertyTableCell = React.memo<PropertyTableCellProps<any>>(
95
95
  const internalValueRef = useRef(value);
96
96
 
97
97
  const [error, setError] = useState<Error | undefined>();
98
+ const [validationError, setValidationError] = useState<Error | undefined>();
98
99
  const [saved, setSaved] = useState<boolean>(false);
99
100
 
100
101
  const onValueUpdated = useCallback(() => {
@@ -120,7 +121,7 @@ export const PropertyTableCell = React.memo<PropertyTableCellProps<any>>(
120
121
  useEffect(
121
122
  () => {
122
123
  if (!equal(value, internalValueRef.current)) {
123
- setError(undefined);
124
+ setValidationError(undefined);
124
125
  setInternalValue(value);
125
126
  internalValueRef.current = value;
126
127
  onValueUpdated();
@@ -136,7 +137,7 @@ export const PropertyTableCell = React.memo<PropertyTableCellProps<any>>(
136
137
  validation
137
138
  .validate(value)
138
139
  .then(() => {
139
- setError(undefined);
140
+ setValidationError(undefined);
140
141
  internalValueRef.current = value;
141
142
  if (onValueChange) {
142
143
  onValueChange({
@@ -151,17 +152,15 @@ export const PropertyTableCell = React.memo<PropertyTableCellProps<any>>(
151
152
  }
152
153
  })
153
154
  .catch((e) => {
154
- setError(e);
155
+ setValidationError(e);
155
156
  });
156
157
  };
157
158
 
158
159
  useEffect(() => {
159
160
  validation
160
161
  .validate(internalValue)
161
- .then(() => setError(undefined))
162
- .catch((e) => {
163
- setError(e);
164
- });
162
+ .then(() => setValidationError(undefined))
163
+ .catch(setValidationError);
165
164
  }, [internalValue, validation, propertyKey, property, entity]);
166
165
 
167
166
  const updateValue = (newValue: any | null) => {
@@ -237,7 +236,6 @@ export const PropertyTableCell = React.memo<PropertyTableCellProps<any>>(
237
236
  height={getRowHeight(size)}
238
237
  propertyKey={propertyKey}
239
238
  property={property}
240
- // entity={entity}
241
239
  value={internalValue}
242
240
  size={getPreviewSizeFrom(size)}
243
241
  />
@@ -247,7 +245,7 @@ export const PropertyTableCell = React.memo<PropertyTableCellProps<any>>(
247
245
  if (!customField && (!customPreview || selected)) {
248
246
  const isAStorageProperty = isStorageProperty(property);
249
247
  if (isAStorageProperty) {
250
- innerComponent = <TableStorageUpload error={error}
248
+ innerComponent = <TableStorageUpload error={validationError ?? error}
251
249
  disabled={disabled}
252
250
  focused={selected}
253
251
  selected={selected}
@@ -274,7 +272,7 @@ export const PropertyTableCell = React.memo<PropertyTableCellProps<any>>(
274
272
  valueType={"number"}
275
273
  small={getPreviewSizeFrom(size) !== "medium"}
276
274
  enumValues={numberProperty.enumValues}
277
- error={error}
275
+ error={validationError ?? error}
278
276
  internalValue={internalValue as string | number}
279
277
  updateValue={updateValue}
280
278
  />;
@@ -282,7 +280,7 @@ export const PropertyTableCell = React.memo<PropertyTableCellProps<any>>(
282
280
  } else {
283
281
  innerComponent = <VirtualTableNumberInput
284
282
  align={align}
285
- error={error}
283
+ error={validationError ?? error}
286
284
  focused={selected}
287
285
  disabled={disabled}
288
286
  value={internalValue as number}
@@ -300,14 +298,14 @@ export const PropertyTableCell = React.memo<PropertyTableCellProps<any>>(
300
298
  valueType={"string"}
301
299
  small={getPreviewSizeFrom(size) !== "medium"}
302
300
  enumValues={stringProperty.enumValues}
303
- error={error}
301
+ error={validationError ?? error}
304
302
  internalValue={internalValue as string | number}
305
303
  updateValue={updateValue}
306
304
  />;
307
305
  fullHeight = true;
308
306
  } else if (!stringProperty.storage) {
309
307
  const multiline = Boolean(stringProperty.multiline) || Boolean(stringProperty.markdown);
310
- innerComponent = <VirtualTableInput error={error}
308
+ innerComponent = <VirtualTableInput error={validationError ?? error}
311
309
  disabled={disabled}
312
310
  multiline={multiline}
313
311
  focused={selected}
@@ -317,7 +315,7 @@ export const PropertyTableCell = React.memo<PropertyTableCellProps<any>>(
317
315
  allowScroll = true;
318
316
  }
319
317
  } else if (property.dataType === "boolean") {
320
- innerComponent = <VirtualTableSwitch error={error}
318
+ innerComponent = <VirtualTableSwitch error={validationError ?? error}
321
319
  disabled={disabled}
322
320
  focused={selected}
323
321
  internalValue={internalValue as boolean}
@@ -325,7 +323,7 @@ export const PropertyTableCell = React.memo<PropertyTableCellProps<any>>(
325
323
  />;
326
324
  } else if (property.dataType === "date") {
327
325
  innerComponent = <VirtualTableDateField name={propertyKey as string}
328
- error={error}
326
+ error={validationError ?? error}
329
327
  disabled={disabled}
330
328
  mode={property.mode}
331
329
  focused={selected}
@@ -368,7 +366,7 @@ export const PropertyTableCell = React.memo<PropertyTableCellProps<any>>(
368
366
  small={getPreviewSizeFrom(size) !== "medium"}
369
367
  valueType={arrayProperty.of.dataType}
370
368
  enumValues={arrayProperty.of.enumValues}
371
- error={error}
369
+ error={validationError ?? error}
372
370
  internalValue={internalValue as string | number}
373
371
  updateValue={updateValue}
374
372
  />;
@@ -403,9 +401,8 @@ export const PropertyTableCell = React.memo<PropertyTableCellProps<any>>(
403
401
  allowScroll = false;
404
402
  showExpandIcon = selected && !innerComponent && !disabled && !readOnlyProperty;
405
403
  innerComponent = (
406
- <PropertyPreview width={width}
404
+ <PropertyPreview width={width}
407
405
  height={height}
408
- // entity={entity}
409
406
  propertyKey={propertyKey as string}
410
407
  value={internalValue}
411
408
  property={property}
@@ -426,7 +423,7 @@ export const PropertyTableCell = React.memo<PropertyTableCellProps<any>>(
426
423
  removePadding={removePadding}
427
424
  fullHeight={fullHeight}
428
425
  saved={saved}
429
- error={error}
426
+ error={validationError ?? error}
430
427
  align={align}
431
428
  allowScroll={allowScroll}
432
429
  showExpandIcon={showExpandIcon}
@@ -29,7 +29,7 @@ export function TableReferenceField(props: TableReferenceFieldProps) {
29
29
 
30
30
  const navigationController = useNavigationController();
31
31
  const { path } = props;
32
- const collection = navigationController.getCollection<EntityCollection>(path);
32
+ const collection = navigationController.getCollection(path);
33
33
  if (!collection) {
34
34
  if (customizationController.components?.missingReference) {
35
35
  return <customizationController.components.missingReference path={path}/>;
@@ -16,20 +16,27 @@ import { useLargeLayout } from "../../../hooks";
16
16
 
17
17
  interface CollectionTableToolbarProps {
18
18
  size: CollectionSize;
19
- filterIsSet: boolean;
20
19
  loading: boolean;
21
- forceFilter?: boolean;
22
20
  actionsStart?: React.ReactNode;
23
21
  actions?: React.ReactNode;
24
22
  title?: React.ReactNode,
25
23
  onTextSearchClick?: () => void;
26
24
  onTextSearch?: (searchString?: string) => void;
27
25
  onSizeChanged: (size: CollectionSize) => void;
28
- clearFilter?: () => void;
29
26
  textSearchLoading?: boolean;
30
27
  }
31
28
 
32
- export function CollectionTableToolbar(props: CollectionTableToolbarProps) {
29
+ export function CollectionTableToolbar({
30
+ actions,
31
+ actionsStart,
32
+ loading,
33
+ onSizeChanged,
34
+ onTextSearch,
35
+ onTextSearchClick,
36
+ size,
37
+ textSearchLoading,
38
+ title
39
+ }: CollectionTableToolbarProps) {
33
40
 
34
41
  const searchInputRef = React.useRef<HTMLInputElement>(null);
35
42
  const largeLayout = useLargeLayout();
@@ -37,30 +44,20 @@ export function CollectionTableToolbar(props: CollectionTableToolbarProps) {
37
44
  const searchLoading = React.useRef<boolean>(false);
38
45
 
39
46
  useEffect(() => {
40
- if (searchInputRef.current && searchLoading.current && !props.textSearchLoading) {
47
+ if (searchInputRef.current && searchLoading.current && !textSearchLoading) {
41
48
  searchInputRef.current.focus();
42
49
  }
43
- searchLoading.current = props.textSearchLoading ?? false;
44
- }, [props.textSearchLoading]);
45
-
46
- const clearFilterButton = !props.forceFilter && props.filterIsSet && props.clearFilter &&
47
- <Button
48
- variant={"outlined"}
49
- className="h-fit-content"
50
- aria-label="filter clear"
51
- onClick={props.clearFilter}
52
- size={"small"}>
53
- <FilterListOffIcon/>
54
- Clear filter
55
- </Button>;
50
+ searchLoading.current = textSearchLoading ?? false;
51
+ }, [textSearchLoading]);
52
+
56
53
 
57
54
  const sizeSelect = (
58
55
  <Tooltip title={"Table row size"} side={"right"} sideOffset={4}>
59
56
  <Select
60
- value={props.size as string}
57
+ value={size as string}
61
58
  className="w-16 h-10"
62
59
  size={"small"}
63
- onValueChange={(v) => props.onSizeChanged(v as CollectionSize)}
60
+ onValueChange={(v) => onSizeChanged(v as CollectionSize)}
64
61
  renderValue={(v) => <div className={"font-medium"}>{v.toUpperCase()}</div>}
65
62
  >
66
63
  {["xs", "s", "m", "l", "xl"].map((size) => (
@@ -78,36 +75,34 @@ export function CollectionTableToolbar(props: CollectionTableToolbarProps) {
78
75
 
79
76
  <div className="flex items-center gap-2 md:mr-4 mr-2">
80
77
 
81
- {props.title && <div className={"hidden lg:block"}>
82
- {props.title}
78
+ {title && <div className={"hidden lg:block"}>
79
+ {title}
83
80
  </div>}
84
81
 
85
82
  {sizeSelect}
86
83
 
87
- {props.actionsStart}
88
-
89
- {clearFilterButton}
84
+ {actionsStart}
90
85
 
91
86
  </div>
92
87
 
93
88
  <div className="flex items-center gap-2">
94
89
 
95
90
  {largeLayout && <div className="w-[22px]">
96
- {props.loading &&
91
+ {loading &&
97
92
  <CircularProgress size={"small"}/>}
98
93
  </div>}
99
94
 
100
- {(props.onTextSearch || props.onTextSearchClick) &&
95
+ {(onTextSearch || onTextSearchClick) &&
101
96
  <SearchBar
102
97
  key={"search-bar"}
103
98
  inputRef={searchInputRef}
104
- loading={props.textSearchLoading}
105
- disabled={Boolean(props.onTextSearchClick)}
106
- onClick={props.onTextSearchClick}
107
- onTextSearch={props.onTextSearchClick ? undefined : props.onTextSearch}
99
+ loading={textSearchLoading}
100
+ disabled={Boolean(onTextSearchClick)}
101
+ onClick={onTextSearchClick}
102
+ onTextSearch={onTextSearchClick ? undefined : onTextSearch}
108
103
  expandable={true}/>}
109
104
 
110
- {props.actions}
105
+ {actions}
111
106
 
112
107
  </div>
113
108
 
@@ -96,7 +96,7 @@ export const EntityTableCell = React.memo<EntityTableCellProps>(
96
96
  const [onHover, setOnHover] = useState(false);
97
97
  const [internalSaved, setInternalSaved] = useState(saved);
98
98
 
99
- const showError = !disabled && error;
99
+ const showError = !disabled && Boolean(error);
100
100
 
101
101
  useEffect(() => {
102
102
  if (saved) {
@@ -176,21 +176,26 @@ export const EntityTableCell = React.memo<EntityTableCellProps>(
176
176
  const setOnHoverTrue = useCallback(() => setOnHover(true), []);
177
177
  const setOnHoverFalse = useCallback(() => setOnHover(false), []);
178
178
 
179
+ const borderClass = showError
180
+ ? "border-red-500"
181
+ : internalSaved
182
+ ? "border-green-500"
183
+ : isSelected
184
+ ? "border-primary"
185
+ : "border-transparent";
186
+
179
187
  return (
180
188
  <div
181
- ref={ref}
182
189
  className={cn(
183
190
  "transition-colors duration-100 ease-in-out",
184
191
  `flex relative h-full rounded-md p-${p} border border-4 border-opacity-75`,
185
192
  onHover && !disabled ? "bg-gray-50 dark:bg-gray-900" : "",
186
193
  saved ? "bg-gray-100 bg-opacity-75 dark:bg-gray-800 dark:bg-opacity-75" : "",
187
- !isSelected && !internalSaved && !showError ? "border-transparent" : "",
188
194
  hideOverflow ? "overflow-hidden" : "",
189
195
  isSelected ? "bg-gray-50 dark:bg-gray-900" : "",
190
- isSelected && !internalSaved ? "border-primary" : "",
191
- internalSaved ? "border-green-500 " : "",
192
- showError ? "border-red-500" : ""
196
+ borderClass
193
197
  )}
198
+ ref={ref}
194
199
  style={{
195
200
  justifyContent,
196
201
  alignItems: disabled || !isOverflowing ? "center" : undefined,
@@ -73,6 +73,7 @@ import {
73
73
  import { DeleteEntityDialog } from "../DeleteEntityDialog";
74
74
  import { useAnalyticsController } from "../../hooks/useAnalyticsController";
75
75
  import { useSelectionController } from "./useSelectionController";
76
+ import { EntityCollectionViewStartActions } from "./EntityCollectionViewStartActions";
76
77
 
77
78
  const COLLECTION_GROUP_PARENT_ID = "collectionGroupParent";
78
79
 
@@ -80,8 +81,18 @@ const COLLECTION_GROUP_PARENT_ID = "collectionGroupParent";
80
81
  * @group Components
81
82
  */
82
83
  export type EntityCollectionViewProps<M extends Record<string, any>> = {
83
- fullPath: string;
84
+ /**
85
+ * Complete path where this collection is located.
86
+ * It defaults to the collection path if not provided.
87
+ */
88
+ fullPath?: string;
89
+ /**
90
+ * If this is a subcollection, specify the parent collection ids.
91
+ */
84
92
  parentCollectionIds?: string[];
93
+ /**
94
+ * Whether this is a subcollection or not.
95
+ */
85
96
  isSubCollection?: boolean;
86
97
  className?: string;
87
98
  } & EntityCollection<M>;
@@ -112,7 +123,7 @@ export type EntityCollectionViewProps<M extends Record<string, any>> = {
112
123
  */
113
124
  export const EntityCollectionView = React.memo(
114
125
  function EntityCollectionView<M extends Record<string, any>>({
115
- fullPath,
126
+ fullPath: fullPathProp,
116
127
  parentCollectionIds,
117
128
  isSubCollection,
118
129
  className,
@@ -120,6 +131,7 @@ export const EntityCollectionView = React.memo(
120
131
  }: EntityCollectionViewProps<M>
121
132
  ) {
122
133
 
134
+ const fullPath = fullPathProp ?? collectionProp.path;
123
135
  const dataSource = useDataSource(collectionProp);
124
136
  const navigation = useNavigationController();
125
137
  const sideEntityController = useSideEntityController();
@@ -128,7 +140,6 @@ export const EntityCollectionView = React.memo(
128
140
  const analyticsController = useAnalyticsController();
129
141
  const customizationController = useCustomizationController();
130
142
 
131
-
132
143
  const containerRef = React.useRef<HTMLDivElement>(null);
133
144
 
134
145
  const collection = useMemo(() => {
@@ -175,7 +186,6 @@ export const EntityCollectionView = React.memo(
175
186
  const usedSelectionController = collection.selectionController ?? selectionController;
176
187
  const {
177
188
  selectedEntities,
178
- toggleEntitySelection,
179
189
  isEntitySelected,
180
190
  setSelectedEntities
181
191
  } = usedSelectionController;
@@ -327,7 +337,10 @@ export const EntityCollectionView = React.memo(
327
337
  callbacks: collection.callbacks,
328
338
  dataSource,
329
339
  context,
330
- onSaveSuccess: () => onValueUpdated(),
340
+ onSaveSuccess: () => {
341
+ setError(undefined);
342
+ onValueUpdated();
343
+ },
331
344
  onSaveFailure: (e: Error) => {
332
345
  console.error("Save failure");
333
346
  console.error(e);
@@ -606,6 +619,14 @@ export const EntityCollectionView = React.memo(
606
619
  onTextSearchClick={textSearchInitialised ? undefined : onTextSearchClick}
607
620
  textSearchLoading={textSearchLoading}
608
621
  textSearchEnabled={textSearchEnabled}
622
+ actionsStart={<EntityCollectionViewStartActions
623
+ parentCollectionIds={parentCollectionIds ?? []}
624
+ collection={collection}
625
+ tableController={tableController}
626
+ path={fullPath}
627
+ relativePath={collection.path}
628
+ selectionController={usedSelectionController}
629
+ collectionEntitiesCount={docsCount}/>}
609
630
  actions={<EntityCollectionViewActions
610
631
  parentCollectionIds={parentCollectionIds ?? []}
611
632
  collection={collection}
@@ -683,6 +704,8 @@ export const EntityCollectionView = React.memo(
683
704
  equal(a.selectionController, b.selectionController) &&
684
705
  equal(a.Actions, b.Actions) &&
685
706
  equal(a.defaultSize, b.defaultSize) &&
707
+ equal(a.initialFilter, b.initialFilter) &&
708
+ equal(a.initialSort, b.initialSort) &&
686
709
  equal(a.textSearchEnabled, b.textSearchEnabled) &&
687
710
  equal(a.additionalFields, b.additionalFields) &&
688
711
  equal(a.forceFilter, b.forceFilter);
@@ -0,0 +1,68 @@
1
+ import React from "react";
2
+ import { useCustomizationController, useFireCMSContext } from "../../hooks";
3
+ import { CollectionActionsProps, EntityCollection, EntityTableController, SelectionController } from "../../types";
4
+ import { toArray } from "../../util/arrays";
5
+ import { ErrorBoundary } from "../ErrorBoundary";
6
+ import { ClearFilterSortButton } from "../ClearFilterSortButton";
7
+
8
+ export type EntityCollectionViewStartActionsProps<M extends Record<string, any>> = {
9
+ collection: EntityCollection<M>;
10
+ path: string;
11
+ relativePath: string;
12
+ parentCollectionIds: string[];
13
+ selectionController: SelectionController<M>;
14
+ tableController: EntityTableController<M>;
15
+ collectionEntitiesCount: number;
16
+ }
17
+
18
+ export function EntityCollectionViewStartActions<M extends Record<string, any>>({
19
+ collection,
20
+ relativePath,
21
+ parentCollectionIds,
22
+ path,
23
+ selectionController,
24
+ tableController,
25
+ collectionEntitiesCount
26
+ }: EntityCollectionViewStartActionsProps<M>) {
27
+
28
+ const context = useFireCMSContext();
29
+
30
+ const customizationController = useCustomizationController();
31
+ const plugins = customizationController.plugins ?? [];
32
+
33
+ const actionProps: CollectionActionsProps = {
34
+ path,
35
+ relativePath,
36
+ parentCollectionIds,
37
+ collection,
38
+ selectionController,
39
+ context,
40
+ tableController,
41
+ collectionEntitiesCount
42
+ };
43
+ const actions: React.ReactNode[] = [
44
+ <ClearFilterSortButton
45
+ key={"clear_filter"}
46
+ tableController={tableController}
47
+ enabled={!collection.forceFilter}/>
48
+ ];
49
+
50
+ if (plugins) {
51
+ plugins.forEach((plugin, i) => {
52
+ if (plugin.collectionView?.CollectionActionsStart) {
53
+ actions.push(...toArray(plugin.collectionView?.CollectionActionsStart)
54
+ .map((Action, j) => (
55
+ <ErrorBoundary key={`plugin_actions_${i}_${j}`}>
56
+ <Action {...actionProps} {...plugin.collectionView?.collectionActionsStartProps}/>
57
+ </ErrorBoundary>
58
+ )));
59
+ }
60
+ });
61
+ }
62
+
63
+ return (
64
+ <>
65
+ {actions}
66
+ </>
67
+ );
68
+ }
@@ -49,7 +49,7 @@ export function EntityPreview({
49
49
 
50
50
  const navigationController = useNavigationController();
51
51
 
52
- const collection = collectionProp ?? navigationController.getCollection<EntityCollection>(entity.path);
52
+ const collection = collectionProp ?? navigationController.getCollection(entity.path);
53
53
 
54
54
  if (!collection) {
55
55
  throw Error(`Couldn't find the corresponding collection view for the path: ${entity.path}`);
@@ -168,9 +168,10 @@ export function EntityPreview({
168
168
  </EntityPreviewContainer>;
169
169
  }
170
170
 
171
- type EntityPreviewContainerProps = {
171
+ export type EntityPreviewContainerProps = {
172
172
  children: React.ReactNode;
173
173
  hover?: boolean;
174
+ fullwidth?: boolean;
174
175
  size: PreviewSize;
175
176
  className?: string;
176
177
  style?: React.CSSProperties;
@@ -184,6 +185,7 @@ const EntityPreviewContainerInner = React.forwardRef<HTMLDivElement, EntityPrevi
184
185
  size,
185
186
  style,
186
187
  className,
188
+ fullwidth = true,
187
189
  ...props
188
190
  }, ref) => {
189
191
  return <div
@@ -195,6 +197,7 @@ const EntityPreviewContainerInner = React.forwardRef<HTMLDivElement, EntityPrevi
195
197
  }}
196
198
  className={cn(
197
199
  "bg-white dark:bg-gray-900",
200
+ fullwidth ? "w-full" : "",
198
201
  "items-center",
199
202
  hover ? "hover:bg-slate-50 dark:hover:bg-gray-800 group-hover:bg-slate-50 dark:group-hover:bg-gray-800" : "",
200
203
  size === "tiny" ? "p-1" : "p-2",
@@ -58,7 +58,7 @@ export function EntityView<M extends Record<string, any>>(
58
58
  </div>
59
59
  {Object.entries(properties)
60
60
  .map(([key, property]) => {
61
- const value = (entity.values)[key];
61
+ const value = entity.values?.[key];
62
62
  return (
63
63
  <div
64
64
  key={`reference_previews_${key}`}
@@ -102,7 +102,7 @@ export function DefaultHomePage({
102
102
  return (
103
103
  <NavigationGroup
104
104
  group={section.title}
105
- key={`plugin_section_${plugin.name}`}>
105
+ key={`plugin_section_${plugin.key}`}>
106
106
  {section.children}
107
107
  </NavigationGroup>
108
108
  );
@@ -191,7 +191,7 @@ export function DefaultHomePage({
191
191
  />
192
192
  </div>
193
193
  ))}
194
- {AdditionalCards &&
194
+ {group?.toLowerCase() !== "admin" && AdditionalCards &&
195
195
  AdditionalCards.map((AdditionalCard, i) => (
196
196
  <div key={`nav_${group}_add_${i}`}>
197
197
  <AdditionalCard {...actionProps} />
@@ -52,7 +52,7 @@ export function NavigationCard({
52
52
  {description && <Typography variant="body2"
53
53
  color="secondary"
54
54
  component="div">
55
- <Markdown source={description}/>
55
+ <Markdown source={description} size={"small"}/>
56
56
  </Typography>}
57
57
  </div>
58
58
 
@@ -50,7 +50,7 @@ export function ReferenceWidget<M extends Record<string, any>>({
50
50
 
51
51
  const collection: EntityCollection | undefined = useMemo(() => {
52
52
  return navigationController.getCollection(path);
53
- }, [path, navigationController]);
53
+ }, [path, navigationController.getCollection]);
54
54
 
55
55
  // if (!collection) {
56
56
  // throw Error(`Couldn't find the corresponding collection for the path: ${path}`);
@@ -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";
@@ -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
  }