@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.
- package/README.md +1 -1
- package/dist/components/ClearFilterSortButton.d.ts +5 -0
- package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +11 -11
- package/dist/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +1 -1
- package/dist/components/EntityCollectionTable/internal/CollectionTableToolbar.d.ts +1 -4
- package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +11 -1
- package/dist/components/EntityCollectionView/EntityCollectionViewStartActions.d.ts +11 -0
- package/dist/components/EntityPreview.d.ts +2 -2
- package/dist/components/SelectableTable/SelectableTable.d.ts +1 -1
- package/dist/components/common/types.d.ts +1 -1
- package/dist/contexts/AuthControllerContext.d.ts +1 -1
- package/dist/form/components/ErrorFocus.d.ts +1 -1
- package/dist/hooks/data/delete.d.ts +2 -2
- package/dist/hooks/data/save.d.ts +1 -1
- package/dist/hooks/data/useDataSource.d.ts +1 -1
- package/dist/hooks/data/useEntityFetch.d.ts +3 -3
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/useBuildNavigationController.d.ts +1 -2
- package/dist/hooks/useProjectLog.d.ts +2 -2
- package/dist/hooks/useValidateAuthenticator.d.ts +21 -0
- package/dist/index.es.js +3948 -3737
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +5 -5
- package/dist/index.umd.js.map +1 -1
- package/dist/internal/useBuildDataSource.d.ts +1 -16
- package/dist/internal/useRestoreScroll.d.ts +1 -1
- package/dist/preview/PropertyPreviewProps.d.ts +1 -4
- package/dist/types/auth.d.ts +30 -1
- package/dist/types/collections.d.ts +8 -4
- package/dist/types/datasource.d.ts +3 -6
- package/dist/types/entities.d.ts +5 -1
- package/dist/types/entity_callbacks.d.ts +2 -2
- package/dist/types/index.d.ts +1 -1
- package/dist/types/navigation.d.ts +4 -4
- package/dist/types/plugins.d.ts +5 -3
- package/dist/types/properties.d.ts +2 -2
- package/dist/types/roles.d.ts +31 -0
- package/dist/types/storage.d.ts +11 -3
- package/dist/types/user.d.ts +5 -0
- package/dist/util/collections.d.ts +1 -1
- package/dist/util/entities.d.ts +1 -1
- package/dist/util/navigation_utils.d.ts +2 -2
- package/dist/util/resolutions.d.ts +5 -5
- package/dist/util/useTraceUpdate.d.ts +1 -0
- package/package.json +23 -20
- package/src/components/ClearFilterSortButton.tsx +41 -0
- package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +10 -11
- package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +1 -1
- package/src/components/EntityCollectionTable/PropertyTableCell.tsx +16 -19
- package/src/components/EntityCollectionTable/fields/TableReferenceField.tsx +1 -1
- package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +27 -32
- package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +11 -6
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +28 -5
- package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +68 -0
- package/src/components/EntityPreview.tsx +5 -2
- package/src/components/EntityView.tsx +1 -1
- package/src/components/HomePage/DefaultHomePage.tsx +2 -2
- package/src/components/HomePage/NavigationCard.tsx +1 -1
- package/src/components/ReferenceWidget.tsx +1 -1
- package/src/components/SelectableTable/SelectableTable.tsx +1 -1
- package/src/components/SelectableTable/filters/BooleanFilterField.tsx +2 -3
- package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +23 -8
- package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +24 -5
- package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +35 -15
- package/src/components/VirtualTable/VirtualTable.tsx +28 -20
- package/src/components/VirtualTable/fields/VirtualTableDateField.tsx +1 -1
- package/src/components/common/types.tsx +1 -1
- package/src/contexts/AuthControllerContext.tsx +1 -1
- package/src/core/FireCMS.tsx +2 -3
- package/src/core/field_configs.tsx +1 -2
- package/src/form/EntityForm.tsx +1 -1
- package/src/form/field_bindings/DateTimeFieldBinding.tsx +1 -1
- package/src/hooks/data/delete.ts +3 -3
- package/src/hooks/data/save.ts +2 -1
- package/src/hooks/data/useDataSource.tsx +1 -1
- package/src/hooks/data/useEntityFetch.tsx +3 -3
- package/src/hooks/index.tsx +2 -0
- package/src/hooks/useBuildLocalConfigurationPersistence.tsx +9 -10
- package/src/hooks/useBuildModeController.tsx +11 -5
- package/src/hooks/useBuildNavigationController.tsx +136 -59
- package/src/hooks/useProjectLog.tsx +8 -6
- package/src/hooks/useValidateAuthenticator.tsx +115 -0
- package/src/internal/useBuildDataSource.ts +42 -47
- package/src/internal/useBuildSideEntityController.tsx +18 -12
- package/src/preview/PropertyPreview.tsx +2 -12
- package/src/preview/PropertyPreviewProps.tsx +1 -11
- package/src/preview/components/BooleanPreview.tsx +4 -2
- package/src/preview/components/ReferencePreview.tsx +1 -1
- package/src/types/auth.tsx +40 -1
- package/src/types/collections.ts +8 -4
- package/src/types/datasource.ts +8 -5
- package/src/types/entities.ts +9 -1
- package/src/types/entity_callbacks.ts +2 -2
- package/src/types/index.ts +1 -1
- package/src/types/navigation.ts +6 -6
- package/src/types/plugins.tsx +6 -5
- package/src/types/properties.ts +5 -4
- package/src/types/roles.ts +41 -0
- package/src/types/storage.ts +12 -3
- package/src/types/user.ts +7 -0
- package/src/util/collections.ts +1 -1
- package/src/util/entities.ts +1 -1
- package/src/util/navigation_utils.ts +6 -6
- package/src/util/strings.ts +2 -2
- package/src/util/useTraceUpdate.tsx +2 -1
- package/dist/internal/useLocaleConfig.d.ts +0 -1
- package/dist/types/appcheck.d.ts +0 -26
- package/src/internal/useLocaleConfig.tsx +0 -18
- 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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
155
|
+
setValidationError(e);
|
|
155
156
|
});
|
|
156
157
|
};
|
|
157
158
|
|
|
158
159
|
useEffect(() => {
|
|
159
160
|
validation
|
|
160
161
|
.validate(internalValue)
|
|
161
|
-
.then(() =>
|
|
162
|
-
.catch(
|
|
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
|
|
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
|
|
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(
|
|
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 && !
|
|
47
|
+
if (searchInputRef.current && searchLoading.current && !textSearchLoading) {
|
|
41
48
|
searchInputRef.current.focus();
|
|
42
49
|
}
|
|
43
|
-
searchLoading.current =
|
|
44
|
-
}, [
|
|
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={
|
|
57
|
+
value={size as string}
|
|
61
58
|
className="w-16 h-10"
|
|
62
59
|
size={"small"}
|
|
63
|
-
onValueChange={(v) =>
|
|
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
|
-
{
|
|
82
|
-
{
|
|
78
|
+
{title && <div className={"hidden lg:block"}>
|
|
79
|
+
{title}
|
|
83
80
|
</div>}
|
|
84
81
|
|
|
85
82
|
{sizeSelect}
|
|
86
83
|
|
|
87
|
-
{
|
|
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
|
-
{
|
|
91
|
+
{loading &&
|
|
97
92
|
<CircularProgress size={"small"}/>}
|
|
98
93
|
</div>}
|
|
99
94
|
|
|
100
|
-
{(
|
|
95
|
+
{(onTextSearch || onTextSearchClick) &&
|
|
101
96
|
<SearchBar
|
|
102
97
|
key={"search-bar"}
|
|
103
98
|
inputRef={searchInputRef}
|
|
104
|
-
loading={
|
|
105
|
-
disabled={Boolean(
|
|
106
|
-
onClick={
|
|
107
|
-
onTextSearch={
|
|
99
|
+
loading={textSearchLoading}
|
|
100
|
+
disabled={Boolean(onTextSearchClick)}
|
|
101
|
+
onClick={onTextSearchClick}
|
|
102
|
+
onTextSearch={onTextSearchClick ? undefined : onTextSearch}
|
|
108
103
|
expandable={true}/>}
|
|
109
104
|
|
|
110
|
-
{
|
|
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
|
-
|
|
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
|
-
|
|
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: () =>
|
|
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
|
|
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 =
|
|
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.
|
|
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} />
|
|
@@ -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
|
|
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-[
|
|
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
|
}
|