@aduptive/strapi-blockscene 2.0.0-alpha.10 → 2.0.0-alpha.12
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 +89 -11
- package/dist/admin.cjs +1103 -584
- package/dist/admin.mjs +1100 -581
- package/dist/server.cjs +177 -27
- package/package.json +1 -1
package/dist/server.cjs
CHANGED
|
@@ -21,6 +21,10 @@ var require_groups = __commonJS({
|
|
|
21
21
|
return Object.keys(out).length ? out : null;
|
|
22
22
|
}
|
|
23
23
|
var uidOf = (row) => typeof row?.__component === "string" ? row.__component : "";
|
|
24
|
+
var invalidComponents2 = (rows, allowed) => {
|
|
25
|
+
const uids = new Set(Array.isArray(allowed) ? allowed : []);
|
|
26
|
+
return (Array.isArray(rows) ? rows : []).flatMap((row, index) => uidOf(row) && !uids.has(uidOf(row)) ? [{ index, uid: uidOf(row) }] : []);
|
|
27
|
+
};
|
|
24
28
|
var isOpener = (row, g) => Boolean(g) && Object.prototype.hasOwnProperty.call(g, uidOf(row));
|
|
25
29
|
var isClose = (row, g) => Boolean(g) && Object.values(g).includes(uidOf(row));
|
|
26
30
|
var blockKey = (row) => row && row.id != null ? `${row.__component}#${row.id}` : row && row.__temp_key__ != null ? String(row.__temp_key__) : null;
|
|
@@ -127,6 +131,7 @@ var require_groups = __commonJS({
|
|
|
127
131
|
module2.exports = {
|
|
128
132
|
safeGroups: safeGroups2,
|
|
129
133
|
validateGroups: validateGroups2,
|
|
134
|
+
invalidComponents: invalidComponents2,
|
|
130
135
|
groupRange,
|
|
131
136
|
groupRows,
|
|
132
137
|
topLevelRanges,
|
|
@@ -182,7 +187,7 @@ var require_settings = __commonJS({
|
|
|
182
187
|
// Edit view labels that are still the raw attribute name read as "Mobile columns count" (see README "Field labels").
|
|
183
188
|
friendlyLabels: true,
|
|
184
189
|
// Page preview pane (Strapi 5): which toolbar controls show, in order, and the width menu's entries.
|
|
185
|
-
previewToolbar: ["modes", "history", "devices", "status", "actions"],
|
|
190
|
+
previewToolbar: ["modes", "history", "versions", "devices", "status", "actions"],
|
|
186
191
|
previewDevices: ["fit", "mobile", "tablet", "desktop"]
|
|
187
192
|
},
|
|
188
193
|
// Per content type (only the ones with a Dynamic Zone): { enabled: false } turns the plugin off there;
|
|
@@ -197,7 +202,7 @@ var require_settings = __commonJS({
|
|
|
197
202
|
var SIDEBAR_POSITIONS = ["left", "right", "bottom"];
|
|
198
203
|
var OPENS = ["modal", "drawer"];
|
|
199
204
|
var LABEL = /^[^<>]{1,40}$/;
|
|
200
|
-
var TOOLBAR = ["modes", "history", "devices", "status", "actions"];
|
|
205
|
+
var TOOLBAR = ["modes", "history", "versions", "devices", "status", "actions"];
|
|
201
206
|
var DEVICE_NAMES = ["fit", "mobile", "tablet", "desktop"];
|
|
202
207
|
var previewToolbar = (value) => Array.isArray(value) && value.every((id) => TOOLBAR.includes(id)) && new Set(value).size === value.length;
|
|
203
208
|
var DEVICE_LABEL = /^[^<>]{1,24}$/;
|
|
@@ -619,6 +624,102 @@ var require_settings = __commonJS({
|
|
|
619
624
|
}
|
|
620
625
|
return out;
|
|
621
626
|
}
|
|
627
|
+
function requiredProblems(schema, values, schemas, path, media, problems) {
|
|
628
|
+
for (const [field, attr] of Object.entries(schema?.attributes || {})) {
|
|
629
|
+
const at = `${path}.${field}`;
|
|
630
|
+
const supplied = Object.hasOwn(values, field);
|
|
631
|
+
const value = supplied ? values[field] : attr.default;
|
|
632
|
+
if (attr.type === "media" || attr.type === "relation") {
|
|
633
|
+
if (attr.required && !supplied) media.push(at);
|
|
634
|
+
continue;
|
|
635
|
+
}
|
|
636
|
+
if (attr.type === "component") {
|
|
637
|
+
const nested = schemas[attr.component];
|
|
638
|
+
if (!nested) {
|
|
639
|
+
problems.push(`${at}: unknown component "${attr.component}"`);
|
|
640
|
+
continue;
|
|
641
|
+
}
|
|
642
|
+
if (attr.repeatable) {
|
|
643
|
+
const minimum = Math.max(attr.min ?? 0, attr.required ? 1 : 0);
|
|
644
|
+
const items = supplied ? value : Array.from({ length: minimum }, () => ({}));
|
|
645
|
+
if (!Array.isArray(items) || items.length < minimum) problems.push(`${at} requires at least ${minimum} item${minimum === 1 ? "" : "s"}`);
|
|
646
|
+
else items.forEach((item, index) => requiredProblems(nested, item, schemas, `${at}[${index}]`, media, problems));
|
|
647
|
+
} else if (supplied && value === null) {
|
|
648
|
+
if (attr.required) problems.push(`${at} is required`);
|
|
649
|
+
} else if (supplied || attr.required) requiredProblems(nested, supplied ? value : {}, schemas, at, media, problems);
|
|
650
|
+
continue;
|
|
651
|
+
}
|
|
652
|
+
if (attr.required && (value === void 0 || value === null || value === "")) problems.push(`${at} is required`);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
function validateKits2(input, contentTypes = {}, schemas = {}, groups = null, notes = []) {
|
|
656
|
+
if (input === null || input === void 0) return {};
|
|
657
|
+
if (!plain(input) || JSON.stringify(input).length > 256 * 1024) {
|
|
658
|
+
notes.push("expected an object up to 256 KB");
|
|
659
|
+
return {};
|
|
660
|
+
}
|
|
661
|
+
const out = {};
|
|
662
|
+
for (const [uid, kits] of Object.entries(input)) {
|
|
663
|
+
const type = contentTypes[uid];
|
|
664
|
+
if (!type || !uid.startsWith("api::")) {
|
|
665
|
+
notes.push(`${uid}: unknown content type`);
|
|
666
|
+
continue;
|
|
667
|
+
}
|
|
668
|
+
if (!Array.isArray(kits) || kits.length > 12) {
|
|
669
|
+
notes.push(`${uid}: kits must be a list of at most 12`);
|
|
670
|
+
continue;
|
|
671
|
+
}
|
|
672
|
+
const ids = /* @__PURE__ */ new Set();
|
|
673
|
+
for (const kit of kits) {
|
|
674
|
+
const name = `${uid} kit "${kit?.id ?? "?"}"`;
|
|
675
|
+
try {
|
|
676
|
+
if (!plain(kit) || Object.keys(kit).some((key) => !["id", "label", "locales", "zones"].includes(key))) throw new Error("expected { id, label, locales?, zones }");
|
|
677
|
+
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');
|
|
678
|
+
if (!fieldText(kit.label, 60)) throw new Error('label must be a string of 1 to 60 characters, or { "<locale>": string }');
|
|
679
|
+
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");
|
|
680
|
+
if (!plain(kit.zones) || !Object.keys(kit.zones).length) throw new Error("zones must be a non-empty object");
|
|
681
|
+
const zones = {};
|
|
682
|
+
for (const [zoneName, rows] of Object.entries(kit.zones)) {
|
|
683
|
+
const zone = type.attributes?.[zoneName];
|
|
684
|
+
if (zone?.type !== "dynamiczone") throw new Error(`unknown Dynamic Zone "${zoneName}"`);
|
|
685
|
+
if (!Array.isArray(rows) || !rows.length || rows.length > 50) throw new Error(`${zoneName} must contain 1 to 50 rows`);
|
|
686
|
+
const clean = [];
|
|
687
|
+
for (let index = 0; index < rows.length; index++) {
|
|
688
|
+
const row = rows[index];
|
|
689
|
+
if (!plain(row) || !text(row.__component)) throw new Error(`${zoneName}[${index}] must have __component`);
|
|
690
|
+
const component = row.__component;
|
|
691
|
+
if (!zone.components?.includes(component) || !schemas[component]) throw new Error(`${zoneName}[${index}]: component "${component}" is not allowed`);
|
|
692
|
+
const skipped = [];
|
|
693
|
+
const values = variantValues(row, schemas[component], schemas, `${zoneName}[${index}]`, skipped);
|
|
694
|
+
if (skipped.length) notes.push(`${name}: media and relation values are not inserted (${skipped.slice(0, 5).join(", ")}${skipped.length > 5 ? ", ..." : ""})`);
|
|
695
|
+
const media = [], required = [];
|
|
696
|
+
requiredProblems(schemas[component], values, schemas, `${zoneName}[${index}]`, media, required);
|
|
697
|
+
if (required.length) throw new Error(required.slice(0, 5).join("; "));
|
|
698
|
+
if (media.length) notes.push(`${name}: required media or relations must be completed before publishing (${media.slice(0, 5).join(", ")}${media.length > 5 ? ", ..." : ""})`);
|
|
699
|
+
clean.push({ __component: component, values });
|
|
700
|
+
const close = groups?.[component];
|
|
701
|
+
if (close) {
|
|
702
|
+
if (!zone.components?.includes(close) || !schemas[close]) throw new Error(`${zoneName}[${index}]: close component "${close}" is not allowed`);
|
|
703
|
+
clean.push({ __component: close, values: {} });
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
if (clean.length > (zone.max ?? Infinity)) throw new Error(`${zoneName} exceeds its maximum of ${zone.max}`);
|
|
707
|
+
zones[zoneName] = clean;
|
|
708
|
+
}
|
|
709
|
+
for (const [zoneName, zone] of Object.entries(type.attributes || {})) {
|
|
710
|
+
if (zone?.type !== "dynamiczone") continue;
|
|
711
|
+
const minimum = Math.max(zone.min ?? 0, zone.required ? 1 : 0);
|
|
712
|
+
if ((zones[zoneName]?.length || 0) < minimum) throw new Error(`${zoneName} requires at least ${minimum} row${minimum === 1 ? "" : "s"}`);
|
|
713
|
+
}
|
|
714
|
+
ids.add(kit.id);
|
|
715
|
+
(out[uid] ||= []).push({ id: kit.id, label: structuredClone(kit.label), ...kit.locales && { locales: [...new Set(kit.locales)] }, zones });
|
|
716
|
+
} catch (error) {
|
|
717
|
+
notes.push(`${name} ignored: ${error.message}`);
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
return out;
|
|
722
|
+
}
|
|
622
723
|
var PREFS = { starred: 200, recent: 20 };
|
|
623
724
|
function validatePrefs2(input, componentUids2) {
|
|
624
725
|
if (!input || typeof input !== "object" || Array.isArray(input)) fail2("Preferences must be an object");
|
|
@@ -631,7 +732,7 @@ var require_settings = __commonJS({
|
|
|
631
732
|
return out;
|
|
632
733
|
}
|
|
633
734
|
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) : []]));
|
|
634
|
-
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 };
|
|
735
|
+
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, validateKits: validateKits2, schemaMetadata: schemaMetadata2, mergeSaved: mergeSaved2, layer: layer2, overrides: overrides2, safeUrl: safeUrl2, fail: fail2 };
|
|
635
736
|
}
|
|
636
737
|
});
|
|
637
738
|
|
|
@@ -821,8 +922,8 @@ var require_diff = __commonJS({
|
|
|
821
922
|
}
|
|
822
923
|
function summarize(before, after, schema) {
|
|
823
924
|
const zones = Object.entries(schema?.attributes || {}).filter(([, attr]) => attr?.type === "dynamiczone").map(([name]) => name);
|
|
824
|
-
const blocks = { added: 0, removed: 0, changed: 0 };
|
|
825
|
-
if (!before) return { initial: true, fields: [], blocks };
|
|
925
|
+
const blocks = { total: zones.reduce((n, name) => n + (Array.isArray(after?.[name]) ? after[name].length : 0), 0), added: 0, removed: 0, changed: 0 };
|
|
926
|
+
if (!before) return { initial: true, fields: [], blocks: { ...blocks, added: blocks.total } };
|
|
826
927
|
const names = [.../* @__PURE__ */ new Set([...Object.keys(before), ...Object.keys(after || {})])];
|
|
827
928
|
const fields = names.filter((name) => !zones.includes(name) && !same(before[name], after?.[name])).sort();
|
|
828
929
|
for (const name of zones) for (const { op } of diffRows(before[name], after?.[name])) if (op !== "same") blocks[op]++;
|
|
@@ -1293,7 +1394,6 @@ var require_history = __commonJS({
|
|
|
1293
1394
|
var CRON2 = "blocksceneHistoryPurge";
|
|
1294
1395
|
var BATCH = 500;
|
|
1295
1396
|
var DAY = 24 * 60 * 60 * 1e3;
|
|
1296
|
-
var LIST_LIMIT = 100;
|
|
1297
1397
|
var ACTORS_LIMIT = 500;
|
|
1298
1398
|
var SEARCH_LIMIT = 200;
|
|
1299
1399
|
var eventContentType2 = { schema: {
|
|
@@ -1436,14 +1536,23 @@ var require_history = __commonJS({
|
|
|
1436
1536
|
return name && name !== "id" && schemaOf(uid)?.attributes?.[name] && !["relation", "media", "component", "dynamiczone", "password", "json", "blocks"].includes(schemaOf(uid).attributes[name].type) ? name : null;
|
|
1437
1537
|
},
|
|
1438
1538
|
// Latest events of one document and locale, newest first; `stored`: its snapshot (or an identical one) can be loaded.
|
|
1439
|
-
async list({ uid, documentId, locale }) {
|
|
1440
|
-
const
|
|
1441
|
-
const
|
|
1442
|
-
|
|
1443
|
-
events().findMany({ select: ["hash"], where: {
|
|
1539
|
+
async list({ uid, documentId, locale, actor = "", page = 1, pageSize = 25 }) {
|
|
1540
|
+
const scope2 = { contentType: uid, relatedDocumentId: documentId, locale: locale || null };
|
|
1541
|
+
const where = { ...scope2, ...actor && { actor } };
|
|
1542
|
+
const [list, kept, total, people] = await Promise.all([
|
|
1543
|
+
events().findMany({ select: ["id", "action", "actor", "actorName", "at", "summary", "hash", "size"], where, orderBy: [{ at: "desc" }, { id: "desc" }], offset: (page - 1) * pageSize, limit: pageSize }),
|
|
1544
|
+
events().findMany({ select: ["hash"], where: { ...scope2, size: { $gt: 0 } } }),
|
|
1545
|
+
events().count({ where }),
|
|
1546
|
+
events().findMany({ select: ["actor", "actorName"], where: scope2, orderBy: [{ at: "desc" }, { id: "desc" }] })
|
|
1444
1547
|
]);
|
|
1445
1548
|
const hashes = new Set(kept.map((row) => row.hash));
|
|
1446
|
-
|
|
1549
|
+
const actors2 = [...new Map(people.slice().reverse().map(({ actor: actor2, actorName }) => [actor2, { actor: actor2, actorName }])).values()];
|
|
1550
|
+
return {
|
|
1551
|
+
results: list.map(({ hash, size, ...event }) => ({ ...event, stored: Boolean(hash && hashes.has(hash)) })),
|
|
1552
|
+
pagination: { page, pageSize, total, pageCount: Math.ceil(total / pageSize) },
|
|
1553
|
+
actors: actors2,
|
|
1554
|
+
locale: locale || null
|
|
1555
|
+
};
|
|
1447
1556
|
},
|
|
1448
1557
|
// One event with its snapshot (from an identical event when this one was deduplicated) and what loading it needs:
|
|
1449
1558
|
// the media files and relation targets that still exist (relation labels from the Content Manager's main field).
|
|
@@ -1655,10 +1764,13 @@ var require_history = __commonJS({
|
|
|
1655
1764
|
async list(ctx) {
|
|
1656
1765
|
const { uid, documentId } = ctx.params || {};
|
|
1657
1766
|
const locale = ctx.query?.locale || "";
|
|
1658
|
-
|
|
1767
|
+
const actor = ctx.query?.actor || "";
|
|
1768
|
+
const page = int(ctx.query?.page, 1, 1e6), pageSize = int(ctx.query?.pageSize, 25, 100);
|
|
1769
|
+
if (typeof actor !== "string" || actor && !ACTOR.test(actor) || [page, pageSize].some(Number.isNaN)) return ctx.badRequest("Invalid history filters");
|
|
1770
|
+
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");
|
|
1659
1771
|
if (!canRead(strapi, ctx, uid)) return ctx.forbidden();
|
|
1660
1772
|
const history = strapi.plugin(PLUGIN2).service("history");
|
|
1661
|
-
ctx.body =
|
|
1773
|
+
ctx.body = await history.list({ uid, documentId, locale: (await history.scope(uid, locale || void 0))[0], actor, page, pageSize });
|
|
1662
1774
|
},
|
|
1663
1775
|
async find(ctx) {
|
|
1664
1776
|
const id = Number(ctx.params?.id);
|
|
@@ -1685,8 +1797,8 @@ var require_history = __commonJS({
|
|
|
1685
1797
|
});
|
|
1686
1798
|
|
|
1687
1799
|
// server/index.js
|
|
1688
|
-
var { PLUGIN, TEMPLATES, TYPOLOGIES, DEFAULTS, catalog, validateSettings, validateFields, validateVariants, schemaMetadata, mergeSaved, layer, overrides, validatePrefs, mergePrefs, safeUrl, fail } = require_settings();
|
|
1689
|
-
var { safeGroups, validateGroups, layoutFields } = require_groups();
|
|
1800
|
+
var { PLUGIN, TEMPLATES, TYPOLOGIES, DEFAULTS, catalog, validateSettings, validateFields, validateVariants, validateKits, schemaMetadata, mergeSaved, layer, overrides, validatePrefs, mergePrefs, safeUrl, fail } = require_settings();
|
|
1801
|
+
var { safeGroups, validateGroups, invalidComponents, layoutFields } = require_groups();
|
|
1690
1802
|
var { hiddenName, injectHidden, hideFromBuilder, registerHiddenStrip } = require_hidden();
|
|
1691
1803
|
var { CRON, covers, eventContentType, historyService, historyController, registerHistory, registerPurge } = require_history();
|
|
1692
1804
|
var { trashContentType, trashService, trashController } = require_trash();
|
|
@@ -1719,6 +1831,18 @@ var contentTypeUids = (strapi) => Object.fromEntries(Object.entries(strapi.conte
|
|
|
1719
1831
|
var apiUids = (strapi) => Object.keys(strapi.contentTypes || {}).filter((uid) => uid.startsWith("api::"));
|
|
1720
1832
|
var zonesOf = (schema) => Object.entries(schema?.attributes || {}).filter(([, attr]) => attr?.type === "dynamiczone").map(([name]) => name);
|
|
1721
1833
|
var label = (error) => `row ${error.index + 1}: ${error.code === "closeBeforeOpen" ? `close marker ${error.uid} has no open marker before it` : error.code === "mismatch" ? `close marker ${error.uid} does not match the open group ${error.open} (expected ${error.expected})` : `group ${error.uid} is not closed (expected ${error.expected})`}`;
|
|
1834
|
+
var componentLabel = (error) => `row ${error.index + 1}: component "${error.uid}" is not allowed in this Dynamic Zone`;
|
|
1835
|
+
function checkComponents(strapi, uid, entry) {
|
|
1836
|
+
const schema = strapi.getModel(uid);
|
|
1837
|
+
for (const name of zonesOf(schema)) {
|
|
1838
|
+
if (!Array.isArray(entry?.[name])) continue;
|
|
1839
|
+
const errors = invalidComponents(entry[name], schema.attributes[name].components);
|
|
1840
|
+
if (errors.length) fail(
|
|
1841
|
+
`Block components in "${name}" are not allowed by its schema (${errors.map(componentLabel).join("; ")}).`,
|
|
1842
|
+
{ plugin: PLUGIN, field: name, errors: errors.map((error) => ({ path: [name, error.index], message: componentLabel(error), name: "ValidationError", code: "componentNotAllowed", uid: error.uid })) }
|
|
1843
|
+
);
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1722
1846
|
function checkZones(strapi, uid, entry, groups) {
|
|
1723
1847
|
for (const name of zonesOf(strapi.getModel(uid))) {
|
|
1724
1848
|
const errors = validateGroups(Array.isArray(entry?.[name]) ? entry[name] : [], groups);
|
|
@@ -1728,11 +1852,10 @@ function checkZones(strapi, uid, entry, groups) {
|
|
|
1728
1852
|
);
|
|
1729
1853
|
}
|
|
1730
1854
|
}
|
|
1731
|
-
function
|
|
1855
|
+
function registerZoneGuards(strapi) {
|
|
1732
1856
|
const plugin = strapi.plugin(PLUGIN);
|
|
1733
1857
|
const groups = safeGroups(plugin.config("groups"), componentUids(strapi));
|
|
1734
1858
|
if (plugin.config("groups") && !groups) strapi.log.warn(`[${PLUGIN}] "groups" config ignored: expected { "<open component uid>": "<close component uid>" } with existing components; every block is treated as ordinary.`);
|
|
1735
|
-
if (!groups) return;
|
|
1736
1859
|
const active = async (uid) => {
|
|
1737
1860
|
if (plugin.config("disabled") === true) return false;
|
|
1738
1861
|
const settings = await plugin.service("settings").get();
|
|
@@ -1749,12 +1872,14 @@ function registerPublishGuard(strapi) {
|
|
|
1749
1872
|
strapi.documents.use(async (ctx, next) => {
|
|
1750
1873
|
const { action, params = {} } = ctx;
|
|
1751
1874
|
const publishing = action === "publish" || (action === "create" || action === "update") && params.status === "published";
|
|
1752
|
-
if (!
|
|
1875
|
+
if (!ctx.uid || !["create", "update", "publish"].includes(action)) return next();
|
|
1753
1876
|
const model = strapi.getModel(ctx.uid);
|
|
1754
1877
|
const zones = zonesOf(model);
|
|
1755
1878
|
if (!zones.length || !await active(ctx.uid)) return next();
|
|
1879
|
+
if (action === "create" || action === "update") checkComponents(strapi, ctx.uid, params.data || {});
|
|
1880
|
+
if (!publishing) return next();
|
|
1756
1881
|
if (action === "create") {
|
|
1757
|
-
checkZones(strapi, ctx.uid, params.data || {}, groups);
|
|
1882
|
+
if (groups) checkZones(strapi, ctx.uid, params.data || {}, groups);
|
|
1758
1883
|
return next();
|
|
1759
1884
|
}
|
|
1760
1885
|
const populate = Object.fromEntries(zones.map((name) => [name, true]));
|
|
@@ -1769,7 +1894,8 @@ function registerPublishGuard(strapi) {
|
|
|
1769
1894
|
}
|
|
1770
1895
|
for (const draft of drafts) {
|
|
1771
1896
|
const entry = action === "update" ? { ...draft || {}, ...Object.fromEntries(zones.filter((name) => Array.isArray(params.data?.[name])).map((name) => [name, params.data[name]])) } : draft;
|
|
1772
|
-
|
|
1897
|
+
checkComponents(strapi, ctx.uid, entry);
|
|
1898
|
+
if (groups) checkZones(strapi, ctx.uid, entry, groups);
|
|
1773
1899
|
}
|
|
1774
1900
|
return next();
|
|
1775
1901
|
});
|
|
@@ -1778,20 +1904,31 @@ function registerPublishGuard(strapi) {
|
|
|
1778
1904
|
const published = (data) => Boolean(data && data.publishedAt);
|
|
1779
1905
|
strapi.db.lifecycles.subscribe({
|
|
1780
1906
|
async beforeCreate(event) {
|
|
1781
|
-
|
|
1907
|
+
const data = event.params?.data, uid = event.model.uid;
|
|
1908
|
+
if (!zonesOf(strapi.getModel(uid)).length || !await active(uid)) return;
|
|
1909
|
+
checkComponents(strapi, uid, data || {});
|
|
1910
|
+
if (groups && published(data)) checkZones(strapi, uid, data, groups);
|
|
1782
1911
|
},
|
|
1783
1912
|
async beforeUpdate(event) {
|
|
1784
1913
|
const { data, where } = event.params || {};
|
|
1785
1914
|
const zones = zonesOf(strapi.getModel(event.model.uid));
|
|
1786
|
-
if (!
|
|
1915
|
+
if (!zones.length || !await active(event.model.uid)) return;
|
|
1916
|
+
checkComponents(strapi, event.model.uid, data || {});
|
|
1917
|
+
if (!published(data)) return;
|
|
1787
1918
|
const entry = zones.every((name) => Array.isArray(data[name])) ? data : { ...await strapi.entityService.findOne(event.model.uid, where?.id, { populate: zones }), ...data };
|
|
1788
|
-
|
|
1919
|
+
checkComponents(strapi, event.model.uid, entry);
|
|
1920
|
+
if (groups) checkZones(strapi, event.model.uid, entry, groups);
|
|
1789
1921
|
},
|
|
1790
1922
|
async beforeUpdateMany(event) {
|
|
1791
1923
|
const { data, where } = event.params || {};
|
|
1792
1924
|
const zones = zonesOf(strapi.getModel(event.model.uid));
|
|
1793
|
-
if (!
|
|
1794
|
-
|
|
1925
|
+
if (!zones.length || !await active(event.model.uid)) return;
|
|
1926
|
+
checkComponents(strapi, event.model.uid, data || {});
|
|
1927
|
+
if (!published(data)) return;
|
|
1928
|
+
for (const entry of await strapi.entityService.findMany(event.model.uid, { filters: where, populate: zones })) {
|
|
1929
|
+
checkComponents(strapi, event.model.uid, entry);
|
|
1930
|
+
if (groups) checkZones(strapi, event.model.uid, entry, groups);
|
|
1931
|
+
}
|
|
1795
1932
|
}
|
|
1796
1933
|
});
|
|
1797
1934
|
}
|
|
@@ -1812,6 +1949,8 @@ module.exports = {
|
|
|
1812
1949
|
settings: null,
|
|
1813
1950
|
// Edit view field texts from code (never stored): { uid: { attribute: { label, description, placeholder } } }. See README "Field labels".
|
|
1814
1951
|
fields: null,
|
|
1952
|
+
// Initial block sets per content type, shown only on a new empty entry. See README "Starter kits".
|
|
1953
|
+
kits: null,
|
|
1815
1954
|
// Other languages for the schema metadata (pluginOptions.blockscene, info.description), one flat map per locale:
|
|
1816
1955
|
// { 'pt-BR': require('./blockscene/pt-BR.json') }. See README "Describing blocks and fields in the schema".
|
|
1817
1956
|
translations: null,
|
|
@@ -1846,7 +1985,8 @@ module.exports = {
|
|
|
1846
1985
|
strapi.plugin(PLUGIN).service("settings").projectDefaults();
|
|
1847
1986
|
strapi.plugin(PLUGIN).service("settings").fields();
|
|
1848
1987
|
strapi.plugin(PLUGIN).service("settings").variants();
|
|
1849
|
-
|
|
1988
|
+
strapi.plugin(PLUGIN).service("settings").kits();
|
|
1989
|
+
registerZoneGuards(strapi);
|
|
1850
1990
|
registerHiddenStrip(strapi, hiddenName(strapi.plugin(PLUGIN).config("hiddenAttribute")), strapi.plugin(PLUGIN));
|
|
1851
1991
|
if (withHidden.length) hideFromBuilder(typeof strapi.get === "function" ? strapi.get("services") : strapi.container.get("services"), withHidden, hiddenName(strapi.plugin(PLUGIN).config("hiddenAttribute")));
|
|
1852
1992
|
if (STRAPI5) {
|
|
@@ -1904,6 +2044,14 @@ module.exports = {
|
|
|
1904
2044
|
for (const note of notes) strapi.log?.warn(`[${PLUGIN}] components variants: ${note}.`);
|
|
1905
2045
|
return variants;
|
|
1906
2046
|
};
|
|
2047
|
+
let kits;
|
|
2048
|
+
const starterKits = () => {
|
|
2049
|
+
if (kits !== void 0) return kits;
|
|
2050
|
+
const notes = [];
|
|
2051
|
+
kits = validateKits(strapi.plugin(PLUGIN).config("kits"), strapi.contentTypes || {}, strapi.components || {}, safeGroups(strapi.plugin(PLUGIN).config("groups"), componentUids(strapi)), notes);
|
|
2052
|
+
for (const note of notes) strapi.log?.warn(`[${PLUGIN}] starter kits: ${note}.`);
|
|
2053
|
+
return kits;
|
|
2054
|
+
};
|
|
1907
2055
|
const get = async () => mergeSaved(layer(projectDefaults(), await readSettings(strapi)), componentUids(strapi), contentTypeUids(strapi), apiUids(strapi), strapi.components);
|
|
1908
2056
|
return {
|
|
1909
2057
|
projectDefaults,
|
|
@@ -1911,6 +2059,7 @@ module.exports = {
|
|
|
1911
2059
|
fields: fieldTexts,
|
|
1912
2060
|
schema: schemaMeta,
|
|
1913
2061
|
variants: insertVariants,
|
|
2062
|
+
kits: starterKits,
|
|
1914
2063
|
async set(value) {
|
|
1915
2064
|
const next = validateSettings(value, componentUids(strapi), contentTypeUids(strapi), apiUids(strapi), strapi.components);
|
|
1916
2065
|
for (const [uid, entry] of Object.entries(next.components)) {
|
|
@@ -1961,6 +2110,7 @@ module.exports = {
|
|
|
1961
2110
|
ctx.body = {
|
|
1962
2111
|
...base,
|
|
1963
2112
|
layouts,
|
|
2113
|
+
kits: plugin.service("settings").kits(),
|
|
1964
2114
|
palette: settings.palette,
|
|
1965
2115
|
contentTypes: settings.contentTypes,
|
|
1966
2116
|
hiddenAttribute: hidden,
|
package/package.json
CHANGED