@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.
@@ -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 columns use the column id.
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.231",
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.231",
54
- "@firecms/formex": "^3.0.0-canary.231",
55
- "@firecms/ui": "^3.0.0-canary.231",
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": "c38a44b87565537d51e654a0565b0921c933c55e",
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 and sort";
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: false,
291
+ minimalistView: true,
292
292
  autoFocus: open
293
293
  }
294
294
  : undefined;
@@ -69,6 +69,8 @@ export function KeyValueFieldBinding({
69
69
  title={property.name}
70
70
  className={"text-text-secondary dark:text-text-secondary-dark"}/>;
71
71
 
72
+
73
+ console.log("minimalistView", propertyKey, minimalistView)
72
74
  return (
73
75
  <>
74
76
 
@@ -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>
@@ -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 columns use the column id.
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
- const cleanPath = removeInitialAndTrailingSlashes(path);
36
- const subpaths = cleanPath.split("/");
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
- if (subpaths.length === 1) {
49
- // Find collection by ID and return its path
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
- // Try to match a multi-segment collection path
55
- let matchingCollection: EntityCollection | undefined;
56
- let entityIndex = 1;
57
-
58
- // Check if the path starts with a multi-segment collection path
59
- for (const collection of allCollections) {
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
- if (!matchingCollections.length) {
76
- return cleanPath;
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
- matchingCollection = matchingCollections[0];
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
- const entityId = subpaths[entityIndex];
83
- const remainingPath = subpaths.slice(entityIndex + 1);
95
+ resolvedPathParts.push(entityId); // Append entity ID
96
+ currentCollections = foundCollection.subcollections; // Move to subcollections
97
+ foundMatch = true;
84
98
 
85
- // If we have a subcollection ID, try to resolve it
86
- if (remainingPath.length > 0) {
87
- const subcollectionId = remainingPath[0];
88
- const subcollection = matchingCollection.subcollections?.find(
89
- subcol => subcol.id === subcollectionId
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
- // If there are no remaining path segments, just return the collection path with entity ID
98
- if (remainingPath.length === 0) {
99
- return `${matchingCollection.path}/${entityId}`;
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
- // Default case - couldn't match subcollection
103
- return `${matchingCollection.path}/${entityId}/${remainingPath.join("/")}`;
118
+ return resolvedPathParts.join("/");
104
119
  }
105
120
 
106
121
  /**