@firecms/core 3.0.0-beta.13 → 3.0.0-beta.14
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.
- package/dist/components/ArrayContainer.d.ts +7 -12
- package/dist/components/EntityPreview.d.ts +4 -2
- package/dist/components/SelectableTable/SelectableTable.d.ts +1 -1
- package/dist/components/VirtualTable/VirtualTableProps.d.ts +0 -4
- package/dist/components/index.d.ts +1 -0
- package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +3 -9
- package/dist/hooks/useBuildNavigationController.d.ts +2 -9
- package/dist/index.es.js +1183 -705
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +1191 -716
- package/dist/index.umd.js.map +1 -1
- package/dist/types/collections.d.ts +20 -2
- package/dist/types/firecms.d.ts +2 -1
- package/dist/types/navigation.d.ts +5 -0
- package/dist/types/plugins.d.ts +12 -0
- package/dist/types/side_entity_controller.d.ts +4 -0
- package/dist/util/callbacks.d.ts +2 -0
- package/dist/util/index.d.ts +1 -0
- package/package.json +8 -6
- package/src/components/ArrayContainer.tsx +409 -294
- package/src/components/ClearFilterSortButton.tsx +1 -1
- package/src/components/ConfirmationDialog.tsx +9 -9
- package/src/components/EntityCollectionTable/PropertyTableCell.tsx +1 -1
- package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +1 -1
- package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +13 -2
- package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +53 -27
- package/src/components/EntityCollectionTable/internal/popup_field/useDraggable.tsx +9 -9
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +4 -0
- package/src/components/EntityPreview.tsx +18 -14
- package/src/components/ErrorView.tsx +1 -1
- package/src/components/HomePage/DefaultHomePage.tsx +2 -1
- package/src/components/HomePage/NavigationCardBinding.tsx +3 -1
- package/src/components/SelectableTable/SelectableTable.tsx +140 -143
- package/src/components/VirtualTable/VirtualTable.tsx +8 -30
- package/src/components/VirtualTable/VirtualTableProps.tsx +0 -5
- package/src/components/VirtualTable/fields/VirtualTableInput.tsx +0 -1
- package/src/components/index.tsx +2 -0
- package/src/core/EntityEditView.tsx +26 -14
- package/src/core/EntitySidePanel.tsx +15 -20
- package/src/core/FireCMS.tsx +7 -1
- package/src/form/EntityForm.tsx +1 -1
- package/src/form/PropertyFieldBinding.tsx +0 -1
- package/src/form/components/CustomIdField.tsx +3 -1
- package/src/form/components/LabelWithIcon.tsx +1 -1
- package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +3 -2
- package/src/form/field_bindings/MapFieldBinding.tsx +5 -4
- package/src/form/field_bindings/MultiSelectFieldBinding.tsx +1 -1
- package/src/form/field_bindings/RepeatFieldBinding.tsx +1 -0
- package/src/form/field_bindings/SelectFieldBinding.tsx +2 -1
- package/src/form/field_bindings/StorageUploadFieldBinding.tsx +222 -154
- package/src/hooks/data/save.ts +0 -6
- package/src/hooks/useBuildNavigationController.tsx +30 -16
- package/src/internal/useBuildSideEntityController.tsx +1 -1
- package/src/preview/components/ImagePreview.tsx +2 -2
- package/src/preview/components/ReferencePreview.tsx +1 -1
- package/src/preview/property_previews/ArrayOfMapsPreview.tsx +1 -1
- package/src/preview/property_previews/MapPropertyPreview.tsx +1 -1
- package/src/preview/property_previews/SkeletonPropertyComponent.tsx +1 -1
- package/src/preview/property_previews/StringPropertyPreview.tsx +1 -1
- package/src/types/collections.ts +24 -2
- package/src/types/firecms.tsx +2 -2
- package/src/types/navigation.ts +6 -0
- package/src/types/plugins.tsx +16 -0
- package/src/types/side_entity_controller.tsx +5 -5
- package/src/util/callbacks.ts +119 -0
- package/src/util/index.ts +1 -0
- package/src/util/navigation_utils.ts +70 -55
- package/src/util/objects.ts +53 -20
- package/dist/components/EntityCollectionTable/internal/popup_field/ElementResizeListener.d.ts +0 -5
- 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 =
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
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
|
-
|
|
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,
|
|
@@ -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
|
|
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
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
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}
|
package/src/components/index.tsx
CHANGED
|
@@ -182,11 +182,13 @@ export function EntityEditViewInner<M extends Record<string, any>>({
|
|
|
182
182
|
|
|
183
183
|
const subcollections = (collection.subcollections ?? []).filter(c => !c.hideFromNavigation);
|
|
184
184
|
const subcollectionsCount = subcollections?.length ?? 0;
|
|
185
|
-
const customViews = collection.entityViews;
|
|
185
|
+
const customViews = collection.entityViews ?? [];
|
|
186
186
|
const customViewsCount = customViews?.length ?? 0;
|
|
187
187
|
const includeJsonView = collection.includeJsonView === undefined ? true : collection.includeJsonView;
|
|
188
188
|
const hasAdditionalViews = customViewsCount > 0 || subcollectionsCount > 0 || includeJsonView;
|
|
189
189
|
|
|
190
|
+
const plugins = customizationController.plugins;
|
|
191
|
+
|
|
190
192
|
const {
|
|
191
193
|
resolvedEntityViews,
|
|
192
194
|
selectedEntityView,
|
|
@@ -212,7 +214,6 @@ export function EntityEditViewInner<M extends Record<string, any>>({
|
|
|
212
214
|
}
|
|
213
215
|
|
|
214
216
|
if (!entityId) {
|
|
215
|
-
console.error("INTERNAL: entityId is not defined");
|
|
216
217
|
return null;
|
|
217
218
|
}
|
|
218
219
|
|
|
@@ -254,6 +255,7 @@ export function EntityEditViewInner<M extends Record<string, any>>({
|
|
|
254
255
|
<ErrorBoundary>
|
|
255
256
|
{usedFormContext && <Builder
|
|
256
257
|
collection={collection}
|
|
258
|
+
parentCollectionIds={parentCollectionIds}
|
|
257
259
|
entity={usedEntity}
|
|
258
260
|
modifiedValues={usedFormContext?.formex?.values ?? usedEntity?.values}
|
|
259
261
|
formContext={usedFormContext}
|
|
@@ -335,6 +337,7 @@ export function EntityEditViewInner<M extends Record<string, any>>({
|
|
|
335
337
|
entity={entity}
|
|
336
338
|
path={path}
|
|
337
339
|
collection={collection}/>
|
|
340
|
+
<div className="h-16"/>
|
|
338
341
|
</div>
|
|
339
342
|
</div> : null;
|
|
340
343
|
|
|
@@ -384,14 +387,24 @@ export function EntityEditViewInner<M extends Record<string, any>>({
|
|
|
384
387
|
</Tab>
|
|
385
388
|
);
|
|
386
389
|
|
|
387
|
-
const
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
390
|
+
const customViewTabsStart = resolvedEntityViews.filter(view => view.position === "start")
|
|
391
|
+
.map((view) =>
|
|
392
|
+
<Tab
|
|
393
|
+
className={!view.tabComponent ? "text-sm min-w-[120px]" : undefined}
|
|
394
|
+
value={view.key}
|
|
395
|
+
key={`entity_detail_collection_tab_${view.name}`}>
|
|
396
|
+
{view.tabComponent ?? view.name}
|
|
397
|
+
</Tab>
|
|
398
|
+
);
|
|
399
|
+
const customViewTabsEnd = resolvedEntityViews.filter(view => !view.position || view.position === "end")
|
|
400
|
+
.map((view) =>
|
|
401
|
+
<Tab
|
|
402
|
+
className={!view.tabComponent ? "text-sm min-w-[120px]" : undefined}
|
|
403
|
+
value={view.key}
|
|
404
|
+
key={`entity_detail_collection_tab_${view.name}`}>
|
|
405
|
+
{view.tabComponent ?? view.name}
|
|
406
|
+
</Tab>
|
|
407
|
+
);
|
|
395
408
|
|
|
396
409
|
const shouldShowTopBar = Boolean(barActions) || hasAdditionalViews;
|
|
397
410
|
|
|
@@ -417,11 +430,12 @@ export function EntityEditViewInner<M extends Record<string, any>>({
|
|
|
417
430
|
{includeJsonView && <Tab
|
|
418
431
|
disabled={!hasAdditionalViews}
|
|
419
432
|
value={JSON_TAB_VALUE}
|
|
420
|
-
innerClassName={"block"}
|
|
421
433
|
className={"text-sm"}>
|
|
422
434
|
<CodeIcon size={"small"}/>
|
|
423
435
|
</Tab>}
|
|
424
436
|
|
|
437
|
+
{customViewTabsStart}
|
|
438
|
+
|
|
425
439
|
<Tab
|
|
426
440
|
disabled={!hasAdditionalViews}
|
|
427
441
|
value={MAIN_TAB_VALUE}
|
|
@@ -430,7 +444,7 @@ export function EntityEditViewInner<M extends Record<string, any>>({
|
|
|
430
444
|
</Tab>
|
|
431
445
|
|
|
432
446
|
|
|
433
|
-
{
|
|
447
|
+
{customViewTabsEnd}
|
|
434
448
|
|
|
435
449
|
{subcollectionTabs}
|
|
436
450
|
</Tabs>}
|
|
@@ -453,8 +467,6 @@ export function EntityEditViewInner<M extends Record<string, any>>({
|
|
|
453
467
|
|
|
454
468
|
</div>;
|
|
455
469
|
|
|
456
|
-
const plugins = customizationController.plugins;
|
|
457
|
-
|
|
458
470
|
if (plugins) {
|
|
459
471
|
plugins.forEach((plugin: FireCMSPlugin) => {
|
|
460
472
|
if (plugin.form?.provider) {
|
|
@@ -19,11 +19,18 @@ import { useLocation, useNavigate } from "react-router-dom";
|
|
|
19
19
|
*/
|
|
20
20
|
export function EntitySidePanel(props: EntitySidePanelProps) {
|
|
21
21
|
|
|
22
|
+
const {
|
|
23
|
+
allowFullScreen = true,
|
|
24
|
+
path,
|
|
25
|
+
entityId,
|
|
26
|
+
formProps,
|
|
27
|
+
} = props;
|
|
28
|
+
|
|
22
29
|
const {
|
|
23
30
|
blocked,
|
|
24
31
|
setBlocked,
|
|
25
32
|
setBlockedNavigationMessage,
|
|
26
|
-
close
|
|
33
|
+
close,
|
|
27
34
|
} = useSideDialogContext();
|
|
28
35
|
|
|
29
36
|
const navigate = useNavigate();
|
|
@@ -64,22 +71,10 @@ export function EntitySidePanel(props: EntitySidePanelProps) {
|
|
|
64
71
|
}
|
|
65
72
|
|
|
66
73
|
const parentCollectionIds = useMemo(() => {
|
|
67
|
-
return navigationController.getParentCollectionIds(
|
|
68
|
-
}, [navigationController,
|
|
69
|
-
|
|
70
|
-
const collection = useMemo(() => {
|
|
71
|
-
if (props.collection) {
|
|
72
|
-
return props.collection;
|
|
73
|
-
}
|
|
74
|
+
return navigationController.getParentCollectionIds(path);
|
|
75
|
+
}, [navigationController, path]);
|
|
74
76
|
|
|
75
|
-
|
|
76
|
-
if (registryCollection) {
|
|
77
|
-
return registryCollection;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
console.error("ERROR: No collection found in path `", props.path, "`. Entity id: ", props.entityId);
|
|
81
|
-
throw Error("ERROR: No collection found in path `" + props.path + "`. Make sure you have defined a collection for this path in the root navigation.");
|
|
82
|
-
}, [navigationController, props.collection]);
|
|
77
|
+
const collection = props.collection ?? navigationController.getCollection(path);
|
|
83
78
|
|
|
84
79
|
useEffect(() => {
|
|
85
80
|
function beforeunload(e: any) {
|
|
@@ -126,16 +121,16 @@ export function EntitySidePanel(props: EntitySidePanelProps) {
|
|
|
126
121
|
onClick={onClose}>
|
|
127
122
|
<CloseIcon size={"small"}/>
|
|
128
123
|
</IconButton>
|
|
129
|
-
<IconButton
|
|
124
|
+
{allowFullScreen && <IconButton
|
|
130
125
|
className="self-center"
|
|
131
126
|
onClick={() => {
|
|
132
|
-
if (
|
|
127
|
+
if (entityId)
|
|
133
128
|
navigate(location.pathname);
|
|
134
129
|
else
|
|
135
130
|
navigate(location.pathname + "#new");
|
|
136
131
|
}}>
|
|
137
132
|
<OpenInFullIcon size={"small"}/>
|
|
138
|
-
</IconButton>
|
|
133
|
+
</IconButton>}
|
|
139
134
|
</>}
|
|
140
135
|
onTabChange={({
|
|
141
136
|
path,
|
|
@@ -151,7 +146,7 @@ export function EntitySidePanel(props: EntitySidePanelProps) {
|
|
|
151
146
|
collection,
|
|
152
147
|
});
|
|
153
148
|
}}
|
|
154
|
-
formProps={
|
|
149
|
+
formProps={formProps}
|
|
155
150
|
/>
|
|
156
151
|
</ErrorBoundary>
|
|
157
152
|
|
package/src/core/FireCMS.tsx
CHANGED
|
@@ -44,7 +44,7 @@ export function FireCMS<USER extends User>(props: FireCMSProps<USER>) {
|
|
|
44
44
|
authController,
|
|
45
45
|
storageSource,
|
|
46
46
|
dataSourceDelegate,
|
|
47
|
-
plugins,
|
|
47
|
+
plugins: pluginsProp,
|
|
48
48
|
onAnalyticsEvent,
|
|
49
49
|
propertyConfigs,
|
|
50
50
|
entityViews,
|
|
@@ -53,6 +53,12 @@ export function FireCMS<USER extends User>(props: FireCMSProps<USER>) {
|
|
|
53
53
|
apiKey
|
|
54
54
|
} = props;
|
|
55
55
|
|
|
56
|
+
if (pluginsProp) {
|
|
57
|
+
console.warn("The `plugins` prop is deprecated in the FireCMS component. You should pass your plugins to `useBuildNavigationController` instead.");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const plugins = navigationController.plugins ?? pluginsProp;
|
|
61
|
+
|
|
56
62
|
const sideDialogsController = useBuildSideDialogsController();
|
|
57
63
|
const sideEntityController = useBuildSideEntityController(navigationController, sideDialogsController, authController);
|
|
58
64
|
|
package/src/form/EntityForm.tsx
CHANGED
|
@@ -621,7 +621,7 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
621
621
|
<>
|
|
622
622
|
{!Builder && <div className={"w-full py-2 flex flex-col items-start my-4 lg:my-6"}>
|
|
623
623
|
<Typography
|
|
624
|
-
className={"
|
|
624
|
+
className={"my-4 flex-grow line-clamp-1 " + (collection.hideIdFromForm ? "mb-6" : "")}
|
|
625
625
|
variant={"h4"}>
|
|
626
626
|
{title ?? collection.singularName ?? collection.name}
|
|
627
627
|
</Typography>
|
|
@@ -214,7 +214,6 @@ function FieldInternal<T extends CMSType, CustomProps, M extends Record<string,
|
|
|
214
214
|
|
|
215
215
|
const customFieldProps: any = property.customProps;
|
|
216
216
|
const value = formexFieldProps.field.value;
|
|
217
|
-
// const initialValue = formexFieldProps.meta.initialValue;
|
|
218
217
|
const error = getIn(formexFieldProps.form.errors, propertyKey);
|
|
219
218
|
const touched = getIn(formexFieldProps.form.touched, propertyKey);
|
|
220
219
|
|
|
@@ -103,7 +103,9 @@ export function CustomIdField<M extends Record<string, any>>({
|
|
|
103
103
|
size={"large"}
|
|
104
104
|
error={error}
|
|
105
105
|
fullWidth={true}
|
|
106
|
-
onValueChange={(v) =>
|
|
106
|
+
onValueChange={(v) => {
|
|
107
|
+
onChange(v as string);
|
|
108
|
+
}}
|
|
107
109
|
{...fieldProps}
|
|
108
110
|
renderValue={(option) => {
|
|
109
111
|
const enumConfig = enumValues.find(e => e.id === option);
|
|
@@ -24,7 +24,7 @@ export const LabelWithIcon = forwardRef<HTMLDivElement, LabelWithIconProps>(
|
|
|
24
24
|
return (
|
|
25
25
|
<div
|
|
26
26
|
ref={ref}
|
|
27
|
-
className={cls("inline-flex items-center my-0.5",
|
|
27
|
+
className={cls("align-middle inline-flex items-center my-0.5",
|
|
28
28
|
small ? "gap-1" : "gap-2",
|
|
29
29
|
className)}
|
|
30
30
|
>
|