@firecms/core 3.0.0-alpha.58 → 3.0.0-alpha.60
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/ReferenceWidget.d.ts +20 -16
- package/dist/index.es.js +2812 -2900
- 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/types/entities.d.ts +1 -1
- package/dist/util/entities.d.ts +1 -1
- package/package.json +3 -3
- package/src/components/ReferenceWidget.tsx +100 -210
- package/src/types/entities.ts +1 -1
- package/src/util/entities.ts +1 -1
package/dist/types/entities.d.ts
CHANGED
|
@@ -31,7 +31,7 @@ export type EntityValues<M extends object> = M;
|
|
|
31
31
|
/**
|
|
32
32
|
* Class used to create a reference to an entity in a different path
|
|
33
33
|
*/
|
|
34
|
-
export declare class EntityReference {
|
|
34
|
+
export declare class EntityReference<M extends Record<string, any> = any> {
|
|
35
35
|
/**
|
|
36
36
|
* ID of the entity
|
|
37
37
|
*/
|
package/dist/util/entities.d.ts
CHANGED
|
@@ -23,6 +23,6 @@ export declare function updateDateAutoValues<M extends Record<string, any>>({ in
|
|
|
23
23
|
* @group Datasource
|
|
24
24
|
*/
|
|
25
25
|
export declare function sanitizeData<M extends Record<string, any>>(values: EntityValues<M>, properties: ResolvedProperties<M>): any;
|
|
26
|
-
export declare function getReferenceFrom(entity: Entity<
|
|
26
|
+
export declare function getReferenceFrom<M extends Record<string, any>>(entity: Entity<M>): EntityReference<M>;
|
|
27
27
|
export declare function traverseValuesProperties<M extends Record<string, any>>(inputValues: Partial<EntityValues<M>>, properties: ResolvedProperties<M>, operation: (value: any, property: Property) => any): EntityValues<M> | undefined;
|
|
28
28
|
export declare function traverseValueProperty(inputValue: any, property: Property, operation: (value: any, property: Property) => any): any;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@firecms/core",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.60",
|
|
4
4
|
"description": "Awesome Firebase/Firestore-based headless open-source CMS",
|
|
5
5
|
"funding": {
|
|
6
6
|
"url": "https://github.com/sponsors/firecmsco"
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"generateIcons": "ts-node --esm src/icons/generateIcons.ts"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@firecms/ui": "^3.0.0-alpha.
|
|
48
|
+
"@firecms/ui": "^3.0.0-alpha.60",
|
|
49
49
|
"@fontsource/ibm-plex-mono": "^5.0.8",
|
|
50
50
|
"@fontsource/roboto": "^5.0.8",
|
|
51
51
|
"@hello-pangea/dnd": "^16.5.0",
|
|
@@ -116,7 +116,7 @@
|
|
|
116
116
|
"dist",
|
|
117
117
|
"src"
|
|
118
118
|
],
|
|
119
|
-
"gitHead": "
|
|
119
|
+
"gitHead": "04c920a874385714dd35f320256e6def346c2a9e",
|
|
120
120
|
"publishConfig": {
|
|
121
121
|
"access": "public"
|
|
122
122
|
}
|
|
@@ -1,64 +1,52 @@
|
|
|
1
1
|
import React, { useCallback, useMemo } from "react";
|
|
2
2
|
|
|
3
|
-
import { Entity, EntityCollection, EntityReference, FilterValues
|
|
4
|
-
import { getReferenceFrom
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
3
|
+
import { Entity, EntityCollection, EntityReference, FilterValues } from "../types";
|
|
4
|
+
import { getReferenceFrom } from "../util";
|
|
5
|
+
import { PreviewSize, ReferencePreview } from "../preview";
|
|
6
|
+
import { useNavigationController, useReferenceDialog } from "../hooks";
|
|
7
|
+
import { Button, cn } from "@firecms/ui";
|
|
8
|
+
|
|
9
|
+
export type ReferenceWidgetProps<M extends Record<string, any>> = {
|
|
10
|
+
name?: string,
|
|
11
|
+
multiselect?: boolean,
|
|
12
|
+
value: EntityReference<M> | EntityReference<M>[] | null,
|
|
13
|
+
onReferenceSelected?: (params: {
|
|
14
|
+
reference: EntityReference<M> | null,
|
|
15
|
+
entity: Entity<M> | null
|
|
16
|
+
}) => void,
|
|
17
|
+
onMultipleReferenceSelected?: (params: {
|
|
18
|
+
references: EntityReference<M>[] | null,
|
|
19
|
+
entities: Entity<M>[] | null
|
|
20
|
+
}) => void,
|
|
21
|
+
path: string,
|
|
22
|
+
disabled?: boolean,
|
|
23
|
+
previewProperties?: string[];
|
|
24
|
+
/**
|
|
25
|
+
* Allow selection of entities that pass the given filter only.
|
|
26
|
+
*/
|
|
27
|
+
forceFilter?: FilterValues<string>;
|
|
28
|
+
size: PreviewSize;
|
|
29
|
+
className?: string;
|
|
30
|
+
};
|
|
26
31
|
|
|
27
32
|
/**
|
|
28
33
|
* This field allows selecting reference/s.
|
|
29
|
-
* @param name
|
|
30
|
-
* @param path
|
|
31
|
-
* @param disabled
|
|
32
|
-
* @param value
|
|
33
|
-
* @param setValue
|
|
34
|
-
* @param previewProperties
|
|
35
|
-
* @param forceFilter
|
|
36
|
-
* @constructor
|
|
37
34
|
*/
|
|
38
35
|
export function ReferenceWidget<M extends Record<string, any>>({
|
|
39
36
|
name,
|
|
37
|
+
multiselect = false,
|
|
40
38
|
path,
|
|
41
39
|
disabled,
|
|
42
40
|
value,
|
|
43
|
-
|
|
41
|
+
onReferenceSelected,
|
|
42
|
+
onMultipleReferenceSelected,
|
|
44
43
|
previewProperties,
|
|
45
|
-
forceFilter
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
setValue: (value: EntityReference | null) => void,
|
|
50
|
-
path: string,
|
|
51
|
-
disabled?: boolean,
|
|
52
|
-
previewProperties?: string[];
|
|
53
|
-
/**
|
|
54
|
-
* Allow selection of entities that pass the given filter only.
|
|
55
|
-
*/
|
|
56
|
-
forceFilter?: FilterValues<string>;
|
|
57
|
-
}) {
|
|
44
|
+
forceFilter,
|
|
45
|
+
size,
|
|
46
|
+
className
|
|
47
|
+
}: ReferenceWidgetProps<M>) {
|
|
58
48
|
|
|
59
|
-
const fireCMSContext = useFireCMSContext();
|
|
60
49
|
const navigationController = useNavigationController();
|
|
61
|
-
const sideEntityController = useSideEntityController();
|
|
62
50
|
|
|
63
51
|
const collection: EntityCollection | undefined = useMemo(() => {
|
|
64
52
|
return navigationController.getCollection(path);
|
|
@@ -68,188 +56,90 @@ export function ReferenceWidget<M extends Record<string, any>>({
|
|
|
68
56
|
throw Error(`Couldn't find the corresponding collection for the path: ${path}`);
|
|
69
57
|
}
|
|
70
58
|
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
entityId: validValue ? value.id : undefined,
|
|
80
|
-
collection,
|
|
81
|
-
useCache: true
|
|
82
|
-
});
|
|
59
|
+
const onSingleEntitySelected = useCallback((entity: Entity<M> | null) => {
|
|
60
|
+
if (disabled)
|
|
61
|
+
return;
|
|
62
|
+
if (onReferenceSelected) {
|
|
63
|
+
const reference = entity ? getReferenceFrom(entity) : null;
|
|
64
|
+
onReferenceSelected?.({ reference, entity });
|
|
65
|
+
}
|
|
66
|
+
}, [disabled, onReferenceSelected]);
|
|
83
67
|
|
|
84
|
-
const
|
|
68
|
+
const onMultipleEntitiesSelected = useCallback((entities: Entity<M>[]) => {
|
|
85
69
|
if (disabled)
|
|
86
70
|
return;
|
|
87
|
-
|
|
88
|
-
|
|
71
|
+
if (onMultipleReferenceSelected) {
|
|
72
|
+
const references = entities ? entities.map(e => getReferenceFrom(e)) : null;
|
|
73
|
+
onMultipleReferenceSelected({ references, entities });
|
|
74
|
+
}
|
|
75
|
+
}, [disabled, onReferenceSelected]);
|
|
89
76
|
|
|
90
77
|
const referenceDialogController = useReferenceDialog({
|
|
91
|
-
multiselect
|
|
78
|
+
multiselect,
|
|
92
79
|
path,
|
|
93
80
|
collection,
|
|
94
81
|
onSingleEntitySelected,
|
|
82
|
+
onMultipleEntitiesSelected,
|
|
95
83
|
forceFilter
|
|
96
84
|
}
|
|
97
85
|
);
|
|
98
86
|
|
|
99
|
-
const handleClickOpen = useCallback(() => {
|
|
100
|
-
referenceDialogController.open();
|
|
101
|
-
}, [referenceDialogController]);
|
|
102
|
-
|
|
103
87
|
const clearValue = useCallback((e: React.MouseEvent) => {
|
|
104
88
|
e.stopPropagation();
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
const seeEntityDetails = useCallback((e: React.MouseEvent) => {
|
|
109
|
-
e.stopPropagation();
|
|
110
|
-
if (entity) {
|
|
111
|
-
fireCMSContext.onAnalyticsEvent?.("entity_click_from_reference", {
|
|
112
|
-
path: entity.path,
|
|
113
|
-
entityId: entity.id
|
|
114
|
-
});
|
|
115
|
-
sideEntityController.open({
|
|
116
|
-
entityId: entity.id,
|
|
117
|
-
path,
|
|
118
|
-
updateUrl: true
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
}, [entity, path, sideEntityController]);
|
|
122
|
-
|
|
123
|
-
const buildEntityView = (collection?: EntityCollection<any>) => {
|
|
124
|
-
|
|
125
|
-
const missingEntity = entity && !entity.values;
|
|
126
|
-
|
|
127
|
-
let body: React.ReactNode;
|
|
128
|
-
if (!collection) {
|
|
129
|
-
body = (
|
|
130
|
-
<ErrorView
|
|
131
|
-
error={"The specified collection does not exist. Check console"}/>
|
|
132
|
-
);
|
|
133
|
-
} else if (missingEntity) {
|
|
134
|
-
body = (
|
|
135
|
-
<Tooltip title={value && value.path}>
|
|
136
|
-
<div className="flex items-center p-4 flex-grow">
|
|
137
|
-
<ErrorIcon size={"small"} color={"error"}/>
|
|
138
|
-
<div className="ml-4">Missing
|
|
139
|
-
reference {entity && entity.id}</div>
|
|
140
|
-
</div>
|
|
141
|
-
</Tooltip>
|
|
142
|
-
);
|
|
89
|
+
if (multiselect) {
|
|
90
|
+
onMultipleEntitiesSelected([]);
|
|
143
91
|
} else {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
const listProperties = getReferencePreviewKeys(collection, fireCMSContext.propertyConfigs, previewProperties, 3);
|
|
147
|
-
|
|
148
|
-
body = (
|
|
149
|
-
<div className="flex flex-col flex-grow ml-4 mr-4">
|
|
150
|
-
|
|
151
|
-
{listProperties && listProperties.map((key) => {
|
|
152
|
-
const property = collection.properties[key as string];
|
|
153
|
-
if (!property) return null;
|
|
154
|
-
return (
|
|
155
|
-
<div
|
|
156
|
-
key={`reference_previews_${key as string}`}
|
|
157
|
-
className="mt-1 mb-1">
|
|
158
|
-
<ErrorBoundary>{
|
|
159
|
-
entity
|
|
160
|
-
? <PropertyPreview
|
|
161
|
-
propertyKey={key as string}
|
|
162
|
-
value={(entity.values)[key]}
|
|
163
|
-
property={property as ResolvedProperty}
|
|
164
|
-
entity={entity}
|
|
165
|
-
size={"tiny"}/>
|
|
166
|
-
: <SkeletonPropertyComponent
|
|
167
|
-
property={property as ResolvedProperty}
|
|
168
|
-
size={"tiny"}/>}
|
|
169
|
-
</ErrorBoundary>
|
|
170
|
-
</div>
|
|
171
|
-
);
|
|
172
|
-
})}
|
|
173
|
-
</div>
|
|
174
|
-
);
|
|
175
|
-
} else {
|
|
176
|
-
body = <div className="p-4 flex justify-center"
|
|
177
|
-
onClick={disabled ? undefined : handleClickOpen}>
|
|
178
|
-
<Typography variant={"label"}
|
|
179
|
-
className="flex-grow text-center">No value
|
|
180
|
-
set</Typography>
|
|
181
|
-
{!disabled && <Button variant="outlined"
|
|
182
|
-
color="primary">
|
|
183
|
-
Set
|
|
184
|
-
</Button>}
|
|
185
|
-
</div>;
|
|
186
|
-
}
|
|
92
|
+
onSingleEntitySelected(null);
|
|
187
93
|
}
|
|
94
|
+
}, [onReferenceSelected]);
|
|
95
|
+
|
|
96
|
+
let child: React.ReactNode;
|
|
188
97
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
<div className="flex flex-col flex-grow">
|
|
195
|
-
|
|
196
|
-
<div className="flex flex-col flex-grow">
|
|
197
|
-
<LabelWithIcon icon={<LinkIcon color={"inherit"}
|
|
198
|
-
/>}
|
|
199
|
-
className="text-text-secondary dark:text-text-secondary-dark ml-3.5"
|
|
200
|
-
title={name}
|
|
201
|
-
/>
|
|
202
|
-
|
|
203
|
-
{entity &&
|
|
204
|
-
<div className="self-center m-4">
|
|
205
|
-
<Tooltip title={value && value.path}>
|
|
206
|
-
<Typography variant={"caption"}
|
|
207
|
-
className={"font-mono"}>
|
|
208
|
-
{entity.id}
|
|
209
|
-
</Typography>
|
|
210
|
-
</Tooltip>
|
|
211
|
-
</div>}
|
|
212
|
-
|
|
213
|
-
{!missingEntity && entity && value &&
|
|
214
|
-
<Tooltip title={`See details for ${entity.id}`}>
|
|
215
|
-
<span>
|
|
216
|
-
<IconButton
|
|
217
|
-
onClick={seeEntityDetails}
|
|
218
|
-
size="large">
|
|
219
|
-
<KeyboardTabIcon/>
|
|
220
|
-
</IconButton>
|
|
221
|
-
</span>
|
|
222
|
-
</Tooltip>}
|
|
223
|
-
|
|
224
|
-
{value && <div>
|
|
225
|
-
<Tooltip title=" Clear">
|
|
226
|
-
<span>
|
|
227
|
-
<IconButton
|
|
228
|
-
disabled={disabled}
|
|
229
|
-
onClick={disabled ? undefined : clearValue}
|
|
230
|
-
size="large">
|
|
231
|
-
<ClearIcon/>
|
|
232
|
-
</IconButton>
|
|
233
|
-
</span>
|
|
234
|
-
</Tooltip>
|
|
235
|
-
</div>}
|
|
236
|
-
|
|
237
|
-
</div>
|
|
238
|
-
|
|
239
|
-
{body}
|
|
240
|
-
|
|
241
|
-
</div>
|
|
242
|
-
</div>
|
|
243
|
-
);
|
|
98
|
+
const onEntryClick = () => {
|
|
99
|
+
if (disabled)
|
|
100
|
+
return;
|
|
101
|
+
referenceDialogController.open();
|
|
244
102
|
};
|
|
245
103
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
104
|
+
if (Array.isArray(value)) {
|
|
105
|
+
child = <div className={"flex flex-col gap-4"}>
|
|
106
|
+
{value.map((ref, index) => {
|
|
107
|
+
return <ReferencePreview
|
|
108
|
+
key={`reference_preview_${index}`}
|
|
109
|
+
onClick={onEntryClick}
|
|
110
|
+
reference={ref}
|
|
111
|
+
disabled={disabled}
|
|
112
|
+
previewProperties={previewProperties}
|
|
113
|
+
size={size}/>
|
|
114
|
+
})}
|
|
115
|
+
</div>
|
|
116
|
+
} else if (value instanceof EntityReference) {
|
|
117
|
+
child = <ReferencePreview
|
|
118
|
+
reference={value}
|
|
119
|
+
onClick={onEntryClick}
|
|
120
|
+
disabled={disabled}
|
|
121
|
+
previewProperties={previewProperties}
|
|
122
|
+
size={size}/>
|
|
251
123
|
|
|
252
|
-
|
|
124
|
+
}
|
|
125
|
+
return <div className={cn("text-sm font-medium text-gray-500",
|
|
126
|
+
"min-w-80 flex flex-col gap-4",
|
|
127
|
+
"relative transition-colors duration-200 ease-in rounded font-medium",
|
|
128
|
+
disabled ? "bg-opacity-50" : "hover:bg-opacity-75",
|
|
129
|
+
"text-opacity-50 dark:text-white dark:text-opacity-50",
|
|
130
|
+
className
|
|
131
|
+
)}
|
|
132
|
+
>
|
|
253
133
|
|
|
254
|
-
|
|
134
|
+
{child}
|
|
135
|
+
{!value && <div className="justify-center text-left">
|
|
136
|
+
<Button variant="outlined"
|
|
137
|
+
color="primary"
|
|
138
|
+
disabled={disabled}
|
|
139
|
+
onClick={onEntryClick}>
|
|
140
|
+
Edit {name}
|
|
141
|
+
</Button>
|
|
142
|
+
</div>}
|
|
143
|
+
|
|
144
|
+
</div>;
|
|
255
145
|
}
|
package/src/types/entities.ts
CHANGED
|
@@ -37,7 +37,7 @@ export type EntityValues<M extends object> = M;
|
|
|
37
37
|
/**
|
|
38
38
|
* Class used to create a reference to an entity in a different path
|
|
39
39
|
*/
|
|
40
|
-
export class EntityReference {
|
|
40
|
+
export class EntityReference<M extends Record<string, any> = any> {
|
|
41
41
|
/**
|
|
42
42
|
* ID of the entity
|
|
43
43
|
*/
|
package/src/util/entities.ts
CHANGED
|
@@ -139,7 +139,7 @@ export function sanitizeData<M extends Record<string, any>>
|
|
|
139
139
|
return result;
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
export function getReferenceFrom(entity: Entity<
|
|
142
|
+
export function getReferenceFrom<M extends Record<string, any>>(entity: Entity<M>): EntityReference<M> {
|
|
143
143
|
return new EntityReference(entity.id, entity.path);
|
|
144
144
|
}
|
|
145
145
|
|