strapi-relation-names 0.0.0
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/LICENSE +21 -0
- package/README.md +171 -0
- package/dist/admin/SettingsPage-BQo5mpAY.mjs +199 -0
- package/dist/admin/SettingsPage-C1nFFJjH.js +199 -0
- package/dist/admin/de-BBrO1tf0.js +16 -0
- package/dist/admin/de-a3KtzZ7N.mjs +16 -0
- package/dist/admin/en-8w3y1FSw.mjs +16 -0
- package/dist/admin/en-DlY6ZGdo.js +16 -0
- package/dist/admin/index-CJO9wtUk.mjs +125 -0
- package/dist/admin/index-SsQXjQq0.js +124 -0
- package/dist/admin/index.js +4 -0
- package/dist/admin/index.mjs +4 -0
- package/dist/admin/src/index.d.ts +3 -0
- package/dist/admin/src/pages/SettingsPage.d.ts +2 -0
- package/dist/admin/src/pluginId.d.ts +1 -0
- package/dist/admin/src/types.d.ts +28 -0
- package/dist/admin/src/utils/getTranslation.d.ts +2 -0
- package/dist/admin/src/utils/layout.d.ts +3 -0
- package/dist/admin/src/utils/template.d.ts +5 -0
- package/dist/server/index.js +564 -0
- package/dist/server/index.mjs +564 -0
- package/dist/server/src/bootstrap.d.ts +5 -0
- package/dist/server/src/config/index.d.ts +12 -0
- package/dist/server/src/constants.d.ts +1 -0
- package/dist/server/src/content-types/index.d.ts +2 -0
- package/dist/server/src/controllers/index.d.ts +9 -0
- package/dist/server/src/controllers/settings.d.ts +8 -0
- package/dist/server/src/destroy.d.ts +5 -0
- package/dist/server/src/index.d.ts +66 -0
- package/dist/server/src/middlewares/index.d.ts +2 -0
- package/dist/server/src/policies/index.d.ts +2 -0
- package/dist/server/src/register.d.ts +5 -0
- package/dist/server/src/routes/admin/index.d.ts +12 -0
- package/dist/server/src/routes/content-api/index.d.ts +5 -0
- package/dist/server/src/routes/index.d.ts +18 -0
- package/dist/server/src/services/index.d.ts +19 -0
- package/dist/server/src/services/relation-labels.d.ts +14 -0
- package/dist/server/src/services/settings.d.ts +11 -0
- package/dist/server/src/services/utils/collections.d.ts +1 -0
- package/dist/server/src/services/utils/relation-labels.d.ts +27 -0
- package/dist/server/src/services/utils/relation-values.d.ts +6 -0
- package/dist/server/src/types.d.ts +5 -0
- package/package.json +77 -0
|
@@ -0,0 +1,564 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
|
|
3
|
+
const bootstrap = ({ strapi }) => {
|
|
4
|
+
};
|
|
5
|
+
const destroy = ({ strapi }) => {
|
|
6
|
+
};
|
|
7
|
+
const PLUGIN_ID$1 = "strapi-relation-names";
|
|
8
|
+
const register = ({ strapi }) => {
|
|
9
|
+
const relationLabels2 = strapi.plugin(PLUGIN_ID$1).service("relation-labels");
|
|
10
|
+
const controllers2 = strapi.get("controllers");
|
|
11
|
+
controllers2.extend("plugin::content-manager.relations", (controller) => ({
|
|
12
|
+
...controller,
|
|
13
|
+
async findAvailable(ctx, next) {
|
|
14
|
+
await controller.findAvailable(ctx, next);
|
|
15
|
+
if (Array.isArray(ctx.body?.results)) {
|
|
16
|
+
ctx.body.results = await relationLabels2.decorateRelationResults(
|
|
17
|
+
ctx,
|
|
18
|
+
ctx.params.model,
|
|
19
|
+
ctx.params.targetField,
|
|
20
|
+
ctx.body.results
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
async findExisting(ctx, next) {
|
|
25
|
+
await controller.findExisting(ctx, next);
|
|
26
|
+
if (Array.isArray(ctx.body?.results)) {
|
|
27
|
+
ctx.body.results = await relationLabels2.decorateRelationResults(
|
|
28
|
+
ctx,
|
|
29
|
+
ctx.params.model,
|
|
30
|
+
ctx.params.targetField,
|
|
31
|
+
ctx.body.results
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}));
|
|
36
|
+
controllers2.extend("plugin::content-manager.collection-types", (controller) => ({
|
|
37
|
+
...controller,
|
|
38
|
+
async find(ctx, next) {
|
|
39
|
+
await controller.find(ctx, next);
|
|
40
|
+
if (Array.isArray(ctx.body?.results)) {
|
|
41
|
+
ctx.body.results = await relationLabels2.decorateCollectionResults(
|
|
42
|
+
ctx,
|
|
43
|
+
ctx.params.model,
|
|
44
|
+
ctx.body.results
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}));
|
|
49
|
+
const decorateConfiguration = async (ctx, sourceUid) => {
|
|
50
|
+
if (ctx.body?.data) {
|
|
51
|
+
ctx.body.data = await relationLabels2.decorateConfiguration(ctx.body.data, sourceUid);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
controllers2.extend("plugin::content-manager.content-types", (controller) => ({
|
|
55
|
+
...controller,
|
|
56
|
+
async findContentTypeConfiguration(ctx, next) {
|
|
57
|
+
await controller.findContentTypeConfiguration(ctx, next);
|
|
58
|
+
await decorateConfiguration(ctx, ctx.params.uid);
|
|
59
|
+
},
|
|
60
|
+
async updateContentTypeConfiguration(ctx, next) {
|
|
61
|
+
await controller.updateContentTypeConfiguration(ctx, next);
|
|
62
|
+
await decorateConfiguration(ctx, ctx.params.uid);
|
|
63
|
+
}
|
|
64
|
+
}));
|
|
65
|
+
controllers2.extend("plugin::content-manager.components", (controller) => ({
|
|
66
|
+
...controller,
|
|
67
|
+
async findComponentConfiguration(ctx, next) {
|
|
68
|
+
await controller.findComponentConfiguration(ctx, next);
|
|
69
|
+
await decorateConfiguration(ctx, ctx.params.uid);
|
|
70
|
+
},
|
|
71
|
+
async updateComponentConfiguration(ctx, next) {
|
|
72
|
+
await controller.updateComponentConfiguration(ctx, next);
|
|
73
|
+
await decorateConfiguration(ctx, ctx.params.uid);
|
|
74
|
+
}
|
|
75
|
+
}));
|
|
76
|
+
};
|
|
77
|
+
const validateConfig = (config2) => {
|
|
78
|
+
if (!config2 || typeof config2 !== "object" || Array.isArray(config2) || !Array.isArray(config2.collections) || !config2.collections.every(
|
|
79
|
+
(collection) => typeof collection === "string"
|
|
80
|
+
)) {
|
|
81
|
+
throw new Error("The collections config must be an array of strings");
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
const config = {
|
|
85
|
+
default: {
|
|
86
|
+
collections: []
|
|
87
|
+
},
|
|
88
|
+
validator: validateConfig
|
|
89
|
+
};
|
|
90
|
+
const contentTypes = {};
|
|
91
|
+
const settings$1 = ({ strapi }) => ({
|
|
92
|
+
async find(ctx) {
|
|
93
|
+
const data = await strapi.plugin("strapi-relation-names").service("settings").get();
|
|
94
|
+
ctx.body = { data };
|
|
95
|
+
},
|
|
96
|
+
async update(ctx) {
|
|
97
|
+
const body = ctx.request.body;
|
|
98
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) {
|
|
99
|
+
return ctx.badRequest("Settings must be an object");
|
|
100
|
+
}
|
|
101
|
+
const data = await strapi.plugin("strapi-relation-names").service("settings").set(body);
|
|
102
|
+
ctx.body = { data };
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
const controllers = {
|
|
106
|
+
settings: settings$1
|
|
107
|
+
};
|
|
108
|
+
const middlewares = {};
|
|
109
|
+
const policies = {};
|
|
110
|
+
const contentAPIRoutes = () => ({
|
|
111
|
+
type: "content-api",
|
|
112
|
+
routes: []
|
|
113
|
+
});
|
|
114
|
+
const adminAPIRoutes = () => ({
|
|
115
|
+
type: "admin",
|
|
116
|
+
routes: [
|
|
117
|
+
{
|
|
118
|
+
method: "GET",
|
|
119
|
+
path: "/settings",
|
|
120
|
+
handler: "settings.find",
|
|
121
|
+
config: {
|
|
122
|
+
policies: ["admin::isAuthenticatedAdmin"]
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
method: "PUT",
|
|
127
|
+
path: "/settings",
|
|
128
|
+
handler: "settings.update",
|
|
129
|
+
config: {
|
|
130
|
+
policies: ["admin::isAuthenticatedAdmin"]
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
]
|
|
134
|
+
});
|
|
135
|
+
const routes = {
|
|
136
|
+
"content-api": contentAPIRoutes,
|
|
137
|
+
admin: adminAPIRoutes
|
|
138
|
+
};
|
|
139
|
+
const SCALAR_TYPES = /* @__PURE__ */ new Set([
|
|
140
|
+
"string",
|
|
141
|
+
"text",
|
|
142
|
+
"email",
|
|
143
|
+
"uid",
|
|
144
|
+
"enumeration",
|
|
145
|
+
"integer",
|
|
146
|
+
"biginteger",
|
|
147
|
+
"decimal",
|
|
148
|
+
"float",
|
|
149
|
+
"date",
|
|
150
|
+
"datetime",
|
|
151
|
+
"time",
|
|
152
|
+
"boolean"
|
|
153
|
+
]);
|
|
154
|
+
const isRecord$1 = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
155
|
+
const parseTemplate = (template) => {
|
|
156
|
+
if (!template.trim()) {
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
const placeholders = [];
|
|
160
|
+
let cursor = 0;
|
|
161
|
+
while (cursor < template.length) {
|
|
162
|
+
const openingBrace = template.indexOf("{", cursor);
|
|
163
|
+
const closingBrace = template.indexOf("}", cursor);
|
|
164
|
+
if (closingBrace !== -1 && (openingBrace === -1 || closingBrace < openingBrace)) {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
if (openingBrace === -1) {
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
const end = template.indexOf("}", openingBrace + 1);
|
|
171
|
+
if (end === -1) {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
const name = template.slice(openingBrace + 1, end);
|
|
175
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) {
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
placeholders.push(name);
|
|
179
|
+
cursor = end + 1;
|
|
180
|
+
}
|
|
181
|
+
return placeholders.length > 0 ? placeholders : null;
|
|
182
|
+
};
|
|
183
|
+
const compileTemplate = (template, targetSchema) => {
|
|
184
|
+
const placeholders = parseTemplate(template);
|
|
185
|
+
const attributes = targetSchema?.attributes ?? {};
|
|
186
|
+
if (!placeholders || !targetSchema) {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
const valid = placeholders.every((name) => {
|
|
190
|
+
const attribute = attributes[name];
|
|
191
|
+
return Boolean(
|
|
192
|
+
attribute && attribute.private !== true && SCALAR_TYPES.has(attribute.type ?? "")
|
|
193
|
+
);
|
|
194
|
+
});
|
|
195
|
+
if (!valid) {
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
return {
|
|
199
|
+
template,
|
|
200
|
+
placeholders,
|
|
201
|
+
displayField: placeholders[0]
|
|
202
|
+
};
|
|
203
|
+
};
|
|
204
|
+
const renderTemplate = (compiled, values) => {
|
|
205
|
+
const rendered = compiled.template.replace(
|
|
206
|
+
/\{([A-Za-z_][A-Za-z0-9_]*)\}/g,
|
|
207
|
+
(_match, name) => {
|
|
208
|
+
const value = values[name];
|
|
209
|
+
return value === null || value === void 0 ? "" : String(value);
|
|
210
|
+
}
|
|
211
|
+
);
|
|
212
|
+
return rendered.trim();
|
|
213
|
+
};
|
|
214
|
+
const getIdentity = (value, modelType) => modelType === "component" ? value.id : value.documentId ?? value.id;
|
|
215
|
+
const matchesRelation = (source, candidate, targetModelType) => {
|
|
216
|
+
if (source.id !== void 0 && candidate.id === source.id) {
|
|
217
|
+
return true;
|
|
218
|
+
}
|
|
219
|
+
if (source.documentId !== void 0 && candidate.documentId === source.documentId) {
|
|
220
|
+
if (source.locale !== void 0 && candidate.locale !== source.locale) {
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
if (source.publishedAt !== void 0 && candidate.publishedAt !== source.publishedAt) {
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
return getIdentity(source, targetModelType) === getIdentity(candidate, targetModelType);
|
|
229
|
+
};
|
|
230
|
+
const applyLabel = (value, hydrated, runtime) => {
|
|
231
|
+
const label = renderTemplate(runtime, hydrated);
|
|
232
|
+
if (label) {
|
|
233
|
+
return { ...value, [runtime.displayField]: label };
|
|
234
|
+
}
|
|
235
|
+
if (runtime.displayField === runtime.originalMainField) {
|
|
236
|
+
return value;
|
|
237
|
+
}
|
|
238
|
+
const fallbackField = runtime.originalMainField === "id" ? "documentId" : runtime.originalMainField;
|
|
239
|
+
const fallback = Object.prototype.hasOwnProperty.call(hydrated, fallbackField) ? hydrated[fallbackField] : void 0;
|
|
240
|
+
return { ...value, [runtime.displayField]: fallback };
|
|
241
|
+
};
|
|
242
|
+
const relationValues = (value) => {
|
|
243
|
+
if (Array.isArray(value)) {
|
|
244
|
+
return value.filter(isRecord$1);
|
|
245
|
+
}
|
|
246
|
+
return isRecord$1(value) ? [value] : [];
|
|
247
|
+
};
|
|
248
|
+
const replaceRelationValue = (original, values, hydrated, runtime) => {
|
|
249
|
+
const decorated = values.map((value) => applyLabel(value, hydrated.get(value) ?? value, runtime));
|
|
250
|
+
return Array.isArray(original) ? decorated : decorated[0] ?? original;
|
|
251
|
+
};
|
|
252
|
+
const isCollectionEnabled = (collections, uid) => collections.length === 0 || collections.includes(uid);
|
|
253
|
+
const getOriginalMainField = async (strapi, sourceSchema, targetSchema, targetField, userAbility) => {
|
|
254
|
+
const serviceName = sourceSchema.modelType === "component" ? "components" : "content-types";
|
|
255
|
+
const configuration = await strapi.plugin("content-manager").service(serviceName).findConfiguration(sourceSchema);
|
|
256
|
+
const configuredMainField = configuration?.metadatas?.[targetField]?.edit?.mainField;
|
|
257
|
+
if (typeof configuredMainField !== "string" || configuredMainField === "documentId" || configuredMainField === "id") {
|
|
258
|
+
return configuredMainField === "documentId" ? "documentId" : "id";
|
|
259
|
+
}
|
|
260
|
+
const permissionChecker = strapi.plugin("content-manager").service("permission-checker").create({ userAbility, model: targetSchema.uid });
|
|
261
|
+
const attribute = targetSchema.attributes?.[configuredMainField];
|
|
262
|
+
if (!attribute || attribute.private === true || permissionChecker.cannot.read(null, configuredMainField)) {
|
|
263
|
+
return "documentId";
|
|
264
|
+
}
|
|
265
|
+
return configuredMainField;
|
|
266
|
+
};
|
|
267
|
+
const getRuntime = async (strapi, settings2, sourceUid, targetField, userAbility) => {
|
|
268
|
+
const sourceSchema = strapi.getModel(sourceUid);
|
|
269
|
+
const attribute = sourceSchema?.attributes?.[targetField];
|
|
270
|
+
if (!sourceSchema || !attribute || attribute.type !== "relation" || !attribute.target) {
|
|
271
|
+
return null;
|
|
272
|
+
}
|
|
273
|
+
const template = settings2.relations[sourceUid]?.[targetField];
|
|
274
|
+
const targetSchema = strapi.getModel(attribute.target);
|
|
275
|
+
const compiled = typeof template === "string" ? compileTemplate(template, targetSchema) : null;
|
|
276
|
+
if (!compiled || !targetSchema) {
|
|
277
|
+
return null;
|
|
278
|
+
}
|
|
279
|
+
return {
|
|
280
|
+
...compiled,
|
|
281
|
+
sourceUid,
|
|
282
|
+
targetUid: targetSchema.uid,
|
|
283
|
+
originalMainField: await getOriginalMainField(
|
|
284
|
+
strapi,
|
|
285
|
+
sourceSchema,
|
|
286
|
+
targetSchema,
|
|
287
|
+
targetField,
|
|
288
|
+
userAbility
|
|
289
|
+
)
|
|
290
|
+
};
|
|
291
|
+
};
|
|
292
|
+
const hydrateValues = async (strapi, ctx, runtime, values) => {
|
|
293
|
+
const targetSchema = strapi.getModel(runtime.targetUid);
|
|
294
|
+
const targetModelType = targetSchema.modelType;
|
|
295
|
+
const missingFields = runtime.placeholders.filter(
|
|
296
|
+
(field) => values.some((value) => !Object.prototype.hasOwnProperty.call(value, field))
|
|
297
|
+
);
|
|
298
|
+
if (missingFields.length === 0) {
|
|
299
|
+
return new Map(values.map((value) => [value, value]));
|
|
300
|
+
}
|
|
301
|
+
const identities = values.map((value) => getIdentity(value, targetModelType)).filter((identity) => identity !== void 0 && identity !== null);
|
|
302
|
+
if (identities.length === 0) {
|
|
303
|
+
return new Map(values.map((value) => [value, value]));
|
|
304
|
+
}
|
|
305
|
+
try {
|
|
306
|
+
const permissionChecker = strapi.plugin("content-manager").service("permission-checker").create({ userAbility: ctx.state.userAbility, model: runtime.targetUid });
|
|
307
|
+
const fields = Array.from(
|
|
308
|
+
/* @__PURE__ */ new Set([
|
|
309
|
+
...runtime.placeholders,
|
|
310
|
+
runtime.originalMainField,
|
|
311
|
+
"id",
|
|
312
|
+
"documentId",
|
|
313
|
+
"locale",
|
|
314
|
+
"publishedAt"
|
|
315
|
+
])
|
|
316
|
+
);
|
|
317
|
+
const identityField = targetModelType === "component" ? "id" : "documentId";
|
|
318
|
+
const permissionQuery = await permissionChecker.sanitizedQuery.read({
|
|
319
|
+
fields,
|
|
320
|
+
filters: { [identityField]: { $in: identities } }
|
|
321
|
+
});
|
|
322
|
+
const query = strapi.get("query-params").transform(runtime.targetUid, permissionQuery);
|
|
323
|
+
const hydrated = await strapi.db.query(runtime.targetUid).findMany(query);
|
|
324
|
+
return new Map(
|
|
325
|
+
values.map((value) => [
|
|
326
|
+
value,
|
|
327
|
+
hydrated.find((candidate) => matchesRelation(value, candidate, targetModelType)) ?? value
|
|
328
|
+
])
|
|
329
|
+
);
|
|
330
|
+
} catch {
|
|
331
|
+
return new Map(values.map((value) => [value, value]));
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
const relationLabels = ({ strapi }) => {
|
|
335
|
+
const getSettings = () => strapi.plugin("strapi-relation-names").service("settings").get();
|
|
336
|
+
const decorateRelationResults = async (ctx, sourceUid, targetField, results) => {
|
|
337
|
+
const settings2 = await getSettings();
|
|
338
|
+
if (!isCollectionEnabled(settings2.collections, sourceUid)) {
|
|
339
|
+
return results;
|
|
340
|
+
}
|
|
341
|
+
const runtime = await getRuntime(
|
|
342
|
+
strapi,
|
|
343
|
+
settings2,
|
|
344
|
+
sourceUid,
|
|
345
|
+
targetField,
|
|
346
|
+
ctx.state.userAbility
|
|
347
|
+
);
|
|
348
|
+
if (!runtime) {
|
|
349
|
+
return results;
|
|
350
|
+
}
|
|
351
|
+
const values = results.filter(isRecord$1);
|
|
352
|
+
const hydrated = await hydrateValues(strapi, ctx, runtime, values);
|
|
353
|
+
return results.map(
|
|
354
|
+
(result) => isRecord$1(result) ? applyLabel(result, hydrated.get(result) ?? result, runtime) : result
|
|
355
|
+
);
|
|
356
|
+
};
|
|
357
|
+
const decorateConfiguration = async (configuration, sourceUid) => {
|
|
358
|
+
if (!configuration || !isRecord$1(configuration.metadatas)) {
|
|
359
|
+
return configuration;
|
|
360
|
+
}
|
|
361
|
+
const settings2 = await getSettings();
|
|
362
|
+
const metadatas = { ...configuration.metadatas };
|
|
363
|
+
const relationNames = {};
|
|
364
|
+
for (const [fieldName, metadata] of Object.entries(metadatas)) {
|
|
365
|
+
const sourceSchema = strapi.getModel(sourceUid);
|
|
366
|
+
const attribute = sourceSchema?.attributes?.[fieldName];
|
|
367
|
+
if (!attribute || attribute.type !== "relation" || !attribute.target) {
|
|
368
|
+
continue;
|
|
369
|
+
}
|
|
370
|
+
const targetSchema = strapi.getModel(attribute.target);
|
|
371
|
+
const compiled = compileTemplate(
|
|
372
|
+
settings2.relations[sourceUid]?.[fieldName] ?? "",
|
|
373
|
+
targetSchema
|
|
374
|
+
);
|
|
375
|
+
if (!compiled || !isRecord$1(metadata)) {
|
|
376
|
+
continue;
|
|
377
|
+
}
|
|
378
|
+
metadatas[fieldName] = {
|
|
379
|
+
...metadata,
|
|
380
|
+
edit: {
|
|
381
|
+
...isRecord$1(metadata.edit) ? metadata.edit : {},
|
|
382
|
+
mainField: compiled.displayField
|
|
383
|
+
},
|
|
384
|
+
list: {
|
|
385
|
+
...isRecord$1(metadata.list) ? metadata.list : {},
|
|
386
|
+
mainField: compiled.displayField
|
|
387
|
+
}
|
|
388
|
+
};
|
|
389
|
+
relationNames[fieldName] = { mainField: compiled.displayField };
|
|
390
|
+
}
|
|
391
|
+
return {
|
|
392
|
+
...configuration,
|
|
393
|
+
metadatas,
|
|
394
|
+
settings: {
|
|
395
|
+
...isRecord$1(configuration.settings) ? configuration.settings : {},
|
|
396
|
+
relationNames
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
};
|
|
400
|
+
const decorateContentManagerConfiguration = async (data, sourceUid) => {
|
|
401
|
+
if (!isRecord$1(data)) {
|
|
402
|
+
return data;
|
|
403
|
+
}
|
|
404
|
+
const settings2 = await getSettings();
|
|
405
|
+
if (!isCollectionEnabled(settings2.collections, sourceUid)) {
|
|
406
|
+
return data;
|
|
407
|
+
}
|
|
408
|
+
const next = { ...data };
|
|
409
|
+
if (next.contentType) {
|
|
410
|
+
next.contentType = await decorateConfiguration(next.contentType, sourceUid);
|
|
411
|
+
}
|
|
412
|
+
if (next.component) {
|
|
413
|
+
next.component = await decorateConfiguration(next.component, sourceUid);
|
|
414
|
+
}
|
|
415
|
+
if (isRecord$1(next.components)) {
|
|
416
|
+
const components = { ...next.components };
|
|
417
|
+
for (const [uid, configuration] of Object.entries(components)) {
|
|
418
|
+
components[uid] = await decorateConfiguration(configuration, uid);
|
|
419
|
+
}
|
|
420
|
+
next.components = components;
|
|
421
|
+
}
|
|
422
|
+
return next;
|
|
423
|
+
};
|
|
424
|
+
const decorateCollectionResults = async (ctx, sourceUid, results) => {
|
|
425
|
+
const settings2 = await getSettings();
|
|
426
|
+
if (!isCollectionEnabled(settings2.collections, sourceUid)) {
|
|
427
|
+
return results;
|
|
428
|
+
}
|
|
429
|
+
const runtimeCache = /* @__PURE__ */ new Map();
|
|
430
|
+
const sourceSchemas = /* @__PURE__ */ new Map();
|
|
431
|
+
const getSchema = (uid) => {
|
|
432
|
+
if (!sourceSchemas.has(uid)) {
|
|
433
|
+
sourceSchemas.set(uid, strapi.getModel(uid));
|
|
434
|
+
}
|
|
435
|
+
return sourceSchemas.get(uid);
|
|
436
|
+
};
|
|
437
|
+
const visit = async (value, uid) => {
|
|
438
|
+
if (Array.isArray(value)) {
|
|
439
|
+
for (const item of value) {
|
|
440
|
+
await visit(item, uid);
|
|
441
|
+
}
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
if (!isRecord$1(value)) {
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
const schema = getSchema(uid);
|
|
448
|
+
for (const [fieldName, attribute] of Object.entries(schema?.attributes ?? {})) {
|
|
449
|
+
if (attribute.type === "relation" && attribute.target) {
|
|
450
|
+
const cacheKey = `${uid}:${fieldName}`;
|
|
451
|
+
if (!runtimeCache.has(cacheKey)) {
|
|
452
|
+
runtimeCache.set(
|
|
453
|
+
cacheKey,
|
|
454
|
+
await getRuntime(strapi, settings2, uid, fieldName, ctx.state.userAbility)
|
|
455
|
+
);
|
|
456
|
+
}
|
|
457
|
+
const runtime = runtimeCache.get(cacheKey);
|
|
458
|
+
if (runtime) {
|
|
459
|
+
const originalRelation = value[fieldName];
|
|
460
|
+
const relationItems = relationValues(originalRelation);
|
|
461
|
+
const hydrated = await hydrateValues(strapi, ctx, runtime, relationItems);
|
|
462
|
+
value[fieldName] = replaceRelationValue(
|
|
463
|
+
originalRelation,
|
|
464
|
+
relationItems,
|
|
465
|
+
hydrated,
|
|
466
|
+
runtime
|
|
467
|
+
);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
if (attribute.type === "component" && attribute.component) {
|
|
471
|
+
await visit(value[fieldName], attribute.component);
|
|
472
|
+
}
|
|
473
|
+
if (attribute.type === "dynamiczone" && Array.isArray(attribute.components)) {
|
|
474
|
+
for (const item of relationValues(value[fieldName])) {
|
|
475
|
+
if (typeof item.__component === "string" && attribute.components.includes(item.__component)) {
|
|
476
|
+
await visit(item, item.__component);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
};
|
|
482
|
+
for (const result of results) {
|
|
483
|
+
await visit(result, sourceUid);
|
|
484
|
+
}
|
|
485
|
+
return results;
|
|
486
|
+
};
|
|
487
|
+
return {
|
|
488
|
+
decorateCollectionResults,
|
|
489
|
+
decorateConfiguration: decorateContentManagerConfiguration,
|
|
490
|
+
decorateRelationResults,
|
|
491
|
+
compileTemplate,
|
|
492
|
+
parseTemplate,
|
|
493
|
+
renderTemplate
|
|
494
|
+
};
|
|
495
|
+
};
|
|
496
|
+
const EMPTY_SETTINGS = {
|
|
497
|
+
collections: [],
|
|
498
|
+
relations: {}
|
|
499
|
+
};
|
|
500
|
+
const PLUGIN_ID = "strapi-relation-names";
|
|
501
|
+
const STORE_KEY = "settings";
|
|
502
|
+
const isRecord = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
503
|
+
const normalizeSettings = (value, collections = []) => {
|
|
504
|
+
if (!isRecord(value) || !isRecord(value.relations)) {
|
|
505
|
+
return { collections, relations: {} };
|
|
506
|
+
}
|
|
507
|
+
const relations = {};
|
|
508
|
+
for (const [sourceUid, sourceRelations] of Object.entries(value.relations)) {
|
|
509
|
+
if (!isRecord(sourceRelations)) {
|
|
510
|
+
continue;
|
|
511
|
+
}
|
|
512
|
+
const normalizedRelations = {};
|
|
513
|
+
for (const [fieldName, template] of Object.entries(sourceRelations)) {
|
|
514
|
+
if (typeof template === "string" && template.length > 0) {
|
|
515
|
+
normalizedRelations[fieldName] = template;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
if (Object.keys(normalizedRelations).length > 0) {
|
|
519
|
+
relations[sourceUid] = normalizedRelations;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
return { collections, relations };
|
|
523
|
+
};
|
|
524
|
+
const settings = ({ strapi }) => {
|
|
525
|
+
const getCollections = () => {
|
|
526
|
+
const config2 = strapi.config.get("plugin::strapi-relation-names");
|
|
527
|
+
return Array.isArray(config2?.collections) ? config2.collections.filter(
|
|
528
|
+
(collection) => typeof collection === "string"
|
|
529
|
+
) : [];
|
|
530
|
+
};
|
|
531
|
+
const store = () => strapi.store({
|
|
532
|
+
type: "plugin",
|
|
533
|
+
name: PLUGIN_ID,
|
|
534
|
+
key: STORE_KEY
|
|
535
|
+
});
|
|
536
|
+
return {
|
|
537
|
+
async get() {
|
|
538
|
+
const value = await store().get();
|
|
539
|
+
return normalizeSettings(value ?? EMPTY_SETTINGS, getCollections());
|
|
540
|
+
},
|
|
541
|
+
async set(value) {
|
|
542
|
+
const normalized = normalizeSettings(value, getCollections());
|
|
543
|
+
await store().set({ value: normalized });
|
|
544
|
+
return normalized;
|
|
545
|
+
}
|
|
546
|
+
};
|
|
547
|
+
};
|
|
548
|
+
const services = {
|
|
549
|
+
"relation-labels": relationLabels,
|
|
550
|
+
settings
|
|
551
|
+
};
|
|
552
|
+
const index = {
|
|
553
|
+
register,
|
|
554
|
+
bootstrap,
|
|
555
|
+
destroy,
|
|
556
|
+
config,
|
|
557
|
+
controllers,
|
|
558
|
+
routes,
|
|
559
|
+
services,
|
|
560
|
+
contentTypes,
|
|
561
|
+
policies,
|
|
562
|
+
middlewares
|
|
563
|
+
};
|
|
564
|
+
exports.default = index;
|