@firecms/core 3.0.0-beta.1 → 3.0.0-beta.2-pre.2

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 (44) hide show
  1. package/dist/components/ArrayContainer.d.ts +1 -3
  2. package/dist/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +1 -2
  3. package/dist/components/EntityCollectionTable/{SimpleEntityCollectionTable.d.ts → SimpleTable.d.ts} +7 -26
  4. package/dist/components/EntityCollectionTable/index.d.ts +1 -1
  5. package/dist/components/EntityCollectionTable/useDataSourceEntityCollectionTableController.d.ts +1 -1
  6. package/dist/components/{FieldConfigBadge.d.ts → PropertyConfigBadge.d.ts} +1 -1
  7. package/dist/components/index.d.ts +1 -1
  8. package/dist/core/Scaffold.d.ts +5 -2
  9. package/dist/form/components/CustomIdField.d.ts +2 -1
  10. package/dist/index.es.js +4269 -4446
  11. package/dist/index.es.js.map +1 -1
  12. package/dist/index.umd.js +5 -5
  13. package/dist/index.umd.js.map +1 -1
  14. package/dist/types/datasource.d.ts +3 -3
  15. package/dist/types/entity_callbacks.d.ts +1 -1
  16. package/dist/util/strings.d.ts +1 -1
  17. package/package.json +16 -16
  18. package/src/components/ArrayContainer.tsx +31 -67
  19. package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +78 -262
  20. package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +1 -2
  21. package/src/components/EntityCollectionTable/{SimpleEntityCollectionTable.tsx → SimpleTable.tsx} +36 -73
  22. package/src/components/EntityCollectionTable/index.tsx +1 -1
  23. package/src/components/EntityCollectionTable/useDataSourceEntityCollectionTableController.tsx +1 -1
  24. package/src/components/EntityCollectionView/EntityCollectionView.tsx +9 -8
  25. package/src/components/EntityPreview.tsx +0 -1
  26. package/src/components/LabelWithIcon.tsx +1 -1
  27. package/src/components/{FieldConfigBadge.tsx → PropertyConfigBadge.tsx} +1 -1
  28. package/src/components/ReferenceSelectionInner.tsx +0 -1
  29. package/src/components/index.tsx +1 -1
  30. package/src/core/NavigationRoutes.tsx +0 -1
  31. package/src/core/Scaffold.tsx +11 -8
  32. package/src/form/EntityForm.tsx +12 -2
  33. package/src/form/components/CustomIdField.tsx +16 -4
  34. package/src/form/components/ErrorFocus.tsx +1 -1
  35. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +1 -2
  36. package/src/form/field_bindings/MarkdownFieldBinding.tsx +2 -2
  37. package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +1 -2
  38. package/src/form/field_bindings/ReferenceFieldBinding.tsx +1 -2
  39. package/src/hooks/useLargeLayout.tsx +10 -7
  40. package/src/internal/useBuildDataSource.ts +9 -9
  41. package/src/preview/PropertyPreviewProps.tsx +1 -1
  42. package/src/types/datasource.ts +3 -3
  43. package/src/types/entity_callbacks.ts +2 -1
  44. package/src/util/strings.ts +2 -1
@@ -1,35 +1,22 @@
1
- import React, { useCallback, useContext, useEffect, useMemo, useRef } from "react";
1
+ import React, { useCallback, useContext, useMemo, useRef } from "react";
2
2
  import equal from "react-fast-compare";
3
- import {
4
- AdditionalFieldDelegate,
5
- CollectionSize,
6
- Entity,
7
- FilterValues,
8
- FireCMSContext,
9
- ResolvedProperty,
10
- SelectedCellProps,
11
- User
12
- } from "../../types";
3
+ import { AdditionalFieldDelegate, CollectionSize, Entity, FireCMSContext, User } from "../../types";
13
4
  import { PropertyTableCell } from "./PropertyTableCell";
14
5
  import { ErrorBoundary } from "../ErrorBoundary";
15
6
  import { useFireCMSContext, useLargeLayout } from "../../hooks";
16
- import { CellRendererParams, VirtualTable, VirtualTableColumn } from "../VirtualTable";
17
- import { enumToObjectEntries, getValueInPath } from "../../util";
7
+ import { CellRendererParams, VirtualTableColumn } from "../VirtualTable";
8
+ import { getValueInPath } from "../../util";
18
9
  import { getRowHeight } from "../VirtualTable/common";
19
10
  import { EntityCollectionRowActions } from "./EntityCollectionRowActions";
20
11
  import { EntityCollectionTableController } from "./types";
21
12
  import { CollectionTableToolbar } from "./internal/CollectionTableToolbar";
22
13
  import { EntityCollectionTableProps } from "./EntityCollectionTableProps";
23
14
  import { EntityTableCell } from "./internal/EntityTableCell";
24
- import { FilterFormFieldProps } from "../VirtualTable/VirtualTableHeader";
25
- import { ReferenceFilterField } from "./filters/ReferenceFilterField";
26
- import { StringNumberFilterField } from "./filters/StringNumberFilterField";
27
- import { BooleanFilterField } from "./filters/BooleanFilterField";
28
- import { DateTimeFilterField } from "./filters/DateTimeFilterField";
29
15
  import { CustomFieldValidator } from "../../form/validation";
30
16
  import { renderSkeletonText } from "../../preview";
31
17
  import { propertiesToColumns } from "./column_utils";
32
- import { useOutsideAlerter } from "@firecms/ui";
18
+ import { ErrorView } from "../ErrorView";
19
+ import { SimpleTable } from "./SimpleTable";
33
20
 
34
21
  const DEFAULT_STATE = {} as any;
35
22
 
@@ -64,7 +51,6 @@ export const useEntityCollectionTableController = () => useContext<EntityCollect
64
51
  export const EntityCollectionTable = React.memo<EntityCollectionTableProps<any>>(
65
52
  function EntityCollectionTable<M extends Record<string, any>, UserType extends User>
66
53
  ({
67
- debugKey,
68
54
  forceFilter,
69
55
  actionsStart,
70
56
  actions,
@@ -85,25 +71,7 @@ export const EntityCollectionTable = React.memo<EntityCollectionTableProps<any>>
85
71
  displayedColumnIds,
86
72
  defaultSize,
87
73
  properties,
88
- tableController:
89
- {
90
- data,
91
- dataLoading,
92
- noMoreToLoad,
93
- dataLoadingError,
94
- filterValues,
95
- setFilterValues,
96
- sortBy,
97
- setSortBy,
98
- setSearchString,
99
- clearFilter,
100
- itemCount,
101
- setItemCount,
102
- pageSize = 50,
103
- paginationEnabled,
104
- checkFilterCombination,
105
- setPopupCell
106
- },
74
+ tableController,
107
75
  filterable = true,
108
76
  sortable = true,
109
77
  endAdornment,
@@ -126,38 +94,9 @@ export const EntityCollectionTable = React.memo<EntityCollectionTableProps<any>>
126
94
 
127
95
  const [size, setSize] = React.useState<CollectionSize>(defaultSize ?? "m");
128
96
 
129
- const [selectedCell, setSelectedCell] = React.useState<SelectedCellProps<M> | undefined>(undefined);
130
-
131
97
  const selectedEntityIds = selectedEntities?.map(e => e.id);
132
98
 
133
- const filterIsSet = !!filterValues && Object.keys(filterValues).length > 0;
134
-
135
- const loadNextPage = useCallback(() => {
136
- if (!paginationEnabled || dataLoading || noMoreToLoad)
137
- return;
138
- if (itemCount !== undefined)
139
- setItemCount?.(itemCount + pageSize);
140
- }, [dataLoading, itemCount, noMoreToLoad, pageSize, paginationEnabled, setItemCount]);
141
-
142
- useOutsideAlerter(ref,
143
- () => {
144
- if (selectedCell) {
145
- unselect();
146
- }
147
- },
148
- Boolean(selectedCell));
149
-
150
- const resetPagination = useCallback(() => {
151
- setItemCount?.(pageSize);
152
- }, [pageSize]);
153
-
154
- const onRowClickCallback = useCallback(({ rowData }: {
155
- rowData: Entity<M>
156
- }) => {
157
- if (inlineEditing)
158
- return;
159
- return onEntityClick && onEntityClick(rowData);
160
- }, [onEntityClick, inlineEditing]);
99
+ const filterIsSet = !!tableController.filterValues && Object.keys(tableController.filterValues).length > 0;
161
100
 
162
101
  const updateSize = useCallback((size: CollectionSize) => {
163
102
  if (onSizeChanged)
@@ -165,7 +104,7 @@ export const EntityCollectionTable = React.memo<EntityCollectionTableProps<any>>
165
104
  setSize(size);
166
105
  }, []);
167
106
 
168
- const onTextSearch = useCallback((newSearchString?: string) => setSearchString?.(newSearchString), []);
107
+ const onTextSearch = useCallback((newSearchString?: string) => tableController.setSearchString?.(newSearchString), []);
169
108
 
170
109
  const additionalFieldsMap: Record<string, AdditionalFieldDelegate<M, UserType>> = useMemo(() => {
171
110
  return (additionalFields
@@ -175,27 +114,6 @@ export const EntityCollectionTable = React.memo<EntityCollectionTableProps<any>>
175
114
  : {}) as Record<string, AdditionalFieldDelegate<M, UserType>>;
176
115
  }, [additionalFields]);
177
116
 
178
- // on ESC key press
179
- useEffect(() => {
180
- const escFunction = (event: any) => {
181
- if (event.keyCode === 27) {
182
- unselect();
183
- }
184
- };
185
- document.addEventListener("keydown", escFunction, false);
186
- return () => {
187
- document.removeEventListener("keydown", escFunction, false);
188
- };
189
- });
190
-
191
- const select = useCallback((cell?: SelectedCellProps<M>) => {
192
- setSelectedCell(cell);
193
- }, []);
194
-
195
- const unselect = useCallback(() => {
196
- setSelectedCell(undefined);
197
- }, []);
198
-
199
117
  const customFieldValidator: CustomFieldValidator | undefined = uniqueFieldValidator;
200
118
 
201
119
  const propertyCellRenderer = useCallback(({
@@ -338,184 +256,82 @@ export const EntityCollectionTable = React.memo<EntityCollectionTableProps<any>>
338
256
  const column = props.column;
339
257
  const columns = props.columns;
340
258
  const columnKey = column.key;
341
- if (props.columnIndex === 0) {
342
- if (tableRowActionsBuilder)
343
- return tableRowActionsBuilder({
344
- entity: props.rowData,
345
- size,
346
- width: column.width,
347
- frozen: column.frozen
348
- });
349
- else
350
- return <EntityCollectionRowActions entity={props.rowData}
351
- width={column.width}
352
- frozen={column.frozen}
353
- isSelected={false}
354
- size={size}/>;
355
- } else if (additionalFieldsMap[columnKey]) {
356
- return additionalCellRenderer(props);
357
- } else if (props.columnIndex < columns.length + 1) {
358
- return propertyCellRenderer(props);
359
- } else {
360
- throw Error("Internal: columns not mapped properly");
259
+
260
+ try {
261
+ if (props.columnIndex === 0) {
262
+ if (tableRowActionsBuilder)
263
+ return tableRowActionsBuilder({
264
+ entity: props.rowData,
265
+ size,
266
+ width: column.width,
267
+ frozen: column.frozen
268
+ });
269
+ else
270
+ return <EntityCollectionRowActions entity={props.rowData}
271
+ width={column.width}
272
+ frozen={column.frozen}
273
+ isSelected={false}
274
+ size={size}/>;
275
+ } else if (additionalFieldsMap[columnKey]) {
276
+ return additionalCellRenderer(props);
277
+ } else if (props.columnIndex < columns.length + 1) {
278
+ return propertyCellRenderer(props);
279
+ } else {
280
+ throw Error("Internal: columns not mapped properly");
281
+ }
282
+ } catch (e: any) {
283
+ console.error("Error rendering cell", e);
284
+ return <EntityTableCell
285
+ size={size}
286
+ width={column.width}
287
+ saved={false}
288
+ value={null}
289
+ align={"left"}
290
+ fullHeight={false}
291
+ disabled={true}>
292
+ <ErrorView error={e}/>
293
+ </EntityTableCell>;
361
294
  }
362
295
  }, [additionalFieldsMap, tableRowActionsBuilder, size, additionalCellRenderer, propertyCellRenderer])
363
296
 
364
- const onFilterUpdate = useCallback((updatedFilterValues?: FilterValues<any>) => {
365
- setFilterValues?.({ ...updatedFilterValues, ...forceFilter } as FilterValues<any>);
366
- }, [forceFilter]);
367
-
368
- // useTraceUpdate({
369
- // data,
370
- // columns,
371
- // inlineEditing,
372
- // size, selectedEntityIds, additionalCellRenderer, propertyCellRenderer,
373
- // cellRenderer,
374
- // onRowClick,
375
- // onEndReached: loadNextPage,
376
- // onResetPagination: resetPagination,
377
- // error: dataLoadingError,
378
- // paginationEnabled,
379
- // onColumnResize,
380
- // loading: dataLoading,
381
- // filter: filterValues,
382
- // onFilterUpdate,
383
- // sortBy,
384
- // onSortByUpdate: setSortBy,
385
- // hoverRow,
386
- // emptyComponent,
387
- // checkFilterCombination,
388
- // createFilterField,
389
- // });
390
-
391
- const onRowClick = inlineEditing ? undefined : (onEntityClick ? onRowClickCallback : undefined);
392
-
393
297
  return (
394
298
 
395
- <EntityCollectionTableContext.Provider
396
- value={{
397
- setPopupCell: setPopupCell as ((cell?: SelectedCellProps<M>) => void),
398
- select,
399
- onValueChange,
400
- size,
401
- selectedCell
402
- }}
403
- >
404
-
405
- <div ref={ref}
406
- className="h-full w-full flex flex-col bg-white dark:bg-gray-950">
407
-
408
- <CollectionTableToolbar
409
- forceFilter={disabledFilterChange}
410
- filterIsSet={filterIsSet}
411
- onTextSearch={textSearchEnabled ? onTextSearch : undefined}
412
- textSearchLoading={textSearchLoading}
413
- onTextSearchClick={textSearchEnabled ? onTextSearchClick : undefined}
414
- clearFilter={clearFilter}
415
- size={size}
416
- onSizeChanged={updateSize}
417
- title={title}
418
- actionsStart={actionsStart}
419
- actions={actions}
420
- loading={dataLoading}/>
421
-
422
- <VirtualTable
423
- data={data}
424
- columns={columns}
425
- cellRenderer={cellRenderer}
426
- onRowClick={onRowClick}
427
- onEndReached={loadNextPage}
428
- onResetPagination={resetPagination}
429
- error={dataLoadingError}
430
- paginationEnabled={paginationEnabled}
431
- onColumnResize={onColumnResize}
432
- size={size}
433
- loading={dataLoading}
434
- filter={filterValues}
435
- onFilterUpdate={setFilterValues ? onFilterUpdate : undefined}
436
- sortBy={sortBy}
437
- onSortByUpdate={setSortBy as ((sortBy?: [string, "asc" | "desc"]) => void)}
438
- hoverRow={hoverRow}
439
- emptyComponent={emptyComponent}
440
- checkFilterCombination={checkFilterCombination}
441
- createFilterField={filterable ? createFilterField : undefined}
442
- rowClassName={useCallback((entity: Entity<M>) => {
443
- return selectedEntityIds?.includes(entity.id) ? "bg-gray-100 bg-opacity-75 dark:bg-gray-800 dark:bg-opacity-75" : "";
444
- }, [selectedEntityIds])}
445
- className="flex-grow"
446
- endAdornment={endAdornment}
447
- AddColumnComponent={AddColumnComponent}
448
- />
449
-
450
- </div>
451
- </EntityCollectionTableContext.Provider>
299
+ <div ref={ref}
300
+ className="h-full w-full flex flex-col bg-white dark:bg-gray-950">
301
+
302
+ <CollectionTableToolbar
303
+ forceFilter={disabledFilterChange}
304
+ filterIsSet={filterIsSet}
305
+ onTextSearch={textSearchEnabled ? onTextSearch : undefined}
306
+ textSearchLoading={textSearchLoading}
307
+ onTextSearchClick={textSearchEnabled ? onTextSearchClick : undefined}
308
+ clearFilter={tableController.clearFilter}
309
+ size={size}
310
+ onSizeChanged={updateSize}
311
+ title={title}
312
+ actionsStart={actionsStart}
313
+ actions={actions}
314
+ loading={tableController.dataLoading}/>
315
+
316
+ <SimpleTable columns={columns}
317
+ size={size}
318
+ inlineEditing={inlineEditing}
319
+ cellRenderer={cellRenderer}
320
+ onEntityClick={onEntityClick}
321
+ highlightedRow={useCallback((entity: Entity<M>) => selectedEntityIds?.includes(entity.id) ?? false, [selectedEntityIds])}
322
+ tableController={tableController}
323
+ onValueChange={onValueChange}
324
+ onColumnResize={onColumnResize}
325
+ hoverRow={hoverRow}
326
+ filterable={filterable}
327
+ emptyComponent={emptyComponent}
328
+ endAdornment={endAdornment}
329
+ AddColumnComponent={AddColumnComponent}/>
330
+
331
+
332
+ </div>
452
333
  );
453
334
 
454
335
  },
455
336
  equal
456
337
  );
457
-
458
- function createFilterField({
459
- id,
460
- filterValue,
461
- setFilterValue,
462
- column,
463
- hidden,
464
- setHidden
465
- }: FilterFormFieldProps<{
466
- resolvedProperty: ResolvedProperty,
467
- disabled: boolean,
468
- }>): React.ReactNode {
469
-
470
- if (!column.custom) {
471
- return null;
472
- }
473
-
474
- const { resolvedProperty } = column.custom;
475
-
476
- const isArray = resolvedProperty?.dataType === "array";
477
- const baseProperty: ResolvedProperty = isArray ? resolvedProperty.of : resolvedProperty;
478
- if (!baseProperty) {
479
- return null;
480
- }
481
- if (baseProperty.dataType === "reference") {
482
- return <ReferenceFilterField value={filterValue}
483
- setValue={setFilterValue}
484
- name={id as string}
485
- isArray={isArray}
486
- path={baseProperty.path}
487
- title={resolvedProperty?.name}
488
- previewProperties={baseProperty?.previewProperties}
489
- hidden={hidden}
490
- setHidden={setHidden}/>;
491
- } else if (baseProperty.dataType === "number" || baseProperty.dataType === "string") {
492
- const name = baseProperty.name;
493
- const enumValues = baseProperty.enumValues ? enumToObjectEntries(baseProperty.enumValues) : undefined;
494
- return <StringNumberFilterField value={filterValue}
495
- setValue={setFilterValue}
496
- name={id as string}
497
- dataType={baseProperty.dataType}
498
- isArray={isArray}
499
- enumValues={enumValues}
500
- title={name}/>;
501
- } else if (baseProperty.dataType === "boolean") {
502
- const name = baseProperty.name;
503
- return <BooleanFilterField value={filterValue}
504
- setValue={setFilterValue}
505
- name={id as string}
506
- title={name}/>;
507
-
508
- } else if (baseProperty.dataType === "date") {
509
- const title = baseProperty.name;
510
- return <DateTimeFilterField value={filterValue}
511
- setValue={setFilterValue}
512
- name={id as string}
513
- mode={baseProperty.mode}
514
- isArray={isArray}
515
- title={title}/>;
516
- }
517
-
518
- return (
519
- <div>{`Currently the filter field ${resolvedProperty.dataType} is not supported`}</div>
520
- );
521
- }
@@ -23,7 +23,6 @@ export type OnColumnResizeParams = { width: number, key: string };
23
23
  export type EntityCollectionTableProps<M extends Record<string, any>,
24
24
  UserType extends User = User> = {
25
25
 
26
- debugKey?: string;
27
26
  /**
28
27
  * Display these entities as selected
29
28
  */
@@ -103,7 +102,7 @@ export type EntityCollectionTableProps<M extends Record<string, any>,
103
102
 
104
103
  textSearchEnabled?: boolean;
105
104
 
106
- inlineEditing?: boolean | ((entity: Entity<M>) => boolean);
105
+ inlineEditing?: boolean;
107
106
 
108
107
  additionalFields?: AdditionalFieldDelegate<M, UserType>[];
109
108
 
@@ -1,4 +1,4 @@
1
- import React, { useCallback, useEffect } from "react";
1
+ import React, { useCallback, useEffect, useRef } from "react";
2
2
  import equal from "react-fast-compare";
3
3
  import {
4
4
  CollectionSize,
@@ -6,33 +6,21 @@ import {
6
6
  EntityTableController,
7
7
  FilterValues,
8
8
  ResolvedProperty,
9
- SelectedCellProps,
10
- User
9
+ SelectedCellProps
11
10
  } from "../../types";
12
- import { useLargeLayout } from "../../hooks";
13
11
  import { CellRendererParams, VirtualTable, VirtualTableColumn } from "../VirtualTable";
14
12
  import { enumToObjectEntries } from "../../util";
15
13
  import { OnCellValueChange } from "./types";
16
- import { CollectionTableToolbar } from "./internal/CollectionTableToolbar";
17
- import { EntityCollectionTableProps, OnColumnResizeParams } from "./EntityCollectionTableProps";
14
+ import { OnColumnResizeParams } from "./EntityCollectionTableProps";
18
15
  import { FilterFormFieldProps } from "../VirtualTable/VirtualTableHeader";
19
16
  import { ReferenceFilterField } from "./filters/ReferenceFilterField";
20
17
  import { StringNumberFilterField } from "./filters/StringNumberFilterField";
21
18
  import { BooleanFilterField } from "./filters/BooleanFilterField";
22
19
  import { DateTimeFilterField } from "./filters/DateTimeFilterField";
23
20
  import { EntityCollectionTableContext } from "./EntityCollectionTable";
21
+ import { useOutsideAlerter } from "@firecms/ui";
24
22
 
25
- export type SimpleEntityCollectionTableProps<M extends Record<string, any>> = {
26
-
27
- /**
28
- * List of entities that will be displayed as selected;
29
- */
30
- highlightedEntities?: Entity<M>[];
31
-
32
- /**
33
- * Override the title in the toolbar
34
- */
35
- title?: React.ReactNode;
23
+ export type SimpleTableProps<M extends Record<string, any>> = {
36
24
 
37
25
  /**
38
26
  * Callback when a cell value changes.
@@ -65,28 +53,11 @@ export type SimpleEntityCollectionTableProps<M extends Record<string, any>> = {
65
53
  */
66
54
  onColumnResize?(params: OnColumnResizeParams): void;
67
55
 
68
- /**
69
- * Callback when the selected size of the table is changed
70
- */
71
- onSizeChanged?(size: CollectionSize): void;
72
-
73
56
  /**
74
57
  * Should apply a different style to a row when hovering
75
58
  */
76
59
  hoverRow?: boolean;
77
60
 
78
- /**
79
- * Additional component that renders actions such as buttons in the
80
- * collection toolbar, displayed on the left side
81
- */
82
- actionsStart?: React.ReactNode;
83
-
84
- /**
85
- * Additional component that renders actions such as buttons in the
86
- * collection toolbar, displayed on the right side
87
- */
88
- actions?: React.ReactNode;
89
-
90
61
  /**
91
62
  * Controller holding the logic for the table
92
63
  * {@link useDataSourceEntityCollectionTableController}
@@ -100,14 +71,18 @@ export type SimpleEntityCollectionTableProps<M extends Record<string, any>> = {
100
71
 
101
72
  inlineEditing?: boolean;
102
73
 
103
- textSearchEnabled?: boolean;
74
+ forceFilter?: FilterValues<keyof M extends string ? keyof M : never>;
75
+
76
+ highlightedRow?: (data: Entity<M>) => boolean;
104
77
 
105
- emptyComponent?: React.ReactNode;
78
+ size?: CollectionSize;
106
79
 
107
- forceFilter?: FilterValues<keyof M extends string ? keyof M : never>;
108
- }
80
+ emptyComponent?: React.ReactNode;
109
81
 
82
+ endAdornment?: React.ReactNode;
110
83
 
84
+ AddColumnComponent?: React.ComponentType;
85
+ }
111
86
 
112
87
  /**
113
88
  * This component is in charge of rendering a collection table with a high
@@ -133,18 +108,13 @@ export type SimpleEntityCollectionTableProps<M extends Record<string, any>> = {
133
108
  * @see VirtualTable
134
109
  * @group Components
135
110
  */
136
- export const SimpleEntityCollectionTable = React.memo<SimpleEntityCollectionTableProps<any>>(
137
- function SimpleEntityCollectionTable<M extends Record<string, any>, UserType extends User>
111
+ export const SimpleTable = React.memo<SimpleTableProps<any>>(
112
+ function SimpleTable<M extends Record<string, any>>
138
113
  ({
139
- actionsStart,
140
- actions,
141
- title,
142
114
  onValueChange,
143
115
  cellRenderer,
144
- highlightedEntities,
145
116
  onEntityClick,
146
117
  onColumnResize,
147
- onSizeChanged,
148
118
  hoverRow = true,
149
119
  inlineEditing = false,
150
120
  tableController:
@@ -167,21 +137,19 @@ export const SimpleEntityCollectionTable = React.memo<SimpleEntityCollectionTabl
167
137
  setPopupCell
168
138
  },
169
139
  filterable = true,
170
- sortable = true,
171
140
  emptyComponent,
172
- textSearchEnabled,
173
141
  columns,
174
- forceFilter
175
- }: SimpleEntityCollectionTableProps<M>) {
176
-
177
- const largeLayout = useLargeLayout();
142
+ forceFilter,
143
+ highlightedRow,
144
+ endAdornment,
145
+ AddColumnComponent
146
+ }: SimpleTableProps<M>) {
178
147
 
148
+ const ref = useRef<HTMLDivElement>(null);
179
149
  const [size, setSize] = React.useState<CollectionSize>("m");
180
150
 
181
151
  const [selectedCell, setSelectedCell] = React.useState<SelectedCellProps<M> | undefined>(undefined);
182
152
 
183
- const filterIsSet = !!filterValues && Object.keys(filterValues).length > 0;
184
-
185
153
  const loadNextPage = () => {
186
154
  if (!paginationEnabled || dataLoading || noMoreToLoad)
187
155
  return;
@@ -201,13 +169,13 @@ export const SimpleEntityCollectionTable = React.memo<SimpleEntityCollectionTabl
201
169
  return onEntityClick && onEntityClick(rowData);
202
170
  }, [onEntityClick, inlineEditing]);
203
171
 
204
- const updateSize = useCallback((size: CollectionSize) => {
205
- if (onSizeChanged)
206
- onSizeChanged(size);
207
- setSize(size);
208
- }, []);
209
-
210
- const onTextSearch = useCallback((newSearchString?: string) => setSearchString?.(newSearchString), []);
172
+ useOutsideAlerter(ref,
173
+ () => {
174
+ if (selectedCell) {
175
+ unselect();
176
+ }
177
+ },
178
+ Boolean(selectedCell));
211
179
 
212
180
  // on ESC key press
213
181
  useEffect(() => {
@@ -244,18 +212,8 @@ export const SimpleEntityCollectionTable = React.memo<SimpleEntityCollectionTabl
244
212
  selectedCell,
245
213
  }}
246
214
  >
247
- <div className="h-full w-full flex flex-col bg-white dark:bg-gray-950">
248
-
249
- <CollectionTableToolbar
250
- filterIsSet={filterIsSet}
251
- onTextSearch={textSearchEnabled ? onTextSearch : undefined}
252
- clearFilter={clearFilter}
253
- size={size}
254
- onSizeChanged={updateSize}
255
- title={title}
256
- actionsStart={actionsStart}
257
- actions={actions}
258
- loading={dataLoading}/>
215
+ <div className="h-full w-full flex flex-col bg-white dark:bg-gray-950"
216
+ ref={ref}>
259
217
 
260
218
  <VirtualTable
261
219
  data={data}
@@ -274,10 +232,15 @@ export const SimpleEntityCollectionTable = React.memo<SimpleEntityCollectionTabl
274
232
  sortBy={sortBy}
275
233
  onSortByUpdate={setSortBy as ((sortBy?: [string, "asc" | "desc"]) => void)}
276
234
  hoverRow={hoverRow}
277
- emptyComponent={emptyComponent}
278
235
  checkFilterCombination={checkFilterCombination}
279
236
  createFilterField={filterable ? createFilterField : undefined}
237
+ rowClassName={useCallback((entity: Entity<M>) => {
238
+ return highlightedRow?.(entity) ? "bg-gray-100 bg-opacity-75 dark:bg-gray-800 dark:bg-opacity-75" : "";
239
+ }, [highlightedRow])}
280
240
  className="flex-grow"
241
+ emptyComponent={emptyComponent}
242
+ endAdornment={endAdornment}
243
+ AddColumnComponent={AddColumnComponent}
281
244
  />
282
245
 
283
246
  </div>
@@ -14,7 +14,7 @@ export type {
14
14
  } from "./types";
15
15
 
16
16
  export * from "./PropertyTableCell";
17
- export * from "./SimpleEntityCollectionTable";
17
+ export * from "./SimpleTable";
18
18
  export * from "./EntityCollectionRowActions";
19
19
  export * from "./useDataSourceEntityCollectionTableController";
20
20
  export * from "./column_utils";
@@ -5,10 +5,10 @@ import { useDataOrder } from "../../hooks/data/useDataOrder";
5
5
  import {
6
6
  Entity,
7
7
  EntityCollection,
8
+ EntityTableController,
8
9
  FilterValues,
9
10
  FireCMSContext,
10
11
  SelectedCellProps,
11
- EntityTableController,
12
12
  User
13
13
  } from "../../types";
14
14
  import { useDebouncedData } from "./useDebouncedData";
@@ -754,14 +754,15 @@ function EntitiesCount({
754
754
  const resolvedPath = useMemo(() => navigation.resolveAliasesFrom(fullPath), [fullPath, navigation.resolveAliasesFrom]);
755
755
 
756
756
  useEffect(() => {
757
- dataSource.countEntities({
758
- path: resolvedPath,
759
- collection,
760
- filter,
761
- orderBy: sortByProperty,
762
- order: currentSort
763
- }).then(setCount).catch(setError);
764
- }, [fullPath, dataSource, resolvedPath, collection, filter, sortByProperty, currentSort]);
757
+ if (dataSource.countEntities)
758
+ dataSource.countEntities({
759
+ path: resolvedPath,
760
+ collection,
761
+ filter,
762
+ orderBy: sortByProperty,
763
+ order: currentSort
764
+ }).then(setCount).catch(setError);
765
+ }, [fullPath, dataSource.countEntities, resolvedPath, collection, filter, sortByProperty, currentSort]);
765
766
 
766
767
  useEffect(() => {
767
768
  if (onCountChange) {