@aduptive/strapi-blockscene 1.0.0-alpha.10 → 1.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 +111 -18
- package/dist/admin.cjs +1073 -298
- package/dist/admin.mjs +1073 -298
- package/dist/server.cjs +180 -18
- 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: {
|
|
@@ -1343,6 +1460,18 @@ var require_history = __commonJS({
|
|
|
1343
1460
|
var hashOf = (text) => createHash("sha256").update(text).digest("hex");
|
|
1344
1461
|
var covers2 = (history, uid) => Boolean(history?.enabled) && uid.startsWith("api::") && (history.contentTypes === "all" || Array.isArray(history.contentTypes) && history.contentTypes.includes(uid));
|
|
1345
1462
|
var retention = ({ retentionDays, eventDays }, now = Date.now()) => ({ snapshotsBefore: new Date(now - retentionDays * DAY), eventsBefore: new Date(now - eventDays * DAY) });
|
|
1463
|
+
var hasChanges = (summary) => Boolean(summary?.initial || summary?.fields?.length || ["added", "removed", "changed"].some((key) => summary?.blocks?.[key] > 0));
|
|
1464
|
+
function collapseVersions(events) {
|
|
1465
|
+
const versions = [];
|
|
1466
|
+
for (const event of events) {
|
|
1467
|
+
const previous = versions[versions.length - 1];
|
|
1468
|
+
if (event.hash && previous?.hash === event.hash) {
|
|
1469
|
+
if (!previous.actions.includes(event.action)) previous.actions.push(event.action);
|
|
1470
|
+
if (!hasChanges(previous.summary) && hasChanges(event.summary)) previous.summary = event.summary;
|
|
1471
|
+
} else versions.push({ ...event, actions: [event.action] });
|
|
1472
|
+
}
|
|
1473
|
+
return versions;
|
|
1474
|
+
}
|
|
1346
1475
|
function actorOf(strapi) {
|
|
1347
1476
|
let ctx;
|
|
1348
1477
|
try {
|
|
@@ -1441,14 +1570,25 @@ var require_history = __commonJS({
|
|
|
1441
1570
|
return name && name !== "id" && schemaOf(uid)?.attributes?.[name] && !["relation", "media", "component", "dynamiczone", "password", "json", "blocks"].includes(schemaOf(uid).attributes[name].type) ? name : null;
|
|
1442
1571
|
},
|
|
1443
1572
|
// 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: {
|
|
1573
|
+
async list({ uid, documentId, locale, actor = "", page = 1, pageSize = 25 }) {
|
|
1574
|
+
const scope2 = { contentType: uid, relatedDocumentId: documentId, locale: locale || null };
|
|
1575
|
+
const where = { ...scope2, ...actor && { actor } };
|
|
1576
|
+
const [timeline, kept, people] = await Promise.all([
|
|
1577
|
+
events().findMany({ select: ["id", "action", "actor", "actorName", "at", "summary", "hash", "size"], where, orderBy: [{ at: "desc" }, { id: "desc" }] }),
|
|
1578
|
+
events().findMany({ select: ["hash"], where: { ...scope2, size: { $gt: 0 } } }),
|
|
1579
|
+
events().findMany({ select: ["actor", "actorName"], where: scope2, orderBy: [{ at: "desc" }, { id: "desc" }] })
|
|
1449
1580
|
]);
|
|
1581
|
+
const versions = collapseVersions(timeline);
|
|
1582
|
+
const total = versions.length;
|
|
1583
|
+
const list = versions.slice((page - 1) * pageSize, page * pageSize);
|
|
1450
1584
|
const hashes = new Set(kept.map((row) => row.hash));
|
|
1451
|
-
|
|
1585
|
+
const actors2 = [...new Map(people.slice().reverse().map(({ actor: actor2, actorName }) => [actor2, { actor: actor2, actorName }])).values()];
|
|
1586
|
+
return {
|
|
1587
|
+
results: list.map(({ hash, size, ...event }) => ({ ...event, stored: Boolean(hash && hashes.has(hash)) })),
|
|
1588
|
+
pagination: { page, pageSize, total, pageCount: Math.ceil(total / pageSize) },
|
|
1589
|
+
actors: actors2,
|
|
1590
|
+
locale: locale || null
|
|
1591
|
+
};
|
|
1452
1592
|
},
|
|
1453
1593
|
// One event with its snapshot (from an identical event when this one was deduplicated) and what loading it needs:
|
|
1454
1594
|
// the media files and relation targets that still exist (relation labels from the Content Manager's main field).
|
|
@@ -1660,10 +1800,13 @@ var require_history = __commonJS({
|
|
|
1660
1800
|
async list(ctx) {
|
|
1661
1801
|
const { uid, documentId } = ctx.params || {};
|
|
1662
1802
|
const locale = ctx.query?.locale || "";
|
|
1663
|
-
|
|
1803
|
+
const actor = ctx.query?.actor || "";
|
|
1804
|
+
const page = int(ctx.query?.page, 1, 1e6), pageSize = int(ctx.query?.pageSize, 25, 100);
|
|
1805
|
+
if (typeof actor !== "string" || actor && !ACTOR.test(actor) || [page, pageSize].some(Number.isNaN)) return ctx.badRequest("Invalid history filters");
|
|
1806
|
+
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
1807
|
if (!canRead(strapi, ctx, uid)) return ctx.forbidden();
|
|
1665
1808
|
const history = strapi.plugin(PLUGIN2).service("history");
|
|
1666
|
-
ctx.body =
|
|
1809
|
+
ctx.body = await history.list({ uid, documentId, locale: (await history.scope(uid, locale || void 0))[0], actor, page, pageSize });
|
|
1667
1810
|
},
|
|
1668
1811
|
async find(ctx) {
|
|
1669
1812
|
const id = Number(ctx.params?.id);
|
|
@@ -1685,12 +1828,12 @@ var require_history = __commonJS({
|
|
|
1685
1828
|
};
|
|
1686
1829
|
}
|
|
1687
1830
|
});
|
|
1688
|
-
module2.exports = { EVENT_UID, ACTIONS, CAPTURED, CRON: CRON2, BATCH, eventContentType: eventContentType2, covers: covers2, retention, actorOf, refsOf, can, readableTypes, historyService: historyService2, registerHistory: registerHistory2, registerPurge: registerPurge2, historyController: historyController2 };
|
|
1831
|
+
module2.exports = { EVENT_UID, ACTIONS, CAPTURED, CRON: CRON2, BATCH, eventContentType: eventContentType2, covers: covers2, retention, actorOf, refsOf, collapseVersions, can, readableTypes, historyService: historyService2, registerHistory: registerHistory2, registerPurge: registerPurge2, historyController: historyController2 };
|
|
1689
1832
|
}
|
|
1690
1833
|
});
|
|
1691
1834
|
|
|
1692
1835
|
// server/index.js
|
|
1693
|
-
var { PLUGIN, TEMPLATES, TYPOLOGIES, DEFAULTS, catalog, validateSettings, validateFields, validateVariants, schemaMetadata, mergeSaved, layer, overrides, validatePrefs, mergePrefs, safeUrl, fail } = require_settings();
|
|
1836
|
+
var { PLUGIN, TEMPLATES, TYPOLOGIES, DEFAULTS, catalog, settingsComponentUids, safeComponentCategories, validateSettings, validateFields, validateVariants, validateKits, schemaMetadata, mergeSaved, layer, overrides, validatePrefs, mergePrefs, safeUrl, fail } = require_settings();
|
|
1694
1837
|
var { safeGroups, validateGroups, invalidComponents, layoutFields } = require_groups();
|
|
1695
1838
|
var { hiddenName, injectHidden, hideFromBuilder, registerHiddenStrip } = require_hidden();
|
|
1696
1839
|
var { CRON, covers, eventContentType, historyService, historyController, registerHistory, registerPurge } = require_history();
|
|
@@ -1838,10 +1981,15 @@ module.exports = {
|
|
|
1838
1981
|
// Optional layout groups: OPEN component uid -> its CLOSE uid, e.g. { 'wrappers.join': 'wrappers.close' }.
|
|
1839
1982
|
// Empty/absent: every Dynamic Zone component is an ordinary block. See README "Layout groups".
|
|
1840
1983
|
groups: null,
|
|
1984
|
+
// Optional Strapi component categories shown as configurable cards in Settings > Block gallery.
|
|
1985
|
+
// This does not change the components allowed by each Dynamic Zone.
|
|
1986
|
+
settingsComponentCategories: null,
|
|
1841
1987
|
// Project defaults from code: same shape as the stored settings, e.g. require('./blockscene.json'). See README "Settings page".
|
|
1842
1988
|
settings: null,
|
|
1843
1989
|
// Edit view field texts from code (never stored): { uid: { attribute: { label, description, placeholder } } }. See README "Field labels".
|
|
1844
1990
|
fields: null,
|
|
1991
|
+
// Initial block sets per content type, shown only on a new empty entry. See README "Starter kits".
|
|
1992
|
+
kits: null,
|
|
1845
1993
|
// Other languages for the schema metadata (pluginOptions.blockscene, info.description), one flat map per locale:
|
|
1846
1994
|
// { 'pt-BR': require('./blockscene/pt-BR.json') }. See README "Describing blocks and fields in the schema".
|
|
1847
1995
|
translations: null,
|
|
@@ -1856,6 +2004,7 @@ module.exports = {
|
|
|
1856
2004
|
const name = hiddenName(plugin.config("hiddenAttribute"));
|
|
1857
2005
|
withHidden = [];
|
|
1858
2006
|
if (name === null) strapi.log.warn(`[${PLUGIN}] "hiddenAttribute" config ignored: expected a name like "bsHidden" or false. Hiding blocks is off.`);
|
|
2007
|
+
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
2008
|
if (!name) return;
|
|
1860
2009
|
const { added, skipped } = injectHidden(strapi.components, strapi.contentTypes, name);
|
|
1861
2010
|
withHidden = added;
|
|
@@ -1876,6 +2025,7 @@ module.exports = {
|
|
|
1876
2025
|
strapi.plugin(PLUGIN).service("settings").projectDefaults();
|
|
1877
2026
|
strapi.plugin(PLUGIN).service("settings").fields();
|
|
1878
2027
|
strapi.plugin(PLUGIN).service("settings").variants();
|
|
2028
|
+
strapi.plugin(PLUGIN).service("settings").kits();
|
|
1879
2029
|
registerZoneGuards(strapi);
|
|
1880
2030
|
registerHiddenStrip(strapi, hiddenName(strapi.plugin(PLUGIN).config("hiddenAttribute")), strapi.plugin(PLUGIN));
|
|
1881
2031
|
if (withHidden.length) hideFromBuilder(typeof strapi.get === "function" ? strapi.get("services") : strapi.container.get("services"), withHidden, hiddenName(strapi.plugin(PLUGIN).config("hiddenAttribute")));
|
|
@@ -1934,6 +2084,14 @@ module.exports = {
|
|
|
1934
2084
|
for (const note of notes) strapi.log?.warn(`[${PLUGIN}] components variants: ${note}.`);
|
|
1935
2085
|
return variants;
|
|
1936
2086
|
};
|
|
2087
|
+
let kits;
|
|
2088
|
+
const starterKits = () => {
|
|
2089
|
+
if (kits !== void 0) return kits;
|
|
2090
|
+
const notes = [];
|
|
2091
|
+
kits = validateKits(strapi.plugin(PLUGIN).config("kits"), strapi.contentTypes || {}, strapi.components || {}, safeGroups(strapi.plugin(PLUGIN).config("groups"), componentUids(strapi)), notes);
|
|
2092
|
+
for (const note of notes) strapi.log?.warn(`[${PLUGIN}] starter kits: ${note}.`);
|
|
2093
|
+
return kits;
|
|
2094
|
+
};
|
|
1937
2095
|
const get = async () => mergeSaved(layer(projectDefaults(), await readSettings(strapi)), componentUids(strapi), contentTypeUids(strapi), apiUids(strapi), strapi.components);
|
|
1938
2096
|
return {
|
|
1939
2097
|
projectDefaults,
|
|
@@ -1941,6 +2099,7 @@ module.exports = {
|
|
|
1941
2099
|
fields: fieldTexts,
|
|
1942
2100
|
schema: schemaMeta,
|
|
1943
2101
|
variants: insertVariants,
|
|
2102
|
+
kits: starterKits,
|
|
1944
2103
|
async set(value) {
|
|
1945
2104
|
const next = validateSettings(value, componentUids(strapi), contentTypeUids(strapi), apiUids(strapi), strapi.components);
|
|
1946
2105
|
for (const [uid, entry] of Object.entries(next.components)) {
|
|
@@ -1981,7 +2140,8 @@ module.exports = {
|
|
|
1981
2140
|
...media[uid],
|
|
1982
2141
|
template: entry.template,
|
|
1983
2142
|
...entry.typology && { typology: entry.typology },
|
|
1984
|
-
...entry.tags && { tags: entry.tags }
|
|
2143
|
+
...entry.tags && { tags: entry.tags },
|
|
2144
|
+
...typeof entry.showRowThumbnail === "boolean" && { showRowThumbnail: entry.showRowThumbnail }
|
|
1985
2145
|
};
|
|
1986
2146
|
}
|
|
1987
2147
|
const hidden = hiddenName(plugin.config("hiddenAttribute")) || null;
|
|
@@ -1991,6 +2151,7 @@ module.exports = {
|
|
|
1991
2151
|
ctx.body = {
|
|
1992
2152
|
...base,
|
|
1993
2153
|
layouts,
|
|
2154
|
+
kits: plugin.service("settings").kits(),
|
|
1994
2155
|
palette: settings.palette,
|
|
1995
2156
|
contentTypes: settings.contentTypes,
|
|
1996
2157
|
hiddenAttribute: hidden,
|
|
@@ -2005,7 +2166,8 @@ module.exports = {
|
|
|
2005
2166
|
async find(ctx) {
|
|
2006
2167
|
const settings = await strapi.plugin(PLUGIN).service("settings").get();
|
|
2007
2168
|
const auto = catalog({ components: strapi.plugin(PLUGIN).config("components"), schemas: strapi.components, blocks: strapi.plugin(PLUGIN).service("settings").schema().blocks }).components;
|
|
2008
|
-
const
|
|
2169
|
+
const visible = new Set(settingsComponentUids(strapi.contentTypes, strapi.components, settings.contentTypes, strapi.plugin(PLUGIN).config("settingsComponentCategories")));
|
|
2170
|
+
const components = Object.entries(strapi.components || {}).filter(([uid]) => visible.has(uid)).map(([uid, schema]) => ({
|
|
2009
2171
|
uid,
|
|
2010
2172
|
displayName: schema.info?.displayName || uid,
|
|
2011
2173
|
category: schema.category || uid.split(".")[0],
|
package/package.json
CHANGED