@firecms/core 3.0.0-canary.231 → 3.0.0-canary.233
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/index.es.js +59 -41
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +59 -41
- package/dist/index.umd.js.map +1 -1
- package/dist/types/collections.d.ts +1 -1
- package/package.json +5 -5
- package/src/components/ClearFilterSortButton.tsx +1 -1
- package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +1 -1
- package/src/form/field_bindings/KeyValueFieldBinding.tsx +2 -0
- package/src/preview/property_previews/MapPropertyPreview.tsx +1 -1
- package/src/types/collections.ts +1 -1
- package/src/util/navigation_utils.ts +70 -55
|
@@ -97,7 +97,7 @@ export interface EntityCollection<M extends Record<string, any> = any, USER exte
|
|
|
97
97
|
* `hidden` in the property definition, will be ignored.
|
|
98
98
|
* `propertiesOrder` has precedence over `hidden`.
|
|
99
99
|
* - For properties use the property key.
|
|
100
|
-
* - For additional
|
|
100
|
+
* - For additional fields use the field key.
|
|
101
101
|
* - If you have subcollections, you get a column for each subcollection,
|
|
102
102
|
* with the path (or alias) as the subcollection, prefixed with
|
|
103
103
|
* `subcollection:`. e.g. `subcollection:orders`.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@firecms/core",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "3.0.0-canary.
|
|
4
|
+
"version": "3.0.0-canary.233",
|
|
5
5
|
"description": "Awesome Firebase/Firestore-based headless open-source CMS",
|
|
6
6
|
"funding": {
|
|
7
7
|
"url": "https://github.com/sponsors/firecmsco"
|
|
@@ -50,9 +50,9 @@
|
|
|
50
50
|
"./package.json": "./package.json"
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@firecms/editor": "^3.0.0-canary.
|
|
54
|
-
"@firecms/formex": "^3.0.0-canary.
|
|
55
|
-
"@firecms/ui": "^3.0.0-canary.
|
|
53
|
+
"@firecms/editor": "^3.0.0-canary.233",
|
|
54
|
+
"@firecms/formex": "^3.0.0-canary.233",
|
|
55
|
+
"@firecms/ui": "^3.0.0-canary.233",
|
|
56
56
|
"@hello-pangea/dnd": "^17.0.0",
|
|
57
57
|
"@radix-ui/react-portal": "^1.1.3",
|
|
58
58
|
"clsx": "^2.1.1",
|
|
@@ -105,7 +105,7 @@
|
|
|
105
105
|
"dist",
|
|
106
106
|
"src"
|
|
107
107
|
],
|
|
108
|
-
"gitHead": "
|
|
108
|
+
"gitHead": "783647d996fe38fe8f0b162acc482a6008152e30",
|
|
109
109
|
"publishConfig": {
|
|
110
110
|
"access": "public"
|
|
111
111
|
},
|
|
@@ -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 {
|
|
@@ -288,7 +288,7 @@ export function PopupFormFieldInternal<M extends Record<string, any>>({
|
|
|
288
288
|
underlyingValueHasChanged: false,
|
|
289
289
|
context: formContext,
|
|
290
290
|
partOfArray: false,
|
|
291
|
-
minimalistView:
|
|
291
|
+
minimalistView: true,
|
|
292
292
|
autoFocus: open
|
|
293
293
|
}
|
|
294
294
|
: undefined;
|
|
@@ -128,7 +128,7 @@ export function KeyValuePreview({ value }: { value: any }) {
|
|
|
128
128
|
</div>
|
|
129
129
|
<div
|
|
130
130
|
className="flex-grow max-w-[75%]">
|
|
131
|
-
{childValue && <Typography>
|
|
131
|
+
{childValue && typeof childValue !== "object" && <Typography>
|
|
132
132
|
<ErrorBoundary>
|
|
133
133
|
{childValue.toString()}
|
|
134
134
|
</ErrorBoundary>
|
package/src/types/collections.ts
CHANGED
|
@@ -112,7 +112,7 @@ export interface EntityCollection<M extends Record<string, any> = any, USER exte
|
|
|
112
112
|
* `hidden` in the property definition, will be ignored.
|
|
113
113
|
* `propertiesOrder` has precedence over `hidden`.
|
|
114
114
|
* - For properties use the property key.
|
|
115
|
-
* - For additional
|
|
115
|
+
* - For additional fields use the field key.
|
|
116
116
|
* - If you have subcollections, you get a column for each subcollection,
|
|
117
117
|
* with the path (or alias) as the subcollection, prefixed with
|
|
118
118
|
* `subcollection:`. e.g. `subcollection:orders`.
|
|
@@ -32,75 +32,90 @@ export function getLastSegment(path: string) {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
export function resolveCollectionPathIds(path: string, allCollections: EntityCollection[]): string {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if (subpaths.length % 2 === 0) {
|
|
39
|
-
throw Error(`resolveCollectionPathIds: Collection paths must have an odd number of segments: ${path}`);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Check if the path exactly matches a collection path
|
|
43
|
-
const exactMatch = allCollections.find(col => col.path === cleanPath);
|
|
44
|
-
if (exactMatch) {
|
|
45
|
-
return exactMatch.path;
|
|
35
|
+
let remainingPath = removeInitialAndTrailingSlashes(path);
|
|
36
|
+
if (!remainingPath) {
|
|
37
|
+
return "";
|
|
46
38
|
}
|
|
47
39
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const aliasedCollection = allCollections.find((col) => col.id === subpaths[0]);
|
|
51
|
-
return aliasedCollection?.path ?? subpaths[0];
|
|
52
|
-
}
|
|
40
|
+
let currentCollections: EntityCollection[] | undefined = allCollections;
|
|
41
|
+
const resolvedPathParts: string[] = [];
|
|
53
42
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const pathSegments = collection.path.split("/");
|
|
61
|
-
if (pathSegments.length > 1 &&
|
|
62
|
-
subpaths.slice(0, pathSegments.length).join("/") === collection.path) {
|
|
63
|
-
matchingCollection = collection;
|
|
64
|
-
entityIndex = pathSegments.length;
|
|
43
|
+
while (remainingPath.length > 0) {
|
|
44
|
+
if (!currentCollections || currentCollections.length === 0) {
|
|
45
|
+
// We have remaining path segments but no more collections to match against
|
|
46
|
+
console.warn(`resolveCollectionPathIds: Path structure implies subcollections, but none found before segment starting with "${remainingPath}" in original path "${path}". Appending remaining original path.`);
|
|
47
|
+
resolvedPathParts.push(remainingPath);
|
|
48
|
+
remainingPath = ""; // Stop processing
|
|
65
49
|
break;
|
|
66
50
|
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// If no multi-segment match, fall back to single segment matching
|
|
70
|
-
if (!matchingCollection) {
|
|
71
|
-
const matchingCollections = allCollections.filter(col =>
|
|
72
|
-
col.id === subpaths[0] || col.path === subpaths[0]
|
|
73
|
-
);
|
|
74
51
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
52
|
+
let foundMatch = false;
|
|
53
|
+
// Sort potential matches by length descending to prioritize longer matches (e.g., "a/b" over "a")
|
|
54
|
+
const potentialMatches: { col: EntityCollection; match: string; }[] = currentCollections
|
|
55
|
+
.flatMap(col => [{
|
|
56
|
+
col,
|
|
57
|
+
match: col.path
|
|
58
|
+
}, {
|
|
59
|
+
col,
|
|
60
|
+
match: col.id
|
|
61
|
+
}])
|
|
62
|
+
.filter(p => p.match && remainingPath.startsWith(p.match))
|
|
63
|
+
.sort((a, b) => b.match.length - a.match.length);
|
|
64
|
+
|
|
65
|
+
if (potentialMatches.length > 0) {
|
|
66
|
+
const {
|
|
67
|
+
col: foundCollection,
|
|
68
|
+
match: matchString
|
|
69
|
+
} = potentialMatches[0];
|
|
70
|
+
|
|
71
|
+
resolvedPathParts.push(foundCollection.path); // Use the defined path
|
|
72
|
+
remainingPath = removeInitialSlash(remainingPath.substring(matchString.length));
|
|
73
|
+
|
|
74
|
+
// Check if we are at the end of the path
|
|
75
|
+
if (remainingPath.length === 0) {
|
|
76
|
+
foundMatch = true;
|
|
77
|
+
break; // Path ends with a collection segment
|
|
78
|
+
}
|
|
78
79
|
|
|
79
|
-
|
|
80
|
-
|
|
80
|
+
// The next segment must be an entity ID
|
|
81
|
+
const idSeparatorIndex = remainingPath.indexOf("/");
|
|
82
|
+
let entityId: string;
|
|
83
|
+
if (idSeparatorIndex > -1) {
|
|
84
|
+
entityId = remainingPath.substring(0, idSeparatorIndex);
|
|
85
|
+
remainingPath = remainingPath.substring(idSeparatorIndex + 1);
|
|
86
|
+
} else {
|
|
87
|
+
// This should not happen if the original path is valid (odd segments)
|
|
88
|
+
// but handle it defensively: assume the rest is the ID
|
|
89
|
+
entityId = remainingPath;
|
|
90
|
+
remainingPath = "";
|
|
91
|
+
console.warn(`resolveCollectionPathIds: Path seems to end with an entity ID "${entityId}" instead of a collection segment in original path "${path}". This might indicate an invalid input path.`);
|
|
92
|
+
// Even if it ends here, we still need to push the ID
|
|
93
|
+
}
|
|
81
94
|
|
|
82
|
-
|
|
83
|
-
|
|
95
|
+
resolvedPathParts.push(entityId); // Append entity ID
|
|
96
|
+
currentCollections = foundCollection.subcollections; // Move to subcollections
|
|
97
|
+
foundMatch = true;
|
|
84
98
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
99
|
+
if (!currentCollections && remainingPath.length > 0) {
|
|
100
|
+
// Warn if the path continues but no subcollections were defined
|
|
101
|
+
console.warn(`resolveCollectionPathIds: Path continues after entity ID "${entityId}", but no subcollections are defined for the preceding collection "${foundCollection.path}" in path "${path}". Appending remaining original path.`);
|
|
102
|
+
resolvedPathParts.push(remainingPath); // Append the rest
|
|
103
|
+
remainingPath = ""; // Stop processing
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
91
106
|
|
|
92
|
-
if (subcollection) {
|
|
93
|
-
return `${matchingCollection.path}/${entityId}/${subcollection.path}`;
|
|
94
107
|
}
|
|
95
|
-
}
|
|
96
108
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
109
|
+
if (!foundMatch) {
|
|
110
|
+
// Collection definition not found for the start of the remaining path
|
|
111
|
+
console.warn(`resolveCollectionPathIds: Collection definition not found for segment starting with "${remainingPath}" in original path "${path}". Appending remaining original path.`);
|
|
112
|
+
resolvedPathParts.push(remainingPath); // Append the rest
|
|
113
|
+
remainingPath = ""; // Stop processing
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
100
116
|
}
|
|
101
117
|
|
|
102
|
-
|
|
103
|
-
return `${matchingCollection.path}/${entityId}/${remainingPath.join("/")}`;
|
|
118
|
+
return resolvedPathParts.join("/");
|
|
104
119
|
}
|
|
105
120
|
|
|
106
121
|
/**
|