@blokkli/editor 2.0.0-alpha.46 → 2.0.0-alpha.47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/module.json +1 -1
- package/dist/module.mjs +2 -1
- package/dist/modules/agent/runtime/app/helpers/validation.d.ts +13 -0
- package/dist/modules/agent/runtime/app/helpers/validation.js +22 -0
- package/dist/modules/agent/runtime/app/tools/add_content_search_paragraph/index.js +12 -0
- package/dist/modules/agent/runtime/app/tools/add_fragment/index.js +12 -1
- package/dist/modules/agent/runtime/app/tools/add_media_paragraph/index.js +12 -0
- package/dist/modules/agent/runtime/app/tools/add_paragraphs/index.js +10 -0
- package/dist/modules/agent/runtime/app/tools/add_reusable_paragraph/index.js +12 -0
- package/dist/modules/agent/runtime/app/tools/add_template/index.js +5 -0
- package/dist/modules/agent/runtime/app/tools/delegate_text_rewrite/index.js +15 -0
- package/dist/modules/agent/runtime/app/tools/delete_paragraphs/index.js +12 -0
- package/dist/modules/agent/runtime/app/tools/detach_reusable_paragraph/index.js +12 -0
- package/dist/modules/agent/runtime/app/tools/duplicate_paragraphs/index.js +16 -1
- package/dist/modules/agent/runtime/app/tools/move_paragraphs/index.js +17 -0
- package/dist/modules/agent/runtime/app/tools/rearrange_paragraphs/index.js +11 -0
- package/dist/modules/agent/runtime/app/tools/replace_content_search_item/index.js +8 -0
- package/dist/modules/agent/runtime/app/tools/replace_media_field/index.js +10 -0
- package/dist/modules/agent/runtime/app/tools/set_paragraph_options/index.js +10 -0
- package/dist/modules/agent/runtime/app/tools/swap_paragraphs/index.js +15 -0
- package/dist/modules/agent/runtime/app/tools/update_text_fields/index.js +21 -1
- package/dist/modules/agent/runtime/app/types/index.d.ts +6 -6
- package/dist/modules/drupal/index.mjs +2 -1
- package/dist/modules/drupal/runtime/adapter/index.js +15 -3
- package/dist/runtime/editor/components/Actions/index.vue +47 -2
- package/dist/runtime/editor/components/AnimationCanvas/index.vue +6 -3
- package/dist/runtime/editor/components/BundleSelector/index.d.vue.ts +8 -4
- package/dist/runtime/editor/components/BundleSelector/index.vue +111 -13
- package/dist/runtime/editor/components/BundleSelector/index.vue.d.ts +8 -4
- package/dist/runtime/editor/components/EditProvider.vue +2 -2
- package/dist/runtime/editor/components/FlexTextarea/index.vue +8 -1
- package/dist/runtime/editor/css/output.css +1 -1
- package/dist/runtime/editor/features/add-list/Blocks/index.vue +6 -3
- package/dist/runtime/editor/features/analyze/Renderer/index.vue +1 -1
- package/dist/runtime/editor/features/block-scheduler/index.vue +7 -1
- package/dist/runtime/editor/features/changelog/Dialog/index.vue +1 -1
- package/dist/runtime/editor/features/changelog/changelog.json +18 -10
- package/dist/runtime/editor/features/clipboard/index.vue +6 -1
- package/dist/runtime/editor/features/comments/AddForm/index.d.vue.ts +2 -2
- package/dist/runtime/editor/features/comments/AddForm/index.vue.d.ts +2 -2
- package/dist/runtime/editor/features/delete/index.vue +17 -2
- package/dist/runtime/editor/features/dragging-overlay/Renderer/index.vue +12 -2
- package/dist/runtime/editor/features/dragging-overlay/index.vue +5 -2
- package/dist/runtime/editor/features/duplicate/index.vue +23 -7
- package/dist/runtime/editor/features/edit/index.vue +29 -8
- package/dist/runtime/editor/features/editable-field/index.vue +15 -1
- package/dist/runtime/editor/features/fragments/index.vue +5 -2
- package/dist/runtime/editor/features/hover/Renderer/index.vue +19 -6
- package/dist/runtime/editor/features/hover/Renderer/vertex.glsl +5 -2
- package/dist/runtime/editor/features/library/index.vue +52 -8
- package/dist/runtime/editor/features/media-library/index.vue +7 -2
- package/dist/runtime/editor/features/multi-select/Renderer/index.vue +4 -1
- package/dist/runtime/editor/features/search/index.vue +7 -2
- package/dist/runtime/editor/features/selection/AddButtons/Renderer/index.vue +1 -1
- package/dist/runtime/editor/features/selection/AddButtons/index.vue +26 -2
- package/dist/runtime/editor/features/selection/Renderer/index.vue +23 -5
- package/dist/runtime/editor/features/selection/Renderer/vertex.glsl +5 -2
- package/dist/runtime/editor/features/selection/index.vue +17 -5
- package/dist/runtime/editor/features/translations/index.vue +17 -11
- package/dist/runtime/editor/helpers/dropTargets/index.d.ts +1 -1
- package/dist/runtime/editor/helpers/dropTargets/index.js +2 -2
- package/dist/runtime/editor/plugins/ItemAction/index.d.vue.ts +4 -1
- package/dist/runtime/editor/plugins/ItemAction/index.vue +9 -3
- package/dist/runtime/editor/plugins/ItemAction/index.vue.d.ts +4 -1
- package/dist/runtime/editor/providers/permissions.d.ts +22 -1
- package/dist/runtime/editor/providers/permissions.js +99 -3
- package/dist/runtime/editor/providers/selection.d.ts +2 -1
- package/dist/runtime/editor/providers/selection.js +10 -5
- package/dist/runtime/editor/translations/de.json +89 -1
- package/dist/runtime/editor/translations/fr.json +89 -1
- package/dist/runtime/editor/translations/gsw_CH.json +89 -1
- package/dist/runtime/editor/translations/it.json +89 -1
- package/dist/runtime/editor/types/definitions.d.ts +2 -0
- package/package.json +1 -1
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -18,7 +18,7 @@ import 'typescript';
|
|
|
18
18
|
import 'oxc-walker';
|
|
19
19
|
|
|
20
20
|
const name = "@blokkli/editor";
|
|
21
|
-
const version = "2.0.0-alpha.
|
|
21
|
+
const version = "2.0.0-alpha.47";
|
|
22
22
|
|
|
23
23
|
function validateOption(optionKey, option, icons) {
|
|
24
24
|
const errors = [];
|
|
@@ -1468,6 +1468,7 @@ const USED_MATERIAL_ICONS = [
|
|
|
1468
1468
|
"bk_mdi_keyboard_arrow_down",
|
|
1469
1469
|
"bk_mdi_keyboard_command_key",
|
|
1470
1470
|
"bk_mdi_lists",
|
|
1471
|
+
"bk_mdi_lock",
|
|
1471
1472
|
"bk_mdi_logo_dev",
|
|
1472
1473
|
"bk_mdi_menu",
|
|
1473
1474
|
"bk_mdi_mobile",
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { BlokkliApp } from '#blokkli/editor/types/app';
|
|
2
2
|
import type { RenderedFieldListItem } from '#blokkli/editor/types/field';
|
|
3
|
+
import type { BlockPermission } from '#blokkli/editor/types/definitions';
|
|
4
|
+
import type { ToolError } from '../types/index.js';
|
|
3
5
|
type ValidationResult = {
|
|
4
6
|
valid: true;
|
|
5
7
|
} | {
|
|
@@ -32,4 +34,15 @@ export declare function validateFieldCardinality(app: BlokkliApp, host: Rendered
|
|
|
32
34
|
* Validate that all bundles are allowed in the field.
|
|
33
35
|
*/
|
|
34
36
|
export declare function validateBundlesAllowed(app: BlokkliApp, host: RenderedFieldListItem['host'], bundles: string[]): ValidationResult;
|
|
37
|
+
/**
|
|
38
|
+
* Check that none of the given blocks are inside a restricted ancestor.
|
|
39
|
+
* Returns a ToolError if any block has a restricted ancestor, or undefined if
|
|
40
|
+
* all are unrestricted.
|
|
41
|
+
*/
|
|
42
|
+
export declare function requireNoRestrictedAncestor(app: BlokkliApp, uuids: string[]): ToolError | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* Check that the user has a specific permission for all given bundles.
|
|
45
|
+
* Returns a ToolError if any bundle is denied, or undefined if all are allowed.
|
|
46
|
+
*/
|
|
47
|
+
export declare function requireBundlePermission(app: BlokkliApp, bundles: string[], operation: BlockPermission): ToolError | undefined;
|
|
35
48
|
export {};
|
|
@@ -75,3 +75,25 @@ export function validateBundlesAllowed(app, host, bundles) {
|
|
|
75
75
|
}
|
|
76
76
|
return { valid: true };
|
|
77
77
|
}
|
|
78
|
+
export function requireNoRestrictedAncestor(app, uuids) {
|
|
79
|
+
for (const uuid of uuids) {
|
|
80
|
+
if (app.permissions.blockHasRestrictedAncestor(uuid)) {
|
|
81
|
+
return {
|
|
82
|
+
error: "Permission denied: block is inside a parent with restricted editing permissions"
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return void 0;
|
|
87
|
+
}
|
|
88
|
+
export function requireBundlePermission(app, bundles, operation) {
|
|
89
|
+
const denied = app.permissions.filterDeniedBundles(bundles, operation);
|
|
90
|
+
if (denied.length > 0) {
|
|
91
|
+
const labels = denied.map(
|
|
92
|
+
(b) => app.types.getBlockBundleDefinition(b)?.label || b
|
|
93
|
+
);
|
|
94
|
+
return {
|
|
95
|
+
error: `Permission denied: cannot ${operation} ${labels.map((l) => `"${l}"`).join(", ")}`
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
return void 0;
|
|
99
|
+
}
|
|
@@ -2,6 +2,7 @@ import { z } from "zod";
|
|
|
2
2
|
import { defineBlokkliAgentTool } from "#blokkli/agent/app/composables";
|
|
3
3
|
import { mutationResultSchema, parentSchema, positionSchema } from "../schemas.js";
|
|
4
4
|
import { resolvePosition } from "../helpers.js";
|
|
5
|
+
import { requireBundlePermission } from "../../helpers/validation.js";
|
|
5
6
|
const paramsSchema = z.object({
|
|
6
7
|
itemId: z.string().describe("Content item ID from search_content results"),
|
|
7
8
|
itemEntityType: z.string().describe("Entity type of the content item"),
|
|
@@ -29,6 +30,17 @@ export default defineBlokkliAgentTool({
|
|
|
29
30
|
resultSchema: mutationResultSchema,
|
|
30
31
|
requiredAdapterMethods: ["addContentSearchItem"],
|
|
31
32
|
execute(ctx, params) {
|
|
33
|
+
const denied = requireBundlePermission(
|
|
34
|
+
ctx.app,
|
|
35
|
+
[params.targetBundle],
|
|
36
|
+
"add"
|
|
37
|
+
);
|
|
38
|
+
if (denied) return denied;
|
|
39
|
+
if (ctx.app.permissions.blockHasRestrictedAncestor(params.parent.uuid)) {
|
|
40
|
+
return {
|
|
41
|
+
error: "Permission denied: target parent is inside a block with restricted editing permissions"
|
|
42
|
+
};
|
|
43
|
+
}
|
|
32
44
|
const { $t, types } = ctx.app;
|
|
33
45
|
const item = {
|
|
34
46
|
id: params.itemId,
|
|
@@ -2,6 +2,7 @@ import { z } from "zod";
|
|
|
2
2
|
import { defineBlokkliAgentTool } from "#blokkli/agent/app/composables";
|
|
3
3
|
import { mutationResultSchema, parentSchema, positionSchema } from "../schemas.js";
|
|
4
4
|
import { resolvePosition } from "../helpers.js";
|
|
5
|
+
import { fragmentBlockBundle } from "#blokkli-build/config";
|
|
5
6
|
const paramsSchema = z.object({
|
|
6
7
|
name: z.string().describe("The fragment name to add"),
|
|
7
8
|
parent: parentSchema.describe("The parent entity to add the fragment to"),
|
|
@@ -21,7 +22,17 @@ export default defineBlokkliAgentTool({
|
|
|
21
22
|
resultSchema: mutationResultSchema,
|
|
22
23
|
requiredAdapterMethods: ["fragmentsAddBlock"],
|
|
23
24
|
execute(ctx, params) {
|
|
24
|
-
const { fields, definitions } = ctx.app;
|
|
25
|
+
const { fields, definitions, permissions } = ctx.app;
|
|
26
|
+
if (!permissions.checkBlockBundlePermission(fragmentBlockBundle, "add")) {
|
|
27
|
+
return {
|
|
28
|
+
error: "Permission denied: cannot add fragment blocks."
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
if (permissions.blockHasRestrictedAncestor(params.parent.uuid)) {
|
|
32
|
+
return {
|
|
33
|
+
error: "Permission denied: target parent is inside a block with restricted editing permissions"
|
|
34
|
+
};
|
|
35
|
+
}
|
|
25
36
|
const fragment = definitions.fragmentDefinitions.value.find(
|
|
26
37
|
(f) => f.name === params.name
|
|
27
38
|
);
|
|
@@ -2,6 +2,7 @@ import { z } from "zod";
|
|
|
2
2
|
import { defineBlokkliAgentTool } from "#blokkli/agent/app/composables";
|
|
3
3
|
import { mutationResultSchema, parentSchema, positionSchema } from "../schemas.js";
|
|
4
4
|
import { resolvePosition } from "../helpers.js";
|
|
5
|
+
import { requireBundlePermission } from "../../helpers/validation.js";
|
|
5
6
|
const paramsSchema = z.object({
|
|
6
7
|
mediaId: z.string().describe("Media item ID from search_media results"),
|
|
7
8
|
mediaBundle: z.string().describe('Media bundle type (e.g., "image")'),
|
|
@@ -25,6 +26,17 @@ export default defineBlokkliAgentTool({
|
|
|
25
26
|
resultSchema: mutationResultSchema,
|
|
26
27
|
requiredAdapterMethods: ["mediaLibraryAddBlock"],
|
|
27
28
|
execute(ctx, params) {
|
|
29
|
+
const denied = requireBundlePermission(
|
|
30
|
+
ctx.app,
|
|
31
|
+
[params.targetBundle],
|
|
32
|
+
"add"
|
|
33
|
+
);
|
|
34
|
+
if (denied) return denied;
|
|
35
|
+
if (ctx.app.permissions.blockHasRestrictedAncestor(params.parent.uuid)) {
|
|
36
|
+
return {
|
|
37
|
+
error: "Permission denied: target parent is inside a block with restricted editing permissions"
|
|
38
|
+
};
|
|
39
|
+
}
|
|
28
40
|
const { $t, types } = ctx.app;
|
|
29
41
|
const item = {
|
|
30
42
|
itemType: "media_library",
|
|
@@ -115,6 +115,9 @@ function validateBlockTree(ctx, blocks, allowedBundles, fieldLabel, pathPrefix)
|
|
|
115
115
|
if (allowedBundles.length && !allowedBundles.includes(block.bundle)) {
|
|
116
116
|
return `${path}: Bundle "${block.bundle}" is not allowed in field "${fieldLabel}". Allowed bundles: ${allowedBundles.join(", ")}`;
|
|
117
117
|
}
|
|
118
|
+
if (!ctx.app.permissions.checkBlockBundlePermission(block.bundle, "add")) {
|
|
119
|
+
return `${path}: Permission denied: cannot add "${bundleDefinition.label}" blocks.`;
|
|
120
|
+
}
|
|
118
121
|
const contentError = validateContentFields(ctx, block, path);
|
|
119
122
|
if (contentError) return contentError;
|
|
120
123
|
const optionsError = validateBlockOptions(ctx, block, path);
|
|
@@ -243,6 +246,13 @@ export default defineBlokkliAgentTool({
|
|
|
243
246
|
error: `Field "${params.parent.field}" not found on bundle "${bundle}". Available fields: ${availableFields.length ? availableFields.join(", ") : "none"}. Use get_child_paragraphs to get the correct parent object.`
|
|
244
247
|
};
|
|
245
248
|
}
|
|
249
|
+
if (!isRootEntity) {
|
|
250
|
+
if (ctx.app.permissions.blockHasRestrictedAncestor(params.parent.uuid)) {
|
|
251
|
+
return {
|
|
252
|
+
error: "Permission denied: target parent is inside a block with restricted editing permissions"
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
}
|
|
246
256
|
const validationError = validateBlockTree(
|
|
247
257
|
ctx,
|
|
248
258
|
params.paragraphs,
|
|
@@ -2,6 +2,7 @@ import { z } from "zod";
|
|
|
2
2
|
import { defineBlokkliAgentTool } from "#blokkli/agent/app/composables";
|
|
3
3
|
import { mutationResultSchema, parentSchema, positionSchema } from "../schemas.js";
|
|
4
4
|
import { resolvePosition } from "../helpers.js";
|
|
5
|
+
import { requireBundlePermission } from "../../helpers/validation.js";
|
|
5
6
|
import { fromLibraryBlockBundle, itemEntityType } from "#blokkli-build/config";
|
|
6
7
|
const paramsSchema = z.object({
|
|
7
8
|
libraryItemUuid: z.string().describe(
|
|
@@ -26,6 +27,17 @@ export default defineBlokkliAgentTool({
|
|
|
26
27
|
resultSchema: mutationResultSchema,
|
|
27
28
|
requiredAdapterMethods: ["addLibraryItem"],
|
|
28
29
|
execute(ctx, params) {
|
|
30
|
+
const denied = requireBundlePermission(
|
|
31
|
+
ctx.app,
|
|
32
|
+
[fromLibraryBlockBundle],
|
|
33
|
+
"add"
|
|
34
|
+
);
|
|
35
|
+
if (denied) return denied;
|
|
36
|
+
if (ctx.app.permissions.blockHasRestrictedAncestor(params.parent.uuid)) {
|
|
37
|
+
return {
|
|
38
|
+
error: "Permission denied: target parent is inside a block with restricted editing permissions"
|
|
39
|
+
};
|
|
40
|
+
}
|
|
29
41
|
const { types, fields, context, blocks, $t } = ctx.app;
|
|
30
42
|
const field = fields.find(params.parent.uuid, params.parent.field);
|
|
31
43
|
if (!field) {
|
|
@@ -24,6 +24,11 @@ export default defineBlokkliAgentTool({
|
|
|
24
24
|
requiredAdapterMethods: ["templatesAdd"],
|
|
25
25
|
execute(ctx, params) {
|
|
26
26
|
const { fields, $t } = ctx.app;
|
|
27
|
+
if (ctx.app.permissions.blockHasRestrictedAncestor(params.parent.uuid)) {
|
|
28
|
+
return {
|
|
29
|
+
error: "Permission denied: target parent is inside a block with restricted editing permissions"
|
|
30
|
+
};
|
|
31
|
+
}
|
|
27
32
|
const field = fields.find(params.parent.uuid, params.parent.field);
|
|
28
33
|
if (!field) {
|
|
29
34
|
return {
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { defineBlokkliAgentTool } from "#blokkli/agent/app/composables";
|
|
3
3
|
import { runReadabilityAnalysis } from "../helpers.js";
|
|
4
|
+
import {
|
|
5
|
+
requireBundlePermission,
|
|
6
|
+
requireNoRestrictedAncestor
|
|
7
|
+
} from "../../helpers/validation.js";
|
|
8
|
+
import { onlyUnique } from "#blokkli/helpers";
|
|
4
9
|
import Component from "./Component.vue";
|
|
5
10
|
import DetailsComponent from "./Details/index.vue";
|
|
6
11
|
const fieldSchema = z.object({
|
|
@@ -55,6 +60,16 @@ export default defineBlokkliAgentTool({
|
|
|
55
60
|
buildDetails: (result) => result,
|
|
56
61
|
async execute(ctx, params) {
|
|
57
62
|
const { blocks, context } = ctx.app;
|
|
63
|
+
const bundles = params.fields.map((f) => blocks.getBlock(f.uuid)?.bundle).filter((b) => !!b).filter(onlyUnique);
|
|
64
|
+
if (bundles.length) {
|
|
65
|
+
const denied = requireBundlePermission(ctx.app, bundles, "edit");
|
|
66
|
+
if (denied) return denied;
|
|
67
|
+
}
|
|
68
|
+
const blockUuids = params.fields.map((f) => f.uuid).filter((uuid) => uuid !== context.value.entityUuid).filter(onlyUnique);
|
|
69
|
+
if (blockUuids.length) {
|
|
70
|
+
const ancestorDenied = requireNoRestrictedAncestor(ctx.app, blockUuids);
|
|
71
|
+
if (ancestorDenied) return ancestorDenied;
|
|
72
|
+
}
|
|
58
73
|
const resolvedFields = [];
|
|
59
74
|
for (const { uuid, fieldName } of params.fields) {
|
|
60
75
|
let entityType;
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { defineBlokkliAgentTool } from "#blokkli/agent/app/composables";
|
|
3
3
|
import { mutationResultSchema } from "../schemas.js";
|
|
4
|
+
import {
|
|
5
|
+
requireBundlePermission,
|
|
6
|
+
requireNoRestrictedAncestor
|
|
7
|
+
} from "../../helpers/validation.js";
|
|
4
8
|
const paramsSchema = z.object({
|
|
5
9
|
uuids: z.array(z.string()).describe("The UUIDs of the paragraphs to delete")
|
|
6
10
|
});
|
|
@@ -30,6 +34,14 @@ export default defineBlokkliAgentTool({
|
|
|
30
34
|
}
|
|
31
35
|
validBlocks.push({ uuid, bundle: block.bundle });
|
|
32
36
|
}
|
|
37
|
+
const denied = requireBundlePermission(
|
|
38
|
+
ctx.app,
|
|
39
|
+
validBlocks.map((b) => b.bundle),
|
|
40
|
+
"delete"
|
|
41
|
+
);
|
|
42
|
+
if (denied) return denied;
|
|
43
|
+
const ancestorDenied = requireNoRestrictedAncestor(ctx.app, params.uuids);
|
|
44
|
+
if (ancestorDenied) return ancestorDenied;
|
|
33
45
|
const { $t } = ctx.app;
|
|
34
46
|
const firstBlock = validBlocks[0];
|
|
35
47
|
const label = validBlocks.length === 1 && firstBlock ? $t("aiAgentDeleteBlockDone", "Deleted @bundle").replace(
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { defineBlokkliAgentTool } from "#blokkli/agent/app/composables";
|
|
3
3
|
import { mutationResultSchema } from "../schemas.js";
|
|
4
|
+
import {
|
|
5
|
+
requireBundlePermission,
|
|
6
|
+
requireNoRestrictedAncestor
|
|
7
|
+
} from "../../helpers/validation.js";
|
|
4
8
|
import { fromLibraryBlockBundle } from "#blokkli-build/config";
|
|
5
9
|
const paramsSchema = z.object({
|
|
6
10
|
uuids: z.array(z.string()).describe("UUIDs of library paragraphs to detach")
|
|
@@ -23,6 +27,14 @@ export default defineBlokkliAgentTool({
|
|
|
23
27
|
if (params.uuids.length === 0) {
|
|
24
28
|
return { error: "No paragraph UUIDs provided" };
|
|
25
29
|
}
|
|
30
|
+
const denied = requireBundlePermission(
|
|
31
|
+
ctx.app,
|
|
32
|
+
[fromLibraryBlockBundle],
|
|
33
|
+
"edit"
|
|
34
|
+
);
|
|
35
|
+
if (denied) return denied;
|
|
36
|
+
const ancestorDenied = requireNoRestrictedAncestor(ctx.app, params.uuids);
|
|
37
|
+
if (ancestorDenied) return ancestorDenied;
|
|
26
38
|
for (const uuid of params.uuids) {
|
|
27
39
|
const block = blocks.getBlock(uuid);
|
|
28
40
|
if (!block) {
|
|
@@ -6,7 +6,9 @@ import {
|
|
|
6
6
|
validateBlocksExist,
|
|
7
7
|
validateSameField,
|
|
8
8
|
validateFieldCardinality,
|
|
9
|
-
validateBundlesAllowed
|
|
9
|
+
validateBundlesAllowed,
|
|
10
|
+
requireBundlePermission,
|
|
11
|
+
requireNoRestrictedAncestor
|
|
10
12
|
} from "../../helpers/validation.js";
|
|
11
13
|
import { getFieldKey } from "#blokkli/helpers";
|
|
12
14
|
import { itemEntityType } from "#blokkli-build/config";
|
|
@@ -34,6 +36,14 @@ export default defineBlokkliAgentTool({
|
|
|
34
36
|
const { $t, types, context, blocks } = ctx.app;
|
|
35
37
|
const blocksResult = validateBlocksExist(ctx.app, params.uuids);
|
|
36
38
|
if ("error" in blocksResult) return blocksResult;
|
|
39
|
+
const denied = requireBundlePermission(
|
|
40
|
+
ctx.app,
|
|
41
|
+
blocksResult.blocks.map((b) => b.bundle),
|
|
42
|
+
"add"
|
|
43
|
+
);
|
|
44
|
+
if (denied) return denied;
|
|
45
|
+
const ancestorDenied = requireNoRestrictedAncestor(ctx.app, params.uuids);
|
|
46
|
+
if (ancestorDenied) return ancestorDenied;
|
|
37
47
|
if (params.parent) {
|
|
38
48
|
if (!ctx.adapter.pasteExistingBlocks) {
|
|
39
49
|
return {
|
|
@@ -46,6 +56,11 @@ export default defineBlokkliAgentTool({
|
|
|
46
56
|
if (!targetBundle) {
|
|
47
57
|
return { error: "Target parent not found." };
|
|
48
58
|
}
|
|
59
|
+
if (!isRootEntity && ctx.app.permissions.blockHasRestrictedAncestor(params.parent.uuid)) {
|
|
60
|
+
return {
|
|
61
|
+
error: "Permission denied: target parent is inside a block with restricted editing permissions"
|
|
62
|
+
};
|
|
63
|
+
}
|
|
49
64
|
const fieldConfig = types.getFieldConfig(
|
|
50
65
|
entityType,
|
|
51
66
|
targetBundle,
|
|
@@ -2,6 +2,10 @@ import { z } from "zod";
|
|
|
2
2
|
import { defineBlokkliAgentTool } from "#blokkli/agent/app/composables";
|
|
3
3
|
import { mutationResultSchema, parentSchema, positionSchema } from "../schemas.js";
|
|
4
4
|
import { resolvePosition } from "../helpers.js";
|
|
5
|
+
import {
|
|
6
|
+
requireBundlePermission,
|
|
7
|
+
requireNoRestrictedAncestor
|
|
8
|
+
} from "../../helpers/validation.js";
|
|
5
9
|
const paramsSchema = z.object({
|
|
6
10
|
uuids: z.array(z.string()).describe("The UUIDs of the paragraphs to move"),
|
|
7
11
|
parent: parentSchema.describe("The target parent entity"),
|
|
@@ -33,6 +37,19 @@ export default defineBlokkliAgentTool({
|
|
|
33
37
|
}
|
|
34
38
|
validBlocks.push({ uuid, bundle: block.bundle });
|
|
35
39
|
}
|
|
40
|
+
const denied = requireBundlePermission(
|
|
41
|
+
ctx.app,
|
|
42
|
+
validBlocks.map((b) => b.bundle),
|
|
43
|
+
"edit"
|
|
44
|
+
);
|
|
45
|
+
if (denied) return denied;
|
|
46
|
+
const ancestorDenied = requireNoRestrictedAncestor(ctx.app, params.uuids);
|
|
47
|
+
if (ancestorDenied) return ancestorDenied;
|
|
48
|
+
if (ctx.app.permissions.blockHasRestrictedAncestor(params.parent.uuid)) {
|
|
49
|
+
return {
|
|
50
|
+
error: "Permission denied: target parent is inside a block with restricted editing permissions"
|
|
51
|
+
};
|
|
52
|
+
}
|
|
36
53
|
const { $t } = ctx.app;
|
|
37
54
|
const firstBlock = validBlocks[0];
|
|
38
55
|
const label = validBlocks.length === 1 && firstBlock ? $t("aiAgentMoveBlockDone", "Moved @bundle").replace(
|
|
@@ -2,6 +2,10 @@ import { z } from "zod";
|
|
|
2
2
|
import { defineBlokkliAgentTool } from "#blokkli/agent/app/composables";
|
|
3
3
|
import { mutationResultSchema, parentSchema } from "../schemas.js";
|
|
4
4
|
import { itemEntityType } from "#blokkli-build/config";
|
|
5
|
+
import {
|
|
6
|
+
requireBundlePermission,
|
|
7
|
+
requireNoRestrictedAncestor
|
|
8
|
+
} from "../../helpers/validation.js";
|
|
5
9
|
const paramsSchema = z.object({
|
|
6
10
|
parent: parentSchema.describe("The parent field containing the paragraphs"),
|
|
7
11
|
uuids: z.array(z.string()).min(2).describe(
|
|
@@ -69,6 +73,13 @@ export default defineBlokkliAgentTool({
|
|
|
69
73
|
};
|
|
70
74
|
}
|
|
71
75
|
}
|
|
76
|
+
const blockBundles = params.uuids.map((uuid) => blocks.getBlock(uuid)?.bundle).filter((b) => !!b);
|
|
77
|
+
if (blockBundles.length) {
|
|
78
|
+
const denied = requireBundlePermission(ctx.app, blockBundles, "edit");
|
|
79
|
+
if (denied) return denied;
|
|
80
|
+
}
|
|
81
|
+
const ancestorDenied = requireNoRestrictedAncestor(ctx.app, params.uuids);
|
|
82
|
+
if (ancestorDenied) return ancestorDenied;
|
|
72
83
|
const isAlreadyInOrder = params.uuids.every(
|
|
73
84
|
(uuid, i) => uuid === currentUuids[i]
|
|
74
85
|
);
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { defineBlokkliAgentTool } from "#blokkli/agent/app/composables";
|
|
3
3
|
import { mutationResultSchema } from "../schemas.js";
|
|
4
|
+
import {
|
|
5
|
+
requireBundlePermission,
|
|
6
|
+
requireNoRestrictedAncestor
|
|
7
|
+
} from "../../helpers/validation.js";
|
|
4
8
|
const paramsSchema = z.object({
|
|
5
9
|
uuid: z.string().describe("The paragraph UUID containing the content reference field"),
|
|
6
10
|
field: z.string().describe("The content field name (reference type)"),
|
|
@@ -30,6 +34,10 @@ export default defineBlokkliAgentTool({
|
|
|
30
34
|
if (!block) {
|
|
31
35
|
return { error: `Paragraph not found: ${params.uuid}` };
|
|
32
36
|
}
|
|
37
|
+
const denied = requireBundlePermission(ctx.app, [block.bundle], "edit");
|
|
38
|
+
if (denied) return denied;
|
|
39
|
+
const ancestorDenied = requireNoRestrictedAncestor(ctx.app, [params.uuid]);
|
|
40
|
+
if (ancestorDenied) return ancestorDenied;
|
|
33
41
|
const config = types.droppableFieldConfig.forName(
|
|
34
42
|
ctx.itemEntityType,
|
|
35
43
|
block.bundle,
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { defineBlokkliAgentTool } from "#blokkli/agent/app/composables";
|
|
3
3
|
import { mutationResultSchema } from "../schemas.js";
|
|
4
|
+
import {
|
|
5
|
+
requireBundlePermission,
|
|
6
|
+
requireNoRestrictedAncestor
|
|
7
|
+
} from "../../helpers/validation.js";
|
|
4
8
|
const paramsSchema = z.object({
|
|
5
9
|
uuid: z.string().describe("The paragraph UUID or entity UUID containing the media field"),
|
|
6
10
|
field: z.string().describe("The content field name (reference type)"),
|
|
@@ -27,6 +31,12 @@ export default defineBlokkliAgentTool({
|
|
|
27
31
|
if (!isEntity && !block) {
|
|
28
32
|
return { error: `Paragraph not found: ${params.uuid}` };
|
|
29
33
|
}
|
|
34
|
+
if (block) {
|
|
35
|
+
const denied = requireBundlePermission(ctx.app, [block.bundle], "edit");
|
|
36
|
+
if (denied) return denied;
|
|
37
|
+
const ancestorDenied = requireNoRestrictedAncestor(ctx.app, [params.uuid]);
|
|
38
|
+
if (ancestorDenied) return ancestorDenied;
|
|
39
|
+
}
|
|
30
40
|
const entityType = isEntity ? context.value.entityType : ctx.itemEntityType;
|
|
31
41
|
const bundle = isEntity ? context.value.entityBundle : block.bundle;
|
|
32
42
|
const config = types.droppableFieldConfig.forName(
|
|
@@ -7,6 +7,10 @@ import {
|
|
|
7
7
|
import { mutationResultSchema, optionValueSchema } from "../schemas.js";
|
|
8
8
|
import { validateOptionValue } from "../helpers.js";
|
|
9
9
|
import { onlyUnique } from "#blokkli/helpers";
|
|
10
|
+
import {
|
|
11
|
+
requireBundlePermission,
|
|
12
|
+
requireNoRestrictedAncestor
|
|
13
|
+
} from "../../helpers/validation.js";
|
|
10
14
|
const paragraphOptionsSchema = z.object({
|
|
11
15
|
uuid: z.string().describe("The paragraph UUID"),
|
|
12
16
|
options: z.record(z.string(), optionValueSchema).describe("Options to set as key-value pairs")
|
|
@@ -43,6 +47,12 @@ export default defineBlokkliAgentTool({
|
|
|
43
47
|
if (!block) {
|
|
44
48
|
return { error: `Paragraph not found: ${blockEntry.uuid}` };
|
|
45
49
|
}
|
|
50
|
+
const denied = requireBundlePermission(ctx.app, [block.bundle], "edit");
|
|
51
|
+
if (denied) return denied;
|
|
52
|
+
const ancestorDenied = requireNoRestrictedAncestor(ctx.app, [
|
|
53
|
+
blockEntry.uuid
|
|
54
|
+
]);
|
|
55
|
+
if (ancestorDenied) return ancestorDenied;
|
|
46
56
|
const bundle = block.library?.reusableBundle || block.bundle;
|
|
47
57
|
const selectionItem = selection.items.value.find(
|
|
48
58
|
(v) => v.uuid === blockEntry.uuid
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { defineBlokkliAgentTool } from "#blokkli/agent/app/composables";
|
|
3
3
|
import { mutationResultSchema } from "../schemas.js";
|
|
4
|
+
import {
|
|
5
|
+
requireBundlePermission,
|
|
6
|
+
requireNoRestrictedAncestor
|
|
7
|
+
} from "../../helpers/validation.js";
|
|
4
8
|
const paramsSchema = z.object({
|
|
5
9
|
uuidA: z.string().describe("First paragraph UUID"),
|
|
6
10
|
uuidB: z.string().describe("Second paragraph UUID")
|
|
@@ -31,6 +35,17 @@ export default defineBlokkliAgentTool({
|
|
|
31
35
|
if (!blockB) {
|
|
32
36
|
return { error: `Paragraph not found: ${params.uuidB}` };
|
|
33
37
|
}
|
|
38
|
+
const denied = requireBundlePermission(
|
|
39
|
+
ctx.app,
|
|
40
|
+
[blockA.bundle, blockB.bundle],
|
|
41
|
+
"edit"
|
|
42
|
+
);
|
|
43
|
+
if (denied) return denied;
|
|
44
|
+
const ancestorDenied = requireNoRestrictedAncestor(ctx.app, [
|
|
45
|
+
params.uuidA,
|
|
46
|
+
params.uuidB
|
|
47
|
+
]);
|
|
48
|
+
if (ancestorDenied) return ancestorDenied;
|
|
34
49
|
const fieldConfigA = types.getFieldConfig(
|
|
35
50
|
blockA.host.type,
|
|
36
51
|
blockA.host.bundle,
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { defineBlokkliAgentTool } from "#blokkli/agent/app/composables";
|
|
3
|
+
import {
|
|
4
|
+
requireBundlePermission,
|
|
5
|
+
requireNoRestrictedAncestor
|
|
6
|
+
} from "../../helpers/validation.js";
|
|
7
|
+
import { onlyUnique } from "#blokkli/helpers";
|
|
3
8
|
import Component from "./Component.vue";
|
|
4
9
|
import DetailsComponent from "./Details/index.vue";
|
|
5
10
|
const operationSchema = z.object({
|
|
@@ -61,7 +66,22 @@ export default defineBlokkliAgentTool({
|
|
|
61
66
|
component: Component,
|
|
62
67
|
detailsComponent: DetailsComponent,
|
|
63
68
|
buildDetails: (result) => result,
|
|
64
|
-
execute(
|
|
69
|
+
execute(ctx, params) {
|
|
70
|
+
const blockUuids = [];
|
|
71
|
+
if (params.uuids) {
|
|
72
|
+
blockUuids.push(...Object.keys(params.uuids));
|
|
73
|
+
}
|
|
74
|
+
if (params.operations) {
|
|
75
|
+
blockUuids.push(...params.operations.map((op) => op.uuid));
|
|
76
|
+
}
|
|
77
|
+
const bundles = blockUuids.filter(onlyUnique).map((uuid) => ctx.app.blocks.getBlock(uuid)?.bundle).filter((b) => !!b).filter(onlyUnique);
|
|
78
|
+
if (bundles.length) {
|
|
79
|
+
const denied = requireBundlePermission(ctx.app, bundles, "edit");
|
|
80
|
+
if (denied) return denied;
|
|
81
|
+
}
|
|
82
|
+
const uniqueUuids = blockUuids.filter(onlyUnique);
|
|
83
|
+
const ancestorDenied = requireNoRestrictedAncestor(ctx.app, uniqueUuids);
|
|
84
|
+
if (ancestorDenied) return ancestorDenied;
|
|
65
85
|
return params;
|
|
66
86
|
},
|
|
67
87
|
mockParams: () => ({
|
|
@@ -297,11 +297,11 @@ declare const userConversationItemSchema: z.ZodObject<{
|
|
|
297
297
|
id: z.ZodString;
|
|
298
298
|
content: z.ZodString;
|
|
299
299
|
format: z.ZodEnum<{
|
|
300
|
+
html: "html";
|
|
300
301
|
code: "code";
|
|
301
302
|
markdown: "markdown";
|
|
302
|
-
html: "html";
|
|
303
|
-
plaintext: "plaintext";
|
|
304
303
|
csv: "csv";
|
|
304
|
+
plaintext: "plaintext";
|
|
305
305
|
}>;
|
|
306
306
|
}, z.core.$strip>>>;
|
|
307
307
|
}, z.core.$strip>;
|
|
@@ -326,9 +326,9 @@ declare const toolConversationItemSchema: z.ZodObject<{
|
|
|
326
326
|
tool: z.ZodString;
|
|
327
327
|
label: z.ZodString;
|
|
328
328
|
status: z.ZodEnum<{
|
|
329
|
+
active: "active";
|
|
329
330
|
success: "success";
|
|
330
331
|
error: "error";
|
|
331
|
-
active: "active";
|
|
332
332
|
}>;
|
|
333
333
|
}, z.core.$strip>;
|
|
334
334
|
/**
|
|
@@ -370,11 +370,11 @@ export declare const conversationItemSchema: z.ZodDiscriminatedUnion<[z.ZodObjec
|
|
|
370
370
|
id: z.ZodString;
|
|
371
371
|
content: z.ZodString;
|
|
372
372
|
format: z.ZodEnum<{
|
|
373
|
+
html: "html";
|
|
373
374
|
code: "code";
|
|
374
375
|
markdown: "markdown";
|
|
375
|
-
html: "html";
|
|
376
|
-
plaintext: "plaintext";
|
|
377
376
|
csv: "csv";
|
|
377
|
+
plaintext: "plaintext";
|
|
378
378
|
}>;
|
|
379
379
|
}, z.core.$strip>>>;
|
|
380
380
|
}, z.core.$strip>, z.ZodObject<{
|
|
@@ -390,9 +390,9 @@ export declare const conversationItemSchema: z.ZodDiscriminatedUnion<[z.ZodObjec
|
|
|
390
390
|
tool: z.ZodString;
|
|
391
391
|
label: z.ZodString;
|
|
392
392
|
status: z.ZodEnum<{
|
|
393
|
+
active: "active";
|
|
393
394
|
success: "success";
|
|
394
395
|
error: "error";
|
|
395
|
-
active: "active";
|
|
396
396
|
}>;
|
|
397
397
|
}, z.core.$strip>, z.ZodObject<{
|
|
398
398
|
id: z.ZodString;
|
|
@@ -274,7 +274,8 @@ fragment paragraphsBlokkliParagraphEditContext on ParagraphsBlokkliParagraphEdit
|
|
|
274
274
|
"allowReusable",
|
|
275
275
|
"isTranslatable",
|
|
276
276
|
"hasPublishOn",
|
|
277
|
-
"hasUnpublishOn"
|
|
277
|
+
"hasUnpublishOn",
|
|
278
|
+
"permissions"
|
|
278
279
|
].includes(field);
|
|
279
280
|
});
|
|
280
281
|
graphql.addDocument(
|
|
@@ -137,9 +137,21 @@ export default defineBlokkliEditAdapter(
|
|
|
137
137
|
clipboard: v.data.clipboards || [],
|
|
138
138
|
userPermissions: v.data.userPermissions,
|
|
139
139
|
availableFeatures: v.data.features,
|
|
140
|
-
allTypes: (v.data.allTypes.items || []).
|
|
141
|
-
(v2
|
|
142
|
-
|
|
140
|
+
allTypes: (v.data.allTypes.items || []).map((v2) => {
|
|
141
|
+
if (v2 && "id" in v2 && v2.id) {
|
|
142
|
+
return {
|
|
143
|
+
id: v2.id,
|
|
144
|
+
label: v2.label ?? "",
|
|
145
|
+
description: v2.description ?? "",
|
|
146
|
+
allowReusable: !!v2.allowReusable,
|
|
147
|
+
isTranslatable: !!v2.isTranslatable,
|
|
148
|
+
hasPublishOn: !!v2.hasPublishOn,
|
|
149
|
+
hasUnpublishOn: !!v2.hasUnpublishOn,
|
|
150
|
+
permissions: v2.permissions ?? []
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
return null;
|
|
154
|
+
}).filter(falsy),
|
|
143
155
|
fieldConfig: v.data.fieldConfig || [],
|
|
144
156
|
editableFieldConfig: v.data.editableFieldConfig || [],
|
|
145
157
|
droppableFieldConfig: v.data.droppableFieldConfig || [],
|