@firecms/core 3.3.0-canary.d3242eb → 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 +2960 -1338
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +2958 -1336
- 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 +17 -3
- 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 +47 -45
- 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 +24 -3
- 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/HomePage/NavigationCardBinding.tsx +6 -3
- 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 +151 -65
- 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/useBuildNavigationController.tsx +5 -1
- 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 +18 -5
- package/src/locales/en.ts +18 -5
- package/src/locales/es.ts +18 -5
- package/src/locales/fr.ts +18 -5
- package/src/locales/hi.ts +18 -5
- package/src/locales/it.ts +18 -5
- package/src/locales/pl.ts +735 -0
- package/src/locales/pt.ts +18 -5
- 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 +17 -3
- 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 +11 -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
|
|
@@ -414,7 +414,11 @@ export function useBuildNavigationController<EC extends EntityCollection, USER e
|
|
|
414
414
|
const baseCollection = getCollectionByPathOrId(removeInitialAndTrailingSlashes(idOrPath), collections);
|
|
415
415
|
|
|
416
416
|
const userOverride = includeUserOverride ? userConfigPersistence?.getCollectionConfig(idOrPath) : undefined;
|
|
417
|
-
|
|
417
|
+
let overriddenCollection = baseCollection;
|
|
418
|
+
if (baseCollection && userOverride) {
|
|
419
|
+
const { properties, ...rest } = userOverride;
|
|
420
|
+
overriddenCollection = mergeDeep(baseCollection, rest);
|
|
421
|
+
}
|
|
418
422
|
|
|
419
423
|
let result: Partial<EntityCollection> | undefined = overriddenCollection;
|
|
420
424
|
|
|
@@ -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",
|
|
@@ -437,8 +438,8 @@ export const de: FireCMSTranslations = {
|
|
|
437
438
|
cms_users: "CMS-Benutzer",
|
|
438
439
|
roles_menu: "Rollen",
|
|
439
440
|
project_settings: "Projekteinstellungen",
|
|
440
|
-
|
|
441
|
-
|
|
441
|
+
firestore_manager: "Firestore-Manager",
|
|
442
|
+
manage_your_firestore_data: "Deine Firestore-Daten verwalten",
|
|
442
443
|
|
|
443
444
|
// ─── FireCMS Cloud Login ──────────────────────────────────────
|
|
444
445
|
build_admin_panel_in_minutes: "Erstellen Sie Ihr Firebase Admin Panel in wenigen Minuten",
|
|
@@ -514,10 +515,18 @@ export const de: FireCMSTranslations = {
|
|
|
514
515
|
auto_setup_collections_button: "Sammlungen automatisch einrichten",
|
|
515
516
|
auto_setup_collections_title: "Sammlungen automatisch einrichten?",
|
|
516
517
|
auto_setup_collections_desc: "Dadurch werden automatisch Sammlungskonfigurationen für Sammlungen erstellt, die noch <b>NICHT</b> zugeordnet sind.",
|
|
517
|
-
|
|
518
|
+
setting_up_collections: "Sammlungen werden eingerichtet",
|
|
519
|
+
setting_up_collection: "{{name}} wird eingerichtet",
|
|
518
520
|
no_collections_found_to_setup: "Keine einzurichtenden Sammlungen gefunden",
|
|
519
521
|
collections_have_been_setup: "Sammlungen wurden automatisch eingerichtet",
|
|
520
522
|
error_setting_up_collections: "Fehler beim automatischen Einrichten der Sammlungen",
|
|
523
|
+
setup_collections_title: "Set up collections",
|
|
524
|
+
setup_collections_select_desc: "Select which collections to automatically set up:",
|
|
525
|
+
select_all: "Select all",
|
|
526
|
+
deselect_all: "Deselect all",
|
|
527
|
+
setup_collections_confirm: "Set up ({{count}})",
|
|
528
|
+
collection_setup_success: "{{name}} has been set up",
|
|
529
|
+
go_to_collection: "Go to collection",
|
|
521
530
|
add_your: "Fügen Sie Ihre",
|
|
522
531
|
database_collections: "Datenbanksammlungen",
|
|
523
532
|
to_firecms: "zu FireCMS hinzu",
|
|
@@ -578,6 +587,10 @@ export const de: FireCMSTranslations = {
|
|
|
578
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.",
|
|
579
588
|
no_number_properties: "Keine Zahlen-Eigenschaften gefunden. Fügen Sie eine Zahlen-Eigenschaft hinzu, um die Sortierung zu aktivieren.",
|
|
580
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.",
|
|
581
594
|
display_settings: "Anzeigeeinstellungen",
|
|
582
595
|
default_row_size: "Standard-Zeilengröße",
|
|
583
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",
|
|
@@ -445,8 +446,8 @@ export const en: FireCMSTranslations = {
|
|
|
445
446
|
cms_users: "CMS Users",
|
|
446
447
|
roles_menu: "Roles",
|
|
447
448
|
project_settings: "Project settings",
|
|
448
|
-
|
|
449
|
-
|
|
449
|
+
firestore_manager: "Firestore Manager",
|
|
450
|
+
manage_your_firestore_data: "Manage your Firestore data",
|
|
450
451
|
|
|
451
452
|
// ─── FireCMS Cloud Login ──────────────────────────────────────
|
|
452
453
|
build_admin_panel_in_minutes: "Build Your Firebase Admin Panel in Minutes",
|
|
@@ -522,10 +523,18 @@ export const en: FireCMSTranslations = {
|
|
|
522
523
|
auto_setup_collections_button: "Automatically set up collections",
|
|
523
524
|
auto_setup_collections_title: "Automatically set up collections?",
|
|
524
525
|
auto_setup_collections_desc: "This will automatically create collection configs for collections that are <b>NOT</b> already mapped",
|
|
525
|
-
|
|
526
|
+
setting_up_collections: "Setting up collections",
|
|
527
|
+
setting_up_collection: "Setting up {{name}}",
|
|
526
528
|
no_collections_found_to_setup: "No collections found to setup.",
|
|
527
529
|
collections_have_been_setup: "Collections have been automatically setup.",
|
|
528
530
|
error_setting_up_collections: "Error automatically setting up collections",
|
|
531
|
+
setup_collections_title: "Set up collections",
|
|
532
|
+
setup_collections_select_desc: "Select which collections to automatically set up:",
|
|
533
|
+
select_all: "Select all",
|
|
534
|
+
deselect_all: "Deselect all",
|
|
535
|
+
setup_collections_confirm: "Set up ({{count}})",
|
|
536
|
+
collection_setup_success: "{{name}} has been set up",
|
|
537
|
+
go_to_collection: "Go to collection",
|
|
529
538
|
|
|
530
539
|
// --- Home Suggestions ---
|
|
531
540
|
add_your: "Add your",
|
|
@@ -590,6 +599,10 @@ export const en: FireCMSTranslations = {
|
|
|
590
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.",
|
|
591
600
|
no_number_properties: "No number properties found. Add a number property to enable ordering.",
|
|
592
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.",
|
|
593
606
|
display_settings: "Display settings",
|
|
594
607
|
default_row_size: "Default row size",
|
|
595
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",
|
|
@@ -445,8 +446,8 @@ export const es: FireCMSTranslations = {
|
|
|
445
446
|
cms_users: "Usuarios del CMS",
|
|
446
447
|
roles_menu: "Roles",
|
|
447
448
|
project_settings: "Ajustes del proyecto",
|
|
448
|
-
|
|
449
|
-
|
|
449
|
+
firestore_manager: "Gestor de Firestore",
|
|
450
|
+
manage_your_firestore_data: "Gestiona tus datos de Firestore",
|
|
450
451
|
|
|
451
452
|
// ─── FireCMS Cloud Login ──────────────────────────────────────
|
|
452
453
|
build_admin_panel_in_minutes: "Crea tu panel de administración de Firebase en minutos",
|
|
@@ -522,10 +523,18 @@ export const es: FireCMSTranslations = {
|
|
|
522
523
|
auto_setup_collections_button: "Configurar colecciones automáticamente",
|
|
523
524
|
auto_setup_collections_title: "¿Configurar colecciones automáticamente?",
|
|
524
525
|
auto_setup_collections_desc: "Esto creará automáticamente la configuración de las colecciones que <b>NO</b> estén mapeadas",
|
|
525
|
-
|
|
526
|
+
setting_up_collections: "Configurando colecciones",
|
|
527
|
+
setting_up_collection: "Configurando {{name}}",
|
|
526
528
|
no_collections_found_to_setup: "No se encontraron colecciones para configurar",
|
|
527
529
|
collections_have_been_setup: "¡Tus colecciones han sido configuradas!",
|
|
528
530
|
error_setting_up_collections: "Error al configurar colecciones",
|
|
531
|
+
setup_collections_title: "Set up collections",
|
|
532
|
+
setup_collections_select_desc: "Select which collections to automatically set up:",
|
|
533
|
+
select_all: "Select all",
|
|
534
|
+
deselect_all: "Deselect all",
|
|
535
|
+
setup_collections_confirm: "Set up ({{count}})",
|
|
536
|
+
collection_setup_success: "{{name}} has been set up",
|
|
537
|
+
go_to_collection: "Go to collection",
|
|
529
538
|
|
|
530
539
|
// --- Home Suggestions ---
|
|
531
540
|
add_your: "Añade tus",
|
|
@@ -590,6 +599,10 @@ export const es: FireCMSTranslations = {
|
|
|
590
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.",
|
|
591
600
|
no_number_properties: "No se encontraron propiedades numéricas. Agrega una propiedad numérica para habilitar el ordenamiento.",
|
|
592
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.",
|
|
593
606
|
display_settings: "Configuración de visualización",
|
|
594
607
|
default_row_size: "Tamaño de fila predeterminado",
|
|
595
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",
|
|
@@ -437,8 +438,8 @@ export const fr: FireCMSTranslations = {
|
|
|
437
438
|
cms_users: "Utilisateurs du CMS",
|
|
438
439
|
roles_menu: "Rôles",
|
|
439
440
|
project_settings: "Paramètres du projet",
|
|
440
|
-
|
|
441
|
-
|
|
441
|
+
firestore_manager: "Gestionnaire Firestore",
|
|
442
|
+
manage_your_firestore_data: "Gérez vos données Firestore",
|
|
442
443
|
|
|
443
444
|
// ─── FireCMS Cloud Login ──────────────────────────────────────
|
|
444
445
|
build_admin_panel_in_minutes: "Créez votre panneau d'administration Firebase en quelques minutes",
|
|
@@ -514,10 +515,18 @@ export const fr: FireCMSTranslations = {
|
|
|
514
515
|
auto_setup_collections_button: "Configurer les collections automatiquement",
|
|
515
516
|
auto_setup_collections_title: "Configurer les collections automatiquement ?",
|
|
516
517
|
auto_setup_collections_desc: "Cela créera automatiquement des configurations de collection pour les collections qui ne sont <b>PAS</b> déjà mappées",
|
|
517
|
-
|
|
518
|
+
setting_up_collections: "Configuration des collections",
|
|
519
|
+
setting_up_collection: "Configuration de {{name}}",
|
|
518
520
|
no_collections_found_to_setup: "Aucune collection à configurer trouvée",
|
|
519
521
|
collections_have_been_setup: "Les collections ont été configurées",
|
|
520
522
|
error_setting_up_collections: "Erreur lors de la configuration des collections",
|
|
523
|
+
setup_collections_title: "Set up collections",
|
|
524
|
+
setup_collections_select_desc: "Select which collections to automatically set up:",
|
|
525
|
+
select_all: "Select all",
|
|
526
|
+
deselect_all: "Deselect all",
|
|
527
|
+
setup_collections_confirm: "Set up ({{count}})",
|
|
528
|
+
collection_setup_success: "{{name}} has been set up",
|
|
529
|
+
go_to_collection: "Go to collection",
|
|
521
530
|
add_your: "Ajoutez vos",
|
|
522
531
|
database_collections: "collections de base de données",
|
|
523
532
|
to_firecms: "à FireCMS",
|
|
@@ -578,6 +587,10 @@ export const fr: FireCMSTranslations = {
|
|
|
578
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.",
|
|
579
588
|
no_number_properties: "Aucune propriété numérique trouvée. Ajoutez une propriété numérique pour activer le tri.",
|
|
580
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.",
|
|
581
594
|
display_settings: "Paramètres d'affichage",
|
|
582
595
|
default_row_size: "Taille de ligne par défaut",
|
|
583
596
|
side_dialog_width: "Largeur du dialogue latéral",
|