@aduptive/strapi-blockscene 2.0.0-alpha.11 → 2.0.0-alpha.13
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/README.md +111 -18
- package/dist/admin.cjs +1701 -654
- package/dist/admin.mjs +1698 -651
- package/dist/server.cjs +165 -17
- package/package.json +1 -1
package/dist/server.cjs
CHANGED
|
@@ -108,8 +108,17 @@ var require_groups = __commonJS({
|
|
|
108
108
|
const start = rows.findIndex((row) => blockKey(row) === String(key));
|
|
109
109
|
if (start < 0 || !isOpener(rows[start], g)) return null;
|
|
110
110
|
const [, end] = groupRange(rows, start, g);
|
|
111
|
+
if (end <= start || uidOf(rows[end]) !== g[uidOf(rows[start])]) return null;
|
|
111
112
|
return [...rows.slice(0, start), ...rows.slice(end + 1)];
|
|
112
113
|
}
|
|
114
|
+
function unwrapGroup(rows, key, g) {
|
|
115
|
+
if (!g) return null;
|
|
116
|
+
const start = rows.findIndex((row) => blockKey(row) === String(key));
|
|
117
|
+
if (start < 0 || !isOpener(rows[start], g)) return null;
|
|
118
|
+
const [, end] = groupRange(rows, start, g);
|
|
119
|
+
if (end <= start || uidOf(rows[end]) !== g[uidOf(rows[start])]) return null;
|
|
120
|
+
return [...rows.slice(0, start), ...rows.slice(start + 1, end), ...rows.slice(end + 1)];
|
|
121
|
+
}
|
|
113
122
|
var MAX_COLUMNS = 12;
|
|
114
123
|
var parseColumns = (value) => {
|
|
115
124
|
const n = typeof value === "number" ? value : typeof value === "string" && /^\s*\d{1,3}\s*$/.test(value) ? Number(value) : NaN;
|
|
@@ -137,6 +146,7 @@ var require_groups = __commonJS({
|
|
|
137
146
|
topLevelRanges,
|
|
138
147
|
moveGroup,
|
|
139
148
|
removeGroup,
|
|
149
|
+
unwrapGroup,
|
|
140
150
|
blockKey,
|
|
141
151
|
isOpener,
|
|
142
152
|
isClose,
|
|
@@ -187,7 +197,7 @@ var require_settings = __commonJS({
|
|
|
187
197
|
// Edit view labels that are still the raw attribute name read as "Mobile columns count" (see README "Field labels").
|
|
188
198
|
friendlyLabels: true,
|
|
189
199
|
// Page preview pane (Strapi 5): which toolbar controls show, in order, and the width menu's entries.
|
|
190
|
-
previewToolbar: ["modes", "history", "devices", "status", "actions"],
|
|
200
|
+
previewToolbar: ["modes", "history", "versions", "devices", "status", "actions"],
|
|
191
201
|
previewDevices: ["fit", "mobile", "tablet", "desktop"]
|
|
192
202
|
},
|
|
193
203
|
// Per content type (only the ones with a Dynamic Zone): { enabled: false } turns the plugin off there;
|
|
@@ -202,7 +212,7 @@ var require_settings = __commonJS({
|
|
|
202
212
|
var SIDEBAR_POSITIONS = ["left", "right", "bottom"];
|
|
203
213
|
var OPENS = ["modal", "drawer"];
|
|
204
214
|
var LABEL = /^[^<>]{1,40}$/;
|
|
205
|
-
var TOOLBAR = ["modes", "history", "devices", "status", "actions"];
|
|
215
|
+
var TOOLBAR = ["modes", "history", "versions", "devices", "status", "actions"];
|
|
206
216
|
var DEVICE_NAMES = ["fit", "mobile", "tablet", "desktop"];
|
|
207
217
|
var previewToolbar = (value) => Array.isArray(value) && value.every((id) => TOOLBAR.includes(id)) && new Set(value).size === value.length;
|
|
208
218
|
var DEVICE_LABEL = /^[^<>]{1,24}$/;
|
|
@@ -239,6 +249,13 @@ var require_settings = __commonJS({
|
|
|
239
249
|
var TAG = /^[^<>\n]{1,24}$/;
|
|
240
250
|
var cleanTags = (value) => Array.isArray(value) ? [...new Set(value.filter((tag) => typeof tag === "string" && TAG.test(tag.trim())).map((tag) => tag.trim()))].slice(0, 10) : [];
|
|
241
251
|
var validTags = (value) => Array.isArray(value) && value.length <= 10 && value.every((tag) => typeof tag === "string" && TAG.test(tag.trim()));
|
|
252
|
+
var directComponentUids = (contentTypes, perType = {}) => [...new Set(Object.entries(contentTypes || {}).filter(([uid]) => perType?.[uid]?.enabled !== false).flatMap(([, schema]) => Object.values(schema?.attributes || {}).filter((attr) => attr?.type === "dynamiczone").flatMap((attr) => attr.components || [])))];
|
|
253
|
+
var COMPONENT_CATEGORY = /^[a-z0-9][a-z0-9_-]{0,49}$/;
|
|
254
|
+
var safeComponentCategories2 = (value) => value == null ? null : Array.isArray(value) && value.length > 0 && value.length <= 50 && value.every((category) => typeof category === "string" && COMPONENT_CATEGORY.test(category)) ? [...new Set(value)] : null;
|
|
255
|
+
var settingsComponentUids2 = (contentTypes, components, perType = {}, categories = null) => {
|
|
256
|
+
const allowed = safeComponentCategories2(categories);
|
|
257
|
+
return directComponentUids(contentTypes, perType).filter((uid) => !allowed || allowed.includes(components?.[uid]?.category || uid.split(".")[0]));
|
|
258
|
+
};
|
|
242
259
|
var GUESSES = [
|
|
243
260
|
["hero", /hero|banner|cover/],
|
|
244
261
|
["text", /text|rich|quote|title/],
|
|
@@ -301,6 +318,7 @@ var require_settings = __commonJS({
|
|
|
301
318
|
["label", "description", "category", "keywords"].filter((key) => typeof entry[key] === "string").map((key) => [key, entry[key]])
|
|
302
319
|
);
|
|
303
320
|
entries[uid].image = safeUrl2(entry.image);
|
|
321
|
+
if (typeof entry.showRowThumbnail === "boolean") entries[uid].showRowThumbnail = entry.showRowThumbnail;
|
|
304
322
|
if (TYPOLOGIES2.includes(entry.typology)) entries[uid].typology = entry.typology;
|
|
305
323
|
const tags = cleanTags(entry.tags);
|
|
306
324
|
if (tags.length || entries[uid].category) entries[uid].tags = tags.length ? tags : cleanTags([entries[uid].category]);
|
|
@@ -358,6 +376,9 @@ var require_settings = __commonJS({
|
|
|
358
376
|
} else if (key === "mediaId") {
|
|
359
377
|
if (!Number.isInteger(entry.mediaId) || entry.mediaId <= 0) fail2(`Invalid media for "${uid}"`);
|
|
360
378
|
clean.mediaId = entry.mediaId;
|
|
379
|
+
} else if (key === "showRowThumbnail") {
|
|
380
|
+
if (typeof entry.showRowThumbnail !== "boolean") fail2(`Invalid row thumbnail setting for "${uid}"`);
|
|
381
|
+
clean.showRowThumbnail = entry.showRowThumbnail;
|
|
361
382
|
} else if (key === "layout") {
|
|
362
383
|
if (!validLayout(entry.layout, schemas && (schemas[uid]?.attributes || {}))) fail2(`Invalid layout for "${uid}": columnsField (and mobileColumnsField) must name a number, string or numeric enumeration attribute of the component; maxColumns 1 to 12`);
|
|
363
384
|
clean.layout = structuredClone(entry.layout);
|
|
@@ -416,6 +437,7 @@ var require_settings = __commonJS({
|
|
|
416
437
|
clean.tags = cleanTags(clean.tags);
|
|
417
438
|
if (!clean.tags.length) delete clean.tags;
|
|
418
439
|
}
|
|
440
|
+
if ("showRowThumbnail" in clean && typeof clean.showRowThumbnail !== "boolean") delete clean.showRowThumbnail;
|
|
419
441
|
if ("layout" in clean && !validLayout(clean.layout, schemas && (schemas[uid]?.attributes || {}))) delete clean.layout;
|
|
420
442
|
if (Object.keys(clean).length) out.components[uid] = clean;
|
|
421
443
|
}
|
|
@@ -624,6 +646,102 @@ var require_settings = __commonJS({
|
|
|
624
646
|
}
|
|
625
647
|
return out;
|
|
626
648
|
}
|
|
649
|
+
function requiredProblems(schema, values, schemas, path, media, problems) {
|
|
650
|
+
for (const [field, attr] of Object.entries(schema?.attributes || {})) {
|
|
651
|
+
const at = `${path}.${field}`;
|
|
652
|
+
const supplied = Object.hasOwn(values, field);
|
|
653
|
+
const value = supplied ? values[field] : attr.default;
|
|
654
|
+
if (attr.type === "media" || attr.type === "relation") {
|
|
655
|
+
if (attr.required && !supplied) media.push(at);
|
|
656
|
+
continue;
|
|
657
|
+
}
|
|
658
|
+
if (attr.type === "component") {
|
|
659
|
+
const nested = schemas[attr.component];
|
|
660
|
+
if (!nested) {
|
|
661
|
+
problems.push(`${at}: unknown component "${attr.component}"`);
|
|
662
|
+
continue;
|
|
663
|
+
}
|
|
664
|
+
if (attr.repeatable) {
|
|
665
|
+
const minimum = Math.max(attr.min ?? 0, attr.required ? 1 : 0);
|
|
666
|
+
const items = supplied ? value : Array.from({ length: minimum }, () => ({}));
|
|
667
|
+
if (!Array.isArray(items) || items.length < minimum) problems.push(`${at} requires at least ${minimum} item${minimum === 1 ? "" : "s"}`);
|
|
668
|
+
else items.forEach((item, index) => requiredProblems(nested, item, schemas, `${at}[${index}]`, media, problems));
|
|
669
|
+
} else if (supplied && value === null) {
|
|
670
|
+
if (attr.required) problems.push(`${at} is required`);
|
|
671
|
+
} else if (supplied || attr.required) requiredProblems(nested, supplied ? value : {}, schemas, at, media, problems);
|
|
672
|
+
continue;
|
|
673
|
+
}
|
|
674
|
+
if (attr.required && (value === void 0 || value === null || value === "")) problems.push(`${at} is required`);
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
function validateKits2(input, contentTypes = {}, schemas = {}, groups = null, notes = []) {
|
|
678
|
+
if (input === null || input === void 0) return {};
|
|
679
|
+
if (!plain(input) || JSON.stringify(input).length > 256 * 1024) {
|
|
680
|
+
notes.push("expected an object up to 256 KB");
|
|
681
|
+
return {};
|
|
682
|
+
}
|
|
683
|
+
const out = {};
|
|
684
|
+
for (const [uid, kits] of Object.entries(input)) {
|
|
685
|
+
const type = contentTypes[uid];
|
|
686
|
+
if (!type || !uid.startsWith("api::")) {
|
|
687
|
+
notes.push(`${uid}: unknown content type`);
|
|
688
|
+
continue;
|
|
689
|
+
}
|
|
690
|
+
if (!Array.isArray(kits) || kits.length > 12) {
|
|
691
|
+
notes.push(`${uid}: kits must be a list of at most 12`);
|
|
692
|
+
continue;
|
|
693
|
+
}
|
|
694
|
+
const ids = /* @__PURE__ */ new Set();
|
|
695
|
+
for (const kit of kits) {
|
|
696
|
+
const name = `${uid} kit "${kit?.id ?? "?"}"`;
|
|
697
|
+
try {
|
|
698
|
+
if (!plain(kit) || Object.keys(kit).some((key) => !["id", "label", "locales", "zones"].includes(key))) throw new Error("expected { id, label, locales?, zones }");
|
|
699
|
+
if (!text(kit.id) || !VARIANT.id.test(kit.id) || ids.has(kit.id)) throw new Error('id must be 1 to 40 lowercase letters, digits, "-" or "_", unique per content type');
|
|
700
|
+
if (!fieldText(kit.label, 60)) throw new Error('label must be a string of 1 to 60 characters, or { "<locale>": string }');
|
|
701
|
+
if (kit.locales !== void 0 && (!Array.isArray(kit.locales) || !kit.locales.length || kit.locales.length > 20 || kit.locales.some((locale) => !text(locale) || !LOCALE.test(locale)))) throw new Error("locales must be 1 to 20 locale codes");
|
|
702
|
+
if (!plain(kit.zones) || !Object.keys(kit.zones).length) throw new Error("zones must be a non-empty object");
|
|
703
|
+
const zones = {};
|
|
704
|
+
for (const [zoneName, rows] of Object.entries(kit.zones)) {
|
|
705
|
+
const zone = type.attributes?.[zoneName];
|
|
706
|
+
if (zone?.type !== "dynamiczone") throw new Error(`unknown Dynamic Zone "${zoneName}"`);
|
|
707
|
+
if (!Array.isArray(rows) || !rows.length || rows.length > 50) throw new Error(`${zoneName} must contain 1 to 50 rows`);
|
|
708
|
+
const clean = [];
|
|
709
|
+
for (let index = 0; index < rows.length; index++) {
|
|
710
|
+
const row = rows[index];
|
|
711
|
+
if (!plain(row) || !text(row.__component)) throw new Error(`${zoneName}[${index}] must have __component`);
|
|
712
|
+
const component = row.__component;
|
|
713
|
+
if (!zone.components?.includes(component) || !schemas[component]) throw new Error(`${zoneName}[${index}]: component "${component}" is not allowed`);
|
|
714
|
+
const skipped = [];
|
|
715
|
+
const values = variantValues(row, schemas[component], schemas, `${zoneName}[${index}]`, skipped);
|
|
716
|
+
if (skipped.length) notes.push(`${name}: media and relation values are not inserted (${skipped.slice(0, 5).join(", ")}${skipped.length > 5 ? ", ..." : ""})`);
|
|
717
|
+
const media = [], required = [];
|
|
718
|
+
requiredProblems(schemas[component], values, schemas, `${zoneName}[${index}]`, media, required);
|
|
719
|
+
if (required.length) throw new Error(required.slice(0, 5).join("; "));
|
|
720
|
+
if (media.length) notes.push(`${name}: required media or relations must be completed before publishing (${media.slice(0, 5).join(", ")}${media.length > 5 ? ", ..." : ""})`);
|
|
721
|
+
clean.push({ __component: component, values });
|
|
722
|
+
const close = groups?.[component];
|
|
723
|
+
if (close) {
|
|
724
|
+
if (!zone.components?.includes(close) || !schemas[close]) throw new Error(`${zoneName}[${index}]: close component "${close}" is not allowed`);
|
|
725
|
+
clean.push({ __component: close, values: {} });
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
if (clean.length > (zone.max ?? Infinity)) throw new Error(`${zoneName} exceeds its maximum of ${zone.max}`);
|
|
729
|
+
zones[zoneName] = clean;
|
|
730
|
+
}
|
|
731
|
+
for (const [zoneName, zone] of Object.entries(type.attributes || {})) {
|
|
732
|
+
if (zone?.type !== "dynamiczone") continue;
|
|
733
|
+
const minimum = Math.max(zone.min ?? 0, zone.required ? 1 : 0);
|
|
734
|
+
if ((zones[zoneName]?.length || 0) < minimum) throw new Error(`${zoneName} requires at least ${minimum} row${minimum === 1 ? "" : "s"}`);
|
|
735
|
+
}
|
|
736
|
+
ids.add(kit.id);
|
|
737
|
+
(out[uid] ||= []).push({ id: kit.id, label: structuredClone(kit.label), ...kit.locales && { locales: [...new Set(kit.locales)] }, zones });
|
|
738
|
+
} catch (error) {
|
|
739
|
+
notes.push(`${name} ignored: ${error.message}`);
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
return out;
|
|
744
|
+
}
|
|
627
745
|
var PREFS = { starred: 200, recent: 20 };
|
|
628
746
|
function validatePrefs2(input, componentUids2) {
|
|
629
747
|
if (!input || typeof input !== "object" || Array.isArray(input)) fail2("Preferences must be an object");
|
|
@@ -636,7 +754,7 @@ var require_settings = __commonJS({
|
|
|
636
754
|
return out;
|
|
637
755
|
}
|
|
638
756
|
var mergePrefs2 = (saved, componentUids2) => Object.fromEntries(Object.entries(PREFS).map(([key, max]) => [key, Array.isArray(saved?.[key]) ? [...new Set(saved[key].filter((uid) => componentUids2.includes(uid)))].slice(0, max) : []]));
|
|
639
|
-
module2.exports = { PLUGIN: PLUGIN2, HIDDEN_MODES, TEMPLATES: TEMPLATES2, TYPOLOGIES: TYPOLOGIES2, guessTypology, facetsOf, validatePrefs: validatePrefs2, mergePrefs: mergePrefs2, ICONS, DEFAULTS: DEFAULTS2, catalog: catalog2, validateSettings: validateSettings2, validateFields: validateFields2, validateVariants: validateVariants2, schemaMetadata: schemaMetadata2, mergeSaved: mergeSaved2, layer: layer2, overrides: overrides2, safeUrl: safeUrl2, fail: fail2 };
|
|
757
|
+
module2.exports = { PLUGIN: PLUGIN2, HIDDEN_MODES, TEMPLATES: TEMPLATES2, TYPOLOGIES: TYPOLOGIES2, guessTypology, facetsOf, directComponentUids, settingsComponentUids: settingsComponentUids2, safeComponentCategories: safeComponentCategories2, validatePrefs: validatePrefs2, mergePrefs: mergePrefs2, ICONS, DEFAULTS: DEFAULTS2, catalog: catalog2, validateSettings: validateSettings2, validateFields: validateFields2, validateVariants: validateVariants2, validateKits: validateKits2, schemaMetadata: schemaMetadata2, mergeSaved: mergeSaved2, layer: layer2, overrides: overrides2, safeUrl: safeUrl2, fail: fail2 };
|
|
640
758
|
}
|
|
641
759
|
});
|
|
642
760
|
|
|
@@ -826,8 +944,8 @@ var require_diff = __commonJS({
|
|
|
826
944
|
}
|
|
827
945
|
function summarize(before, after, schema) {
|
|
828
946
|
const zones = Object.entries(schema?.attributes || {}).filter(([, attr]) => attr?.type === "dynamiczone").map(([name]) => name);
|
|
829
|
-
const blocks = { added: 0, removed: 0, changed: 0 };
|
|
830
|
-
if (!before) return { initial: true, fields: [], blocks };
|
|
947
|
+
const blocks = { total: zones.reduce((n, name) => n + (Array.isArray(after?.[name]) ? after[name].length : 0), 0), added: 0, removed: 0, changed: 0 };
|
|
948
|
+
if (!before) return { initial: true, fields: [], blocks: { ...blocks, added: blocks.total } };
|
|
831
949
|
const names = [.../* @__PURE__ */ new Set([...Object.keys(before), ...Object.keys(after || {})])];
|
|
832
950
|
const fields = names.filter((name) => !zones.includes(name) && !same(before[name], after?.[name])).sort();
|
|
833
951
|
for (const name of zones) for (const { op } of diffRows(before[name], after?.[name])) if (op !== "same") blocks[op]++;
|
|
@@ -1298,7 +1416,6 @@ var require_history = __commonJS({
|
|
|
1298
1416
|
var CRON2 = "blocksceneHistoryPurge";
|
|
1299
1417
|
var BATCH = 500;
|
|
1300
1418
|
var DAY = 24 * 60 * 60 * 1e3;
|
|
1301
|
-
var LIST_LIMIT = 100;
|
|
1302
1419
|
var ACTORS_LIMIT = 500;
|
|
1303
1420
|
var SEARCH_LIMIT = 200;
|
|
1304
1421
|
var eventContentType2 = { schema: {
|
|
@@ -1441,14 +1558,23 @@ var require_history = __commonJS({
|
|
|
1441
1558
|
return name && name !== "id" && schemaOf(uid)?.attributes?.[name] && !["relation", "media", "component", "dynamiczone", "password", "json", "blocks"].includes(schemaOf(uid).attributes[name].type) ? name : null;
|
|
1442
1559
|
},
|
|
1443
1560
|
// Latest events of one document and locale, newest first; `stored`: its snapshot (or an identical one) can be loaded.
|
|
1444
|
-
async list({ uid, documentId, locale }) {
|
|
1445
|
-
const
|
|
1446
|
-
const
|
|
1447
|
-
|
|
1448
|
-
events().findMany({ select: ["hash"], where: {
|
|
1561
|
+
async list({ uid, documentId, locale, actor = "", page = 1, pageSize = 25 }) {
|
|
1562
|
+
const scope2 = { contentType: uid, relatedDocumentId: documentId, locale: locale || null };
|
|
1563
|
+
const where = { ...scope2, ...actor && { actor } };
|
|
1564
|
+
const [list, kept, total, people] = await Promise.all([
|
|
1565
|
+
events().findMany({ select: ["id", "action", "actor", "actorName", "at", "summary", "hash", "size"], where, orderBy: [{ at: "desc" }, { id: "desc" }], offset: (page - 1) * pageSize, limit: pageSize }),
|
|
1566
|
+
events().findMany({ select: ["hash"], where: { ...scope2, size: { $gt: 0 } } }),
|
|
1567
|
+
events().count({ where }),
|
|
1568
|
+
events().findMany({ select: ["actor", "actorName"], where: scope2, orderBy: [{ at: "desc" }, { id: "desc" }] })
|
|
1449
1569
|
]);
|
|
1450
1570
|
const hashes = new Set(kept.map((row) => row.hash));
|
|
1451
|
-
|
|
1571
|
+
const actors2 = [...new Map(people.slice().reverse().map(({ actor: actor2, actorName }) => [actor2, { actor: actor2, actorName }])).values()];
|
|
1572
|
+
return {
|
|
1573
|
+
results: list.map(({ hash, size, ...event }) => ({ ...event, stored: Boolean(hash && hashes.has(hash)) })),
|
|
1574
|
+
pagination: { page, pageSize, total, pageCount: Math.ceil(total / pageSize) },
|
|
1575
|
+
actors: actors2,
|
|
1576
|
+
locale: locale || null
|
|
1577
|
+
};
|
|
1452
1578
|
},
|
|
1453
1579
|
// One event with its snapshot (from an identical event when this one was deduplicated) and what loading it needs:
|
|
1454
1580
|
// the media files and relation targets that still exist (relation labels from the Content Manager's main field).
|
|
@@ -1660,10 +1786,13 @@ var require_history = __commonJS({
|
|
|
1660
1786
|
async list(ctx) {
|
|
1661
1787
|
const { uid, documentId } = ctx.params || {};
|
|
1662
1788
|
const locale = ctx.query?.locale || "";
|
|
1663
|
-
|
|
1789
|
+
const actor = ctx.query?.actor || "";
|
|
1790
|
+
const page = int(ctx.query?.page, 1, 1e6), pageSize = int(ctx.query?.pageSize, 25, 100);
|
|
1791
|
+
if (typeof actor !== "string" || actor && !ACTOR.test(actor) || [page, pageSize].some(Number.isNaN)) return ctx.badRequest("Invalid history filters");
|
|
1792
|
+
if (!String(uid).startsWith("api::") || !strapi.contentTypes?.[uid] || !DOCUMENT_ID.test(documentId || "") || typeof locale !== "string" || locale && !LOCALE.test(locale)) return ctx.badRequest("Invalid content type, document or locale");
|
|
1664
1793
|
if (!canRead(strapi, ctx, uid)) return ctx.forbidden();
|
|
1665
1794
|
const history = strapi.plugin(PLUGIN2).service("history");
|
|
1666
|
-
ctx.body =
|
|
1795
|
+
ctx.body = await history.list({ uid, documentId, locale: (await history.scope(uid, locale || void 0))[0], actor, page, pageSize });
|
|
1667
1796
|
},
|
|
1668
1797
|
async find(ctx) {
|
|
1669
1798
|
const id = Number(ctx.params?.id);
|
|
@@ -1690,7 +1819,7 @@ var require_history = __commonJS({
|
|
|
1690
1819
|
});
|
|
1691
1820
|
|
|
1692
1821
|
// server/index.js
|
|
1693
|
-
var { PLUGIN, TEMPLATES, TYPOLOGIES, DEFAULTS, catalog, validateSettings, validateFields, validateVariants, schemaMetadata, mergeSaved, layer, overrides, validatePrefs, mergePrefs, safeUrl, fail } = require_settings();
|
|
1822
|
+
var { PLUGIN, TEMPLATES, TYPOLOGIES, DEFAULTS, catalog, settingsComponentUids, safeComponentCategories, validateSettings, validateFields, validateVariants, validateKits, schemaMetadata, mergeSaved, layer, overrides, validatePrefs, mergePrefs, safeUrl, fail } = require_settings();
|
|
1694
1823
|
var { safeGroups, validateGroups, invalidComponents, layoutFields } = require_groups();
|
|
1695
1824
|
var { hiddenName, injectHidden, hideFromBuilder, registerHiddenStrip } = require_hidden();
|
|
1696
1825
|
var { CRON, covers, eventContentType, historyService, historyController, registerHistory, registerPurge } = require_history();
|
|
@@ -1838,10 +1967,15 @@ module.exports = {
|
|
|
1838
1967
|
// Optional layout groups: OPEN component uid -> its CLOSE uid, e.g. { 'wrappers.join': 'wrappers.close' }.
|
|
1839
1968
|
// Empty/absent: every Dynamic Zone component is an ordinary block. See README "Layout groups".
|
|
1840
1969
|
groups: null,
|
|
1970
|
+
// Optional Strapi component categories shown as configurable cards in Settings > Block gallery.
|
|
1971
|
+
// This does not change the components allowed by each Dynamic Zone.
|
|
1972
|
+
settingsComponentCategories: null,
|
|
1841
1973
|
// Project defaults from code: same shape as the stored settings, e.g. require('./blockscene.json'). See README "Settings page".
|
|
1842
1974
|
settings: null,
|
|
1843
1975
|
// Edit view field texts from code (never stored): { uid: { attribute: { label, description, placeholder } } }. See README "Field labels".
|
|
1844
1976
|
fields: null,
|
|
1977
|
+
// Initial block sets per content type, shown only on a new empty entry. See README "Starter kits".
|
|
1978
|
+
kits: null,
|
|
1845
1979
|
// Other languages for the schema metadata (pluginOptions.blockscene, info.description), one flat map per locale:
|
|
1846
1980
|
// { 'pt-BR': require('./blockscene/pt-BR.json') }. See README "Describing blocks and fields in the schema".
|
|
1847
1981
|
translations: null,
|
|
@@ -1856,6 +1990,7 @@ module.exports = {
|
|
|
1856
1990
|
const name = hiddenName(plugin.config("hiddenAttribute"));
|
|
1857
1991
|
withHidden = [];
|
|
1858
1992
|
if (name === null) strapi.log.warn(`[${PLUGIN}] "hiddenAttribute" config ignored: expected a name like "bsHidden" or false. Hiding blocks is off.`);
|
|
1993
|
+
if (plugin.config("settingsComponentCategories") != null && !safeComponentCategories(plugin.config("settingsComponentCategories"))) strapi.log.warn(`[${PLUGIN}] "settingsComponentCategories" config ignored: expected 1 to 50 Strapi component category names.`);
|
|
1859
1994
|
if (!name) return;
|
|
1860
1995
|
const { added, skipped } = injectHidden(strapi.components, strapi.contentTypes, name);
|
|
1861
1996
|
withHidden = added;
|
|
@@ -1876,6 +2011,7 @@ module.exports = {
|
|
|
1876
2011
|
strapi.plugin(PLUGIN).service("settings").projectDefaults();
|
|
1877
2012
|
strapi.plugin(PLUGIN).service("settings").fields();
|
|
1878
2013
|
strapi.plugin(PLUGIN).service("settings").variants();
|
|
2014
|
+
strapi.plugin(PLUGIN).service("settings").kits();
|
|
1879
2015
|
registerZoneGuards(strapi);
|
|
1880
2016
|
registerHiddenStrip(strapi, hiddenName(strapi.plugin(PLUGIN).config("hiddenAttribute")), strapi.plugin(PLUGIN));
|
|
1881
2017
|
if (withHidden.length) hideFromBuilder(typeof strapi.get === "function" ? strapi.get("services") : strapi.container.get("services"), withHidden, hiddenName(strapi.plugin(PLUGIN).config("hiddenAttribute")));
|
|
@@ -1934,6 +2070,14 @@ module.exports = {
|
|
|
1934
2070
|
for (const note of notes) strapi.log?.warn(`[${PLUGIN}] components variants: ${note}.`);
|
|
1935
2071
|
return variants;
|
|
1936
2072
|
};
|
|
2073
|
+
let kits;
|
|
2074
|
+
const starterKits = () => {
|
|
2075
|
+
if (kits !== void 0) return kits;
|
|
2076
|
+
const notes = [];
|
|
2077
|
+
kits = validateKits(strapi.plugin(PLUGIN).config("kits"), strapi.contentTypes || {}, strapi.components || {}, safeGroups(strapi.plugin(PLUGIN).config("groups"), componentUids(strapi)), notes);
|
|
2078
|
+
for (const note of notes) strapi.log?.warn(`[${PLUGIN}] starter kits: ${note}.`);
|
|
2079
|
+
return kits;
|
|
2080
|
+
};
|
|
1937
2081
|
const get = async () => mergeSaved(layer(projectDefaults(), await readSettings(strapi)), componentUids(strapi), contentTypeUids(strapi), apiUids(strapi), strapi.components);
|
|
1938
2082
|
return {
|
|
1939
2083
|
projectDefaults,
|
|
@@ -1941,6 +2085,7 @@ module.exports = {
|
|
|
1941
2085
|
fields: fieldTexts,
|
|
1942
2086
|
schema: schemaMeta,
|
|
1943
2087
|
variants: insertVariants,
|
|
2088
|
+
kits: starterKits,
|
|
1944
2089
|
async set(value) {
|
|
1945
2090
|
const next = validateSettings(value, componentUids(strapi), contentTypeUids(strapi), apiUids(strapi), strapi.components);
|
|
1946
2091
|
for (const [uid, entry] of Object.entries(next.components)) {
|
|
@@ -1981,7 +2126,8 @@ module.exports = {
|
|
|
1981
2126
|
...media[uid],
|
|
1982
2127
|
template: entry.template,
|
|
1983
2128
|
...entry.typology && { typology: entry.typology },
|
|
1984
|
-
...entry.tags && { tags: entry.tags }
|
|
2129
|
+
...entry.tags && { tags: entry.tags },
|
|
2130
|
+
...typeof entry.showRowThumbnail === "boolean" && { showRowThumbnail: entry.showRowThumbnail }
|
|
1985
2131
|
};
|
|
1986
2132
|
}
|
|
1987
2133
|
const hidden = hiddenName(plugin.config("hiddenAttribute")) || null;
|
|
@@ -1991,6 +2137,7 @@ module.exports = {
|
|
|
1991
2137
|
ctx.body = {
|
|
1992
2138
|
...base,
|
|
1993
2139
|
layouts,
|
|
2140
|
+
kits: plugin.service("settings").kits(),
|
|
1994
2141
|
palette: settings.palette,
|
|
1995
2142
|
contentTypes: settings.contentTypes,
|
|
1996
2143
|
hiddenAttribute: hidden,
|
|
@@ -2005,7 +2152,8 @@ module.exports = {
|
|
|
2005
2152
|
async find(ctx) {
|
|
2006
2153
|
const settings = await strapi.plugin(PLUGIN).service("settings").get();
|
|
2007
2154
|
const auto = catalog({ components: strapi.plugin(PLUGIN).config("components"), schemas: strapi.components, blocks: strapi.plugin(PLUGIN).service("settings").schema().blocks }).components;
|
|
2008
|
-
const
|
|
2155
|
+
const visible = new Set(settingsComponentUids(strapi.contentTypes, strapi.components, settings.contentTypes, strapi.plugin(PLUGIN).config("settingsComponentCategories")));
|
|
2156
|
+
const components = Object.entries(strapi.components || {}).filter(([uid]) => visible.has(uid)).map(([uid, schema]) => ({
|
|
2009
2157
|
uid,
|
|
2010
2158
|
displayName: schema.info?.displayName || uid,
|
|
2011
2159
|
category: schema.category || uid.split(".")[0],
|
package/package.json
CHANGED