@firecms/core 3.0.0-alpha.27 → 3.0.0-alpha.29
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/Popover.d.ts +3 -1
- package/dist/core/FireCMS.d.ts +2 -2
- package/dist/core/builders.d.ts +5 -5
- package/dist/core/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +4 -2
- package/dist/core/components/EntityCollectionTable/filters/ReferenceFilterField.d.ts +3 -3
- package/dist/core/components/EntityCollectionTable/internal/EntityCollectionRowActions.d.ts +15 -11
- package/dist/core/components/EntityCollectionTable/internal/default_entity_actions.d.ts +5 -0
- package/dist/core/components/EntityCollectionTable/types.d.ts +1 -37
- package/dist/core/components/FieldConfigBadge.d.ts +3 -3
- package/dist/core/components/VirtualTable/VirtualTableHeader.d.ts +2 -2
- package/dist/core/components/VirtualTable/VirtualTableProps.d.ts +1 -1
- package/dist/core/contexts/DialogsProvider.d.ts +4 -0
- package/dist/core/form_field_configs.d.ts +3 -3
- package/dist/core/index.d.ts +1 -1
- package/dist/core/internal/useBuildNavigationContext.d.ts +3 -3
- package/dist/core/util/property_utils.d.ts +5 -5
- package/dist/core/util/references.d.ts +2 -2
- package/dist/core/util/resolutions.d.ts +6 -6
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/useBuildDataSource.d.ts +23 -0
- package/dist/hooks/useDialogsController.d.ts +11 -0
- package/dist/index.es.js +8996 -8583
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +67 -67
- package/dist/index.umd.js.map +1 -1
- package/dist/styles.d.ts +1 -1
- package/dist/types/collections.d.ts +36 -13
- package/dist/types/datasource.d.ts +120 -11
- package/dist/types/dialogs_controller.d.ts +30 -0
- package/dist/types/entity_actions.d.ts +33 -0
- package/dist/types/fields.d.ts +1 -1
- package/dist/types/firecms.d.ts +8 -8
- package/dist/types/firecms_context.d.ts +10 -3
- package/dist/types/index.d.ts +2 -1
- package/dist/types/navigation.d.ts +3 -3
- package/dist/types/plugins.d.ts +11 -10
- package/dist/types/properties.d.ts +1 -1
- package/dist/types/{field_config.d.ts → property_config.d.ts} +3 -4
- package/package.json +3 -3
- package/src/components/Popover.tsx +10 -3
- package/src/components/Sheet.tsx +1 -0
- package/src/components/TextareaAutosize.tsx +2 -1
- package/src/core/FireCMS.tsx +9 -6
- package/src/core/builders.ts +11 -11
- package/src/core/components/ArrayContainer.tsx +1 -1
- package/src/core/components/EntityCollectionTable/EntityCollectionTable.tsx +20 -13
- package/src/core/components/EntityCollectionTable/EntityCollectionTableProps.tsx +5 -2
- package/src/core/components/EntityCollectionTable/filters/ReferenceFilterField.tsx +11 -6
- package/src/core/components/EntityCollectionTable/internal/EntityCollectionRowActions.tsx +96 -79
- package/src/core/components/EntityCollectionTable/internal/PropertyTableCell.tsx +2 -2
- package/src/core/components/EntityCollectionTable/internal/default_entity_actions.tsx +107 -0
- package/src/core/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +6 -2
- package/src/core/components/EntityCollectionTable/types.tsx +1 -56
- package/src/core/components/EntityCollectionView/EntityCollectionView.tsx +67 -43
- package/src/core/components/FieldConfigBadge.tsx +4 -4
- package/src/core/components/ReferenceSelectionInner.tsx +2 -2
- package/src/core/components/VirtualTable/VirtualTable.tsx +4 -6
- package/src/core/components/VirtualTable/VirtualTableHeader.tsx +21 -18
- package/src/core/components/VirtualTable/VirtualTableProps.tsx +1 -1
- package/src/core/contexts/DialogsProvider.tsx +50 -0
- package/src/core/form_field_configs.tsx +5 -5
- package/src/core/index.tsx +1 -1
- package/src/core/internal/useBuildNavigationContext.tsx +13 -13
- package/src/core/internal/useBuildSideEntityController.tsx +9 -1
- package/src/core/util/property_utils.tsx +5 -5
- package/src/core/util/references.ts +2 -2
- package/src/core/util/resolutions.ts +16 -11
- package/src/form/EntityForm.tsx +64 -7
- package/src/form/PropertyFieldBinding.tsx +4 -4
- package/src/form/field_bindings/KeyValueFieldBinding.tsx +1 -1
- package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +4 -6
- package/src/hooks/index.tsx +1 -0
- package/src/hooks/useBuildDataSource.ts +351 -0
- package/src/hooks/useDialogsController.tsx +14 -0
- package/src/hooks/useFireCMSContext.tsx +5 -11
- package/src/preview/property_previews/StringPropertyPreview.tsx +4 -2
- package/src/styles.ts +1 -1
- package/src/types/collections.ts +36 -17
- package/src/types/datasource.ts +174 -10
- package/src/types/dialogs_controller.tsx +31 -0
- package/src/types/entity_actions.tsx +36 -0
- package/src/types/fields.tsx +1 -1
- package/src/types/firecms.tsx +8 -8
- package/src/types/firecms_context.tsx +11 -3
- package/src/types/index.ts +2 -1
- package/src/types/navigation.ts +3 -3
- package/src/types/plugins.tsx +11 -10
- package/src/types/properties.ts +1 -1
- package/src/types/{field_config.tsx → property_config.tsx} +3 -4
- /package/dist/core/contexts/{SnackbarContext.d.ts → SnackbarProvider.d.ts} +0 -0
- /package/src/core/contexts/{SnackbarContext.tsx → SnackbarProvider.tsx} +0 -0
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
import { useCallback } from "react";
|
|
2
|
+
import {
|
|
3
|
+
DataSource,
|
|
4
|
+
DataSourceDelegate, DeleteEntityProps,
|
|
5
|
+
Entity,
|
|
6
|
+
EntityCollection,
|
|
7
|
+
EntityReference,
|
|
8
|
+
EntityValues,
|
|
9
|
+
FetchCollectionProps,
|
|
10
|
+
FetchEntityProps,
|
|
11
|
+
FilterValues,
|
|
12
|
+
GeoPoint,
|
|
13
|
+
ListenCollectionProps,
|
|
14
|
+
ListenEntityProps,
|
|
15
|
+
PropertyConfig,
|
|
16
|
+
ResolvedProperties,
|
|
17
|
+
SaveEntityProps
|
|
18
|
+
} from "../types";
|
|
19
|
+
import { resolveCollection, updateDateAutoValues } from "../core";
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Use this hook to build a {@link DataSource} based on Firestore
|
|
23
|
+
* @param firebaseApp
|
|
24
|
+
* @param textSearchController
|
|
25
|
+
* @param collectionRegistry
|
|
26
|
+
* @category Firebase
|
|
27
|
+
*/
|
|
28
|
+
export function useBuildDataSource({
|
|
29
|
+
delegate,
|
|
30
|
+
customFields
|
|
31
|
+
}: {
|
|
32
|
+
delegate: DataSourceDelegate,
|
|
33
|
+
customFields: Record<string, PropertyConfig>;
|
|
34
|
+
}): DataSource {
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Fetch entities in a Firestore path
|
|
40
|
+
* @param path
|
|
41
|
+
* @param collection
|
|
42
|
+
* @param filter
|
|
43
|
+
* @param limit
|
|
44
|
+
* @param startAfter
|
|
45
|
+
* @param searchString
|
|
46
|
+
* @param orderBy
|
|
47
|
+
* @param order
|
|
48
|
+
* @return Function to cancel subscription
|
|
49
|
+
* @see useCollectionFetch if you need this functionality implemented as a hook
|
|
50
|
+
* @category Firestore
|
|
51
|
+
*/
|
|
52
|
+
fetchCollection: useCallback(<M extends Record<string, any>>({
|
|
53
|
+
path,
|
|
54
|
+
collection,
|
|
55
|
+
filter,
|
|
56
|
+
limit,
|
|
57
|
+
startAfter,
|
|
58
|
+
searchString,
|
|
59
|
+
orderBy,
|
|
60
|
+
order
|
|
61
|
+
}: FetchCollectionProps<M>
|
|
62
|
+
): Promise<Entity<M>[]> => {
|
|
63
|
+
|
|
64
|
+
return delegate.fetchCollection<M>({
|
|
65
|
+
path,
|
|
66
|
+
filter,
|
|
67
|
+
limit,
|
|
68
|
+
startAfter,
|
|
69
|
+
searchString,
|
|
70
|
+
orderBy,
|
|
71
|
+
order
|
|
72
|
+
});
|
|
73
|
+
}, [delegate]),
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Listen to a entities in a given path
|
|
77
|
+
* @param path
|
|
78
|
+
* @param collection
|
|
79
|
+
* @param onError
|
|
80
|
+
* @param filter
|
|
81
|
+
* @param limit
|
|
82
|
+
* @param startAfter
|
|
83
|
+
* @param searchString
|
|
84
|
+
* @param orderBy
|
|
85
|
+
* @param order
|
|
86
|
+
* @param onUpdate
|
|
87
|
+
* @return Function to cancel subscription
|
|
88
|
+
* @see useCollectionFetch if you need this functionality implemented as a hook
|
|
89
|
+
* @category Firestore
|
|
90
|
+
*/
|
|
91
|
+
listenCollection: delegate.listenCollection
|
|
92
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
93
|
+
? useCallback(<M extends Record<string, any>>(
|
|
94
|
+
{
|
|
95
|
+
path,
|
|
96
|
+
collection,
|
|
97
|
+
filter,
|
|
98
|
+
limit,
|
|
99
|
+
startAfter,
|
|
100
|
+
searchString,
|
|
101
|
+
orderBy,
|
|
102
|
+
order,
|
|
103
|
+
onUpdate,
|
|
104
|
+
onError
|
|
105
|
+
}: ListenCollectionProps<M>
|
|
106
|
+
): () => void => {
|
|
107
|
+
|
|
108
|
+
const isCollectionGroup = Boolean(collection.collectionGroup) ?? false;
|
|
109
|
+
if (!delegate.listenCollection)
|
|
110
|
+
throw Error("useBuildDataSource delegate not initialised");
|
|
111
|
+
|
|
112
|
+
return delegate.listenCollection<M>({
|
|
113
|
+
path,
|
|
114
|
+
filter,
|
|
115
|
+
limit,
|
|
116
|
+
startAfter,
|
|
117
|
+
searchString,
|
|
118
|
+
orderBy,
|
|
119
|
+
order,
|
|
120
|
+
onUpdate,
|
|
121
|
+
onError,
|
|
122
|
+
isCollectionGroup
|
|
123
|
+
});
|
|
124
|
+
}, [delegate])
|
|
125
|
+
: undefined,
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Retrieve an entity given a path and a collection
|
|
129
|
+
* @param path
|
|
130
|
+
* @param entityId
|
|
131
|
+
* @param collection
|
|
132
|
+
* @category Firestore
|
|
133
|
+
*/
|
|
134
|
+
fetchEntity: useCallback(<M extends Record<string, any>>({
|
|
135
|
+
path,
|
|
136
|
+
entityId
|
|
137
|
+
}: FetchEntityProps<M>
|
|
138
|
+
): Promise<Entity<M> | undefined> => delegate.fetchEntity({
|
|
139
|
+
path,
|
|
140
|
+
entityId
|
|
141
|
+
}), [delegate]),
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
*
|
|
145
|
+
* @param path
|
|
146
|
+
* @param entityId
|
|
147
|
+
* @param collection
|
|
148
|
+
* @param onUpdate
|
|
149
|
+
* @param onError
|
|
150
|
+
* @return Function to cancel subscription
|
|
151
|
+
* @category Firestore
|
|
152
|
+
*/
|
|
153
|
+
listenEntity: delegate.listenEntity
|
|
154
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
155
|
+
? useCallback(<M extends Record<string, any>>(
|
|
156
|
+
{
|
|
157
|
+
path,
|
|
158
|
+
entityId,
|
|
159
|
+
collection,
|
|
160
|
+
onUpdate,
|
|
161
|
+
onError
|
|
162
|
+
}: ListenEntityProps<M>): () => void => {
|
|
163
|
+
if (!delegate.listenEntity)
|
|
164
|
+
throw Error("useBuildDataSource delegate not initialised");
|
|
165
|
+
|
|
166
|
+
return delegate.listenEntity<M>({
|
|
167
|
+
path,
|
|
168
|
+
entityId,
|
|
169
|
+
onUpdate,
|
|
170
|
+
onError
|
|
171
|
+
})
|
|
172
|
+
}, [delegate.listenEntity]) : undefined,
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Save entity to the specified path. Note that Firestore does not allow
|
|
176
|
+
* undefined values.
|
|
177
|
+
* @param path
|
|
178
|
+
* @param entityId
|
|
179
|
+
* @param values
|
|
180
|
+
* @param schemaId
|
|
181
|
+
* @param collection
|
|
182
|
+
* @param status
|
|
183
|
+
* @category Firestore
|
|
184
|
+
*/
|
|
185
|
+
saveEntity: useCallback(<M extends Record<string, any>>(
|
|
186
|
+
{
|
|
187
|
+
path,
|
|
188
|
+
entityId,
|
|
189
|
+
values,
|
|
190
|
+
collection,
|
|
191
|
+
status
|
|
192
|
+
}: SaveEntityProps<M>): Promise<Entity<M>> => {
|
|
193
|
+
|
|
194
|
+
const resolvedCollection = resolveCollection<M>({
|
|
195
|
+
collection,
|
|
196
|
+
path,
|
|
197
|
+
entityId,
|
|
198
|
+
fields: customFields
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
const properties: ResolvedProperties<M> = resolvedCollection.properties;
|
|
202
|
+
|
|
203
|
+
const firestoreValues = cmsToDelegateModel(
|
|
204
|
+
values,
|
|
205
|
+
delegate.buildReference,
|
|
206
|
+
delegate.buildGeoPoint,
|
|
207
|
+
delegate.buildDate,
|
|
208
|
+
delegate.buildDeleteFieldValue
|
|
209
|
+
);
|
|
210
|
+
const updatedFirestoreValues: EntityValues<M> = updateDateAutoValues(
|
|
211
|
+
{
|
|
212
|
+
inputValues: firestoreValues,
|
|
213
|
+
properties,
|
|
214
|
+
status,
|
|
215
|
+
timestampNowValue: delegate.currentTime(),
|
|
216
|
+
setDateToMidnight: delegate.setDateToMidnight
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
console.debug("Saving entity", path, entityId, updatedFirestoreValues);
|
|
220
|
+
|
|
221
|
+
return delegate.saveEntity({
|
|
222
|
+
path,
|
|
223
|
+
entityId,
|
|
224
|
+
values: updatedFirestoreValues,
|
|
225
|
+
status
|
|
226
|
+
}).then((res) => {
|
|
227
|
+
return {
|
|
228
|
+
id: res.id,
|
|
229
|
+
path: res.path,
|
|
230
|
+
values: delegate.delegateToCMSModel(updatedFirestoreValues)
|
|
231
|
+
} as Entity<M>;
|
|
232
|
+
});
|
|
233
|
+
}, [delegate.saveEntity]),
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Delete an entity
|
|
237
|
+
* @param entity
|
|
238
|
+
* @param collection
|
|
239
|
+
* @category Firestore
|
|
240
|
+
*/
|
|
241
|
+
deleteEntity: useCallback(<M extends Record<string, any>>(
|
|
242
|
+
{
|
|
243
|
+
entity
|
|
244
|
+
}: DeleteEntityProps<M>
|
|
245
|
+
): Promise<void> => {
|
|
246
|
+
return delegate.deleteEntity({entity});
|
|
247
|
+
}, [delegate.deleteEntity]),
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Check if the given property is unique in the given collection
|
|
251
|
+
* @param path Collection path
|
|
252
|
+
* @param name of the property
|
|
253
|
+
* @param value
|
|
254
|
+
* @param property
|
|
255
|
+
* @param entityId
|
|
256
|
+
* @return `true` if there are no other fields besides the given entity
|
|
257
|
+
* @category Firestore
|
|
258
|
+
*/
|
|
259
|
+
checkUniqueField: useCallback((
|
|
260
|
+
path: string,
|
|
261
|
+
name: string,
|
|
262
|
+
value: any,
|
|
263
|
+
entityId?: string
|
|
264
|
+
): Promise<boolean> => {
|
|
265
|
+
return delegate.checkUniqueField(path, name, value, entityId);
|
|
266
|
+
}, [delegate.checkUniqueField]),
|
|
267
|
+
|
|
268
|
+
generateEntityId: useCallback((path: string): string => {
|
|
269
|
+
return delegate.generateEntityId(path, );
|
|
270
|
+
}, [delegate.generateEntityId]),
|
|
271
|
+
|
|
272
|
+
countEntities: useCallback(async ({
|
|
273
|
+
path,
|
|
274
|
+
collection,
|
|
275
|
+
filter,
|
|
276
|
+
order,
|
|
277
|
+
orderBy
|
|
278
|
+
}: {
|
|
279
|
+
path: string,
|
|
280
|
+
collection: EntityCollection<any>,
|
|
281
|
+
filter?: FilterValues<Extract<keyof any, string>>,
|
|
282
|
+
orderBy?: string,
|
|
283
|
+
order?: "desc" | "asc",
|
|
284
|
+
}): Promise<number> => {
|
|
285
|
+
return delegate.countEntities({
|
|
286
|
+
path,
|
|
287
|
+
filter,
|
|
288
|
+
orderBy,
|
|
289
|
+
order,
|
|
290
|
+
isCollectionGroup: Boolean(collection.collectionGroup) ?? false
|
|
291
|
+
});
|
|
292
|
+
}, [delegate.countEntities]),
|
|
293
|
+
|
|
294
|
+
isFilterCombinationValid: useCallback(({
|
|
295
|
+
path,
|
|
296
|
+
filterValues,
|
|
297
|
+
sortBy
|
|
298
|
+
}: {
|
|
299
|
+
path: string,
|
|
300
|
+
filterValues: FilterValues<any>,
|
|
301
|
+
sortBy?: [string, "asc" | "desc"]
|
|
302
|
+
}): boolean => {
|
|
303
|
+
if (!delegate.isFilterCombinationValid)
|
|
304
|
+
return true;
|
|
305
|
+
return delegate.isFilterCombinationValid(
|
|
306
|
+
{
|
|
307
|
+
path,
|
|
308
|
+
filterValues,
|
|
309
|
+
sortBy
|
|
310
|
+
}
|
|
311
|
+
)
|
|
312
|
+
}, [delegate.isFilterCombinationValid])
|
|
313
|
+
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Recursive function that converts Firestore data types into CMS or plain
|
|
320
|
+
* JS types.
|
|
321
|
+
* FireCMS uses Javascript dates internally instead of Firestore timestamps.
|
|
322
|
+
* This makes it easier to interact with the rest of the libraries and
|
|
323
|
+
* bindings.
|
|
324
|
+
* Also, Firestore references are replaced with {@link EntityReference}
|
|
325
|
+
* @param data
|
|
326
|
+
* @category Firestore
|
|
327
|
+
*/
|
|
328
|
+
export function cmsToDelegateModel(data: any,
|
|
329
|
+
buildReference: (reference: EntityReference) => any,
|
|
330
|
+
buildGeoPoint: (geoPoint: GeoPoint) => any,
|
|
331
|
+
buildDate: (date: Date) => any,
|
|
332
|
+
buildDelete: () => any
|
|
333
|
+
): any {
|
|
334
|
+
if (data === undefined) {
|
|
335
|
+
return buildDelete();
|
|
336
|
+
} else if (Array.isArray(data)) {
|
|
337
|
+
return data.map(v => cmsToDelegateModel(v, buildReference, buildGeoPoint, buildDate, buildDelete));
|
|
338
|
+
} else if (data instanceof EntityReference) {
|
|
339
|
+
return buildReference(data);
|
|
340
|
+
} else if (data instanceof GeoPoint) {
|
|
341
|
+
return buildGeoPoint(data);
|
|
342
|
+
} else if (data instanceof Date) {
|
|
343
|
+
return buildDate(data);
|
|
344
|
+
} else if (data && typeof data === "object") {
|
|
345
|
+
return Object.entries(data)
|
|
346
|
+
.map(([key, v]) => ({ [key]: cmsToDelegateModel(v, buildReference, buildGeoPoint, buildDate, buildDelete) }))
|
|
347
|
+
.reduce((a, b) => ({ ...a, ...b }), {});
|
|
348
|
+
}
|
|
349
|
+
return data;
|
|
350
|
+
}
|
|
351
|
+
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { useContext } from "react";
|
|
2
|
+
import { DialogsController } from "../types/dialogs_controller";
|
|
3
|
+
import { DialogsControllerContext } from "../core/contexts/DialogsProvider";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Use this hook to open a dialog imperatively.
|
|
7
|
+
* Alternatively, you can use dialogs declaratively using the `Dialog` component.
|
|
8
|
+
*
|
|
9
|
+
* Consider that in order to use this hook you need to have a parent
|
|
10
|
+
* `FireCMS`
|
|
11
|
+
*
|
|
12
|
+
* @category Hooks and utilities
|
|
13
|
+
*/
|
|
14
|
+
export const useDialogsController = (): DialogsController => useContext(DialogsControllerContext);
|
|
@@ -8,17 +8,9 @@ import { useDataSource } from "./data/useDataSource";
|
|
|
8
8
|
import { useStorageSource } from "./useStorageSource";
|
|
9
9
|
import { useSnackbarController } from "./useSnackbarController";
|
|
10
10
|
import { useUserConfigurationPersistence } from "./useUserConfigurationPersistence";
|
|
11
|
+
import { useDialogsController } from "./useDialogsController";
|
|
11
12
|
|
|
12
|
-
export const FireCMSContextInstance = createContext<Partial<FireCMSContext>>({
|
|
13
|
-
sideDialogsController: {} as any,
|
|
14
|
-
sideEntityController: {} as any,
|
|
15
|
-
navigation: {} as any,
|
|
16
|
-
dataSource: {} as any,
|
|
17
|
-
storageSource: {} as any,
|
|
18
|
-
authController: {} as any,
|
|
19
|
-
snackbarController: {} as any,
|
|
20
|
-
fields: {}
|
|
21
|
-
});
|
|
13
|
+
export const FireCMSContextInstance = createContext<Partial<FireCMSContext>>({});
|
|
22
14
|
|
|
23
15
|
/**
|
|
24
16
|
* Hook to retrieve the {@link FireCMSContext}.
|
|
@@ -40,6 +32,7 @@ export const useFireCMSContext = <UserType extends User = User, AuthControllerTy
|
|
|
40
32
|
const storageSource = useStorageSource();
|
|
41
33
|
const snackbarController = useSnackbarController();
|
|
42
34
|
const userConfigPersistence = useUserConfigurationPersistence();
|
|
35
|
+
const dialogsController = useDialogsController();
|
|
43
36
|
|
|
44
37
|
return {
|
|
45
38
|
...partialContext,
|
|
@@ -50,7 +43,8 @@ export const useFireCMSContext = <UserType extends User = User, AuthControllerTy
|
|
|
50
43
|
dataSource,
|
|
51
44
|
storageSource,
|
|
52
45
|
snackbarController,
|
|
53
|
-
userConfigPersistence
|
|
46
|
+
userConfigPersistence,
|
|
47
|
+
dialogsController
|
|
54
48
|
}
|
|
55
49
|
|
|
56
50
|
};
|
|
@@ -45,13 +45,15 @@ export function StringPropertyPreview({
|
|
|
45
45
|
if (!value) return <></>;
|
|
46
46
|
const lines = value.split("\n");
|
|
47
47
|
return value && value.includes("\n")
|
|
48
|
-
? <div>
|
|
48
|
+
? <div className={"overflow-x-scroll"}>
|
|
49
49
|
{lines.map((str, index) =>
|
|
50
50
|
<React.Fragment key={`string_preview_${index}`}>
|
|
51
51
|
<span>{str}</span>
|
|
52
52
|
{index !== lines.length - 1 && <br/>}
|
|
53
53
|
</React.Fragment>)}
|
|
54
54
|
</div>
|
|
55
|
-
: <>
|
|
55
|
+
: <>
|
|
56
|
+
{value}
|
|
57
|
+
</>;
|
|
56
58
|
}
|
|
57
59
|
}
|
package/src/styles.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const focusedMixin = "focus:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-transparent";
|
|
1
|
+
export const focusedMixin = "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-transparent";
|
|
2
2
|
export const focusedInvisibleMixin = "focus:bg-opacity-70 focus:bg-gray-100 focus:dark:bg-gray-800 focus:dark:bg-opacity-60";
|
|
3
3
|
export const focusedClasses = "z-30 outline-none ring-2 ring-primary ring-opacity-75 ring-offset-2 ring-offset-transparent ";
|
|
4
4
|
export const fieldBackgroundMixin = "bg-opacity-70 bg-gray-100 dark:bg-gray-800 dark:bg-opacity-60 transition duration-150 ease-in-out";
|
package/src/types/collections.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { EntityCallbacks } from "./entity_callbacks";
|
|
|
6
6
|
import { Permissions, PermissionsBuilder } from "./permissions";
|
|
7
7
|
import { EnumValues, PropertiesOrBuilders } from "./properties";
|
|
8
8
|
import { FormContext } from "./fields";
|
|
9
|
+
import { EntityAction } from "./entity_actions";
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* This interface represents a view that includes a collection of entities.
|
|
@@ -14,9 +15,7 @@ import { FormContext } from "./fields";
|
|
|
14
15
|
*
|
|
15
16
|
* @category Models
|
|
16
17
|
*/
|
|
17
|
-
export interface EntityCollection<M extends Record<string, any> = any,
|
|
18
|
-
AdditionalKey extends string = string,
|
|
19
|
-
UserType extends User = User> {
|
|
18
|
+
export interface EntityCollection<M extends Record<string, any> = any, UserType extends User = User> {
|
|
20
19
|
|
|
21
20
|
/**
|
|
22
21
|
* Name of the collection, typically plural.
|
|
@@ -58,9 +57,9 @@ export interface EntityCollection<M extends Record<string, any> = any,
|
|
|
58
57
|
|
|
59
58
|
/**
|
|
60
59
|
* Icon key to use in this collection.
|
|
61
|
-
* You can use any of the icons in the
|
|
62
|
-
* https://
|
|
63
|
-
* e.g. '
|
|
60
|
+
* You can use any of the icons in the Material specs:
|
|
61
|
+
* https://fonts.google.com/icons
|
|
62
|
+
* e.g. 'account_tree' or 'person'
|
|
64
63
|
*/
|
|
65
64
|
icon?: string;
|
|
66
65
|
|
|
@@ -93,7 +92,7 @@ export interface EntityCollection<M extends Record<string, any> = any,
|
|
|
93
92
|
* - If you are using a collection group, you will also have an
|
|
94
93
|
* additional `collectionGroupParent` column.
|
|
95
94
|
*/
|
|
96
|
-
propertiesOrder?: Extract<keyof M
|
|
95
|
+
propertiesOrder?: Extract<keyof M, string>[];
|
|
97
96
|
|
|
98
97
|
/**
|
|
99
98
|
* If enabled, content is loaded in batches. If `false` all entities in the
|
|
@@ -113,7 +112,7 @@ export interface EntityCollection<M extends Record<string, any> = any,
|
|
|
113
112
|
* Permissions the logged-in user can perform on this collection.
|
|
114
113
|
* If not specified everything defaults to `true`.
|
|
115
114
|
*/
|
|
116
|
-
permissions?: Permissions | PermissionsBuilder<
|
|
115
|
+
permissions?: Permissions | PermissionsBuilder<any, UserType, M>;
|
|
117
116
|
|
|
118
117
|
/**
|
|
119
118
|
* Are the entities in this collection selectable. Defaults to `true`
|
|
@@ -140,6 +139,31 @@ export interface EntityCollection<M extends Record<string, any> = any,
|
|
|
140
139
|
*/
|
|
141
140
|
Actions?: React.ComponentType<CollectionActionsProps> | React.ComponentType<CollectionActionsProps>[];
|
|
142
141
|
|
|
142
|
+
/**
|
|
143
|
+
* You can define additional actions that can be performed on the entities
|
|
144
|
+
* in this collection. These actions can be displayed in the collection
|
|
145
|
+
* view or in the entity view.
|
|
146
|
+
*
|
|
147
|
+
* You can use the `onClick` method to implement your own logic.
|
|
148
|
+
* In the `context` prop you can access all the controllers of FireCMS.
|
|
149
|
+
*
|
|
150
|
+
* ```
|
|
151
|
+
* const archiveEntityAction: EntityAction = {
|
|
152
|
+
* icon: <ArchiveIcon/>,
|
|
153
|
+
* name: "Archive",
|
|
154
|
+
* onClick({
|
|
155
|
+
* entity,
|
|
156
|
+
* collection,
|
|
157
|
+
* context,
|
|
158
|
+
* }): Promise<void> {
|
|
159
|
+
* // Add your code here
|
|
160
|
+
* return Promise.resolve(undefined);
|
|
161
|
+
* }
|
|
162
|
+
* }
|
|
163
|
+
* ```
|
|
164
|
+
*/
|
|
165
|
+
entityActions?: EntityAction<M, UserType>[];
|
|
166
|
+
|
|
143
167
|
/**
|
|
144
168
|
* Pass your own selection controller if you want to control selected
|
|
145
169
|
* entities externally.
|
|
@@ -190,8 +214,7 @@ export interface EntityCollection<M extends Record<string, any> = any,
|
|
|
190
214
|
* You can add additional fields to the collection view by implementing
|
|
191
215
|
* an additional field delegate.
|
|
192
216
|
*/
|
|
193
|
-
additionalFields?: AdditionalFieldDelegate<M,
|
|
194
|
-
|
|
217
|
+
additionalFields?: AdditionalFieldDelegate<M, UserType>[];
|
|
195
218
|
|
|
196
219
|
/**
|
|
197
220
|
* Default size of the rendered collection
|
|
@@ -245,10 +268,8 @@ export interface EntityCollection<M extends Record<string, any> = any,
|
|
|
245
268
|
|
|
246
269
|
/**
|
|
247
270
|
* Parameter passed to the `Actions` prop in the collection configuration.
|
|
248
|
-
*
|
|
249
|
-
*
|
|
250
|
-
* If you don't want to render the actions in the home page card, you can
|
|
251
|
-
* return `null` if mode is `home`.
|
|
271
|
+
* The component will receive this prop when it is rendered in the collection
|
|
272
|
+
* toolbar.
|
|
252
273
|
*
|
|
253
274
|
* @category Models
|
|
254
275
|
*/
|
|
@@ -349,7 +370,6 @@ export type FilterCombination<Key extends string> = Partial<Record<Key, "asc" |
|
|
|
349
370
|
*/
|
|
350
371
|
export type CollectionSize = "xs" | "s" | "m" | "l" | "xl";
|
|
351
372
|
|
|
352
|
-
|
|
353
373
|
export type AdditionalFieldDelegateProps<M extends Record<string, any> = any, UserType extends User = User> = {
|
|
354
374
|
entity: Entity<M>,
|
|
355
375
|
context: FireCMSContext<UserType>
|
|
@@ -361,14 +381,13 @@ export type AdditionalFieldDelegateProps<M extends Record<string, any> = any, Us
|
|
|
361
381
|
* @category Models
|
|
362
382
|
*/
|
|
363
383
|
export interface AdditionalFieldDelegate<M extends Record<string, any> = any,
|
|
364
|
-
AdditionalKey extends string = string,
|
|
365
384
|
UserType extends User = User> {
|
|
366
385
|
|
|
367
386
|
/**
|
|
368
387
|
* ID of this column. You can use this id in the `properties` field of the
|
|
369
388
|
* collection in any order you want
|
|
370
389
|
*/
|
|
371
|
-
id:
|
|
390
|
+
id: string;
|
|
372
391
|
|
|
373
392
|
/**
|
|
374
393
|
* Header of this column
|