@firecms/core 3.0.0-beta.12 → 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/app/Scaffold.d.ts +4 -0
- package/dist/components/ArrayContainer.d.ts +13 -11
- package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +4 -0
- package/dist/components/EntityJsonPreview.d.ts +3 -0
- 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/core/DefaultAppBar.d.ts +8 -2
- package/dist/core/EntityEditView.d.ts +8 -1
- package/dist/core/FireCMS.d.ts +2 -2
- package/dist/form/EntityForm.d.ts +5 -1
- package/dist/form/PropertyFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +3 -9
- package/dist/hooks/data/save.d.ts +1 -1
- package/dist/hooks/useBuildNavigationController.d.ts +2 -9
- package/dist/index.es.js +9251 -8721
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +16686 -16160
- package/dist/index.umd.js.map +1 -1
- package/dist/internal/useBuildDataSource.d.ts +3 -2
- package/dist/internal/useBuildSideEntityController.d.ts +3 -3
- package/dist/types/collections.d.ts +26 -2
- package/dist/types/fields.d.ts +4 -1
- package/dist/types/firecms.d.ts +3 -2
- package/dist/types/navigation.d.ts +9 -0
- package/dist/types/plugins.d.ts +13 -0
- package/dist/types/properties.d.ts +22 -1
- package/dist/types/side_entity_controller.d.ts +4 -0
- package/dist/util/callbacks.d.ts +2 -0
- package/dist/util/createFormexStub.d.ts +2 -0
- package/dist/util/index.d.ts +1 -0
- package/dist/util/navigation_utils.d.ts +2 -1
- package/dist/util/objects.d.ts +1 -1
- package/dist/util/property_utils.d.ts +2 -2
- package/dist/util/references.d.ts +2 -2
- package/dist/util/resolutions.d.ts +11 -6
- package/package.json +9 -6
- package/src/app/Scaffold.tsx +13 -3
- package/src/components/ArrayContainer.tsx +414 -282
- package/src/components/ClearFilterSortButton.tsx +1 -1
- package/src/components/ConfirmationDialog.tsx +9 -9
- package/src/components/DeleteEntityDialog.tsx +4 -2
- package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +8 -6
- 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 +58 -29
- package/src/components/EntityCollectionTable/internal/popup_field/useDraggable.tsx +9 -9
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +26 -6
- package/src/components/EntityJsonPreview.tsx +66 -0
- package/src/components/EntityPreview.tsx +27 -16
- package/src/components/EntityView.tsx +4 -1
- 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/ReferenceTable/ReferenceSelectionTable.tsx +3 -1
- package/src/components/SelectableTable/SelectableTable.tsx +140 -143
- package/src/components/VirtualTable/VirtualTable.tsx +37 -31
- package/src/components/VirtualTable/VirtualTableProps.tsx +0 -5
- package/src/components/VirtualTable/fields/VirtualTableInput.tsx +0 -1
- package/src/components/common/default_entity_actions.tsx +15 -4
- package/src/components/index.tsx +2 -0
- package/src/core/DefaultAppBar.tsx +17 -5
- package/src/core/EntityEditView.tsx +135 -47
- package/src/core/EntitySidePanel.tsx +15 -20
- package/src/core/FireCMS.tsx +19 -12
- package/src/form/EntityForm.tsx +32 -24
- package/src/form/PropertyFieldBinding.tsx +8 -6
- package/src/form/components/CustomIdField.tsx +3 -1
- package/src/form/components/LabelWithIcon.tsx +1 -1
- package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +4 -1
- package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +4 -2
- package/src/form/field_bindings/BlockFieldBinding.tsx +1 -1
- package/src/form/field_bindings/KeyValueFieldBinding.tsx +1 -1
- package/src/form/field_bindings/MapFieldBinding.tsx +5 -4
- package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +6 -2
- package/src/form/field_bindings/MultiSelectFieldBinding.tsx +3 -3
- package/src/form/field_bindings/RepeatFieldBinding.tsx +9 -2
- package/src/form/field_bindings/SelectFieldBinding.tsx +3 -2
- package/src/form/field_bindings/StorageUploadFieldBinding.tsx +227 -156
- package/src/hooks/data/save.ts +24 -35
- package/src/hooks/useBuildNavigationController.tsx +42 -17
- package/src/hooks/useFireCMSContext.tsx +0 -30
- package/src/internal/useBuildDataSource.ts +9 -5
- package/src/internal/useBuildSideEntityController.tsx +26 -20
- package/src/preview/PropertyPreview.tsx +4 -2
- package/src/preview/components/ImagePreview.tsx +2 -2
- package/src/preview/components/ReferencePreview.tsx +1 -1
- package/src/preview/property_previews/ArrayOfMapsPreview.tsx +5 -4
- package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +4 -3
- package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +4 -2
- package/src/preview/property_previews/ArrayOfStringsPreview.tsx +4 -3
- package/src/preview/property_previews/ArrayOneOfPreview.tsx +4 -2
- package/src/preview/property_previews/ArrayPropertyPreview.tsx +4 -2
- 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/routes/FireCMSRoute.tsx +15 -4
- package/src/types/collections.ts +31 -2
- package/src/types/fields.tsx +5 -1
- package/src/types/firecms.tsx +3 -3
- package/src/types/navigation.ts +11 -0
- package/src/types/plugins.tsx +17 -0
- package/src/types/properties.ts +27 -1
- package/src/types/side_entity_controller.tsx +5 -0
- package/src/util/callbacks.ts +119 -0
- package/src/util/createFormexStub.tsx +62 -0
- package/src/util/index.ts +1 -0
- package/src/util/join_collections.ts +3 -1
- package/src/util/navigation_from_path.ts +5 -1
- package/src/util/navigation_utils.ts +84 -20
- package/src/util/objects.ts +54 -17
- package/src/util/property_utils.tsx +7 -3
- package/src/util/references.ts +8 -6
- package/src/util/resolutions.ts +17 -9
- package/src/util/useStorageUploadController.tsx +21 -2
- package/dist/components/EntityCollectionTable/internal/popup_field/ElementResizeListener.d.ts +0 -5
- package/src/components/EntityCollectionTable/internal/popup_field/ElementResizeListener.tsx +0 -59
|
@@ -18,7 +18,7 @@ export function ClearFilterSortButton({
|
|
|
18
18
|
if ((filterIsSet || sortIsSet) && (tableController.clearFilter || tableController.setSortBy)) {
|
|
19
19
|
let label;
|
|
20
20
|
if (filterIsSet && sortIsSet) {
|
|
21
|
-
label = "Clear filter
|
|
21
|
+
label = "Clear filter/sort";
|
|
22
22
|
} else if (filterIsSet) {
|
|
23
23
|
label = "Clear filter";
|
|
24
24
|
} else {
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
|
|
3
|
-
import { Button, Dialog, DialogActions, DialogContent, DialogTitle, LoadingButton
|
|
3
|
+
import { Button, Dialog, DialogActions, DialogContent, DialogTitle, LoadingButton } from "@firecms/ui";
|
|
4
4
|
|
|
5
5
|
export function ConfirmationDialog({
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
6
|
+
open,
|
|
7
|
+
onAccept,
|
|
8
|
+
onCancel,
|
|
9
|
+
title,
|
|
10
|
+
loading,
|
|
11
|
+
body
|
|
12
|
+
}: {
|
|
13
13
|
open: boolean,
|
|
14
14
|
onAccept: () => void,
|
|
15
15
|
onCancel: () => void,
|
|
@@ -38,7 +38,7 @@ export function ConfirmationDialog({
|
|
|
38
38
|
type="submit"
|
|
39
39
|
loading={loading}
|
|
40
40
|
onClick={onAccept}
|
|
41
|
-
|
|
41
|
+
autoFocus>
|
|
42
42
|
Ok
|
|
43
43
|
</LoadingButton>
|
|
44
44
|
</DialogActions>
|
|
@@ -3,6 +3,7 @@ import React, { useCallback, useMemo, useState } from "react";
|
|
|
3
3
|
import { Button, CircularProgress, Dialog, DialogActions, DialogContent, DialogTitle } from "@firecms/ui";
|
|
4
4
|
import {
|
|
5
5
|
deleteEntityWithCallbacks,
|
|
6
|
+
useAuthController,
|
|
6
7
|
useCustomizationController,
|
|
7
8
|
useDataSource,
|
|
8
9
|
useFireCMSContext,
|
|
@@ -34,7 +35,7 @@ export function DeleteEntityDialog<M extends Record<string, any>>({
|
|
|
34
35
|
onMultipleEntitiesDelete,
|
|
35
36
|
path
|
|
36
37
|
}: DeleteEntityDialogProps<M>) {
|
|
37
|
-
|
|
38
|
+
const authController = useAuthController();
|
|
38
39
|
const dataSource = useDataSource(collection);
|
|
39
40
|
const customizationController = useCustomizationController();
|
|
40
41
|
const snackbarController = useSnackbarController();
|
|
@@ -50,7 +51,8 @@ export function DeleteEntityDialog<M extends Record<string, any>>({
|
|
|
50
51
|
const resolvedCollection = useMemo(() => resolveCollection<M>({
|
|
51
52
|
collection,
|
|
52
53
|
path,
|
|
53
|
-
propertyConfigs: customizationController.propertyConfigs
|
|
54
|
+
propertyConfigs: customizationController.propertyConfigs,
|
|
55
|
+
authController
|
|
54
56
|
}), [collection, path]);
|
|
55
57
|
|
|
56
58
|
const handleCancel = useCallback(() => {
|
|
@@ -165,19 +165,21 @@ export const EntityCollectionRowActions = function EntityCollectionRowActions({
|
|
|
165
165
|
|
|
166
166
|
{!hideId && size !== "xs" && (
|
|
167
167
|
<div
|
|
168
|
-
className="w-[138px] overflow-hidden truncate font-mono text-xs text-text-secondary dark:text-text-secondary-dark max-w-full text-ellipsis px-2 align-center flex items-center
|
|
168
|
+
className="w-[138px] overflow-hidden truncate font-mono text-xs text-text-secondary dark:text-text-secondary-dark max-w-full text-ellipsis px-2 align-center justify-center flex items-center gap-1"
|
|
169
169
|
onClick={(event) => {
|
|
170
170
|
event.stopPropagation();
|
|
171
171
|
}}>
|
|
172
|
-
{hasDraft && <Tooltip title={"
|
|
172
|
+
{hasDraft && <Tooltip title={"Local unsaved changes"} className={"inline"}>
|
|
173
173
|
<Chip colorScheme={"orangeDarker"} className={"p-0.5"}>
|
|
174
174
|
<EditIcon size={12}/>
|
|
175
175
|
</Chip>
|
|
176
176
|
</Tooltip>}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
177
|
+
<span className="min-w-0 truncate text-center">
|
|
178
|
+
{entity
|
|
179
|
+
? entity.id
|
|
180
|
+
: <Skeleton/>
|
|
181
|
+
}
|
|
182
|
+
</span>
|
|
181
183
|
</div>
|
|
182
184
|
)}
|
|
183
185
|
|
|
@@ -394,7 +394,7 @@ export const PropertyTableCell = React.memo<PropertyTableCellProps<any>>(
|
|
|
394
394
|
size={size}
|
|
395
395
|
multiselect={true}
|
|
396
396
|
path={arrayProperty.of.path}
|
|
397
|
-
previewProperties={arrayProperty.of.
|
|
397
|
+
previewProperties={arrayProperty.of.previewKeys}
|
|
398
398
|
title={arrayProperty.name}
|
|
399
399
|
forceFilter={arrayProperty.of.forceFilter}
|
|
400
400
|
includeId={arrayProperty.of.includeId}
|
|
@@ -55,7 +55,7 @@ export function CollectionTableToolbar({
|
|
|
55
55
|
<Tooltip title={"Table row size"} side={"right"} sideOffset={4}>
|
|
56
56
|
<Select
|
|
57
57
|
value={size as string}
|
|
58
|
-
className="w-16
|
|
58
|
+
className="w-16 ml-2"
|
|
59
59
|
size={"small"}
|
|
60
60
|
onValueChange={(v) => onSizeChanged(v as CollectionSize)}
|
|
61
61
|
renderValue={(v) => <div className={"font-medium"}>{v.toUpperCase()}</div>}
|
|
@@ -5,6 +5,7 @@ import useMeasure from "react-use-measure";
|
|
|
5
5
|
import { cls, DoNotDisturbOnIcon, Tooltip } from "@firecms/ui";
|
|
6
6
|
import { ErrorBoundary } from "../../../components";
|
|
7
7
|
import { getRowHeight, TableSize } from "../../common/table_height";
|
|
8
|
+
import { ErrorTooltip } from "../../ErrorTooltip";
|
|
8
9
|
|
|
9
10
|
interface EntityTableCellProps {
|
|
10
11
|
children: React.ReactNode;
|
|
@@ -183,7 +184,7 @@ export const EntityTableCell = React.memo<EntityTableCellProps>(
|
|
|
183
184
|
? "border-primary"
|
|
184
185
|
: "border-transparent";
|
|
185
186
|
|
|
186
|
-
|
|
187
|
+
const result = <>
|
|
187
188
|
<div
|
|
188
189
|
className={cls(
|
|
189
190
|
"transition-colors duration-100 ease-in-out",
|
|
@@ -241,7 +242,17 @@ export const EntityTableCell = React.memo<EntityTableCellProps>(
|
|
|
241
242
|
</div>}
|
|
242
243
|
|
|
243
244
|
</div>
|
|
244
|
-
|
|
245
|
+
</>;
|
|
246
|
+
if (showError) {
|
|
247
|
+
return (
|
|
248
|
+
<ErrorTooltip
|
|
249
|
+
align={"start"}
|
|
250
|
+
title={error?.message ?? "Error"}>
|
|
251
|
+
{result}
|
|
252
|
+
</ErrorTooltip>
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
return result;
|
|
245
256
|
}, (a, b) => {
|
|
246
257
|
return a.error === b.error &&
|
|
247
258
|
a.value === b.value &&
|
|
@@ -17,11 +17,10 @@ import { Formex, useCreateFormex } from "@firecms/formex";
|
|
|
17
17
|
import { useDraggable } from "./useDraggable";
|
|
18
18
|
import { CustomFieldValidator, getYupEntitySchema } from "../../../../form/validation";
|
|
19
19
|
import { useWindowSize } from "./useWindowSize";
|
|
20
|
-
import { ElementResizeListener } from "./ElementResizeListener";
|
|
21
20
|
import { getPropertyInPath, isReadOnly, resolveCollection } from "../../../../util";
|
|
22
21
|
import { Button, CloseIcon, DialogActions, IconButton, Typography } from "@firecms/ui";
|
|
23
22
|
import { PropertyFieldBinding, yupToFormErrors } from "../../../../form";
|
|
24
|
-
import { useCustomizationController, useDataSource, useFireCMSContext } from "../../../../hooks";
|
|
23
|
+
import { useAuthController, useCustomizationController, useDataSource, useFireCMSContext } from "../../../../hooks";
|
|
25
24
|
import { OnCellValueChangeParams } from "../../../common";
|
|
26
25
|
|
|
27
26
|
interface PopupFormFieldProps<M extends Record<string, any>> {
|
|
@@ -71,7 +70,7 @@ export function PopupFormFieldLoading<M extends Record<string, any>>({
|
|
|
71
70
|
collection: inputCollection
|
|
72
71
|
}).then(setEntity);
|
|
73
72
|
}
|
|
74
|
-
}, [entityId, inputCollection]);
|
|
73
|
+
}, [entityId, inputCollection, dataSource, path]);
|
|
75
74
|
|
|
76
75
|
if (!entity) return null;
|
|
77
76
|
return <PopupFormFieldInternal {...{
|
|
@@ -107,6 +106,7 @@ export function PopupFormFieldInternal<M extends Record<string, any>>({
|
|
|
107
106
|
}) {
|
|
108
107
|
|
|
109
108
|
const fireCMSContext = useFireCMSContext();
|
|
109
|
+
const authController = useAuthController();
|
|
110
110
|
const customizationController = useCustomizationController();
|
|
111
111
|
|
|
112
112
|
const [savingError, setSavingError] = React.useState<any>();
|
|
@@ -121,7 +121,8 @@ export function PopupFormFieldInternal<M extends Record<string, any>>({
|
|
|
121
121
|
path,
|
|
122
122
|
values: entity?.values,
|
|
123
123
|
entityId,
|
|
124
|
-
propertyConfigs: customizationController.propertyConfigs
|
|
124
|
+
propertyConfigs: customizationController.propertyConfigs,
|
|
125
|
+
authController
|
|
125
126
|
})
|
|
126
127
|
: undefined;
|
|
127
128
|
|
|
@@ -145,33 +146,35 @@ export function PopupFormFieldInternal<M extends Record<string, any>>({
|
|
|
145
146
|
};
|
|
146
147
|
}, [cellRect, windowSize.height, windowSize.width]);
|
|
147
148
|
|
|
148
|
-
const normalizePosition = useCallback((
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
149
|
+
const normalizePosition = useCallback((
|
|
150
|
+
pos: { x: number, y: number },
|
|
151
|
+
draggableBoundingRect: DOMRect,
|
|
152
|
+
currentWindowSize: { width: number, height: number }
|
|
153
|
+
) => {
|
|
154
|
+
if (!draggableBoundingRect || draggableBoundingRect.width === 0 || draggableBoundingRect.height === 0) {
|
|
155
|
+
return pos;
|
|
156
|
+
}
|
|
157
157
|
return {
|
|
158
|
-
x: Math.max(0, Math.min(x,
|
|
159
|
-
y: Math.max(0, Math.min(y,
|
|
158
|
+
x: Math.max(0, Math.min(pos.x, currentWindowSize.width - draggableBoundingRect.width)),
|
|
159
|
+
y: Math.max(0, Math.min(pos.y, currentWindowSize.height - draggableBoundingRect.height))
|
|
160
160
|
};
|
|
161
|
-
}, [
|
|
161
|
+
}, []);
|
|
162
162
|
|
|
163
|
-
const updatePopupLocation = useCallback((
|
|
163
|
+
const updatePopupLocation = useCallback((newPositionCandidate?: {
|
|
164
164
|
x: number,
|
|
165
165
|
y: number
|
|
166
166
|
}) => {
|
|
167
|
-
|
|
168
167
|
const draggableBoundingRect = draggableRef.current?.getBoundingClientRect();
|
|
169
|
-
if (!cellRect || !draggableBoundingRect)
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
168
|
+
if (!cellRect || !draggableBoundingRect || draggableBoundingRect.width === 0 || draggableBoundingRect.height === 0) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const basePosition = newPositionCandidate ?? getInitialLocation();
|
|
172
|
+
const newNormalizedPosition = normalizePosition(basePosition, draggableBoundingRect, windowSize);
|
|
173
|
+
|
|
174
|
+
if (!popupLocation || newNormalizedPosition.x !== popupLocation.x || newNormalizedPosition.y !== popupLocation.y) {
|
|
175
|
+
setPopupLocation(newNormalizedPosition);
|
|
176
|
+
}
|
|
177
|
+
}, [cellRect, getInitialLocation, normalizePosition, popupLocation, windowSize]);
|
|
175
178
|
|
|
176
179
|
useDraggable({
|
|
177
180
|
containerRef: draggableRef,
|
|
@@ -190,19 +193,25 @@ export function PopupFormFieldInternal<M extends Record<string, any>>({
|
|
|
190
193
|
|
|
191
194
|
useLayoutEffect(
|
|
192
195
|
() => {
|
|
196
|
+
if (!cellRect || initialPositionSet.current) return;
|
|
197
|
+
// Ensure draggableRef is available and has dimensions before initial positioning
|
|
193
198
|
const draggableBoundingRect = draggableRef.current?.getBoundingClientRect();
|
|
194
|
-
if (!
|
|
199
|
+
if (!draggableBoundingRect || draggableBoundingRect.width === 0 || draggableBoundingRect.height === 0) {
|
|
200
|
+
// If not ready, perhaps wait or log. For now, just return.
|
|
201
|
+
// This might need a retry mechanism or ensure content is rendered first.
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
195
204
|
updatePopupLocation();
|
|
196
205
|
initialPositionSet.current = true;
|
|
197
206
|
},
|
|
198
|
-
[cellRect, updatePopupLocation
|
|
207
|
+
[cellRect, updatePopupLocation] // Removed initialPositionSet.current from deps as it's a ref
|
|
199
208
|
);
|
|
200
209
|
|
|
201
210
|
useLayoutEffect(
|
|
202
211
|
() => {
|
|
203
212
|
updatePopupLocation(popupLocation);
|
|
204
213
|
},
|
|
205
|
-
[windowSize, cellRect]
|
|
214
|
+
[windowSize, cellRect, updatePopupLocation, popupLocation]
|
|
206
215
|
);
|
|
207
216
|
|
|
208
217
|
const validationSchema = useMemo(() => {
|
|
@@ -216,9 +225,28 @@ export function PopupFormFieldInternal<M extends Record<string, any>>({
|
|
|
216
225
|
}, [collection, entityId, propertyKey, customFieldValidator]);
|
|
217
226
|
|
|
218
227
|
const adaptResize = useCallback(() => {
|
|
228
|
+
// When the popup resizes, we want to re-evaluate its position
|
|
229
|
+
// based on its current location and new dimensions.
|
|
219
230
|
return updatePopupLocation(popupLocation);
|
|
220
231
|
}, [popupLocation, updatePopupLocation]);
|
|
221
232
|
|
|
233
|
+
// Setup ResizeObserver
|
|
234
|
+
useEffect(() => {
|
|
235
|
+
const element = draggableRef.current;
|
|
236
|
+
if (!element) return;
|
|
237
|
+
|
|
238
|
+
const observer = new ResizeObserver(() => {
|
|
239
|
+
adaptResize();
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
observer.observe(element);
|
|
243
|
+
|
|
244
|
+
return () => {
|
|
245
|
+
observer.unobserve(element);
|
|
246
|
+
observer.disconnect();
|
|
247
|
+
};
|
|
248
|
+
}, [adaptResize, draggableRef]);
|
|
249
|
+
|
|
222
250
|
const saveValue = async (values: M) => {
|
|
223
251
|
setSavingError(null);
|
|
224
252
|
if (inputCollection && entity && onCellValueChange && propertyKey) {
|
|
@@ -273,6 +301,7 @@ export function PopupFormFieldInternal<M extends Record<string, any>>({
|
|
|
273
301
|
formex,
|
|
274
302
|
status: "existing",
|
|
275
303
|
openEntityMode: "side_panel",
|
|
304
|
+
disabled: false,
|
|
276
305
|
};
|
|
277
306
|
|
|
278
307
|
const property: ResolvedProperty<any> | undefined = propertyKey && getPropertyInPath(collection?.properties ?? {} as ResolvedProperties, propertyKey as string);
|
|
@@ -285,7 +314,7 @@ export function PopupFormFieldInternal<M extends Record<string, any>>({
|
|
|
285
314
|
underlyingValueHasChanged: false,
|
|
286
315
|
context: formContext,
|
|
287
316
|
partOfArray: false,
|
|
288
|
-
minimalistView:
|
|
317
|
+
minimalistView: true,
|
|
289
318
|
autoFocus: open
|
|
290
319
|
}
|
|
291
320
|
: undefined;
|
|
@@ -369,7 +398,7 @@ export function PopupFormFieldInternal<M extends Record<string, any>>({
|
|
|
369
398
|
} cursor-grab overflow-visible`}
|
|
370
399
|
ref={draggableRef}>
|
|
371
400
|
|
|
372
|
-
|
|
401
|
+
{/* ElementResizeListener removed from here */}
|
|
373
402
|
|
|
374
403
|
<div
|
|
375
404
|
className="overflow-hidden">
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import React, { useEffect } from "react";
|
|
1
|
+
import React, { useCallback, useEffect } from "react";
|
|
2
2
|
|
|
3
3
|
interface DraggableProps {
|
|
4
4
|
containerRef: React.RefObject<HTMLDivElement>,
|
|
5
5
|
innerRef: React.RefObject<HTMLDivElement>,
|
|
6
|
-
// ref: React.RefObject<HTMLDivElement>,
|
|
7
6
|
x?: number;
|
|
8
7
|
y?: number;
|
|
9
8
|
onMove: (params: { x: number, y: number }) => void,
|
|
@@ -22,7 +21,7 @@ export function useDraggable({
|
|
|
22
21
|
|
|
23
22
|
const listeningRef = React.useRef(false);
|
|
24
23
|
|
|
25
|
-
const onMouseDown = (event: any) => {
|
|
24
|
+
const onMouseDown = useCallback((event: any) => {
|
|
26
25
|
if (event.button !== 0 || !containerRef.current || event.defaultPrevented || event.innerClicked) {
|
|
27
26
|
return;
|
|
28
27
|
}
|
|
@@ -39,16 +38,17 @@ export function useDraggable({
|
|
|
39
38
|
document.addEventListener("selectstart", onSelect);
|
|
40
39
|
listeningRef.current = true;
|
|
41
40
|
// event.stopPropagation();
|
|
42
|
-
};
|
|
43
|
-
|
|
41
|
+
}, [containerRef, onMove]);
|
|
42
|
+
|
|
43
|
+
const onMouseDownInner = useCallback((event: any) => {
|
|
44
44
|
// @ts-ignore
|
|
45
45
|
event.innerClicked = true;
|
|
46
|
-
}
|
|
46
|
+
}, [])
|
|
47
47
|
|
|
48
|
-
const onSelect = (event: any) => {
|
|
48
|
+
const onSelect = useCallback((event: any) => {
|
|
49
49
|
event.preventDefault()
|
|
50
50
|
event.stopPropagation();
|
|
51
|
-
}
|
|
51
|
+
}, [])
|
|
52
52
|
|
|
53
53
|
const onMouseUp = (event: any) => {
|
|
54
54
|
document.removeEventListener("mousemove", onMouseMove);
|
|
@@ -92,6 +92,6 @@ export function useDraggable({
|
|
|
92
92
|
if (innerCurrent)
|
|
93
93
|
innerCurrent.removeEventListener("mousedown", onMouseDownInner);
|
|
94
94
|
};
|
|
95
|
-
});
|
|
95
|
+
}, [containerRef, innerRef, onMouseDownInner, onMouseDown]);
|
|
96
96
|
|
|
97
97
|
}
|
|
@@ -93,6 +93,10 @@ export type EntityCollectionViewProps<M extends Record<string, any>> = {
|
|
|
93
93
|
* It defaults to the collection path if not provided.
|
|
94
94
|
*/
|
|
95
95
|
fullPath?: string;
|
|
96
|
+
/**
|
|
97
|
+
* Full path using navigation ids.
|
|
98
|
+
*/
|
|
99
|
+
fullIdPath?: string;
|
|
96
100
|
/**
|
|
97
101
|
* If this is a subcollection, specify the parent collection ids.
|
|
98
102
|
*/
|
|
@@ -138,6 +142,7 @@ export type EntityCollectionViewProps<M extends Record<string, any>> = {
|
|
|
138
142
|
export const EntityCollectionView = React.memo(
|
|
139
143
|
function EntityCollectionView<M extends Record<string, any>>({
|
|
140
144
|
fullPath: fullPathProp,
|
|
145
|
+
fullIdPath,
|
|
141
146
|
parentCollectionIds,
|
|
142
147
|
isSubCollection,
|
|
143
148
|
className,
|
|
@@ -146,10 +151,11 @@ export const EntityCollectionView = React.memo(
|
|
|
146
151
|
}: EntityCollectionViewProps<M>
|
|
147
152
|
) {
|
|
148
153
|
|
|
154
|
+
|
|
149
155
|
const context = useFireCMSContext();
|
|
156
|
+
const navigation = useNavigationController();
|
|
150
157
|
const fullPath = fullPathProp ?? collectionProp.path;
|
|
151
158
|
const dataSource = useDataSource(collectionProp);
|
|
152
|
-
const navigation = useNavigationController();
|
|
153
159
|
const sideEntityController = useSideEntityController();
|
|
154
160
|
const authController = useAuthController();
|
|
155
161
|
const userConfigPersistence = useUserConfigurationPersistence();
|
|
@@ -240,6 +246,7 @@ export const EntityCollectionView = React.memo(
|
|
|
240
246
|
navigateToEntity({
|
|
241
247
|
navigation,
|
|
242
248
|
path,
|
|
249
|
+
fullIdPath,
|
|
243
250
|
sideEntityController,
|
|
244
251
|
openEntityMode,
|
|
245
252
|
collection,
|
|
@@ -259,6 +266,7 @@ export const EntityCollectionView = React.memo(
|
|
|
259
266
|
collection,
|
|
260
267
|
entityId: undefined,
|
|
261
268
|
path: fullPath,
|
|
269
|
+
fullIdPath,
|
|
262
270
|
sideEntityController,
|
|
263
271
|
navigation,
|
|
264
272
|
onClose: unselectNavigatedEntity
|
|
@@ -378,7 +386,8 @@ export const EntityCollectionView = React.memo(
|
|
|
378
386
|
const resolvedCollection = useMemo(() => resolveCollection<M>({
|
|
379
387
|
collection,
|
|
380
388
|
path: fullPath,
|
|
381
|
-
propertyConfigs: customizationController.propertyConfigs
|
|
389
|
+
propertyConfigs: customizationController.propertyConfigs,
|
|
390
|
+
authController,
|
|
382
391
|
}), [collection, fullPath]);
|
|
383
392
|
|
|
384
393
|
const getPropertyFor = useCallback(({
|
|
@@ -399,7 +408,8 @@ export const EntityCollectionView = React.memo(
|
|
|
399
408
|
path: entity.path,
|
|
400
409
|
values: entity.values,
|
|
401
410
|
entityId: entity.id,
|
|
402
|
-
propertyConfigs: customizationController.propertyConfigs
|
|
411
|
+
propertyConfigs: customizationController.propertyConfigs,
|
|
412
|
+
authController
|
|
403
413
|
});
|
|
404
414
|
}, [collection.properties, customizationController.propertyConfigs, resolvedCollection.properties]);
|
|
405
415
|
|
|
@@ -415,6 +425,7 @@ export const EntityCollectionView = React.memo(
|
|
|
415
425
|
Builder: ({ entity }) => (
|
|
416
426
|
<Button color={"primary"}
|
|
417
427
|
variant={"outlined"}
|
|
428
|
+
className={"max-w-full truncate justify-start"}
|
|
418
429
|
startIcon={<KeyboardTabIcon size={"small"}/>}
|
|
419
430
|
onClick={(event: any) => {
|
|
420
431
|
event.stopPropagation();
|
|
@@ -424,6 +435,7 @@ export const EntityCollectionView = React.memo(
|
|
|
424
435
|
entityId: entity.id,
|
|
425
436
|
selectedTab: subcollection.id ?? subcollection.path,
|
|
426
437
|
path: fullPath,
|
|
438
|
+
fullIdPath,
|
|
427
439
|
navigation,
|
|
428
440
|
sideEntityController
|
|
429
441
|
})
|
|
@@ -527,7 +539,7 @@ export const EntityCollectionView = React.memo(
|
|
|
527
539
|
highlightEntity={setHighlightedEntity}
|
|
528
540
|
unhighlightEntity={unselectNavigatedEntity}
|
|
529
541
|
collection={collection}
|
|
530
|
-
fullPath={fullPath}
|
|
542
|
+
fullPath={fullIdPath ?? fullPath}
|
|
531
543
|
actions={actions}
|
|
532
544
|
hideId={collection?.hideIdFromCollection}
|
|
533
545
|
onCollectionChange={updateLastDeleteTimestamp}
|
|
@@ -691,6 +703,7 @@ export const EntityCollectionView = React.memo(
|
|
|
691
703
|
getIdColumnWidth={getIdColumnWidth}
|
|
692
704
|
additionalIDHeaderWidget={<EntityIdHeaderWidget
|
|
693
705
|
path={fullPath}
|
|
706
|
+
fullIdPath={fullIdPath ?? fullPath}
|
|
694
707
|
collection={collection}/>}
|
|
695
708
|
openEntityMode={openEntityMode}
|
|
696
709
|
/>
|
|
@@ -737,10 +750,13 @@ export const EntityCollectionView = React.memo(
|
|
|
737
750
|
equal(a.defaultSize, b.defaultSize) &&
|
|
738
751
|
equal(a.initialFilter, b.initialFilter) &&
|
|
739
752
|
equal(a.initialSort, b.initialSort) &&
|
|
753
|
+
equal(a.includeJsonView, b.includeJsonView) &&
|
|
740
754
|
equal(a.textSearchEnabled, b.textSearchEnabled) &&
|
|
741
755
|
equal(a.additionalFields, b.additionalFields) &&
|
|
742
756
|
equal(a.sideDialogWidth, b.sideDialogWidth) &&
|
|
743
757
|
equal(a.openEntityMode, b.openEntityMode) &&
|
|
758
|
+
equal(a.exportable, b.exportable) &&
|
|
759
|
+
equal(a.history, b.history) &&
|
|
744
760
|
equal(a.forceFilter, b.forceFilter);
|
|
745
761
|
}) as React.FunctionComponent<EntityCollectionViewProps<any>>
|
|
746
762
|
|
|
@@ -807,10 +823,12 @@ function buildPropertyWidthOverwrite(key: string, width: number): PartialEntityC
|
|
|
807
823
|
|
|
808
824
|
function EntityIdHeaderWidget({
|
|
809
825
|
collection,
|
|
810
|
-
path
|
|
826
|
+
path,
|
|
827
|
+
fullIdPath
|
|
811
828
|
}: {
|
|
812
829
|
collection: EntityCollection,
|
|
813
|
-
path: string
|
|
830
|
+
path: string,
|
|
831
|
+
fullIdPath: string
|
|
814
832
|
}) {
|
|
815
833
|
|
|
816
834
|
const navigation = useNavigationController();
|
|
@@ -848,6 +866,7 @@ function EntityIdHeaderWidget({
|
|
|
848
866
|
collection,
|
|
849
867
|
entityId,
|
|
850
868
|
path,
|
|
869
|
+
fullIdPath,
|
|
851
870
|
sideEntityController,
|
|
852
871
|
navigation
|
|
853
872
|
})
|
|
@@ -882,6 +901,7 @@ function EntityIdHeaderWidget({
|
|
|
882
901
|
collection,
|
|
883
902
|
entityId: id,
|
|
884
903
|
path,
|
|
904
|
+
fullIdPath,
|
|
885
905
|
sideEntityController,
|
|
886
906
|
navigation
|
|
887
907
|
})
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import React, { useRef } from "react";
|
|
2
|
+
import { Highlight, themes } from "prism-react-renderer";
|
|
3
|
+
import { useModeController } from "../hooks";
|
|
4
|
+
|
|
5
|
+
export function EntityJsonPreview({ values }: { values: object }) {
|
|
6
|
+
const code = JSON.stringify(values, null, "\t");
|
|
7
|
+
const { mode } = useModeController();
|
|
8
|
+
const preRef = useRef<HTMLPreElement>(null);
|
|
9
|
+
|
|
10
|
+
// Global keydown handler
|
|
11
|
+
// const handleGlobalKeyDown = useCallback((e: KeyboardEvent) => {
|
|
12
|
+
// // Check for Control (Windows/Linux) or Command (macOS) + "a":
|
|
13
|
+
// if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "a") {
|
|
14
|
+
// // If our code view is mounted, perform selection
|
|
15
|
+
// if (preRef.current) {
|
|
16
|
+
// e.preventDefault();
|
|
17
|
+
// e.stopPropagation();
|
|
18
|
+
//
|
|
19
|
+
// const selection = window.getSelection();
|
|
20
|
+
// const range = document.createRange();
|
|
21
|
+
// range.selectNodeContents(preRef.current);
|
|
22
|
+
// if (selection) {
|
|
23
|
+
// selection.removeAllRanges();
|
|
24
|
+
// selection.addRange(range);
|
|
25
|
+
// }
|
|
26
|
+
// }
|
|
27
|
+
// }
|
|
28
|
+
// }, []);
|
|
29
|
+
|
|
30
|
+
// // Attach the global keydown listener when component mounts,
|
|
31
|
+
// // and remove it when it unmounts.
|
|
32
|
+
// useEffect(() => {
|
|
33
|
+
// document.addEventListener("keydown", handleGlobalKeyDown);
|
|
34
|
+
// return () => {
|
|
35
|
+
// document.removeEventListener("keydown", handleGlobalKeyDown);
|
|
36
|
+
// };
|
|
37
|
+
// }, [handleGlobalKeyDown]);
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<Highlight
|
|
41
|
+
theme={mode === "dark" ? themes.vsDark : themes.github}
|
|
42
|
+
code={code}
|
|
43
|
+
language="json"
|
|
44
|
+
>
|
|
45
|
+
{({ style, tokens, getLineProps, getTokenProps }) => (
|
|
46
|
+
<pre
|
|
47
|
+
// Bind the ref to our pre element so we can select its contents.
|
|
48
|
+
ref={preRef}
|
|
49
|
+
style={{
|
|
50
|
+
...style,
|
|
51
|
+
backgroundColor: "inherit"
|
|
52
|
+
}}
|
|
53
|
+
className="max-w-6xl mx-auto p-8 rounded text-sm"
|
|
54
|
+
>
|
|
55
|
+
{tokens.map((line, i) => (
|
|
56
|
+
<div key={i} {...getLineProps({ line })} className="text-wrap">
|
|
57
|
+
{line.map((token, key) => (
|
|
58
|
+
<span key={key} {...getTokenProps({ token })} className="word-break" />
|
|
59
|
+
))}
|
|
60
|
+
</div>
|
|
61
|
+
))}
|
|
62
|
+
</pre>
|
|
63
|
+
)}
|
|
64
|
+
</Highlight>
|
|
65
|
+
);
|
|
66
|
+
}
|