@firecms/core 3.3.0 → 3.4.0-canary.63041d0
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/useApp.d.ts +1 -0
- package/dist/components/EntityCollectionTable/column_utils.d.ts +4 -3
- package/dist/components/EntityCollectionTable/internal/CollectionTableToolbar.d.ts +6 -1
- package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +7 -0
- package/dist/components/EntityCollectionView/FiltersDialog.d.ts +2 -1
- package/dist/components/EntityPreview.d.ts +3 -1
- package/dist/components/SelectableTable/filters/filter_text_input.d.ts +30 -0
- package/dist/components/SelectableTable/filters/filter_text_input.test.d.ts +1 -0
- package/dist/components/common/table_url_params.d.ts +24 -0
- package/dist/components/common/useDataSourceTableController.d.ts +7 -1
- package/dist/components/common/useTableSearchHelper.d.ts +7 -1
- package/dist/core/DefaultDrawer.d.ts +10 -3
- package/dist/core/EntityEditView.d.ts +7 -1
- package/dist/core/field_configs.d.ts +1 -1
- package/dist/form/field_bindings/GeopointFieldBinding.d.ts +5 -0
- package/dist/form/index.d.ts +1 -0
- package/dist/hooks/data/save.d.ts +1 -1
- package/dist/hooks/data/useEntityFetch.d.ts +6 -1
- package/dist/index.es.js +2790 -1270
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +2788 -1268
- package/dist/index.umd.js.map +1 -1
- package/dist/locales/pl.d.ts +2 -0
- package/dist/preview/index.d.ts +1 -0
- package/dist/preview/property_previews/GeopointPropertyPreview.d.ts +4 -0
- package/dist/types/collections.d.ts +24 -0
- package/dist/types/datasource.d.ts +42 -0
- package/dist/types/properties.d.ts +17 -1
- package/dist/types/side_entity_controller.d.ts +6 -0
- package/dist/types/translations.d.ts +6 -0
- package/dist/util/__tests__/collections.test.d.ts +1 -0
- package/dist/util/__tests__/urls.test.d.ts +1 -0
- package/dist/util/collections.d.ts +1 -1
- package/dist/util/entities.d.ts +1 -0
- package/dist/util/geopoint.d.ts +22 -0
- package/dist/util/index.d.ts +2 -0
- package/dist/util/navigation_blocking.d.ts +22 -0
- package/dist/util/navigation_from_path.d.ts +17 -0
- package/dist/util/navigation_utils.d.ts +23 -1
- package/dist/util/urls.d.ts +22 -0
- package/package.json +16 -9
- package/src/app/Scaffold.tsx +34 -44
- package/src/app/useApp.tsx +1 -0
- package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +3 -1
- package/src/components/EntityCollectionTable/column_utils.tsx +11 -19
- package/src/components/EntityCollectionTable/fields/TableReferenceField.tsx +1 -1
- package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +7 -0
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +19 -1
- package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +4 -1
- package/src/components/EntityCollectionView/FiltersDialog.tsx +39 -28
- package/src/components/EntityPreview.tsx +41 -40
- package/src/components/ReferenceWidget.tsx +1 -1
- package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +2 -2
- package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +33 -7
- package/src/components/SelectableTable/filters/filter_text_input.test.ts +184 -0
- package/src/components/SelectableTable/filters/filter_text_input.ts +71 -0
- package/src/components/VirtualTable/VirtualTable.tsx +19 -8
- package/src/components/common/table_url_params.ts +172 -0
- package/src/components/common/useDataSourceTableController.tsx +98 -159
- package/src/components/common/useTableSearchHelper.ts +21 -2
- package/src/contexts/SnackbarProvider.tsx +14 -1
- package/src/core/DefaultDrawer.tsx +150 -64
- package/src/core/DrawerNavigationGroup.tsx +27 -29
- package/src/core/DrawerNavigationItem.tsx +10 -12
- package/src/core/EntityEditView.tsx +75 -32
- package/src/core/EntitySidePanel.tsx +2 -0
- package/src/core/field_configs.tsx +15 -0
- package/src/form/EntityForm.tsx +1 -1
- package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +1 -1
- package/src/form/field_bindings/GeopointFieldBinding.tsx +139 -0
- package/src/form/index.tsx +1 -0
- package/src/hooks/data/save.ts +2 -0
- package/src/hooks/data/useEntityFetch.tsx +9 -0
- package/src/hooks/useValidateAuthenticator.tsx +4 -0
- package/src/i18n/FireCMSi18nProvider.tsx +2 -0
- package/src/internal/useBuildDataSource.ts +11 -0
- package/src/internal/useBuildSideEntityController.tsx +8 -1
- package/src/locales/de.ts +7 -2
- package/src/locales/en.ts +7 -2
- package/src/locales/es.ts +7 -2
- package/src/locales/fr.ts +7 -2
- package/src/locales/hi.ts +7 -2
- package/src/locales/it.ts +7 -2
- package/src/locales/pl.ts +735 -0
- package/src/locales/pt.ts +7 -2
- package/src/preview/PropertyPreview.tsx +12 -0
- package/src/preview/components/StorageThumbnail.tsx +24 -2
- package/src/preview/index.ts +1 -0
- package/src/preview/property_previews/GeopointPropertyPreview.tsx +23 -0
- package/src/routes/FireCMSRoute.tsx +47 -25
- package/src/types/collections.ts +26 -0
- package/src/types/datasource.ts +42 -0
- package/src/types/properties.ts +17 -0
- package/src/types/side_entity_controller.tsx +6 -0
- package/src/types/translations.ts +6 -0
- package/src/util/__tests__/collections.test.ts +32 -0
- package/src/util/__tests__/urls.test.ts +131 -0
- package/src/util/collections.ts +1 -1
- package/src/util/entities.ts +13 -0
- package/src/util/geopoint.ts +81 -0
- package/src/util/index.ts +2 -0
- package/src/util/navigation_blocking.ts +45 -0
- package/src/util/navigation_from_path.ts +41 -6
- package/src/util/navigation_utils.ts +40 -2
- package/src/util/parent_references_from_path.ts +4 -2
- package/src/util/previews.ts +8 -1
- package/src/util/resolutions.ts +8 -0
- package/src/util/urls.ts +52 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import React, { useEffect, useRef, useState } from "react";
|
|
2
|
+
|
|
3
|
+
import { CloseIcon, IconButton, TextField } from "@firecms/ui";
|
|
4
|
+
import { FieldProps, GeoPoint } from "../../types";
|
|
5
|
+
import { FieldHelperText, LabelWithIcon } from "../components";
|
|
6
|
+
import { PropertyIdCopyTooltip } from "../../components";
|
|
7
|
+
import { useClearRestoreValue } from "../useClearRestoreValue";
|
|
8
|
+
import { getIconForProperty } from "../../util";
|
|
9
|
+
import { formatGeoPoint, getGeoPointCoordinates, parseGeoPoint } from "../../util/geopoint";
|
|
10
|
+
|
|
11
|
+
type GeopointFieldBindingProps = FieldProps<GeoPoint>;
|
|
12
|
+
|
|
13
|
+
export function GeopointFieldBinding({
|
|
14
|
+
propertyKey,
|
|
15
|
+
value,
|
|
16
|
+
setValue,
|
|
17
|
+
error,
|
|
18
|
+
showError,
|
|
19
|
+
disabled,
|
|
20
|
+
autoFocus,
|
|
21
|
+
property,
|
|
22
|
+
includeDescription,
|
|
23
|
+
size = "large"
|
|
24
|
+
}: GeopointFieldBindingProps) {
|
|
25
|
+
|
|
26
|
+
const coordinates = getGeoPointCoordinates(value);
|
|
27
|
+
const canClear = Boolean((property as any).clearable);
|
|
28
|
+
const [latitude, setLatitude] = useState<string>(coordinates ? coordinates.latitude.toString() : "");
|
|
29
|
+
const [longitude, setLongitude] = useState<string>(coordinates ? coordinates.longitude.toString() : "");
|
|
30
|
+
const [localError, setLocalError] = useState<string | undefined>();
|
|
31
|
+
const skipSyncRef = useRef(false);
|
|
32
|
+
|
|
33
|
+
useClearRestoreValue({
|
|
34
|
+
property,
|
|
35
|
+
value,
|
|
36
|
+
setValue
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
if (skipSyncRef.current) {
|
|
41
|
+
skipSyncRef.current = false;
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const nextCoordinates = getGeoPointCoordinates(value);
|
|
45
|
+
setLatitude(nextCoordinates ? nextCoordinates.latitude.toString() : "");
|
|
46
|
+
setLongitude(nextCoordinates ? nextCoordinates.longitude.toString() : "");
|
|
47
|
+
}, [value]);
|
|
48
|
+
|
|
49
|
+
const updateGeoPoint = (nextLatitude: string, nextLongitude: string) => {
|
|
50
|
+
skipSyncRef.current = true;
|
|
51
|
+
setLatitude(nextLatitude);
|
|
52
|
+
setLongitude(nextLongitude);
|
|
53
|
+
|
|
54
|
+
const trimmedLatitude = nextLatitude.trim();
|
|
55
|
+
const trimmedLongitude = nextLongitude.trim();
|
|
56
|
+
|
|
57
|
+
if (!trimmedLatitude && !trimmedLongitude) {
|
|
58
|
+
setLocalError(undefined);
|
|
59
|
+
setValue(null);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const parsed = parseGeoPoint(`${trimmedLatitude}, ${trimmedLongitude}`);
|
|
64
|
+
|
|
65
|
+
if (parsed.error) {
|
|
66
|
+
setLocalError(parsed.error);
|
|
67
|
+
setValue(null);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
setLocalError(undefined);
|
|
72
|
+
setValue(parsed.point);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const handleClear = (event?: React.MouseEvent) => {
|
|
76
|
+
if (event) {
|
|
77
|
+
event.preventDefault();
|
|
78
|
+
event.stopPropagation();
|
|
79
|
+
}
|
|
80
|
+
updateGeoPoint("", "");
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const resolvedError = localError ?? error;
|
|
84
|
+
const shouldShowError = Boolean(resolvedError) || Boolean(showError && error);
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<>
|
|
88
|
+
<PropertyIdCopyTooltip propertyKey={propertyKey}>
|
|
89
|
+
<div className="flex flex-col gap-2">
|
|
90
|
+
<div className="mt-1">
|
|
91
|
+
<LabelWithIcon
|
|
92
|
+
icon={getIconForProperty(property, "small")}
|
|
93
|
+
required={property.validation?.required}
|
|
94
|
+
title={property.name}
|
|
95
|
+
className={shouldShowError ? "text-red-500 dark:text-red-500" : "text-text-secondary dark:text-text-secondary-dark"}
|
|
96
|
+
/>
|
|
97
|
+
</div>
|
|
98
|
+
<div className="grid grid-cols-1 gap-2 md:grid-cols-2">
|
|
99
|
+
<TextField
|
|
100
|
+
size={size}
|
|
101
|
+
value={latitude}
|
|
102
|
+
onChange={(event) => updateGeoPoint(event.target.value, longitude)}
|
|
103
|
+
autoFocus={autoFocus}
|
|
104
|
+
label={"Latitude"}
|
|
105
|
+
type="number"
|
|
106
|
+
disabled={disabled}
|
|
107
|
+
endAdornment={canClear ? (
|
|
108
|
+
<IconButton onClick={handleClear}>
|
|
109
|
+
<CloseIcon />
|
|
110
|
+
</IconButton>
|
|
111
|
+
) : undefined}
|
|
112
|
+
error={shouldShowError && Boolean(resolvedError)}
|
|
113
|
+
/>
|
|
114
|
+
<TextField
|
|
115
|
+
size={size}
|
|
116
|
+
value={longitude}
|
|
117
|
+
onChange={(event) => updateGeoPoint(latitude, event.target.value)}
|
|
118
|
+
label={"Longitude"}
|
|
119
|
+
type="number"
|
|
120
|
+
disabled={disabled}
|
|
121
|
+
error={shouldShowError && Boolean(resolvedError)}
|
|
122
|
+
/>
|
|
123
|
+
</div>
|
|
124
|
+
{value && !resolvedError && (
|
|
125
|
+
<div className="text-xs text-text-secondary dark:text-text-secondary-dark font-mono">
|
|
126
|
+
{formatGeoPoint(value)}
|
|
127
|
+
</div>
|
|
128
|
+
)}
|
|
129
|
+
</div>
|
|
130
|
+
</PropertyIdCopyTooltip>
|
|
131
|
+
|
|
132
|
+
<FieldHelperText includeDescription={includeDescription}
|
|
133
|
+
showError={shouldShowError}
|
|
134
|
+
error={resolvedError}
|
|
135
|
+
disabled={disabled}
|
|
136
|
+
property={property}/>
|
|
137
|
+
</>
|
|
138
|
+
);
|
|
139
|
+
}
|
package/src/form/index.tsx
CHANGED
|
@@ -11,6 +11,7 @@ export { StorageUploadFieldBinding } from "./field_bindings/StorageUploadFieldBi
|
|
|
11
11
|
export { TextFieldBinding } from "./field_bindings/TextFieldBinding";
|
|
12
12
|
export { SwitchFieldBinding } from "./field_bindings/SwitchFieldBinding";
|
|
13
13
|
export { DateTimeFieldBinding } from "./field_bindings/DateTimeFieldBinding";
|
|
14
|
+
export { GeopointFieldBinding } from "./field_bindings/GeopointFieldBinding";
|
|
14
15
|
export { ReferenceFieldBinding } from "./field_bindings/ReferenceFieldBinding";
|
|
15
16
|
export { ReferenceAsStringFieldBinding } from "./field_bindings/ReferenceAsStringFieldBinding";
|
|
16
17
|
export { MapFieldBinding } from "./field_bindings/MapFieldBinding";
|
package/src/hooks/data/save.ts
CHANGED
|
@@ -43,6 +43,7 @@ export type SaveEntityWithCallbacksProps<M extends Record<string, any>> =
|
|
|
43
43
|
export async function saveEntityWithCallbacks<M extends Record<string, any>, USER extends User>({
|
|
44
44
|
collection,
|
|
45
45
|
path,
|
|
46
|
+
pathSegments,
|
|
46
47
|
entityId,
|
|
47
48
|
values,
|
|
48
49
|
previousValues,
|
|
@@ -103,6 +104,7 @@ export async function saveEntityWithCallbacks<M extends Record<string, any>, USE
|
|
|
103
104
|
return dataSource.saveEntity({
|
|
104
105
|
collection,
|
|
105
106
|
path: resolvedPath,
|
|
107
|
+
pathSegments: pathSegments ?? resolvedPath.split("/"),
|
|
106
108
|
entityId,
|
|
107
109
|
values: updatedValues,
|
|
108
110
|
previousValues,
|
|
@@ -9,6 +9,11 @@ import { useFireCMSContext } from "../useFireCMSContext";
|
|
|
9
9
|
*/
|
|
10
10
|
export interface EntityFetchProps<M extends Record<string, any>, USER extends User = User> {
|
|
11
11
|
path: string;
|
|
12
|
+
/**
|
|
13
|
+
* `path` split at its real segment boundaries. Forwarded to the datasource so a parent
|
|
14
|
+
* entity id containing "/" stays unambiguous. Defaults to splitting the resolved path.
|
|
15
|
+
*/
|
|
16
|
+
pathSegments?: string[];
|
|
12
17
|
entityId?: string;
|
|
13
18
|
databaseId?: string;
|
|
14
19
|
collection: EntityCollection<M, USER>;
|
|
@@ -39,6 +44,7 @@ const CACHE: Record<string, Entity<any> | undefined> = {};
|
|
|
39
44
|
export function useEntityFetch<M extends Record<string, any>, USER extends User>(
|
|
40
45
|
{
|
|
41
46
|
path: inputPath,
|
|
47
|
+
pathSegments: inputPathSegments,
|
|
42
48
|
entityId,
|
|
43
49
|
collection,
|
|
44
50
|
databaseId,
|
|
@@ -49,6 +55,7 @@ export function useEntityFetch<M extends Record<string, any>, USER extends User>
|
|
|
49
55
|
const navigationController = useNavigationController();
|
|
50
56
|
|
|
51
57
|
const path = navigationController.resolveIdsFrom(inputPath);
|
|
58
|
+
const pathSegments = inputPathSegments ?? path.split("/");
|
|
52
59
|
|
|
53
60
|
const context: FireCMSContext<USER> = useFireCMSContext();
|
|
54
61
|
|
|
@@ -97,6 +104,7 @@ export function useEntityFetch<M extends Record<string, any>, USER extends User>
|
|
|
97
104
|
if (dataSource.listenEntity) {
|
|
98
105
|
return dataSource.listenEntity<M>({
|
|
99
106
|
path,
|
|
107
|
+
pathSegments,
|
|
100
108
|
entityId,
|
|
101
109
|
databaseId,
|
|
102
110
|
collection,
|
|
@@ -106,6 +114,7 @@ export function useEntityFetch<M extends Record<string, any>, USER extends User>
|
|
|
106
114
|
} else {
|
|
107
115
|
dataSource.fetchEntity<M>({
|
|
108
116
|
path,
|
|
117
|
+
pathSegments,
|
|
109
118
|
entityId,
|
|
110
119
|
databaseId,
|
|
111
120
|
collection
|
|
@@ -74,6 +74,10 @@ export function useValidateAuthenticator<USER extends User = any>
|
|
|
74
74
|
|
|
75
75
|
if (authenticator instanceof Function && delegateUser && !equal(checkedUserRef.current?.uid, delegateUser.uid)) {
|
|
76
76
|
setAuthLoading(true);
|
|
77
|
+
// Reset the error of any previous authentication attempt. Otherwise, a
|
|
78
|
+
// rejected user would keep `canAccessMainView` to false for every user
|
|
79
|
+
// logging in afterwards, locking them out of the CMS until a page reload.
|
|
80
|
+
setNotAllowedError(false);
|
|
77
81
|
try {
|
|
78
82
|
const allowed = await authenticator({
|
|
79
83
|
user: delegateUser,
|
|
@@ -8,6 +8,7 @@ import { fr } from "../locales/fr";
|
|
|
8
8
|
import { it } from "../locales/it";
|
|
9
9
|
import { hi } from "../locales/hi";
|
|
10
10
|
import { pt } from "../locales/pt";
|
|
11
|
+
import { pl } from "../locales/pl";
|
|
11
12
|
import { FireCMSTranslations } from "../types/translations";
|
|
12
13
|
|
|
13
14
|
const FIRECMS_NS = "firecms_core";
|
|
@@ -139,6 +140,7 @@ function buildResources(
|
|
|
139
140
|
it: { [FIRECMS_NS]: { ...it } },
|
|
140
141
|
hi: { [FIRECMS_NS]: { ...hi } },
|
|
141
142
|
pt: { [FIRECMS_NS]: { ...pt } },
|
|
143
|
+
pl: { [FIRECMS_NS]: { ...pl } },
|
|
142
144
|
};
|
|
143
145
|
|
|
144
146
|
if (!translations) return resources;
|
|
@@ -55,6 +55,7 @@ export function useBuildDataSource({
|
|
|
55
55
|
*/
|
|
56
56
|
fetchCollection: useCallback(<M extends Record<string, any>>({
|
|
57
57
|
path,
|
|
58
|
+
pathSegments,
|
|
58
59
|
collection,
|
|
59
60
|
filter,
|
|
60
61
|
limit,
|
|
@@ -67,6 +68,7 @@ export function useBuildDataSource({
|
|
|
67
68
|
const usedDelegate = collection?.overrides?.dataSourceDelegate ?? delegate;
|
|
68
69
|
return usedDelegate.fetchCollection<M>({
|
|
69
70
|
path,
|
|
71
|
+
pathSegments,
|
|
70
72
|
filter,
|
|
71
73
|
limit,
|
|
72
74
|
startAfter,
|
|
@@ -97,6 +99,7 @@ export function useBuildDataSource({
|
|
|
97
99
|
? useCallback(<M extends Record<string, any>>(
|
|
98
100
|
{
|
|
99
101
|
path,
|
|
102
|
+
pathSegments,
|
|
100
103
|
collection: collectionProp,
|
|
101
104
|
filter,
|
|
102
105
|
limit,
|
|
@@ -117,6 +120,7 @@ export function useBuildDataSource({
|
|
|
117
120
|
|
|
118
121
|
return usedDelegate.listenCollection<M>({
|
|
119
122
|
path,
|
|
123
|
+
pathSegments,
|
|
120
124
|
filter,
|
|
121
125
|
limit,
|
|
122
126
|
startAfter,
|
|
@@ -139,6 +143,7 @@ export function useBuildDataSource({
|
|
|
139
143
|
*/
|
|
140
144
|
fetchEntity: useCallback(<M extends Record<string, any>>({
|
|
141
145
|
path,
|
|
146
|
+
pathSegments,
|
|
142
147
|
entityId,
|
|
143
148
|
collection
|
|
144
149
|
}: FetchEntityProps<M>
|
|
@@ -146,6 +151,7 @@ export function useBuildDataSource({
|
|
|
146
151
|
const usedDelegate = collection?.overrides?.dataSourceDelegate ?? delegate;
|
|
147
152
|
return usedDelegate.fetchEntity({
|
|
148
153
|
path,
|
|
154
|
+
pathSegments,
|
|
149
155
|
entityId,
|
|
150
156
|
collection
|
|
151
157
|
});
|
|
@@ -165,6 +171,7 @@ export function useBuildDataSource({
|
|
|
165
171
|
? useCallback(<M extends Record<string, any>>(
|
|
166
172
|
{
|
|
167
173
|
path,
|
|
174
|
+
pathSegments,
|
|
168
175
|
entityId,
|
|
169
176
|
collection,
|
|
170
177
|
onUpdate,
|
|
@@ -177,6 +184,7 @@ export function useBuildDataSource({
|
|
|
177
184
|
|
|
178
185
|
return usedDelegate.listenEntity<M>({
|
|
179
186
|
path,
|
|
187
|
+
pathSegments,
|
|
180
188
|
entityId,
|
|
181
189
|
onUpdate,
|
|
182
190
|
onError,
|
|
@@ -198,6 +206,7 @@ export function useBuildDataSource({
|
|
|
198
206
|
saveEntity: useCallback(async <M extends Record<string, any>>(
|
|
199
207
|
{
|
|
200
208
|
path,
|
|
209
|
+
pathSegments,
|
|
201
210
|
entityId,
|
|
202
211
|
values,
|
|
203
212
|
collection: collectionProp,
|
|
@@ -244,6 +253,7 @@ export function useBuildDataSource({
|
|
|
244
253
|
try {
|
|
245
254
|
const entities = await usedDelegate.fetchCollection({
|
|
246
255
|
path,
|
|
256
|
+
pathSegments,
|
|
247
257
|
orderBy: orderProperty,
|
|
248
258
|
order: "asc",
|
|
249
259
|
limit: 1,
|
|
@@ -270,6 +280,7 @@ export function useBuildDataSource({
|
|
|
270
280
|
|
|
271
281
|
return usedDelegate.saveEntity({
|
|
272
282
|
path,
|
|
283
|
+
pathSegments,
|
|
273
284
|
collection,
|
|
274
285
|
entityId,
|
|
275
286
|
values: finalValues,
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
import { getNavigationEntriesFromPath, NavigationViewInternal } from "../util/navigation_from_path";
|
|
14
14
|
import { useLocation } from "react-router-dom";
|
|
15
15
|
import {
|
|
16
|
+
encodeEntityId,
|
|
16
17
|
removeInitialAndTrailingSlashes,
|
|
17
18
|
resolveCollection,
|
|
18
19
|
resolveDefaultSelectedView,
|
|
@@ -223,12 +224,14 @@ export function buildSidePanelsFromUrl(path: string, collections: EntityCollecti
|
|
|
223
224
|
let sidePanel: EntitySidePanelProps<any> | undefined = undefined;
|
|
224
225
|
let lastCollectionPath = "";
|
|
225
226
|
let lastCollectionId: string | undefined = undefined;
|
|
227
|
+
let lastCollectionSegments: string[] | undefined = undefined;
|
|
226
228
|
for (let i = 0; i < navigationViewsForPath.length; i++) {
|
|
227
229
|
const navigationEntry = navigationViewsForPath[i];
|
|
228
230
|
|
|
229
231
|
if (navigationEntry.type === "collection") {
|
|
230
232
|
lastCollectionPath = navigationEntry.path;
|
|
231
233
|
lastCollectionId = navigationEntry.collection.id;
|
|
234
|
+
lastCollectionSegments = navigationEntry.pathSegments;
|
|
232
235
|
}
|
|
233
236
|
|
|
234
237
|
const previousEntry = navigationViewsForPath[i - 1];
|
|
@@ -236,6 +239,7 @@ export function buildSidePanelsFromUrl(path: string, collections: EntityCollecti
|
|
|
236
239
|
sidePanel = {
|
|
237
240
|
path: navigationEntry.path,
|
|
238
241
|
fullIdPath: navigationEntry.fullIdPath,
|
|
242
|
+
pathSegments: navigationEntry.pathSegments,
|
|
239
243
|
entityId: navigationEntry.entityId,
|
|
240
244
|
copy: false,
|
|
241
245
|
width: navigationEntry.parentCollection?.sideDialogWidth
|
|
@@ -258,6 +262,9 @@ export function buildSidePanelsFromUrl(path: string, collections: EntityCollecti
|
|
|
258
262
|
sidePanel = {
|
|
259
263
|
path: lastCollectionPath,
|
|
260
264
|
fullIdPath: lastCollectionId,
|
|
265
|
+
// A new entity still needs unambiguous segments: it may be created inside a
|
|
266
|
+
// subcollection whose parent id contains "/".
|
|
267
|
+
pathSegments: lastCollectionSegments,
|
|
261
268
|
copy: false
|
|
262
269
|
}
|
|
263
270
|
}
|
|
@@ -277,7 +284,7 @@ const propsToSidePanel = (props: EntitySidePanelProps,
|
|
|
277
284
|
const collectionPath = removeInitialAndTrailingSlashes(props.path);
|
|
278
285
|
|
|
279
286
|
const urlPath = props.entityId
|
|
280
|
-
? buildUrlCollectionPath(`${collectionPath}/${props.entityId}${props.selectedTab ? "/" + props.selectedTab : ""}${locationSearch}#${SIDE_URL_HASH}`)
|
|
287
|
+
? buildUrlCollectionPath(`${collectionPath}/${encodeEntityId(props.entityId)}${props.selectedTab ? "/" + props.selectedTab : ""}${locationSearch}#${SIDE_URL_HASH}`)
|
|
281
288
|
: buildUrlCollectionPath(`${collectionPath}${locationSearch}#${NEW_URL_HASH}`);
|
|
282
289
|
|
|
283
290
|
const resolvedPanelProps: EntitySidePanelProps<any> = {
|
package/src/locales/de.ts
CHANGED
|
@@ -146,8 +146,8 @@ export const de: FireCMSTranslations = {
|
|
|
146
146
|
// ─── Error states ─────────────────────────────────────────────
|
|
147
147
|
error: "Fehler",
|
|
148
148
|
error_uploading_file: "Fehler beim Hochladen der Datei",
|
|
149
|
-
error_deleting: "Fehler beim Löschen",
|
|
150
|
-
error_before_delete: "Fehler vor dem Löschen",
|
|
149
|
+
error_deleting: "Fehler beim Löschen: {{message}}",
|
|
150
|
+
error_before_delete: "Fehler vor dem Löschen: {{message}}",
|
|
151
151
|
error_updating_asset: "Fehler beim Aktualisieren des Assets",
|
|
152
152
|
error_deleting_asset: "Fehler beim Löschen des Assets",
|
|
153
153
|
error_firestore_index: "Für diese Abfrage ist ein Firestore-Index erforderlich.",
|
|
@@ -389,6 +389,7 @@ export const de: FireCMSTranslations = {
|
|
|
389
389
|
download: "Herunterladen",
|
|
390
390
|
large_number_of_documents: "Diese Sammlung hat eine große Anzahl von Dokumenten ({{count}}).",
|
|
391
391
|
include_undefined_values: "Undefinierte Werte einschließen",
|
|
392
|
+
export_apply_filter_sort: "Nur Ergebnisse exportieren, die dem aktuellen Filter/der aktuellen Sortierung entsprechen",
|
|
392
393
|
submit: "Einreichen",
|
|
393
394
|
|
|
394
395
|
no_filterable_properties: "Keine filterbaren Eigenschaften verfügbar",
|
|
@@ -586,6 +587,10 @@ export const de: FireCMSTranslations = {
|
|
|
586
587
|
order_property_not_found: "Eigenschaft \"{{property}}\" existiert nicht oder ist keine Zahlen-Eigenschaft. Bitte wählen Sie eine gültige Eigenschaft oder löschen Sie die Auswahl.",
|
|
587
588
|
no_number_properties: "Keine Zahlen-Eigenschaften gefunden. Fügen Sie eine Zahlen-Eigenschaft hinzu, um die Sortierung zu aktivieren.",
|
|
588
589
|
order_property_description: "Wählen Sie eine Zahlen-Eigenschaft, um die Reihenfolge der Elemente beizubehalten",
|
|
590
|
+
image_property: "Bild-Eigenschaft",
|
|
591
|
+
image_property_not_found: "Eigenschaft \"{{property}}\" existiert nicht oder ist keine Bild-Eigenschaft. Bitte wählen Sie eine gültige Eigenschaft oder löschen Sie die Auswahl.",
|
|
592
|
+
no_image_properties: "Keine Bild-Eigenschaften gefunden. Fügen Sie eine Speicher- oder Bild-URL-Eigenschaft hinzu, um sie als Vorschaubild zu verwenden.",
|
|
593
|
+
image_property_description: "Wählen Sie die Eigenschaft, die als Vorschaubild in den Ansichten Karten und Kanban verwendet wird. Wenn nicht festgelegt, wird automatisch die erste passende Bild-Eigenschaft verwendet.",
|
|
589
594
|
display_settings: "Anzeigeeinstellungen",
|
|
590
595
|
default_row_size: "Standard-Zeilengröße",
|
|
591
596
|
side_dialog_width: "Seitendialog-Breite",
|
package/src/locales/en.ts
CHANGED
|
@@ -154,8 +154,8 @@ export const en: FireCMSTranslations = {
|
|
|
154
154
|
// ─── Error states ─────────────────────────────────────────────
|
|
155
155
|
error: "Error",
|
|
156
156
|
error_uploading_file: "Error uploading file",
|
|
157
|
-
error_deleting: "Error deleting",
|
|
158
|
-
error_before_delete: "Error before delete",
|
|
157
|
+
error_deleting: "Error deleting: {{message}}",
|
|
158
|
+
error_before_delete: "Error before delete: {{message}}",
|
|
159
159
|
error_updating_asset: "Error updating asset",
|
|
160
160
|
error_deleting_asset: "Error deleting asset",
|
|
161
161
|
error_firestore_index: "A Firestore index is required for this query.",
|
|
@@ -397,6 +397,7 @@ export const en: FireCMSTranslations = {
|
|
|
397
397
|
download: "Download",
|
|
398
398
|
large_number_of_documents: "This collections has a large number of documents ({{count}}).",
|
|
399
399
|
include_undefined_values: "Include undefined values",
|
|
400
|
+
export_apply_filter_sort: "Only export results matching the current filter/sort",
|
|
400
401
|
submit: "Submit",
|
|
401
402
|
|
|
402
403
|
no_filterable_properties: "No filterable properties available",
|
|
@@ -598,6 +599,10 @@ export const en: FireCMSTranslations = {
|
|
|
598
599
|
order_property_not_found: "Property \"{{property}}\" does not exist or is not a number property. Please select a valid property or clear the selection.",
|
|
599
600
|
no_number_properties: "No number properties found. Add a number property to enable ordering.",
|
|
600
601
|
order_property_description: "Select a number property to persist the order of items",
|
|
602
|
+
image_property: "Image Property",
|
|
603
|
+
image_property_not_found: "Property \"{{property}}\" does not exist or is not an image property. Please select a valid property or clear the selection.",
|
|
604
|
+
no_image_properties: "No image properties found. Add a storage or URL image property to use as a thumbnail.",
|
|
605
|
+
image_property_description: "Select the property used as the thumbnail image in Cards and Kanban view modes. If not set, the first matching image property will be used automatically.",
|
|
601
606
|
display_settings: "Display settings",
|
|
602
607
|
default_row_size: "Default row size",
|
|
603
608
|
side_dialog_width: "Side dialog width",
|
package/src/locales/es.ts
CHANGED
|
@@ -152,8 +152,8 @@ export const es: FireCMSTranslations = {
|
|
|
152
152
|
// ─── Error states ─────────────────────────────────────────────
|
|
153
153
|
error: "Error",
|
|
154
154
|
error_uploading_file: "Error al subir archivo",
|
|
155
|
-
error_deleting: "Error al eliminar",
|
|
156
|
-
error_before_delete: "Error antes de eliminar",
|
|
155
|
+
error_deleting: "Error al eliminar: {{message}}",
|
|
156
|
+
error_before_delete: "Error antes de eliminar: {{message}}",
|
|
157
157
|
error_updating_asset: "Error al actualizar recurso",
|
|
158
158
|
error_deleting_asset: "Error al eliminar recurso",
|
|
159
159
|
error_firestore_index: "Se requiere un índice de Firestore para esta consulta.",
|
|
@@ -397,6 +397,7 @@ export const es: FireCMSTranslations = {
|
|
|
397
397
|
download: "Descargar",
|
|
398
398
|
large_number_of_documents: "Esta colección posee un gran número de documentos ({{count}}).",
|
|
399
399
|
include_undefined_values: "Incluir valores omitidos (undefined)",
|
|
400
|
+
export_apply_filter_sort: "Exportar solo los resultados que coinciden con el filtro/orden actual",
|
|
400
401
|
submit: "Enviar",
|
|
401
402
|
|
|
402
403
|
no_filterable_properties: "No hay propiedades filtrables disponibles",
|
|
@@ -598,6 +599,10 @@ export const es: FireCMSTranslations = {
|
|
|
598
599
|
order_property_not_found: "La propiedad \"{{property}}\" no existe o no es una propiedad numérica. Selecciona una propiedad válida o borra la selección.",
|
|
599
600
|
no_number_properties: "No se encontraron propiedades numéricas. Agrega una propiedad numérica para habilitar el ordenamiento.",
|
|
600
601
|
order_property_description: "Selecciona una propiedad numérica para mantener el orden de los elementos",
|
|
602
|
+
image_property: "Propiedad de imagen",
|
|
603
|
+
image_property_not_found: "La propiedad \"{{property}}\" no existe o no es una propiedad de imagen. Selecciona una propiedad válida o borra la selección.",
|
|
604
|
+
no_image_properties: "No se encontraron propiedades de imagen. Agrega una propiedad de almacenamiento o URL de imagen para usarla como miniatura.",
|
|
605
|
+
image_property_description: "Selecciona la propiedad usada como miniatura en las vistas de Tarjetas y Kanban. Si no se establece, se usará automáticamente la primera propiedad de imagen que coincida.",
|
|
601
606
|
display_settings: "Configuración de visualización",
|
|
602
607
|
default_row_size: "Tamaño de fila predeterminado",
|
|
603
608
|
side_dialog_width: "Ancho del diálogo lateral",
|
package/src/locales/fr.ts
CHANGED
|
@@ -146,8 +146,8 @@ export const fr: FireCMSTranslations = {
|
|
|
146
146
|
// ─── Error states ─────────────────────────────────────────────
|
|
147
147
|
error: "Erreur",
|
|
148
148
|
error_uploading_file: "Erreur lors du téléchargement du fichier",
|
|
149
|
-
error_deleting: "Erreur lors de la suppression",
|
|
150
|
-
error_before_delete: "Erreur avant la suppression",
|
|
149
|
+
error_deleting: "Erreur lors de la suppression: {{message}}",
|
|
150
|
+
error_before_delete: "Erreur avant la suppression: {{message}}",
|
|
151
151
|
error_updating_asset: "Erreur lors de la mise à jour de l'actif",
|
|
152
152
|
error_deleting_asset: "Erreur lors de la suppression de l'actif",
|
|
153
153
|
error_firestore_index: "Un index Firestore est requis pour cette requête.",
|
|
@@ -389,6 +389,7 @@ export const fr: FireCMSTranslations = {
|
|
|
389
389
|
download: "Télécharger",
|
|
390
390
|
large_number_of_documents: "Cette collection contient un grand nombre de documents ({{count}}).",
|
|
391
391
|
include_undefined_values: "Inclure les valeurs non définies",
|
|
392
|
+
export_apply_filter_sort: "N'exporter que les résultats correspondant au filtre/tri actuel",
|
|
392
393
|
submit: "Soumettre",
|
|
393
394
|
|
|
394
395
|
no_filterable_properties: "Aucune propriété filtrable disponible",
|
|
@@ -586,6 +587,10 @@ export const fr: FireCMSTranslations = {
|
|
|
586
587
|
order_property_not_found: "La propriété \"{{property}}\" n'existe pas ou n'est pas une propriété numérique. Veuillez sélectionner une propriété valide ou effacer la sélection.",
|
|
587
588
|
no_number_properties: "Aucune propriété numérique trouvée. Ajoutez une propriété numérique pour activer le tri.",
|
|
588
589
|
order_property_description: "Sélectionnez une propriété numérique pour conserver l'ordre des éléments",
|
|
590
|
+
image_property: "Propriété d'image",
|
|
591
|
+
image_property_not_found: "La propriété \"{{property}}\" n'existe pas ou n'est pas une propriété d'image. Veuillez sélectionner une propriété valide ou effacer la sélection.",
|
|
592
|
+
no_image_properties: "Aucune propriété d'image trouvée. Ajoutez une propriété de stockage ou d'URL d'image à utiliser comme miniature.",
|
|
593
|
+
image_property_description: "Sélectionnez la propriété utilisée comme miniature dans les vues Cartes et Kanban. Si elle n'est pas définie, la première propriété d'image correspondante sera utilisée automatiquement.",
|
|
589
594
|
display_settings: "Paramètres d'affichage",
|
|
590
595
|
default_row_size: "Taille de ligne par défaut",
|
|
591
596
|
side_dialog_width: "Largeur du dialogue latéral",
|
package/src/locales/hi.ts
CHANGED
|
@@ -146,8 +146,8 @@ export const hi: FireCMSTranslations = {
|
|
|
146
146
|
// ─── Error states ─────────────────────────────────────────────
|
|
147
147
|
error: "त्रुटि",
|
|
148
148
|
error_uploading_file: "फ़ाइल अपलोड करने में त्रुटि",
|
|
149
|
-
error_deleting: "हटाने में
|
|
150
|
-
error_before_delete: "हटाने से पहले
|
|
149
|
+
error_deleting: "हटाने में त्रुटि: {{message}}",
|
|
150
|
+
error_before_delete: "हटाने से पहले त्रुटि: {{message}}",
|
|
151
151
|
error_updating_asset: "एसेट अपडेट करने में त्रुटि",
|
|
152
152
|
error_deleting_asset: "एसेट हटाने में त्रुटि",
|
|
153
153
|
error_firestore_index: "इस क्वेरी के लिए Firestore इंडेक्स आवश्यक है।",
|
|
@@ -389,6 +389,7 @@ export const hi: FireCMSTranslations = {
|
|
|
389
389
|
download: "डाउनलोड",
|
|
390
390
|
large_number_of_documents: "इस संग्रह में बड़ी संख्या में दस्तावेज़ हैं ({{count}})।",
|
|
391
391
|
include_undefined_values: "अपरिभाषित (undefined) मान शामिल करें",
|
|
392
|
+
export_apply_filter_sort: "केवल वर्तमान फ़िल्टर/सॉर्ट से मेल खाने वाले परिणाम निर्यात करें",
|
|
392
393
|
submit: "सबमिट करें",
|
|
393
394
|
|
|
394
395
|
no_filterable_properties: "कोई फ़िल्टर करने योग्य गुण उपलब्ध नहीं हैं",
|
|
@@ -586,6 +587,10 @@ export const hi: FireCMSTranslations = {
|
|
|
586
587
|
order_property_not_found: "प्रॉपर्टी \"{{property}}\" मौजूद नहीं है या एक संख्या प्रॉपर्टी नहीं है। कृपया एक वैध प्रॉपर्टी चुनें या चयन साफ़ करें।",
|
|
587
588
|
no_number_properties: "कोई संख्या प्रॉपर्टी नहीं मिली। क्रम सक्षम करने के लिए एक संख्या प्रॉपर्टी जोड़ें।",
|
|
588
589
|
order_property_description: "आइटम का क्रम बनाए रखने के लिए एक संख्या प्रॉपर्टी चुनें",
|
|
590
|
+
image_property: "इमेज प्रॉपर्टी",
|
|
591
|
+
image_property_not_found: "प्रॉपर्टी \"{{property}}\" मौजूद नहीं है या एक इमेज प्रॉपर्टी नहीं है। कृपया एक वैध प्रॉपर्टी चुनें या चयन साफ़ करें।",
|
|
592
|
+
no_image_properties: "कोई इमेज प्रॉपर्टी नहीं मिली। थंबनेल के रूप में उपयोग करने के लिए एक स्टोरेज या URL इमेज प्रॉपर्टी जोड़ें।",
|
|
593
|
+
image_property_description: "कार्ड्स और कानबन व्यू मोड में थंबनेल इमेज के रूप में उपयोग की जाने वाली प्रॉपर्टी चुनें। यदि सेट नहीं किया गया है, तो पहली मिलान वाली इमेज प्रॉपर्टी स्वचालित रूप से उपयोग की जाएगी।",
|
|
589
594
|
display_settings: "प्रदर्शन सेटिंग्स",
|
|
590
595
|
default_row_size: "डिफ़ॉल्ट पंक्ति आकार",
|
|
591
596
|
side_dialog_width: "साइड डायलॉग चौड़ाई",
|
package/src/locales/it.ts
CHANGED
|
@@ -146,8 +146,8 @@ export const it: FireCMSTranslations = {
|
|
|
146
146
|
// ─── Error states ─────────────────────────────────────────────
|
|
147
147
|
error: "Errore",
|
|
148
148
|
error_uploading_file: "Errore durante il caricamento del file",
|
|
149
|
-
error_deleting: "Errore durante l'eliminazione",
|
|
150
|
-
error_before_delete: "Errore prima dell'eliminazione",
|
|
149
|
+
error_deleting: "Errore durante l'eliminazione: {{message}}",
|
|
150
|
+
error_before_delete: "Errore prima dell'eliminazione: {{message}}",
|
|
151
151
|
error_updating_asset: "Errore durante l'aggiornamento dell'asset",
|
|
152
152
|
error_deleting_asset: "Errore durante l'eliminazione dell'asset",
|
|
153
153
|
error_firestore_index: "Per questa query è richiesto un indice Firestore.",
|
|
@@ -389,6 +389,7 @@ export const it: FireCMSTranslations = {
|
|
|
389
389
|
download: "Scarica",
|
|
390
390
|
large_number_of_documents: "Questa collezione contiene un numero elevato di documenti ({{count}})",
|
|
391
391
|
include_undefined_values: "Includi valori non definiti",
|
|
392
|
+
export_apply_filter_sort: "Esporta solo i risultati che corrispondono al filtro/ordinamento attuale",
|
|
392
393
|
submit: "Invia",
|
|
393
394
|
|
|
394
395
|
no_filterable_properties: "Nessuna proprietà filtrabile disponibile",
|
|
@@ -586,6 +587,10 @@ export const it: FireCMSTranslations = {
|
|
|
586
587
|
order_property_not_found: "La proprietà \"{{property}}\" non esiste o non è una proprietà numerica. Seleziona una proprietà valida o cancella la selezione.",
|
|
587
588
|
no_number_properties: "Nessuna proprietà numerica trovata. Aggiungi una proprietà numerica per abilitare l'ordinamento.",
|
|
588
589
|
order_property_description: "Seleziona una proprietà numerica per mantenere l'ordine degli elementi",
|
|
590
|
+
image_property: "Proprietà immagine",
|
|
591
|
+
image_property_not_found: "La proprietà \"{{property}}\" non esiste o non è una proprietà immagine. Seleziona una proprietà valida o cancella la selezione.",
|
|
592
|
+
no_image_properties: "Nessuna proprietà immagine trovata. Aggiungi una proprietà di archiviazione o URL immagine da usare come miniatura.",
|
|
593
|
+
image_property_description: "Seleziona la proprietà utilizzata come miniatura nelle viste Schede e Kanban. Se non impostata, verrà utilizzata automaticamente la prima proprietà immagine corrispondente.",
|
|
589
594
|
display_settings: "Impostazioni di visualizzazione",
|
|
590
595
|
default_row_size: "Dimensione riga predefinita",
|
|
591
596
|
side_dialog_width: "Larghezza del dialogo laterale",
|