@nitrogenbuilder/connector-payload 1.0.0 → 1.1.1
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/collections/NitrogenComponentUsage.js +3 -21
- package/dist/components/NitrogenComponentInventoryClient.js +1 -1
- package/dist/editor/NitrogenEditorAssetsRoute.js +2 -0
- package/dist/editor/NitrogenEditorPage.js +29 -2
- package/dist/editor-assets/fa620pro/icons.json +1 -0
- package/dist/editor-assets/icons/ionicons.json +1 -0
- package/dist/editor-assets/icons/lucide.json +1 -0
- package/dist/inventory/indexing.d.ts +0 -5
- package/dist/inventory/indexing.js +130 -74
- package/dist/types.d.ts +0 -5
- package/package.json +2 -2
|
@@ -6,12 +6,7 @@ export declare const NITROGEN_COMPONENT_CATALOG_COLLECTION = "nitrogen-component
|
|
|
6
6
|
export declare const NITROGEN_COMPONENT_USAGE_COLLECTION = "nitrogen-component-usage";
|
|
7
7
|
type ComponentUsageRecord = {
|
|
8
8
|
componentName: string;
|
|
9
|
-
depth: number;
|
|
10
9
|
moduleId: string;
|
|
11
|
-
modulePath: string;
|
|
12
|
-
parentComponentName?: string;
|
|
13
|
-
parentModuleId?: string;
|
|
14
|
-
parentModulePath?: string;
|
|
15
10
|
};
|
|
16
11
|
type ReindexResult = {
|
|
17
12
|
catalogCount: number;
|
|
@@ -10,50 +10,41 @@ function moduleNameFromNode(node) {
|
|
|
10
10
|
}
|
|
11
11
|
return null;
|
|
12
12
|
}
|
|
13
|
-
function collectUsageFromTree(modules, pathPrefix, results
|
|
13
|
+
function collectUsageFromTree(modules, pathPrefix, results) {
|
|
14
14
|
if (!Array.isArray(modules))
|
|
15
15
|
return;
|
|
16
16
|
modules.forEach((maybeNode, index) => {
|
|
17
17
|
if (!maybeNode || typeof maybeNode !== 'object')
|
|
18
18
|
return;
|
|
19
19
|
const node = maybeNode;
|
|
20
|
-
const modulePath = `${pathPrefix}[${index}]`;
|
|
21
20
|
const componentName = moduleNameFromNode(node);
|
|
21
|
+
// The tree path is no longer stored, but it is still the identity of last
|
|
22
|
+
// resort for a node that carries no id of its own. Such a node reverts to
|
|
23
|
+
// the old positional behaviour and churns when the tree is reordered.
|
|
24
|
+
const modulePath = `${pathPrefix}[${index}]`;
|
|
22
25
|
const moduleId = typeof node.id === 'string' || typeof node.id === 'number'
|
|
23
26
|
? String(node.id)
|
|
24
27
|
: modulePath;
|
|
25
|
-
const currentContext = componentName
|
|
26
|
-
? {
|
|
27
|
-
componentName,
|
|
28
|
-
moduleId,
|
|
29
|
-
modulePath,
|
|
30
|
-
}
|
|
31
|
-
: parentContext;
|
|
32
28
|
if (componentName) {
|
|
33
29
|
results.push({
|
|
34
30
|
componentName,
|
|
35
|
-
depth,
|
|
36
31
|
moduleId,
|
|
37
|
-
modulePath,
|
|
38
|
-
parentComponentName: parentContext?.componentName,
|
|
39
|
-
parentModuleId: parentContext?.moduleId,
|
|
40
|
-
parentModulePath: parentContext?.modulePath,
|
|
41
32
|
});
|
|
42
33
|
}
|
|
43
34
|
const props = node.props;
|
|
44
35
|
if (props && typeof props === 'object') {
|
|
45
36
|
const children = props.children;
|
|
46
37
|
if (Array.isArray(children)) {
|
|
47
|
-
collectUsageFromTree(children, `${modulePath}.props.children`, results
|
|
38
|
+
collectUsageFromTree(children, `${modulePath}.props.children`, results);
|
|
48
39
|
}
|
|
49
40
|
else if (children && typeof children === 'object') {
|
|
50
41
|
for (const [slotName, slotChildren] of Object.entries(children)) {
|
|
51
|
-
collectUsageFromTree(slotChildren, `${modulePath}.props.children.${slotName}`, results
|
|
42
|
+
collectUsageFromTree(slotChildren, `${modulePath}.props.children.${slotName}`, results);
|
|
52
43
|
}
|
|
53
44
|
}
|
|
54
45
|
}
|
|
55
46
|
if (Array.isArray(node.children)) {
|
|
56
|
-
collectUsageFromTree(node.children, `${modulePath}.children`, results
|
|
47
|
+
collectUsageFromTree(node.children, `${modulePath}.children`, results);
|
|
57
48
|
}
|
|
58
49
|
});
|
|
59
50
|
}
|
|
@@ -84,62 +75,77 @@ export async function findAllDocs(payload, collection, options, req) {
|
|
|
84
75
|
}
|
|
85
76
|
return docs;
|
|
86
77
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
78
|
+
/**
|
|
79
|
+
* Delete usage rows in one bulk statement rather than paginating the ids and
|
|
80
|
+
* issuing a `payload.delete` per row. Usage is rebuilt wholesale on every save,
|
|
81
|
+
* so a document with N modules previously cost N deletes (plus the finds to
|
|
82
|
+
* discover them) on the critical path of the save transaction.
|
|
83
|
+
*/
|
|
84
|
+
async function deleteUsageDocsWhere(payload, where, req) {
|
|
85
|
+
await payload.delete({
|
|
86
|
+
collection: NITROGEN_COMPONENT_USAGE_COLLECTION,
|
|
87
|
+
overrideAccess: true,
|
|
88
|
+
req,
|
|
89
|
+
where,
|
|
90
|
+
});
|
|
96
91
|
}
|
|
97
|
-
|
|
98
|
-
return
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
where: {
|
|
104
|
-
and: [
|
|
105
|
-
{
|
|
106
|
-
sourceCollection: {
|
|
107
|
-
equals: sourceCollection,
|
|
108
|
-
},
|
|
92
|
+
function usageDocsForSourceWhere(sourceCollection, sourceDocumentId) {
|
|
93
|
+
return {
|
|
94
|
+
and: [
|
|
95
|
+
{
|
|
96
|
+
sourceCollection: {
|
|
97
|
+
equals: sourceCollection,
|
|
109
98
|
},
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
sourceDocumentId: {
|
|
102
|
+
equals: sourceDocumentId,
|
|
114
103
|
},
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function usageKeyFor(sourceCollection, sourceDocumentId, record) {
|
|
109
|
+
return `${sourceCollection}:${sourceDocumentId}:${record.moduleId}:${record.componentName}`;
|
|
110
|
+
}
|
|
111
|
+
function usageSourceFields(doc) {
|
|
112
|
+
return {
|
|
113
|
+
sourceTitle: doc.title || '',
|
|
114
|
+
sourceSlug: doc.slug || '',
|
|
115
|
+
sourceStatus: doc.status || doc._status || '',
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* `componentName`, `moduleId`, `sourceCollection` and `sourceDocumentId` are all
|
|
120
|
+
* encoded in the usage key, so a key match already implies they agree; the
|
|
121
|
+
* source fields are reconciled separately by a single bulk update. That leaves
|
|
122
|
+
* only `sourceType`, which is checked defensively so a row written with the
|
|
123
|
+
* wrong value can still heal.
|
|
124
|
+
*/
|
|
125
|
+
function usageRowIsCurrent(row, sourceType) {
|
|
126
|
+
return row.sourceType === sourceType;
|
|
127
|
+
}
|
|
128
|
+
function usageRowData(sourceCollection, sourceType, sourceDocumentId, sourceFields, record) {
|
|
129
|
+
return {
|
|
130
|
+
usageKey: usageKeyFor(sourceCollection, sourceDocumentId, record),
|
|
131
|
+
componentName: record.componentName,
|
|
132
|
+
sourceCollection,
|
|
133
|
+
sourceType,
|
|
134
|
+
sourceDocumentId,
|
|
135
|
+
...sourceFields,
|
|
136
|
+
moduleId: record.moduleId,
|
|
137
|
+
};
|
|
118
138
|
}
|
|
119
139
|
async function createUsageDocs(payload, sourceCollection, sourceType, doc, req) {
|
|
120
140
|
const sourceDocumentId = String(doc.id);
|
|
141
|
+
const sourceFields = usageSourceFields(doc);
|
|
121
142
|
const usageRecords = extractComponentUsageRecords(doc.nitrogenData);
|
|
122
143
|
for (const record of usageRecords) {
|
|
123
144
|
await payload.create({
|
|
124
145
|
collection: NITROGEN_COMPONENT_USAGE_COLLECTION,
|
|
125
146
|
overrideAccess: true,
|
|
126
147
|
req,
|
|
127
|
-
data:
|
|
128
|
-
usageKey: `${sourceCollection}:${sourceDocumentId}:${record.moduleId}:${record.modulePath}:${record.componentName}`,
|
|
129
|
-
componentName: record.componentName,
|
|
130
|
-
depth: record.depth,
|
|
131
|
-
sourceCollection,
|
|
132
|
-
sourceType,
|
|
133
|
-
sourceDocumentId,
|
|
134
|
-
sourceTitle: doc.title || '',
|
|
135
|
-
sourceSlug: doc.slug || '',
|
|
136
|
-
sourceStatus: doc.status || doc._status || '',
|
|
137
|
-
moduleId: record.moduleId,
|
|
138
|
-
modulePath: record.modulePath,
|
|
139
|
-
parentComponentName: record.parentComponentName || '',
|
|
140
|
-
parentModuleId: record.parentModuleId || '',
|
|
141
|
-
parentModulePath: record.parentModulePath || '',
|
|
142
|
-
},
|
|
148
|
+
data: usageRowData(sourceCollection, sourceType, sourceDocumentId, sourceFields, record),
|
|
143
149
|
});
|
|
144
150
|
}
|
|
145
151
|
return usageRecords.length;
|
|
@@ -156,7 +162,8 @@ export async function syncComponentCatalog(payload, manifestInput, req) {
|
|
|
156
162
|
componentName: entry.name,
|
|
157
163
|
scope: entry.scope || '',
|
|
158
164
|
sidebarCategory: entry.sidebarCategory || '',
|
|
159
|
-
|
|
165
|
+
// Icons are no longer carried on the manifest entry; they're assigned in
|
|
166
|
+
// the editor (Settings > Component Icons) and stored in NitrogenSettings.
|
|
160
167
|
definition: entry,
|
|
161
168
|
source: manifest.source || '',
|
|
162
169
|
};
|
|
@@ -192,23 +199,72 @@ export async function syncComponentCatalog(payload, manifestInput, req) {
|
|
|
192
199
|
}
|
|
193
200
|
export async function reindexDocumentUsage(payload, sourceCollection, doc, sourceType = 'document', req) {
|
|
194
201
|
const sourceDocumentId = String(doc.id);
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
202
|
+
const sourceWhere = usageDocsForSourceWhere(sourceCollection, sourceDocumentId);
|
|
203
|
+
const sourceFields = usageSourceFields(doc);
|
|
204
|
+
const usageRecords = extractComponentUsageRecords(doc.nitrogenData);
|
|
205
|
+
// Usage rows describe tree *structure* only — nothing derived from module
|
|
206
|
+
// props or content. Editing copy therefore leaves every row identical, so
|
|
207
|
+
// diffing turns the common autosave case into zero writes instead of a full
|
|
208
|
+
// delete-and-recreate of every row on the save's critical path.
|
|
209
|
+
const existingRows = await findAllDocs(payload, NITROGEN_COMPONENT_USAGE_COLLECTION, { limit: 200, where: sourceWhere }, req);
|
|
210
|
+
const desiredByKey = new Map();
|
|
211
|
+
for (const record of usageRecords) {
|
|
212
|
+
desiredByKey.set(usageKeyFor(sourceCollection, sourceDocumentId, record), record);
|
|
213
|
+
}
|
|
214
|
+
const existingByKey = new Map();
|
|
215
|
+
const staleKeys = [];
|
|
216
|
+
for (const row of existingRows) {
|
|
217
|
+
if (desiredByKey.has(row.usageKey))
|
|
218
|
+
existingByKey.set(row.usageKey, row);
|
|
219
|
+
else
|
|
220
|
+
staleKeys.push(row.usageKey);
|
|
221
|
+
}
|
|
222
|
+
if (staleKeys.length > 0) {
|
|
223
|
+
await deleteUsageDocsWhere(payload, { usageKey: { in: staleKeys } }, req);
|
|
224
|
+
}
|
|
225
|
+
// Title/slug/status are identical across every row of the document, so when
|
|
226
|
+
// they change one bulk update fixes the whole set rather than N row updates.
|
|
227
|
+
const sourceFieldsStale = existingRows.some((row) => (row.sourceTitle || '') !== sourceFields.sourceTitle ||
|
|
228
|
+
(row.sourceSlug || '') !== sourceFields.sourceSlug ||
|
|
229
|
+
(row.sourceStatus || '') !== sourceFields.sourceStatus);
|
|
230
|
+
if (sourceFieldsStale && existingByKey.size > 0) {
|
|
231
|
+
await payload.update({
|
|
232
|
+
collection: NITROGEN_COMPONENT_USAGE_COLLECTION,
|
|
233
|
+
overrideAccess: true,
|
|
234
|
+
req,
|
|
235
|
+
where: sourceWhere,
|
|
236
|
+
data: sourceFields,
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
for (const [usageKey, record] of desiredByKey) {
|
|
240
|
+
const row = existingByKey.get(usageKey);
|
|
241
|
+
const data = usageRowData(sourceCollection, sourceType, sourceDocumentId, sourceFields, record);
|
|
242
|
+
if (!row) {
|
|
243
|
+
await payload.create({
|
|
244
|
+
collection: NITROGEN_COMPONENT_USAGE_COLLECTION,
|
|
245
|
+
overrideAccess: true,
|
|
246
|
+
req,
|
|
247
|
+
data,
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
else if (!usageRowIsCurrent(row, sourceType)) {
|
|
251
|
+
await payload.update({
|
|
252
|
+
collection: NITROGEN_COMPONENT_USAGE_COLLECTION,
|
|
253
|
+
id: row.id,
|
|
254
|
+
overrideAccess: true,
|
|
255
|
+
req,
|
|
256
|
+
data,
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
return usageRecords.length;
|
|
198
261
|
}
|
|
199
262
|
export async function deleteDocumentUsage(payload, sourceCollection, sourceDocumentId, req) {
|
|
200
|
-
|
|
201
|
-
await deleteUsageDocs(payload, docsForSource, req);
|
|
263
|
+
await deleteUsageDocsWhere(payload, usageDocsForSourceWhere(sourceCollection, String(sourceDocumentId)), req);
|
|
202
264
|
}
|
|
203
265
|
export async function reindexAllComponentInventory(payload, collections, manifestInput, req) {
|
|
204
266
|
const entries = await syncComponentCatalog(payload, manifestInput, req);
|
|
205
|
-
|
|
206
|
-
limit: 200,
|
|
207
|
-
select: {
|
|
208
|
-
id: true,
|
|
209
|
-
},
|
|
210
|
-
}, req);
|
|
211
|
-
await deleteUsageDocs(payload, usageDocs, req);
|
|
267
|
+
await deleteUsageDocsWhere(payload, { id: { exists: true } }, req);
|
|
212
268
|
let documentCount = 0;
|
|
213
269
|
let usageCount = 0;
|
|
214
270
|
for (const collection of collections) {
|
package/dist/types.d.ts
CHANGED
|
@@ -152,7 +152,6 @@ export interface NitrogenComponentUsageDoc {
|
|
|
152
152
|
id: string | number;
|
|
153
153
|
usageKey: string;
|
|
154
154
|
componentName: string;
|
|
155
|
-
depth?: number;
|
|
156
155
|
sourceCollection: string;
|
|
157
156
|
sourceType: string;
|
|
158
157
|
sourceDocumentId: string;
|
|
@@ -160,10 +159,6 @@ export interface NitrogenComponentUsageDoc {
|
|
|
160
159
|
sourceSlug?: string;
|
|
161
160
|
sourceStatus?: string;
|
|
162
161
|
moduleId?: string;
|
|
163
|
-
modulePath: string;
|
|
164
|
-
parentComponentName?: string;
|
|
165
|
-
parentModuleId?: string;
|
|
166
|
-
parentModulePath?: string;
|
|
167
162
|
}
|
|
168
163
|
export interface NitrogenInventorySourceDoc {
|
|
169
164
|
id: string | number;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nitrogenbuilder/connector-payload",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Nitrogen page builder connector plugin for Payload CMS 3.x",
|
|
5
5
|
"author": "Leonardo Dentzien <leo@torchmedia.ca>",
|
|
6
6
|
"type": "module",
|
|
@@ -55,4 +55,4 @@
|
|
|
55
55
|
"@nitrogenbuilder/client-core": "link:../monogen/packages/client-core",
|
|
56
56
|
"@nitrogenbuilder/types": "link:../monogen/packages/types"
|
|
57
57
|
}
|
|
58
|
-
}
|
|
58
|
+
}
|