@firecms/core 3.0.0-beta.2-pre.5 → 3.0.0-canary.0
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/EntityCollectionTable/EntityCollectionRowActions.d.ts +2 -6
- package/dist/components/PropertyIdCopyTooltipContent.d.ts +3 -0
- package/dist/form/PropertyFieldBinding.d.ts +1 -1
- package/dist/hooks/useProjectLog.d.ts +4 -0
- package/dist/index.es.js +2438 -2365
- 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/util/index.d.ts +1 -1
- package/dist/util/useDebouncedCallback.d.ts +1 -0
- package/package.json +4 -4
- package/src/components/ArrayContainer.tsx +3 -9
- package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +33 -36
- package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +36 -38
- package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +17 -14
- package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +10 -1
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +15 -14
- package/src/components/PropertyIdCopyTooltipContent.tsx +28 -0
- package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +0 -1
- package/src/components/SelectableTable/SelectableTable.tsx +2 -2
- package/src/components/VirtualTable/fields/VirtualTableInput.tsx +2 -2
- package/src/components/VirtualTable/fields/VirtualTableNumberInput.tsx +2 -2
- package/src/core/Drawer.tsx +17 -15
- package/src/core/FireCMS.tsx +4 -1
- package/src/core/Scaffold.tsx +5 -5
- package/src/core/field_configs.tsx +11 -11
- package/src/form/EntityForm.tsx +16 -4
- package/src/form/PropertyFieldBinding.tsx +3 -8
- package/src/form/field_bindings/MapFieldBinding.tsx +8 -6
- package/src/form/field_bindings/RepeatFieldBinding.tsx +4 -2
- package/src/hooks/useBuildNavigationController.tsx +26 -6
- package/src/hooks/useProjectLog.tsx +31 -0
- package/src/internal/EntityView.tsx +2 -2
- package/src/util/index.ts +1 -1
- package/src/util/{useDebounce.ts → useDebouncedCallback.ts} +1 -1
- package/dist/hooks/useVerifyLicense.d.ts +0 -0
- package/dist/util/useDebounce.d.ts +0 -1
- package/src/hooks/useVerifyLicense.tsx +0 -1
package/src/core/Scaffold.tsx
CHANGED
|
@@ -176,7 +176,7 @@ function StyledDrawer(props: {
|
|
|
176
176
|
className={"relative h-full no-scrollbar overflow-y-auto overflow-x-hidden"}
|
|
177
177
|
style={{
|
|
178
178
|
width,
|
|
179
|
-
transition: "left
|
|
179
|
+
transition: "left 100ms cubic-bezier(0.4, 0, 0.6, 1) 0ms, opacity 100ms cubic-bezier(0.4, 0, 0.6, 1) 0ms, width 100ms cubic-bezier(0.4, 0, 0.6, 1) 0ms"
|
|
180
180
|
}}
|
|
181
181
|
>
|
|
182
182
|
|
|
@@ -201,8 +201,8 @@ function StyledDrawer(props: {
|
|
|
201
201
|
<div className={"flex flex-col h-full"}>
|
|
202
202
|
<div
|
|
203
203
|
style={{
|
|
204
|
-
transition: "padding
|
|
205
|
-
padding: props.open ? "32px
|
|
204
|
+
transition: "padding 100ms cubic-bezier(0.4, 0, 0.6, 1) 0ms",
|
|
205
|
+
padding: props.open ? "32px 144px 0px 24px" : "72px 16px 0px"
|
|
206
206
|
}}
|
|
207
207
|
className={cn("cursor-pointer")}>
|
|
208
208
|
|
|
@@ -215,7 +215,7 @@ function StyledDrawer(props: {
|
|
|
215
215
|
? <img src={props.logo}
|
|
216
216
|
alt="Logo"
|
|
217
217
|
className={cn("max-w-full max-h-full",
|
|
218
|
-
props.open ?? "w-[
|
|
218
|
+
props.open ?? "w-[112px] h-[112px]")}/>
|
|
219
219
|
: <FireCMSLogo/>}
|
|
220
220
|
|
|
221
221
|
</Link>
|
|
@@ -259,7 +259,7 @@ function StyledDrawer(props: {
|
|
|
259
259
|
onMouseLeave={props.onMouseLeave}
|
|
260
260
|
style={{
|
|
261
261
|
width,
|
|
262
|
-
transition: "left
|
|
262
|
+
transition: "left 100ms cubic-bezier(0.4, 0, 0.6, 1) 0ms, opacity 100ms cubic-bezier(0.4, 0, 0.6, 1) 0ms, width 100ms cubic-bezier(0.4, 0, 0.6, 1) 0ms"
|
|
263
263
|
}}>
|
|
264
264
|
|
|
265
265
|
{innerDrawer}
|
|
@@ -104,6 +104,17 @@ export const DEFAULT_FIELD_CONFIGS: Record<string, PropertyConfig<any>> = {
|
|
|
104
104
|
Field: TextFieldBinding
|
|
105
105
|
}
|
|
106
106
|
},
|
|
107
|
+
switch: {
|
|
108
|
+
key: "switch",
|
|
109
|
+
name: "Switch",
|
|
110
|
+
description: "Boolean true or false field (or yes or no, 0 or 1...)",
|
|
111
|
+
Icon: FlagIcon,
|
|
112
|
+
color: "#20d9d2",
|
|
113
|
+
property: {
|
|
114
|
+
dataType: "boolean",
|
|
115
|
+
Field: SwitchFieldBinding
|
|
116
|
+
}
|
|
117
|
+
},
|
|
107
118
|
select: {
|
|
108
119
|
key: "select",
|
|
109
120
|
name: "Select/enum",
|
|
@@ -225,17 +236,6 @@ export const DEFAULT_FIELD_CONFIGS: Record<string, PropertyConfig<any>> = {
|
|
|
225
236
|
Field: ArrayOfReferencesFieldBinding
|
|
226
237
|
}
|
|
227
238
|
},
|
|
228
|
-
switch: {
|
|
229
|
-
key: "switch",
|
|
230
|
-
name: "Switch",
|
|
231
|
-
description: "Boolean true or false field (or yes or no, 0 or 1...)",
|
|
232
|
-
Icon: FlagIcon,
|
|
233
|
-
color: "#20d9d2",
|
|
234
|
-
property: {
|
|
235
|
-
dataType: "boolean",
|
|
236
|
-
Field: SwitchFieldBinding
|
|
237
|
-
}
|
|
238
|
-
},
|
|
239
239
|
date_time: {
|
|
240
240
|
key: "date_time",
|
|
241
241
|
name: "Date/time",
|
package/src/form/EntityForm.tsx
CHANGED
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
} from "../hooks";
|
|
35
35
|
import { ErrorFocus } from "./components/ErrorFocus";
|
|
36
36
|
import { CustomIdField } from "./components/CustomIdField";
|
|
37
|
-
import { Alert, Button, cn, DialogActions, IconButton, Typography } from "@firecms/ui";
|
|
37
|
+
import { Alert, Button, cn, DialogActions, IconButton, Tooltip, Typography } from "@firecms/ui";
|
|
38
38
|
import { ErrorBoundary } from "../components";
|
|
39
39
|
import {
|
|
40
40
|
copyEntityAction,
|
|
@@ -42,6 +42,7 @@ import {
|
|
|
42
42
|
} from "../components/EntityCollectionTable/internal/default_entity_actions";
|
|
43
43
|
import { useAnalyticsController } from "../hooks/useAnalyticsController";
|
|
44
44
|
import { ValidationError } from "yup";
|
|
45
|
+
import { PropertyIdCopyTooltipContent } from "../components/PropertyIdCopyTooltipContent";
|
|
45
46
|
|
|
46
47
|
/**
|
|
47
48
|
* @group Components
|
|
@@ -388,7 +389,10 @@ function EntityFormInternal<M extends Record<string, any>>({
|
|
|
388
389
|
|
|
389
390
|
const authController = useAuthController();
|
|
390
391
|
|
|
391
|
-
const getActionsForEntity = useCallback(({ entity, customEntityActions }: {
|
|
392
|
+
const getActionsForEntity = useCallback(({ entity, customEntityActions }: {
|
|
393
|
+
entity?: Entity<M>,
|
|
394
|
+
customEntityActions?: EntityAction[]
|
|
395
|
+
}): EntityAction[] => {
|
|
392
396
|
const createEnabled = canCreateEntity(inputCollection, authController, fullPathToCollectionSegments(path), null);
|
|
393
397
|
const deleteEnabled = entity ? canDeleteEntity(inputCollection, authController, fullPathToCollectionSegments(path), entity) : true;
|
|
394
398
|
const actions: EntityAction[] = [];
|
|
@@ -481,7 +485,10 @@ function EntityFormInternal<M extends Record<string, any>>({
|
|
|
481
485
|
savingError={savingError}
|
|
482
486
|
closeAfterSaveRef={closeAfterSaveRef}
|
|
483
487
|
autoSave={autoSave}
|
|
484
|
-
entityActions={getActionsForEntity({
|
|
488
|
+
entityActions={getActionsForEntity({
|
|
489
|
+
entity,
|
|
490
|
+
customEntityActions: inputCollection.entityActions
|
|
491
|
+
})}/>}
|
|
485
492
|
|
|
486
493
|
</div>
|
|
487
494
|
</div>
|
|
@@ -588,7 +595,12 @@ function InnerForm<M extends Record<string, any>>(props: FormexController<M> & {
|
|
|
588
595
|
<div id={`form_field_${key}`}
|
|
589
596
|
key={`field_${resolvedCollection.name}_${key}`}>
|
|
590
597
|
<ErrorBoundary>
|
|
591
|
-
<
|
|
598
|
+
<Tooltip title={<PropertyIdCopyTooltipContent propertyId={key}/>}
|
|
599
|
+
delayDuration={800}
|
|
600
|
+
side={"left"}
|
|
601
|
+
sideOffset={16}>
|
|
602
|
+
<PropertyFieldBinding {...cmsFormFieldProps}/>
|
|
603
|
+
</Tooltip>
|
|
592
604
|
</ErrorBoundary>
|
|
593
605
|
</div>
|
|
594
606
|
);
|
|
@@ -67,7 +67,7 @@ export const PropertyFieldBinding = React.memo(PropertyFieldBindingInternal, (a:
|
|
|
67
67
|
return false;
|
|
68
68
|
}) as typeof PropertyFieldBindingInternal;
|
|
69
69
|
|
|
70
|
-
function PropertyFieldBindingInternal<T extends CMSType = CMSType,
|
|
70
|
+
function PropertyFieldBindingInternal<T extends CMSType = CMSType, M extends Record<string, any> = Record<string, any>>
|
|
71
71
|
({
|
|
72
72
|
propertyKey,
|
|
73
73
|
property,
|
|
@@ -83,13 +83,8 @@ function PropertyFieldBindingInternal<T extends CMSType = CMSType, CustomProps =
|
|
|
83
83
|
|
|
84
84
|
const customizationController = useCustomizationController();
|
|
85
85
|
|
|
86
|
-
const shouldAlwaysRerender = shouldPropertyReRender(property, customizationController.plugins);
|
|
87
|
-
// we use the standard Field for user defined fields, since it rebuilds
|
|
88
|
-
// when there are changes in other values, in contrast to Field
|
|
89
|
-
const FieldComponent = Field;
|
|
90
|
-
|
|
91
86
|
return (
|
|
92
|
-
<
|
|
87
|
+
<Field
|
|
93
88
|
name={propertyKey}
|
|
94
89
|
>
|
|
95
90
|
{(fieldProps) => {
|
|
@@ -155,7 +150,7 @@ function PropertyFieldBindingInternal<T extends CMSType = CMSType, CustomProps =
|
|
|
155
150
|
componentProps={componentProps}
|
|
156
151
|
fieldProps={fieldProps}/>;
|
|
157
152
|
}}
|
|
158
|
-
</
|
|
153
|
+
</Field>
|
|
159
154
|
);
|
|
160
155
|
|
|
161
156
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { FieldProps, Properties, ResolvedProperties } from "../../types";
|
|
3
3
|
|
|
4
|
-
import { LabelWithIcon } from "../../components";
|
|
4
|
+
import { ErrorBoundary, LabelWithIcon } from "../../components";
|
|
5
5
|
import { getIconForProperty, isHidden, pick } from "../../util";
|
|
6
6
|
import { FieldHelperText } from "../components";
|
|
7
7
|
import { PropertyFieldBinding } from "../PropertyFieldBinding";
|
|
@@ -70,8 +70,10 @@ export function MapFieldBinding<T extends Record<string, any>>({
|
|
|
70
70
|
};
|
|
71
71
|
return (
|
|
72
72
|
<div key={`map-${propertyKey}-${index}`}>
|
|
73
|
-
<
|
|
74
|
-
|
|
73
|
+
<ErrorBoundary>
|
|
74
|
+
<PropertyFieldBinding
|
|
75
|
+
{...fieldProps}/>
|
|
76
|
+
</ErrorBoundary>
|
|
75
77
|
</div>
|
|
76
78
|
);
|
|
77
79
|
}
|
|
@@ -90,10 +92,10 @@ export function MapFieldBinding<T extends Record<string, any>>({
|
|
|
90
92
|
);
|
|
91
93
|
|
|
92
94
|
return (
|
|
93
|
-
|
|
95
|
+
<ErrorBoundary>
|
|
94
96
|
|
|
95
97
|
{!tableMode && !partOfBlock && <ExpandablePanel initiallyExpanded={expanded}
|
|
96
|
-
className={"px-2 md:px-4 pb-2 md:pb-4 pt-1 md:pt-2"}
|
|
98
|
+
className={"px-2 md:px-4 pb-2 md:pb-4 pt-1 md:pt-2 bg-slate-50 bg-opacity-50 dark:bg-gray-900"}
|
|
97
99
|
title={title}>{mapFormView}</ExpandablePanel>}
|
|
98
100
|
|
|
99
101
|
{(tableMode || partOfBlock) && mapFormView}
|
|
@@ -104,7 +106,7 @@ export function MapFieldBinding<T extends Record<string, any>>({
|
|
|
104
106
|
disabled={disabled}
|
|
105
107
|
property={property}/>
|
|
106
108
|
|
|
107
|
-
|
|
109
|
+
</ErrorBoundary>
|
|
108
110
|
);
|
|
109
111
|
}
|
|
110
112
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { useState } from "react";
|
|
2
2
|
import { CMSType, FieldProps, ResolvedProperty } from "../../types";
|
|
3
3
|
import { FieldHelperText, FormikArrayContainer } from "../components";
|
|
4
|
-
import { LabelWithIcon } from "../../components";
|
|
4
|
+
import { ErrorBoundary, LabelWithIcon } from "../../components";
|
|
5
5
|
import { useClearRestoreValue } from "../../hooks";
|
|
6
6
|
import { getIconForProperty } from "../../util";
|
|
7
7
|
import { PropertyFieldBinding } from "../PropertyFieldBinding";
|
|
@@ -62,7 +62,9 @@ export function RepeatFieldBinding<T extends Array<any>>({
|
|
|
62
62
|
partOfBlock: false,
|
|
63
63
|
autoFocus: internalId === lastAddedId
|
|
64
64
|
};
|
|
65
|
-
return <
|
|
65
|
+
return <ErrorBoundary>
|
|
66
|
+
<PropertyFieldBinding {...fieldProps}/>
|
|
67
|
+
</ErrorBoundary>;
|
|
66
68
|
};
|
|
67
69
|
|
|
68
70
|
const arrayContainer = <FormikArrayContainer value={value}
|
|
@@ -256,7 +256,7 @@ export function useBuildNavigationController<EC extends EntityCollection, UserTy
|
|
|
256
256
|
*/
|
|
257
257
|
const baseLocation = state && state.base_location ? state.base_location : location;
|
|
258
258
|
|
|
259
|
-
const
|
|
259
|
+
const getAllParentReferencesForPath = useCallback((path: string): EntityReference[] => {
|
|
260
260
|
return getParentReferencesFromPath({
|
|
261
261
|
path,
|
|
262
262
|
collections
|
|
@@ -264,8 +264,28 @@ export function useBuildNavigationController<EC extends EntityCollection, UserTy
|
|
|
264
264
|
}, [collections]);
|
|
265
265
|
|
|
266
266
|
const getParentCollectionIds = useCallback((path: string): string[] => {
|
|
267
|
-
|
|
268
|
-
|
|
267
|
+
|
|
268
|
+
const strings = path.split("/");
|
|
269
|
+
const oddPathSegments = strings.filter((_, i) => i % 2 === 0);
|
|
270
|
+
oddPathSegments.pop();
|
|
271
|
+
|
|
272
|
+
const result: string[][] = [];
|
|
273
|
+
|
|
274
|
+
for (let i = 1; i <= oddPathSegments.length; i++) {
|
|
275
|
+
result.push(oddPathSegments.slice(0, i));
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// for each odd path segment, get the collection
|
|
279
|
+
const parentCollectionIds = result.map(r => getCollectionFromPaths(r)?.id).filter(Boolean) as string[];
|
|
280
|
+
|
|
281
|
+
getCollectionFromPaths(oddPathSegments);
|
|
282
|
+
|
|
283
|
+
// const allParentCollectionsForPath = getAllParentReferencesForPath(path);
|
|
284
|
+
// console.log("allParentCollectionsForPath", allParentCollectionsForPath);
|
|
285
|
+
// const parentCollectionIds = allParentCollectionsForPath.map(r => r.id);
|
|
286
|
+
console.log("getParentCollectionIds", path, parentCollectionIds);
|
|
287
|
+
return parentCollectionIds;
|
|
288
|
+
}, [getAllParentReferencesForPath])
|
|
269
289
|
|
|
270
290
|
const convertIdsToPaths = useCallback((ids: string[]): string[] => {
|
|
271
291
|
let currentCollections = collections;
|
|
@@ -282,7 +302,7 @@ export function useBuildNavigationController<EC extends EntityCollection, UserTy
|
|
|
282
302
|
}
|
|
283
303
|
, [getCollectionFromIds]);
|
|
284
304
|
|
|
285
|
-
return
|
|
305
|
+
return {
|
|
286
306
|
collections,
|
|
287
307
|
views,
|
|
288
308
|
loading: !initialised || navigationLoading,
|
|
@@ -303,10 +323,10 @@ export function useBuildNavigationController<EC extends EntityCollection, UserTy
|
|
|
303
323
|
topLevelNavigation,
|
|
304
324
|
baseLocation,
|
|
305
325
|
refreshNavigation,
|
|
306
|
-
getParentReferencesFromPath:
|
|
326
|
+
getParentReferencesFromPath: getAllParentReferencesForPath,
|
|
307
327
|
getParentCollectionIds,
|
|
308
328
|
convertIdsToPaths
|
|
309
|
-
}
|
|
329
|
+
};
|
|
310
330
|
}
|
|
311
331
|
|
|
312
332
|
export function getSidePanelKey(path: string, entityId?: string) {
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { useEffect, useRef } from "react";
|
|
2
|
+
import { AuthController } from "../types";
|
|
3
|
+
|
|
4
|
+
export const DEFAULT_SERVER_DEV = "https://api-kdoe6pj3qq-ey.a.run.app";
|
|
5
|
+
export const DEFAULT_SERVER = "https://api-drplyi3b6q-ey.a.run.app";
|
|
6
|
+
|
|
7
|
+
async function makeRequest(authController: AuthController) {
|
|
8
|
+
const firebaseToken = await authController.getAuthToken();
|
|
9
|
+
return fetch(DEFAULT_SERVER + "/access_log",
|
|
10
|
+
{
|
|
11
|
+
// mode: "no-cors",
|
|
12
|
+
method: "POST",
|
|
13
|
+
headers: {
|
|
14
|
+
"Content-Type": "application/json",
|
|
15
|
+
Authorization: `Basic ${firebaseToken}`,
|
|
16
|
+
},
|
|
17
|
+
body: JSON.stringify({})
|
|
18
|
+
})
|
|
19
|
+
.then(async (res) => {
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function useProjectLog(authController: AuthController) {
|
|
24
|
+
const accessedUserRef = useRef<string | null>(null);
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
if (authController.user && authController.user.uid !== accessedUserRef.current && !authController.initialLoading) {
|
|
27
|
+
makeRequest(authController);
|
|
28
|
+
accessedUserRef.current = authController.user.uid;
|
|
29
|
+
}
|
|
30
|
+
}, [authController]);
|
|
31
|
+
}
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
removeInitialAndTrailingSlashes,
|
|
17
17
|
resolveDefaultSelectedView,
|
|
18
18
|
resolveEntityView,
|
|
19
|
-
|
|
19
|
+
useDebouncedCallback
|
|
20
20
|
} from "../util";
|
|
21
21
|
|
|
22
22
|
import {
|
|
@@ -79,7 +79,7 @@ export function EntityView<M extends Record<string, any>, UserType extends User>
|
|
|
79
79
|
* We use this only when autoSave is enabled.
|
|
80
80
|
*/
|
|
81
81
|
const [valuesToBeSaved, setValuesToBeSaved] = useState<EntityValues<M> | undefined>(undefined);
|
|
82
|
-
|
|
82
|
+
useDebouncedCallback(valuesToBeSaved, () => {
|
|
83
83
|
if (valuesToBeSaved)
|
|
84
84
|
saveEntity({
|
|
85
85
|
entityId: usedEntity?.id,
|
package/src/util/index.ts
CHANGED
|
@@ -7,7 +7,7 @@ export * from "./objects";
|
|
|
7
7
|
export * from "./paths";
|
|
8
8
|
export * from "./regexp";
|
|
9
9
|
export * from "./navigation_utils";
|
|
10
|
-
export * from "./
|
|
10
|
+
export * from "./useDebouncedCallback";
|
|
11
11
|
export * from "./property_utils";
|
|
12
12
|
export * from "./resolutions";
|
|
13
13
|
export * from "./permissions";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
|
|
3
|
-
export function
|
|
3
|
+
export function useDebouncedCallback<T>(value: T, callback: () => void, immediate: boolean, timeoutMs = 300) {
|
|
4
4
|
|
|
5
5
|
const pendingUpdate = React.useRef(false);
|
|
6
6
|
const performUpdate = () => {
|
|
File without changes
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function useDebounce<T>(value: T, callback: () => void, immediate: boolean, timeoutMs?: number): void;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
// export
|