@firecms/core 3.0.0-canary.224 → 3.0.0-canary.226
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 +68 -18
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +68 -18
- package/dist/index.umd.js.map +1 -1
- package/package.json +5 -5
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +6 -2
- package/src/components/VirtualTable/VirtualTable.tsx +29 -1
- package/src/core/EntityEditView.tsx +3 -3
- package/src/util/navigation_utils.ts +59 -14
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.226",
|
|
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.226",
|
|
54
|
+
"@firecms/formex": "^3.0.0-canary.226",
|
|
55
|
+
"@firecms/ui": "^3.0.0-canary.226",
|
|
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": "186d2820e1dd7b69916647c3f887ff275351e863",
|
|
109
109
|
"publishConfig": {
|
|
110
110
|
"access": "public"
|
|
111
111
|
},
|
|
@@ -147,9 +147,13 @@ export const EntityCollectionView = React.memo(
|
|
|
147
147
|
) {
|
|
148
148
|
|
|
149
149
|
const context = useFireCMSContext();
|
|
150
|
-
const fullPath = fullPathProp ?? collectionProp.path;
|
|
151
|
-
const dataSource = useDataSource(collectionProp);
|
|
152
150
|
const navigation = useNavigationController();
|
|
151
|
+
const fullPath = (fullPathProp ? navigation.resolveIdsFrom(fullPathProp) : undefined) ?? collectionProp.path;
|
|
152
|
+
console.log("aaa", {
|
|
153
|
+
fullPathProp,
|
|
154
|
+
fullPath,
|
|
155
|
+
})
|
|
156
|
+
const dataSource = useDataSource(collectionProp);
|
|
153
157
|
const sideEntityController = useSideEntityController();
|
|
154
158
|
const authController = useAuthController();
|
|
155
159
|
const userConfigPersistence = useUserConfigurationPersistence();
|
|
@@ -139,7 +139,35 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
|
|
|
139
139
|
setColumns(columnsProp);
|
|
140
140
|
}, [columnsProp]);
|
|
141
141
|
|
|
142
|
-
const [
|
|
142
|
+
const [_, setForceUpdate] = useState(false);
|
|
143
|
+
useEffect(() => {
|
|
144
|
+
// Create a ResizeObserver to detect size changes more aggressively
|
|
145
|
+
if (tableRef.current) {
|
|
146
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
147
|
+
// Force a re-render when size changes
|
|
148
|
+
setForceUpdate(prev => !prev);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
resizeObserver.observe(tableRef.current);
|
|
152
|
+
|
|
153
|
+
return () => {
|
|
154
|
+
if (tableRef.current) {
|
|
155
|
+
resizeObserver.unobserve(tableRef.current);
|
|
156
|
+
}
|
|
157
|
+
resizeObserver.disconnect();
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
return () => {
|
|
161
|
+
}
|
|
162
|
+
}, [tableRef]);
|
|
163
|
+
|
|
164
|
+
const [measureRef, bounds] = useMeasure({
|
|
165
|
+
debounce: 50,
|
|
166
|
+
polyfill: ResizeObserver,
|
|
167
|
+
scroll: true,
|
|
168
|
+
// This is important for handling zooming in react-flow
|
|
169
|
+
offsetSize: true
|
|
170
|
+
});
|
|
143
171
|
|
|
144
172
|
const onColumnResizeInternal = useCallback((params: OnVirtualTableColumnResizeParams) => {
|
|
145
173
|
if (debug)
|
|
@@ -315,7 +315,7 @@ export function EntityEditViewInner<M extends Record<string, any>>({
|
|
|
315
315
|
}
|
|
316
316
|
};
|
|
317
317
|
|
|
318
|
-
const entityReadOnlyView = <div
|
|
318
|
+
const entityReadOnlyView = !canEdit && entity ? <div
|
|
319
319
|
className={cls("flex-1 flex flex-row w-full overflow-y-auto justify-center", (canEdit || !mainViewVisible || selectedSecondaryForm) ? "hidden" : "")}>
|
|
320
320
|
<div
|
|
321
321
|
className={cls("relative flex flex-col max-w-4xl lg:max-w-3xl xl:max-w-4xl 2xl:max-w-6xl w-full h-fit")}>
|
|
@@ -324,11 +324,11 @@ export function EntityEditViewInner<M extends Record<string, any>>({
|
|
|
324
324
|
</Typography>
|
|
325
325
|
<EntityView
|
|
326
326
|
className={"px-8 h-full overflow-auto"}
|
|
327
|
-
entity={entity
|
|
327
|
+
entity={entity}
|
|
328
328
|
path={path}
|
|
329
329
|
collection={collection}/>
|
|
330
330
|
</div>
|
|
331
|
-
</div
|
|
331
|
+
</div> : null;
|
|
332
332
|
|
|
333
333
|
const entityView = <EntityForm<M>
|
|
334
334
|
collection={collection}
|
|
@@ -32,31 +32,76 @@ export function getLastSegment(path: string) {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
export function resolveCollectionPathIds(path: string, allCollections: EntityCollection[]): string {
|
|
35
|
-
|
|
36
35
|
const cleanPath = removeInitialAndTrailingSlashes(path);
|
|
37
36
|
const subpaths = cleanPath.split("/");
|
|
37
|
+
|
|
38
38
|
if (subpaths.length % 2 === 0) {
|
|
39
|
-
throw Error(`
|
|
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;
|
|
46
|
+
}
|
|
47
|
+
|
|
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];
|
|
40
52
|
}
|
|
41
53
|
|
|
42
|
-
|
|
43
|
-
let
|
|
44
|
-
|
|
45
|
-
|
|
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;
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
46
67
|
}
|
|
47
68
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
+
|
|
75
|
+
if (!matchingCollections.length) {
|
|
51
76
|
return cleanPath;
|
|
52
77
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
} else {
|
|
56
|
-
return resolvedAliased ?? cleanPath;
|
|
78
|
+
|
|
79
|
+
matchingCollection = matchingCollections[0];
|
|
57
80
|
}
|
|
58
|
-
}
|
|
59
81
|
|
|
82
|
+
const entityId = subpaths[entityIndex];
|
|
83
|
+
const remainingPath = subpaths.slice(entityIndex + 1);
|
|
84
|
+
|
|
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
|
+
);
|
|
91
|
+
|
|
92
|
+
if (subcollection) {
|
|
93
|
+
return `${matchingCollection.path}/${entityId}/${subcollection.path}`;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
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}`;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Default case - couldn't match subcollection
|
|
103
|
+
return `${matchingCollection.path}/${entityId}/${remainingPath.join("/")}`;
|
|
104
|
+
}
|
|
60
105
|
/**
|
|
61
106
|
* Find the corresponding view at any depth for a given path.
|
|
62
107
|
* Note that path or segments of the paths can be collection aliases.
|