@firecms/core 3.0.0-beta.13 → 3.0.0-beta.15

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 (124) hide show
  1. package/dist/components/ArrayContainer.d.ts +7 -12
  2. package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +2 -1
  3. package/dist/components/EntityPreview.d.ts +4 -2
  4. package/dist/components/HomePage/DefaultHomePage.d.ts +2 -15
  5. package/dist/components/HomePage/HomePageDnD.d.ts +76 -0
  6. package/dist/components/HomePage/NavigationCard.d.ts +3 -1
  7. package/dist/components/HomePage/NavigationCardBinding.d.ts +3 -2
  8. package/dist/components/HomePage/NavigationGroup.d.ts +7 -1
  9. package/dist/components/HomePage/RenameGroupDialog.d.ts +9 -0
  10. package/dist/components/SelectableTable/SelectableTable.d.ts +1 -1
  11. package/dist/components/VirtualTable/VirtualTableProps.d.ts +0 -4
  12. package/dist/components/index.d.ts +1 -0
  13. package/dist/core/EntityEditView.d.ts +3 -0
  14. package/dist/core/EntityEditViewFormActions.d.ts +1 -1
  15. package/dist/core/field_configs.d.ts +1 -1
  16. package/dist/form/EntityForm.d.ts +2 -1
  17. package/dist/form/EntityFormActions.d.ts +6 -2
  18. package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
  19. package/dist/form/field_bindings/ReferenceAsStringFieldBinding.d.ts +9 -0
  20. package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +3 -9
  21. package/dist/form/index.d.ts +1 -0
  22. package/dist/hooks/useBuildNavigationController.d.ts +50 -8
  23. package/dist/index.es.js +3259 -1649
  24. package/dist/index.es.js.map +1 -1
  25. package/dist/index.umd.js +3265 -1658
  26. package/dist/index.umd.js.map +1 -1
  27. package/dist/types/analytics.d.ts +1 -1
  28. package/dist/types/collections.d.ts +28 -4
  29. package/dist/types/customization_controller.d.ts +8 -0
  30. package/dist/types/entity_actions.d.ts +46 -6
  31. package/dist/types/firecms.d.ts +10 -1
  32. package/dist/types/navigation.d.ts +26 -5
  33. package/dist/types/plugins.d.ts +32 -1
  34. package/dist/types/properties.d.ts +7 -0
  35. package/dist/types/property_config.d.ts +1 -1
  36. package/dist/types/side_entity_controller.d.ts +8 -0
  37. package/dist/util/callbacks.d.ts +2 -0
  38. package/dist/util/icons.d.ts +2 -2
  39. package/dist/util/index.d.ts +1 -0
  40. package/dist/util/navigation_from_path.d.ts +4 -0
  41. package/dist/util/resolutions.d.ts +2 -1
  42. package/package.json +8 -6
  43. package/src/components/ArrayContainer.tsx +409 -294
  44. package/src/components/ClearFilterSortButton.tsx +1 -1
  45. package/src/components/ConfirmationDialog.tsx +10 -9
  46. package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +6 -0
  47. package/src/components/EntityCollectionTable/PropertyTableCell.tsx +26 -4
  48. package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +3 -3
  49. package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +13 -2
  50. package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +53 -27
  51. package/src/components/EntityCollectionTable/internal/popup_field/useDraggable.tsx +9 -9
  52. package/src/components/EntityCollectionView/EntityCollectionView.tsx +11 -4
  53. package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +3 -2
  54. package/src/components/EntityPreview.tsx +18 -14
  55. package/src/components/ErrorView.tsx +1 -1
  56. package/src/components/FireCMSLogo.tsx +7 -51
  57. package/src/components/HomePage/DefaultHomePage.tsx +491 -156
  58. package/src/components/HomePage/FavouritesView.tsx +3 -3
  59. package/src/components/HomePage/HomePageDnD.tsx +599 -0
  60. package/src/components/HomePage/NavigationCard.tsx +47 -38
  61. package/src/components/HomePage/NavigationCardBinding.tsx +13 -7
  62. package/src/components/HomePage/NavigationGroup.tsx +63 -29
  63. package/src/components/HomePage/RenameGroupDialog.tsx +117 -0
  64. package/src/components/SelectableTable/SelectableTable.tsx +140 -143
  65. package/src/components/UnsavedChangesDialog.tsx +6 -2
  66. package/src/components/VirtualTable/VirtualTable.tsx +8 -30
  67. package/src/components/VirtualTable/VirtualTableProps.tsx +0 -5
  68. package/src/components/VirtualTable/fields/VirtualTableInput.tsx +0 -1
  69. package/src/components/common/default_entity_actions.tsx +25 -9
  70. package/src/components/common/useDataSourceTableController.tsx +2 -2
  71. package/src/components/index.tsx +2 -0
  72. package/src/core/DefaultDrawer.tsx +8 -8
  73. package/src/core/DrawerNavigationItem.tsx +1 -1
  74. package/src/core/EntityEditView.tsx +65 -18
  75. package/src/core/EntityEditViewFormActions.tsx +154 -29
  76. package/src/core/EntitySidePanel.tsx +19 -21
  77. package/src/core/FireCMS.tsx +9 -1
  78. package/src/core/field_configs.tsx +15 -1
  79. package/src/form/EntityForm.tsx +37 -5
  80. package/src/form/EntityFormActions.tsx +51 -9
  81. package/src/form/PropertyFieldBinding.tsx +0 -1
  82. package/src/form/components/CustomIdField.tsx +3 -1
  83. package/src/form/components/LabelWithIcon.tsx +1 -1
  84. package/src/form/components/StorageItemPreview.tsx +1 -1
  85. package/src/form/components/StorageUploadProgress.tsx +3 -3
  86. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +3 -2
  87. package/src/form/field_bindings/MapFieldBinding.tsx +5 -4
  88. package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +4 -2
  89. package/src/form/field_bindings/MultiSelectFieldBinding.tsx +1 -1
  90. package/src/form/field_bindings/ReferenceAsStringFieldBinding.tsx +135 -0
  91. package/src/form/field_bindings/SelectFieldBinding.tsx +2 -1
  92. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +216 -153
  93. package/src/form/index.tsx +1 -0
  94. package/src/hooks/data/save.ts +0 -6
  95. package/src/hooks/useBuildNavigationController.tsx +299 -96
  96. package/src/internal/useBuildSideEntityController.tsx +8 -5
  97. package/src/preview/PropertyPreview.tsx +14 -0
  98. package/src/preview/components/ImagePreview.tsx +2 -2
  99. package/src/preview/components/ReferencePreview.tsx +1 -1
  100. package/src/preview/property_previews/ArrayOfMapsPreview.tsx +1 -1
  101. package/src/preview/property_previews/MapPropertyPreview.tsx +1 -1
  102. package/src/preview/property_previews/SkeletonPropertyComponent.tsx +1 -1
  103. package/src/preview/property_previews/StringPropertyPreview.tsx +1 -1
  104. package/src/routes/FireCMSRoute.tsx +3 -3
  105. package/src/types/analytics.ts +3 -0
  106. package/src/types/collections.ts +32 -4
  107. package/src/types/customization_controller.tsx +9 -0
  108. package/src/types/entity_actions.tsx +57 -6
  109. package/src/types/firecms.tsx +11 -2
  110. package/src/types/navigation.ts +34 -6
  111. package/src/types/plugins.tsx +40 -1
  112. package/src/types/properties.ts +8 -0
  113. package/src/types/property_config.tsx +1 -0
  114. package/src/types/side_entity_controller.tsx +10 -5
  115. package/src/util/callbacks.ts +119 -0
  116. package/src/util/icons.tsx +22 -7
  117. package/src/util/index.ts +1 -0
  118. package/src/util/join_collections.ts +3 -1
  119. package/src/util/navigation_from_path.ts +15 -5
  120. package/src/util/navigation_utils.ts +72 -57
  121. package/src/util/objects.ts +53 -20
  122. package/src/util/resolutions.ts +13 -1
  123. package/dist/components/EntityCollectionTable/internal/popup_field/ElementResizeListener.d.ts +0 -5
  124. package/src/components/EntityCollectionTable/internal/popup_field/ElementResizeListener.tsx +0 -59
@@ -1,4 +1,4 @@
1
- import React, { useCallback, useEffect, useRef } from "react";
1
+ import React, { useCallback, useEffect, useMemo, useRef } from "react";
2
2
  import {
3
3
  CollectionSize,
4
4
  Entity,
@@ -119,150 +119,147 @@ export type SelectableTableProps<M extends Record<string, any>> = {
119
119
  * @see VirtualTable
120
120
  * @group Components
121
121
  */
122
- export const SelectableTable = React.memo<SelectableTableProps<any>>(
123
- function SelectableTable<M extends Record<string, any>>
124
- ({
125
- onValueChange,
126
- cellRenderer,
127
- onEntityClick,
128
- onColumnResize,
129
- hoverRow = true,
130
- size = "m",
131
- inlineEditing = false,
132
- tableController:
133
- {
134
- data,
135
- dataLoading,
136
- noMoreToLoad,
137
- dataLoadingError,
138
- filterValues,
139
- setFilterValues,
140
- sortBy,
141
- setSortBy,
142
- itemCount,
143
- setItemCount,
144
- pageSize = 50,
145
- paginationEnabled,
146
- checkFilterCombination,
147
- setPopupCell
148
- },
149
- filterable = true,
150
- onScroll,
151
- initialScroll,
152
- emptyComponent,
153
- columns,
154
- forceFilter,
155
- highlightedRow,
156
- endAdornment,
157
- AddColumnComponent
158
- }: SelectableTableProps<M>) {
159
-
160
- const ref = useRef<HTMLDivElement>(null);
161
-
162
- const [selectedCell, setSelectedCell] = React.useState<SelectedCellProps<M> | undefined>(undefined);
163
-
164
- const loadNextPage = () => {
165
- if (!paginationEnabled || dataLoading || noMoreToLoad)
166
- return;
167
- if (itemCount !== undefined)
168
- setItemCount?.(itemCount + pageSize);
122
+ export const SelectableTable = function SelectableTable<M extends Record<string, any>>
123
+ ({
124
+ onValueChange,
125
+ cellRenderer,
126
+ onEntityClick,
127
+ onColumnResize,
128
+ hoverRow = true,
129
+ size = "m",
130
+ inlineEditing = false,
131
+ tableController:
132
+ {
133
+ data,
134
+ dataLoading,
135
+ noMoreToLoad,
136
+ dataLoadingError,
137
+ filterValues,
138
+ setFilterValues,
139
+ sortBy,
140
+ setSortBy,
141
+ itemCount,
142
+ setItemCount,
143
+ pageSize = 50,
144
+ paginationEnabled,
145
+ checkFilterCombination,
146
+ setPopupCell
147
+ },
148
+ filterable = true,
149
+ onScroll,
150
+ initialScroll,
151
+ emptyComponent,
152
+ columns,
153
+ forceFilter,
154
+ highlightedRow,
155
+ endAdornment,
156
+ AddColumnComponent
157
+ }: SelectableTableProps<M>) {
158
+
159
+ const ref = useRef<HTMLDivElement>(null);
160
+
161
+ const [selectedCell, setSelectedCell] = React.useState<SelectedCellProps<M> | undefined>(undefined);
162
+
163
+ const loadNextPage = () => {
164
+ if (!paginationEnabled || dataLoading || noMoreToLoad)
165
+ return;
166
+ if (itemCount !== undefined)
167
+ setItemCount?.(itemCount + pageSize);
168
+ };
169
+
170
+ const resetPagination = useCallback(() => {
171
+ setItemCount?.(pageSize);
172
+ }, [pageSize]);
173
+
174
+ const onRowClick = useCallback(({ rowData }: {
175
+ rowData: Entity<M>
176
+ }) => {
177
+ if (inlineEditing)
178
+ return;
179
+ return onEntityClick && onEntityClick(rowData);
180
+ }, [onEntityClick, inlineEditing]);
181
+
182
+ useOutsideAlerter(ref,
183
+ () => {
184
+ if (selectedCell) {
185
+ unselect();
186
+ }
187
+ },
188
+ Boolean(selectedCell));
189
+
190
+ const select = useCallback((cell?: SelectedCellProps<M>) => {
191
+ setSelectedCell(cell);
192
+ }, []);
193
+
194
+ const unselect = useCallback(() => {
195
+ setSelectedCell(undefined);
196
+ }, []);
197
+
198
+ // on ESC key press
199
+ useEffect(() => {
200
+ const escFunction = (event: any) => {
201
+ if (event.keyCode === 27) {
202
+ unselect();
203
+ }
169
204
  };
205
+ document.addEventListener("keydown", escFunction, false);
206
+ return () => {
207
+ document.removeEventListener("keydown", escFunction, false);
208
+ };
209
+ }, [unselect]);
210
+
211
+ const onFilterUpdate = useCallback((updatedFilterValues?: FilterValues<any>) => {
212
+ setFilterValues?.({ ...updatedFilterValues, ...forceFilter } as FilterValues<any>);
213
+ }, [forceFilter]);
214
+
215
+ const contextValue = useMemo(() => ({
216
+ setPopupCell: setPopupCell as ((cell?: SelectedCellProps<M>) => void),
217
+ select,
218
+ onValueChange,
219
+ size: size ?? "m",
220
+ selectedCell
221
+ }), [setPopupCell, select, onValueChange, size, selectedCell]);
222
+
223
+ return (
224
+ <SelectableTableContext.Provider
225
+ value={contextValue}>
226
+ <div className="h-full w-full flex flex-col bg-white dark:bg-surface-950"
227
+ ref={ref}>
228
+
229
+ <VirtualTable
230
+ data={data}
231
+ columns={columns}
232
+ cellRenderer={cellRenderer}
233
+ onRowClick={inlineEditing ? undefined : (onEntityClick ? onRowClick : undefined)}
234
+ onEndReached={loadNextPage}
235
+ onResetPagination={resetPagination}
236
+ error={dataLoadingError}
237
+ onColumnResize={onColumnResize}
238
+ rowHeight={getRowHeight(size)}
239
+ loading={dataLoading}
240
+ filter={filterValues}
241
+ onFilterUpdate={setFilterValues ? onFilterUpdate : undefined}
242
+ sortBy={sortBy}
243
+ onSortByUpdate={setSortBy as ((sortBy?: [string, "asc" | "desc"]) => void)}
244
+ hoverRow={hoverRow}
245
+ initialScroll={initialScroll}
246
+ onScroll={onScroll}
247
+ checkFilterCombination={checkFilterCombination}
248
+ createFilterField={filterable ? createFilterField : undefined}
249
+ rowClassName={useCallback((entity: Entity<M>) => {
250
+ return highlightedRow?.(entity) ? "bg-surface-100 bg-opacity-75 dark:bg-surface-800 dark:bg-opacity-75" : "";
251
+ }, [highlightedRow])}
252
+ className="flex-grow"
253
+ emptyComponent={emptyComponent}
254
+ endAdornment={endAdornment}
255
+ AddColumnComponent={AddColumnComponent}
256
+ />
257
+
258
+ </div>
259
+ </SelectableTableContext.Provider>
260
+ );
170
261
 
171
- const resetPagination = useCallback(() => {
172
- setItemCount?.(pageSize);
173
- }, [pageSize]);
174
-
175
- const onRowClick = useCallback(({ rowData }: {
176
- rowData: Entity<M>
177
- }) => {
178
- if (inlineEditing)
179
- return;
180
- return onEntityClick && onEntityClick(rowData);
181
- }, [onEntityClick, inlineEditing]);
182
-
183
- useOutsideAlerter(ref,
184
- () => {
185
- if (selectedCell) {
186
- unselect();
187
- }
188
- },
189
- Boolean(selectedCell));
190
-
191
- // on ESC key press
192
- useEffect(() => {
193
- const escFunction = (event: any) => {
194
- if (event.keyCode === 27) {
195
- unselect();
196
- }
197
- };
198
- document.addEventListener("keydown", escFunction, false);
199
- return () => {
200
- document.removeEventListener("keydown", escFunction, false);
201
- };
202
- });
203
-
204
- const select = useCallback((cell?: SelectedCellProps<M>) => {
205
- setSelectedCell(cell);
206
- }, []);
207
-
208
- const unselect = useCallback(() => {
209
- setSelectedCell(undefined);
210
- }, []);
211
-
212
- const onFilterUpdate = useCallback((updatedFilterValues?: FilterValues<any>) => {
213
- setFilterValues?.({ ...updatedFilterValues, ...forceFilter } as FilterValues<any>);
214
- }, [forceFilter]);
215
-
216
- return (
217
- <SelectableTableContext.Provider
218
- value={{
219
- setPopupCell: setPopupCell as ((cell?: SelectedCellProps<M>) => void),
220
- select,
221
- onValueChange,
222
- size: size ?? "m",
223
- selectedCell,
224
- }}
225
- >
226
- <div className="h-full w-full flex flex-col bg-white dark:bg-surface-950"
227
- ref={ref}>
228
-
229
- <VirtualTable
230
- data={data}
231
- columns={columns}
232
- cellRenderer={cellRenderer}
233
- onRowClick={inlineEditing ? undefined : (onEntityClick ? onRowClick : undefined)}
234
- onEndReached={loadNextPage}
235
- onResetPagination={resetPagination}
236
- error={dataLoadingError}
237
- onColumnResize={onColumnResize}
238
- rowHeight={getRowHeight(size)}
239
- loading={dataLoading}
240
- filter={filterValues}
241
- onFilterUpdate={setFilterValues ? onFilterUpdate : undefined}
242
- sortBy={sortBy}
243
- onSortByUpdate={setSortBy as ((sortBy?: [string, "asc" | "desc"]) => void)}
244
- hoverRow={hoverRow}
245
- initialScroll={initialScroll}
246
- onScroll={onScroll}
247
- checkFilterCombination={checkFilterCombination}
248
- createFilterField={filterable ? createFilterField : undefined}
249
- rowClassName={useCallback((entity: Entity<M>) => {
250
- return highlightedRow?.(entity) ? "bg-surface-100 bg-opacity-75 dark:bg-surface-800 dark:bg-opacity-75" : "";
251
- }, [highlightedRow])}
252
- className="flex-grow"
253
- emptyComponent={emptyComponent}
254
- endAdornment={endAdornment}
255
- AddColumnComponent={AddColumnComponent}
256
- />
257
-
258
- </div>
259
- </SelectableTableContext.Provider>
260
- );
261
-
262
- },
263
- () => false,
264
- // equal
265
- );
262
+ };
266
263
 
267
264
  function createFilterField({
268
265
  id,
@@ -34,8 +34,12 @@ export function UnsavedChangesDialog({
34
34
 
35
35
  </DialogContent>
36
36
  <DialogActions>
37
- <Button variant="text" onClick={handleCancel} autoFocus> Cancel </Button>
38
- <Button onClick={handleOk}> Ok </Button>
37
+ <Button variant="text"
38
+ color={"primary"}
39
+ onClick={handleCancel} autoFocus> Cancel </Button>
40
+ <Button
41
+ color={"primary"}
42
+ onClick={handleOk}> Ok </Button>
39
43
  </DialogActions>
40
44
  </Dialog>
41
45
  );
@@ -115,7 +115,6 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
115
115
  endAdornment,
116
116
  AddColumnComponent,
117
117
  initialScroll = 0,
118
- debug
119
118
  }: VirtualTableProps<T>) {
120
119
 
121
120
  const sortByProperty: string | undefined = sortBy ? sortBy[0] : undefined;
@@ -131,7 +130,8 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
131
130
  // Set initial scroll position
132
131
  useEffect(() => {
133
132
  if (tableRef.current && initialScroll) {
134
- tableRef.current.scrollTo(0, initialScroll);
133
+ const { scrollLeft } = tableRef.current;
134
+ tableRef.current.scrollTo(scrollLeft, initialScroll);
135
135
  }
136
136
  }, [tableRef, initialScroll]);
137
137
 
@@ -170,14 +170,14 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
170
170
  });
171
171
 
172
172
  const onColumnResizeInternal = useCallback((params: OnVirtualTableColumnResizeParams) => {
173
- if (debug)
174
- console.log("onColumnResizeInternal", params);
175
- setColumns(columns.map((column) => column.key === params.column.key ? params.column : column));
176
- }, [columns]);
173
+ setColumns(prevColumns =>
174
+ prevColumns.map((column) =>
175
+ column.key === params.column.key ? params.column : column
176
+ )
177
+ );
178
+ }, []);
177
179
 
178
180
  const onColumnResizeEndInternal = useCallback((params: OnVirtualTableColumnResizeParams) => {
179
- if (debug)
180
- console.log("onColumnResizeEndInternal", params);
181
181
  setColumns(columns.map((column) => column.key === params.column.key ? params.column : column));
182
182
  if (onColumnResize) {
183
183
  onColumnResize(params);
@@ -188,14 +188,10 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
188
188
  const filterRef = useRef<VirtualTableFilterValues<any> | undefined>();
189
189
 
190
190
  useEffect(() => {
191
- if (debug)
192
- console.log("Filter updated", filterInput);
193
191
  filterRef.current = filterInput;
194
192
  }, [filterInput]);
195
193
 
196
194
  const scrollToTop = useCallback(() => {
197
- if (debug)
198
- console.log("scrollToTop");
199
195
  endReachCallbackThreshold.current = 0;
200
196
  if (tableRef.current) {
201
197
  tableRef.current.scrollTo(tableRef.current?.scrollLeft, 0);
@@ -204,9 +200,6 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
204
200
 
205
201
  const onColumnSort = useCallback((key: string) => {
206
202
 
207
- if (debug)
208
- console.log("onColumnSort", key);
209
-
210
203
  const isDesc = sortByProperty === key && currentSort === "desc";
211
204
  const isAsc = sortByProperty === key && currentSort === "asc";
212
205
  const newSort = isAsc ? "desc" : (isDesc ? undefined : "asc");
@@ -234,12 +227,8 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
234
227
  }, [checkFilterCombination, currentSort, onFilterUpdate, onResetPagination, onSortByUpdate, scrollToTop, sortByProperty]);
235
228
 
236
229
  const maxScroll = Math.max((data?.length ?? 0) * rowHeight - bounds.height, 0);
237
- if (debug)
238
- console.log("maxScroll", maxScroll);
239
230
 
240
231
  const onEndReachedInternal = useCallback((scrollOffset: number) => {
241
- if (debug)
242
- console.log("onEndReachedInternal", scrollOffset, endReachCallbackThreshold.current + endOffset);
243
232
  if (onEndReached && (data?.length ?? 0) > 0 && scrollOffset > endReachCallbackThreshold.current + endOffset) {
244
233
  endReachCallbackThreshold.current = scrollOffset;
245
234
  onEndReached();
@@ -255,12 +244,6 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
255
244
  scrollOffset: number,
256
245
  scrollUpdateWasRequested: boolean;
257
246
  }) => {
258
- if (debug)
259
- console.log("onScroll", {
260
- scrollDirection,
261
- scrollOffset,
262
- scrollUpdateWasRequested
263
- });
264
247
  if (onScrollProp) {
265
248
  debouncedScroll({
266
249
  scrollDirection,
@@ -273,8 +256,6 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
273
256
  }, [maxScroll, onEndReachedInternal]);
274
257
 
275
258
  const onFilterUpdateInternal = useCallback((column: VirtualTableColumn, filterForProperty?: [VirtualTableWhereFilterOp, any]) => {
276
- if (debug)
277
- console.log("onFilterUpdateInternal", column, filterForProperty);
278
259
 
279
260
  endReachCallbackThreshold.current = 0;
280
261
  const filter = filterRef.current;
@@ -337,9 +318,6 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
337
318
  AddColumnComponent
338
319
  };
339
320
 
340
- if (debug)
341
- console.log("VirtualTable render", virtualListController);
342
-
343
321
  return (
344
322
  <div
345
323
  ref={measureRef}
@@ -162,11 +162,6 @@ export interface VirtualTableProps<T extends Record<string, any>> {
162
162
  */
163
163
  initialScroll?: number;
164
164
 
165
- /**
166
- * Debug mode
167
- */
168
- debug?: boolean;
169
-
170
165
  }
171
166
 
172
167
  export type CellRendererParams<T = any> = {
@@ -66,7 +66,6 @@ export function VirtualTableInput(props: {
66
66
  width: "100%",
67
67
  color: "unset",
68
68
  fontWeight: "unset",
69
- lineHeight: 1.7142857,
70
69
  fontSize: "unset",
71
70
  fontFamily: "unset",
72
71
  background: "unset",
@@ -5,20 +5,26 @@ import { addRecentId } from "../EntityCollectionView/utils";
5
5
  import { navigateToEntity, resolveDefaultSelectedView } from "../../util";
6
6
 
7
7
  export const editEntityAction: EntityAction = {
8
- icon: <EditIcon/>,
8
+ icon: <EditIcon size={"small"}/>,
9
9
  key: "edit",
10
10
  name: "Edit",
11
11
  collapsed: false,
12
+ isEnabled: ({ entity }) => Boolean(entity),
12
13
  onClick({
13
14
  entity,
14
15
  collection,
15
16
  fullPath,
17
+ fullIdPath,
16
18
  context,
17
19
  highlightEntity,
18
20
  unhighlightEntity,
19
21
  openEntityMode
20
22
  }): Promise<void> {
21
23
 
24
+ if (!entity) {
25
+ throw new Error("INTERNAL: editEntityAction: Entity is undefined");
26
+ }
27
+
22
28
  highlightEntity?.(entity);
23
29
 
24
30
  context.analyticsController?.onAnalyticsEvent?.("entity_click", {
@@ -30,7 +36,8 @@ export const editEntityAction: EntityAction = {
30
36
  addRecentId(collection.id, entity.id);
31
37
  }
32
38
 
33
- const path = collection?.collectionGroup ? collection.id : (fullPath ?? collection?.id ?? entity.path);
39
+ const path = collection?.collectionGroup ? entity.path : (fullPath ?? collection?.path ?? entity.path);
40
+ const newFullIdPath = collection?.collectionGroup ? collection.id : (fullIdPath ?? collection?.id ?? entity.path);
34
41
  const defaultSelectedView = resolveDefaultSelectedView(
35
42
  collection ? collection.defaultSelectedView : undefined,
36
43
  {
@@ -43,7 +50,7 @@ export const editEntityAction: EntityAction = {
43
50
  collection,
44
51
  entityId: entity.id,
45
52
  path,
46
- fullIdPath: path,
53
+ fullIdPath: newFullIdPath,
47
54
  sideEntityController: context.sideEntityController,
48
55
  onClose: () => unhighlightEntity?.(entity),
49
56
  navigation: context.navigation,
@@ -55,9 +62,10 @@ export const editEntityAction: EntityAction = {
55
62
  }
56
63
 
57
64
  export const copyEntityAction: EntityAction = {
58
- icon: <FileCopyIcon/>,
65
+ icon: <FileCopyIcon size={"small"}/>,
59
66
  name: "Copy",
60
67
  key: "copy",
68
+ isEnabled: ({ entity }) => Boolean(entity),
61
69
  onClick({
62
70
  entity,
63
71
  collection,
@@ -67,19 +75,23 @@ export const copyEntityAction: EntityAction = {
67
75
  unhighlightEntity,
68
76
  openEntityMode
69
77
  }): Promise<void> {
78
+ if (!entity) {
79
+ throw new Error("INTERNAL: copyEntityAction: Entity is undefined");
80
+ }
70
81
  highlightEntity?.(entity);
71
82
  context.analyticsController?.onAnalyticsEvent?.("copy_entity_click", {
72
83
  path: entity.path,
73
84
  entityId: entity.id
74
85
  });
75
86
 
76
- const path = collection?.collectionGroup ? collection.id : (fullPath ?? collection?.id ?? entity.path);
87
+ const path = collection?.collectionGroup ? collection.path : (fullPath ?? collection?.path ?? entity.path);
88
+ const fullIdPath = collection?.collectionGroup ? collection.id : (fullPath ?? collection?.id ?? entity.path);
77
89
  navigateToEntity({
78
90
  openEntityMode,
79
91
  collection,
80
92
  entityId: entity.id,
81
93
  path,
82
- fullIdPath: path,
94
+ fullIdPath,
83
95
  copy: true,
84
96
  sideEntityController: context.sideEntityController,
85
97
  onClose: () => unhighlightEntity?.(entity),
@@ -91,9 +103,10 @@ export const copyEntityAction: EntityAction = {
91
103
  }
92
104
 
93
105
  export const deleteEntityAction: EntityAction = {
94
- icon: <DeleteIcon/>,
106
+ icon: <DeleteIcon size={"small"}/>,
95
107
  name: "Delete",
96
108
  key: "delete",
109
+ isEnabled: ({ entity }) => Boolean(entity),
97
110
  onClick({
98
111
  entity,
99
112
  fullPath,
@@ -101,8 +114,11 @@ export const deleteEntityAction: EntityAction = {
101
114
  context,
102
115
  selectionController,
103
116
  onCollectionChange,
104
- sideEntityController
117
+ navigateBack
105
118
  }): Promise<void> {
119
+ if (!entity) {
120
+ throw new Error("INTERNAL: deleteEntityAction: Entity is undefined");
121
+ }
106
122
  const { closeDialog } = context.dialogsController.open({
107
123
  key: "delete_entity_dialog_" + entity.id,
108
124
  Component: ({ open }) => {
@@ -120,7 +136,7 @@ export const deleteEntityAction: EntityAction = {
120
136
  });
121
137
  selectionController?.setSelectedEntities(selectionController.selectedEntities.filter(e => e.id !== entity.id));
122
138
  onCollectionChange?.();
123
- sideEntityController?.close();
139
+ navigateBack?.();
124
140
  }}
125
141
  onClose={closeDialog}/>;
126
142
  }
@@ -134,7 +134,7 @@ export function useDataSourceTableController<M extends Record<string, any> = any
134
134
  } = parseFilterAndSort(window.location.search);
135
135
 
136
136
  const [filterValues, setFilterValues] = React.useState<FilterValues<Extract<keyof M, string>> | undefined>(forceFilter ?? (updateUrl ? initialFilterUrl : undefined) ?? initialFilter ?? undefined);
137
- const [sortBy, setSortBy] = React.useState<[Extract<keyof M, string>, "asc" | "desc"] | undefined>(initialSortUrl ?? initialSortInternal);
137
+ const [sortBy, setSortBy] = React.useState<[Extract<keyof M, string>, "asc" | "desc"] | undefined>((updateUrl ? initialSortUrl : undefined) ?? initialSortInternal);
138
138
 
139
139
  useUpdateUrl(filterValues, sortBy, searchString, updateUrl);
140
140
 
@@ -334,7 +334,7 @@ function encodeFilterAndSort(filterValues?: FilterValues<string>, sortBy?: [stri
334
334
  }
335
335
  if (encodedValue !== undefined) {
336
336
  entries[encodeURIComponent(`${key}_op`)] = encodeURIComponent(op);
337
- entries[encodeURIComponent(`${key}_value`)] = encodeURIComponent(encodedValue.toString());
337
+ entries[encodeURIComponent(`${key}_value`)] = encodedValue ? encodeURIComponent(encodedValue.toString()) : "null";
338
338
  }
339
339
  }
340
340
  });
@@ -36,3 +36,5 @@ export * from "./ArrayContainer";
36
36
  export * from "./ReferenceWidget";
37
37
  export * from "./SearchIconsView";
38
38
  export * from "./FieldCaption";
39
+
40
+ export * from "./EntityPreview";
@@ -3,7 +3,7 @@ import React, { useCallback } from "react";
3
3
  import { useLargeLayout, useNavigationController } from "../hooks";
4
4
 
5
5
  import { Link, useNavigate } from "react-router-dom";
6
- import { CMSAnalyticsEvent, TopNavigationEntry, TopNavigationResult } from "../types";
6
+ import { CMSAnalyticsEvent, NavigationEntry, NavigationResult } from "../types";
7
7
  import { IconForView } from "../util";
8
8
  import { cls, IconButton, Menu, MenuItem, MoreVertIcon, Tooltip, Typography } from "@firecms/ui";
9
9
  import { useAnalyticsController } from "../hooks/useAnalyticsController";
@@ -45,7 +45,7 @@ export function DefaultDrawer({
45
45
  const {
46
46
  navigationEntries,
47
47
  groups
48
- }: TopNavigationResult = navigation.topLevelNavigation;
48
+ }: NavigationResult = navigation.topLevelNavigation;
49
49
 
50
50
  const adminViews = navigationEntries.filter(e => e.type === "admin") ?? [];
51
51
  const groupsWithoutAdmin = groups.filter(g => g !== "Admin");
@@ -63,7 +63,7 @@ export function DefaultDrawer({
63
63
  </div>;
64
64
  }, [drawerOpen]);
65
65
 
66
- const onClick = (view: TopNavigationEntry) => {
66
+ const onClick = (view: NavigationEntry) => {
67
67
  const eventName: CMSAnalyticsEvent = view.type === "collection"
68
68
  ? "drawer_navigate_to_collection"
69
69
  : (view.type === "view" ? "drawer_navigate_to_view" : "unmapped_event");
@@ -90,9 +90,9 @@ export function DefaultDrawer({
90
90
  {buildGroupHeader(group)}
91
91
  {Object.values(navigationEntries)
92
92
  .filter(e => e.group === group)
93
- .map((view, index) =>
93
+ .map((view) =>
94
94
  <DrawerNavigationItem
95
- key={`navigation_${index}`}
95
+ key={view.id}
96
96
  icon={<IconForView collectionOrView={view.collection ?? view.view}
97
97
  size={"small"}/>}
98
98
  tooltipsOpen={tooltipsOpen}
@@ -128,13 +128,13 @@ export function DefaultDrawer({
128
128
  </div>}
129
129
  </IconButton>}
130
130
  >
131
- {adminViews.map((entry, index) =>
131
+ {adminViews.map((entry) =>
132
132
  <MenuItem
133
133
  onClick={(event) => {
134
134
  event.preventDefault();
135
- navigate(entry.path);
135
+ navigate(entry.url); // Consistent use of entry.url for navigation
136
136
  }}
137
- key={`navigation_${index}`}>
137
+ key={entry.id}>
138
138
  {<IconForView collectionOrView={entry.view}/>}
139
139
  {entry.name}
140
140
  </MenuItem>)}
@@ -38,7 +38,7 @@ export function DrawerNavigationItem({
38
38
  "flex flex-row items-center mr-8",
39
39
  // "transition-all ease-in-out delay-100 duration-300",
40
40
  // drawerOpen ? "w-full" : "w-18",
41
- drawerOpen ? "pl-4 h-12" : "pl-4 h-11",
41
+ drawerOpen ? "pl-4 h-10" : "pl-4 h-9",
42
42
  "font-semibold text-xs",
43
43
  isActive ? "bg-surface-accent-200 bg-opacity-60 dark:bg-surface-800 dark:bg-opacity-50" : ""
44
44
  )}