@blokkli/editor 2.0.0-alpha.61 → 2.0.0-alpha.63
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/global/types/colorOptions.d.ts +16 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +168 -14
- package/dist/modules/agent/runtime/app/components/Conversation/Item/Assistant/index.vue +14 -5
- package/dist/modules/agent/runtime/app/features/agent/ConversationsAdmin/ConversationsTab/Item.vue +2 -2
- package/dist/modules/agent/runtime/app/features/agent/ConversationsAdmin/RatingsTab/Item.vue +2 -2
- package/dist/modules/agent/runtime/app/features/agent/ConversationsAdmin/SplitView/ConversationDetail.vue +2 -2
- package/dist/modules/agent/runtime/app/features/agent/Transcript/MessageContent.vue +14 -1
- package/dist/modules/agent/runtime/app/features/agent/Transcript/index.vue +30 -12
- package/dist/modules/agent/runtime/app/helpers/linkifyBlockUuids.d.ts +11 -0
- package/dist/modules/agent/runtime/app/helpers/linkifyBlockUuids.js +47 -0
- package/dist/modules/agent/runtime/app/tools/auto_translate_paragraphs/Component.d.vue.ts +22 -0
- package/dist/modules/agent/runtime/app/tools/auto_translate_paragraphs/Component.vue +28 -26
- package/dist/modules/agent/runtime/app/tools/auto_translate_paragraphs/Component.vue.d.ts +22 -0
- package/dist/modules/agent/runtime/app/tools/auto_translate_paragraphs/index.d.ts +15 -0
- package/dist/modules/agent/runtime/app/tools/delegate_text_rewrite/Component.d.vue.ts +22 -0
- package/dist/modules/agent/runtime/app/tools/delegate_text_rewrite/Component.vue +59 -16
- package/dist/modules/agent/runtime/app/tools/delegate_text_rewrite/Component.vue.d.ts +22 -0
- package/dist/modules/agent/runtime/app/tools/delegate_text_rewrite/index.d.ts +15 -0
- package/dist/modules/agent/runtime/app/tools/fieldDiffApproval.d.ts +85 -15
- package/dist/modules/agent/runtime/app/tools/fieldDiffApproval.js +138 -28
- package/dist/modules/agent/runtime/app/tools/schemas.d.ts +15 -5
- package/dist/modules/agent/runtime/app/tools/schemas.js +29 -12
- package/dist/modules/agent/runtime/app/tools/search_text/index.js +1 -1
- package/dist/modules/agent/runtime/app/tools/update_text_fields/Component.d.vue.ts +22 -0
- package/dist/modules/agent/runtime/app/tools/update_text_fields/Component.vue +54 -30
- package/dist/modules/agent/runtime/app/tools/update_text_fields/Component.vue.d.ts +22 -0
- package/dist/modules/agent/runtime/app/tools/update_text_fields/index.d.ts +15 -0
- package/dist/modules/agent/runtime/server/default-system-prompts/architecture.js +1 -1
- package/dist/modules/agent/runtime/server/default-system-prompts/important-rules.js +1 -0
- package/dist/modules/charts/runtime/blokkli/tools/chart_schemas.d.ts +1 -1
- package/dist/modules/charts/runtime/blokkli/tools/chart_schemas.js +12 -5
- package/dist/modules/charts/runtime/components/ChartRenderer/index.vue +7 -16
- package/dist/modules/charts/runtime/features/charts/Editor/ColorDropdown/index.vue +7 -77
- package/dist/modules/charts/runtime/features/charts/Editor/CsvImport/csvHelpers.d.ts +1 -1
- package/dist/modules/charts/runtime/features/charts/Editor/useChartEditorState.d.ts +1 -1
- package/dist/modules/charts/runtime/helpers/index.d.ts +2 -1
- package/dist/modules/charts/runtime/helpers/index.js +4 -2
- package/dist/modules/drupal/graphql/base/fragment.paragraphsBlokkliMutationResult.graphql +3 -0
- package/dist/modules/drupal/runtime/adapter/index.js +38 -27
- package/dist/runtime/composables/useBlokkliRuntimeConfig.d.ts +50 -0
- package/dist/runtime/composables/useBlokkliRuntimeConfig.js +34 -0
- package/dist/runtime/editor/adapter/index.d.ts +2 -1
- package/dist/runtime/editor/components/ColorDropdown/index.d.vue.ts +26 -0
- package/dist/runtime/editor/components/ColorDropdown/index.vue +116 -0
- package/dist/runtime/editor/components/ColorDropdown/index.vue.d.ts +26 -0
- package/dist/runtime/editor/components/DiffApproval/Highlight/Item.d.vue.ts +14 -20
- package/dist/runtime/editor/components/DiffApproval/Highlight/Item.vue +97 -52
- package/dist/runtime/editor/components/DiffApproval/Highlight/Item.vue.d.ts +14 -20
- package/dist/runtime/editor/components/DiffApproval/Highlight/index.d.vue.ts +6 -6
- package/dist/runtime/editor/components/DiffApproval/Highlight/index.vue +30 -21
- package/dist/runtime/editor/components/DiffApproval/Highlight/index.vue.d.ts +6 -6
- package/dist/runtime/editor/components/DiffApproval/Toolbar/index.d.vue.ts +19 -9
- package/dist/runtime/editor/components/DiffApproval/Toolbar/index.vue +18 -9
- package/dist/runtime/editor/components/DiffApproval/Toolbar/index.vue.d.ts +19 -9
- package/dist/runtime/editor/components/DiffApproval/index.d.vue.ts +14 -6
- package/dist/runtime/editor/components/DiffApproval/index.vue +62 -35
- package/dist/runtime/editor/components/DiffApproval/index.vue.d.ts +14 -6
- package/dist/runtime/editor/components/DiffApproval/types.d.ts +32 -0
- package/dist/runtime/editor/components/DiffApproval/types.js +22 -0
- package/dist/runtime/editor/components/Dropdown/index.d.vue.ts +5 -4
- package/dist/runtime/editor/components/Dropdown/index.vue +89 -29
- package/dist/runtime/editor/components/Dropdown/index.vue.d.ts +5 -4
- package/dist/runtime/editor/components/FlexTextarea/index.d.vue.ts +1 -1
- package/dist/runtime/editor/components/FlexTextarea/index.vue.d.ts +1 -1
- package/dist/runtime/editor/components/NestedEditorOverlay/index.d.vue.ts +2 -2
- package/dist/runtime/editor/components/NestedEditorOverlay/index.vue +3 -3
- package/dist/runtime/editor/components/NestedEditorOverlay/index.vue.d.ts +2 -2
- package/dist/runtime/editor/components/PopupHost/index.d.vue.ts +13 -0
- package/dist/runtime/editor/components/PopupHost/index.vue +12 -0
- package/dist/runtime/editor/components/PopupHost/index.vue.d.ts +13 -0
- package/dist/runtime/editor/components/index.d.ts +2 -0
- package/dist/runtime/editor/components/index.js +2 -0
- package/dist/runtime/editor/css/output.css +1 -1
- package/dist/runtime/editor/features/analyze/Main.vue +15 -2
- package/dist/runtime/editor/features/analyze/Results/ResultsItemNodes.vue +4 -1
- package/dist/runtime/editor/features/analyze/Results/ResultsItemNodesTarget.vue +25 -16
- package/dist/runtime/editor/features/analyze/analyzers/defaults/validations.d.ts +10 -0
- package/dist/runtime/editor/features/analyze/analyzers/defaults/validations.js +39 -0
- package/dist/runtime/editor/features/analyze/analyzers/helpers/Context.d.ts +5 -1
- package/dist/runtime/editor/features/analyze/analyzers/helpers/Context.js +5 -0
- package/dist/runtime/editor/features/analyze/index.vue +0 -1
- package/dist/runtime/editor/features/changelog/changelog.json +9 -1
- package/dist/runtime/editor/features/comments/Comment/Meta/index.vue +1 -1
- package/dist/runtime/editor/features/comments/Comment/index.vue +1 -1
- package/dist/runtime/editor/features/publish/Dialog/Violations.d.vue.ts +12 -0
- package/dist/runtime/editor/features/publish/Dialog/Violations.vue +117 -0
- package/dist/runtime/editor/features/publish/Dialog/Violations.vue.d.ts +12 -0
- package/dist/runtime/editor/features/publish/Dialog/index.vue +61 -24
- package/dist/runtime/editor/features/publish/index.vue +2 -4
- package/dist/runtime/editor/features/publish/types.d.ts +0 -4
- package/dist/runtime/editor/helpers/color/index.d.ts +7 -0
- package/dist/runtime/editor/helpers/color/index.js +14 -0
- package/dist/runtime/editor/helpers/diff/index.d.ts +87 -0
- package/dist/runtime/editor/helpers/diff/index.js +256 -0
- package/dist/runtime/editor/helpers/injections.d.ts +11 -0
- package/dist/runtime/editor/helpers/injections.js +1 -0
- package/dist/runtime/editor/plugins/Sidebar/Detached/index.d.vue.ts +1 -1
- package/dist/runtime/editor/plugins/Sidebar/Detached/index.vue.d.ts +1 -1
- package/dist/runtime/editor/plugins/Sidebar/index.d.vue.ts +2 -2
- package/dist/runtime/editor/plugins/Sidebar/index.vue.d.ts +2 -2
- package/dist/runtime/editor/providers/analyze.js +5 -2
- package/dist/runtime/editor/providers/config.d.ts +3 -1
- package/dist/runtime/editor/providers/config.js +46 -15
- package/dist/runtime/editor/providers/state.d.ts +13 -0
- package/dist/runtime/editor/providers/state.js +7 -0
- package/dist/runtime/editor/translations/de.json +7 -4
- package/dist/runtime/editor/translations/fr.json +2 -4
- package/dist/runtime/editor/translations/gsw_CH.json +7 -4
- package/dist/runtime/editor/translations/it.json +2 -4
- package/dist/runtime/helpers/colors.d.ts +39 -0
- package/dist/runtime/helpers/colors.js +28 -0
- package/dist/runtime/types/colors.d.ts +11 -0
- package/package.json +1 -1
- package/dist/runtime/editor/features/validations/Overlay/Item.d.vue.ts +0 -7
- package/dist/runtime/editor/features/validations/Overlay/Item.vue +0 -36
- package/dist/runtime/editor/features/validations/Overlay/Item.vue.d.ts +0 -7
- package/dist/runtime/editor/features/validations/Overlay/index.d.vue.ts +0 -7
- package/dist/runtime/editor/features/validations/Overlay/index.vue +0 -115
- package/dist/runtime/editor/features/validations/Overlay/index.vue.d.ts +0 -7
- package/dist/runtime/editor/features/validations/SidebarItem/index.d.vue.ts +0 -10
- package/dist/runtime/editor/features/validations/SidebarItem/index.vue +0 -41
- package/dist/runtime/editor/features/validations/SidebarItem/index.vue.d.ts +0 -10
- package/dist/runtime/editor/features/validations/index.d.vue.ts +0 -3
- package/dist/runtime/editor/features/validations/index.vue +0 -91
- package/dist/runtime/editor/features/validations/index.vue.d.ts +0 -3
- package/dist/runtime/editor/types/config.d.ts +0 -5
- /package/dist/runtime/{editor/types/config.js → types/colors.js} +0 -0
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
</p>
|
|
23
23
|
</FormItem>
|
|
24
24
|
|
|
25
|
-
<FormItem class="_bk_relative">
|
|
25
|
+
<FormItem class="_bk_relative _bk_z-50">
|
|
26
26
|
<FormToggle
|
|
27
27
|
v-model="keepVisible"
|
|
28
28
|
:label="$t('analyzeKeepVisible', 'Keep results visible')"
|
|
@@ -122,6 +122,18 @@ const { getCategoryLabel } = useAnalyzeHelper();
|
|
|
122
122
|
const refreshKey = computed(() => {
|
|
123
123
|
return `dom:${dom.settleKey.value}_directive:${directive.settleKey.value}_state:${state.refreshKey.value}`;
|
|
124
124
|
});
|
|
125
|
+
watch(
|
|
126
|
+
() => props.isShown,
|
|
127
|
+
(isShown) => {
|
|
128
|
+
if (isShown) return;
|
|
129
|
+
const activeId2 = ui.activeHighlightId.value;
|
|
130
|
+
if (!activeId2) return;
|
|
131
|
+
const resultId = activeId2.split("_____")[0];
|
|
132
|
+
if (allResults.value.some((r) => r.id === resultId)) {
|
|
133
|
+
ui.activeHighlightId.value = "";
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
);
|
|
125
137
|
const isRunning = defineModel({ type: Boolean, ...{ default: false } });
|
|
126
138
|
const issueCount = defineModel("issueCount", { type: Number, ...{ default: 0 } });
|
|
127
139
|
const hasViolation = defineModel("hasViolation", { type: Boolean, ...{ default: false } });
|
|
@@ -272,7 +284,8 @@ function filterResultsByIgnored(items, wantIgnored) {
|
|
|
272
284
|
const filtered = [];
|
|
273
285
|
for (const result of items) {
|
|
274
286
|
const nodes = result.nodes.filter((n) => n.ignored === wantIgnored);
|
|
275
|
-
|
|
287
|
+
const isStatusOnly = result.nodes.length === 0;
|
|
288
|
+
if (nodes.length || isStatusOnly && !wantIgnored) {
|
|
276
289
|
filtered.push({ ...result, nodes });
|
|
277
290
|
}
|
|
278
291
|
}
|
|
@@ -95,6 +95,9 @@ watch(
|
|
|
95
95
|
shouldRender.value = true;
|
|
96
96
|
isOpen.value = true;
|
|
97
97
|
}
|
|
98
|
-
}
|
|
98
|
+
},
|
|
99
|
+
// Immediate so a panel mounting AFTER a highlight click (e.g. cold-load
|
|
100
|
+
// sidebar open) still sees the already-set `activeHighlightId` and expands.
|
|
101
|
+
{ immediate: true }
|
|
99
102
|
);
|
|
100
103
|
</script>
|
|
@@ -49,7 +49,13 @@
|
|
|
49
49
|
</template>
|
|
50
50
|
|
|
51
51
|
<script setup>
|
|
52
|
-
import {
|
|
52
|
+
import {
|
|
53
|
+
computed,
|
|
54
|
+
onMounted,
|
|
55
|
+
useBlokkli,
|
|
56
|
+
useTemplateRef,
|
|
57
|
+
watch
|
|
58
|
+
} from "#imports";
|
|
53
59
|
import { renderCycle } from "#blokkli/editor/helpers/vue";
|
|
54
60
|
import { Icon, Tooltip, Pill } from "#blokkli/editor/components";
|
|
55
61
|
const props = defineProps({
|
|
@@ -143,19 +149,22 @@ async function onClick() {
|
|
|
143
149
|
});
|
|
144
150
|
ui.activeHighlightId.value = props.resultId + "_____" + props.target.globalIndex;
|
|
145
151
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
)
|
|
152
|
+
function scrollFocusedIntoView() {
|
|
153
|
+
if (elButton.value) {
|
|
154
|
+
elButton.value.scrollIntoView({
|
|
155
|
+
behavior: "smooth",
|
|
156
|
+
block: "nearest"
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
watch(isFocused, (isFocused2) => {
|
|
161
|
+
if (isFocused2) {
|
|
162
|
+
scrollFocusedIntoView();
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
onMounted(() => {
|
|
166
|
+
if (isFocused.value) {
|
|
167
|
+
scrollFocusedIntoView();
|
|
168
|
+
}
|
|
169
|
+
});
|
|
161
170
|
</script>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Analyzer } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Built-in analyzer that surfaces backend-reported validation violations
|
|
4
|
+
* (`state.violations`) inside the analyze sidebar. Always registered by the
|
|
5
|
+
* analyze provider — adapters do not need to opt in.
|
|
6
|
+
*
|
|
7
|
+
* Violations intentionally carry no `identifier` so they cannot be ignored:
|
|
8
|
+
* a validation error must be resolved, not silenced.
|
|
9
|
+
*/
|
|
10
|
+
export declare const validationsAnalyzer: Analyzer;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export const validationsAnalyzer = {
|
|
2
|
+
id: "blokkli:validations",
|
|
3
|
+
type: "generic",
|
|
4
|
+
label: (_langcode, $t) => $t("analyzerValidationsLabel", "Validations"),
|
|
5
|
+
continuous: true,
|
|
6
|
+
run(context) {
|
|
7
|
+
const { violations, $t } = context;
|
|
8
|
+
const title = $t("analyzerValidationsLabel", "Validations");
|
|
9
|
+
if (!violations.length) {
|
|
10
|
+
return {
|
|
11
|
+
id: "blokkli:validations:pass",
|
|
12
|
+
title,
|
|
13
|
+
category: "content",
|
|
14
|
+
description: $t(
|
|
15
|
+
"analyzerValidationsPassDescription",
|
|
16
|
+
"No validation errors for the current state."
|
|
17
|
+
),
|
|
18
|
+
status: "pass",
|
|
19
|
+
nodes: []
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
const nodes = violations.map((violation) => ({
|
|
23
|
+
description: violation.message,
|
|
24
|
+
uuid: violation.entityUuid,
|
|
25
|
+
targets: violation.entityUuid ? [{ uuid: violation.entityUuid }] : []
|
|
26
|
+
}));
|
|
27
|
+
return {
|
|
28
|
+
id: "blokkli:validations:failed",
|
|
29
|
+
title,
|
|
30
|
+
category: "content",
|
|
31
|
+
description: $t(
|
|
32
|
+
"analyzerValidationsDescription",
|
|
33
|
+
"Validation errors reported for the current state."
|
|
34
|
+
),
|
|
35
|
+
status: "violation",
|
|
36
|
+
nodes
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
};
|
|
@@ -2,7 +2,7 @@ import type { FieldListItemTyped } from '#blokkli-build/generated-types';
|
|
|
2
2
|
import type { StateProvider } from '#blokkli/editor/providers/state';
|
|
3
3
|
import type { ReadabilityProvider } from '#blokkli/editor/providers/readability';
|
|
4
4
|
import type { TextProvider } from '#blokkli/editor/providers/texts';
|
|
5
|
-
import type { MutatedField } from '#blokkli/editor/types/state';
|
|
5
|
+
import type { MutatedField, Validation } from '#blokkli/editor/types/state';
|
|
6
6
|
import type { AnalyzeCategory, AnalyzeNode, AnalyzeResult, AnalyzeStatus } from '../types.js';
|
|
7
7
|
import { type TextElement } from './collectTextElements.js';
|
|
8
8
|
export declare class AnalyzerContext {
|
|
@@ -13,6 +13,10 @@ export declare class AnalyzerContext {
|
|
|
13
13
|
readonly $t: TextProvider;
|
|
14
14
|
readonly signal: AbortSignal | undefined;
|
|
15
15
|
readonly mutatedFields: Readonly<MutatedField[]>;
|
|
16
|
+
/**
|
|
17
|
+
* Backend-reported validation violations for the current state.
|
|
18
|
+
*/
|
|
19
|
+
readonly violations: Readonly<Validation[]>;
|
|
16
20
|
/**
|
|
17
21
|
* The readability provider.
|
|
18
22
|
*/
|
|
@@ -9,8 +9,13 @@ export class AnalyzerContext {
|
|
|
9
9
|
this.signal = signal;
|
|
10
10
|
this.readability = readability;
|
|
11
11
|
this.mutatedFields = JSON.parse(JSON.stringify(state.mutatedFields.value));
|
|
12
|
+
this.violations = JSON.parse(JSON.stringify(state.violations.value));
|
|
12
13
|
}
|
|
13
14
|
mutatedFields;
|
|
15
|
+
/**
|
|
16
|
+
* Backend-reported validation violations for the current state.
|
|
17
|
+
*/
|
|
18
|
+
violations;
|
|
14
19
|
/**
|
|
15
20
|
* The readability provider.
|
|
16
21
|
*/
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "2.0.0-alpha.63",
|
|
4
|
+
"date": "2026-06-11",
|
|
5
|
+
"body": {
|
|
6
|
+
"en": "<h3>New Features</h3>\n<h4>Accept AI text changes paragraph by paragraph</h4>\n<p>When the AI assistant proposes changes to a longer text, you no longer have to\naccept or reject the entire text: individual paragraphs or list items can now be\naccepted or discarded selectively – by click or with the keyboard.</p>\n<h4>Validations in the page analysis</h4>\n<p>Validation errors are now shown directly in the page analysis – alongside the\nother analysis results such as readability or accessibility. The separate\nvalidations view is gone; in return, the page analysis is always available.</p>\n<h4>Validation errors when saving/publishing</h4>\n<p>If publishing fails because of validation errors, the dialog now shows the\nspecific problems so you can fix them right away.</p>\n<h4>Blocks linked in AI assistant answers</h4>\n<p>When the AI assistant refers to a block in its answers, its label now appears as\na clickable link that jumps directly to the block on the page. Previously, a\ncryptic ID was sometimes shown instead.</p>\n<h3>Improvements</h3>\n<ul>\n<li>The color picker in the chart editor has been reworked: all colors and their\nshades are now presented as a clear palette.</li>\n</ul>\n<h3>Fixes</h3>\n<ul>\n<li>Clicking a page analysis highlight now reliably jumps to the affected spot,\neven when the sidebar is closed. Highlights are correctly reset when closing\nthe page analysis.</li>\n<li>The AI assistant's text search now attributes text to the correct block when\nblocks are nested inside each other.</li>\n</ul>\n",
|
|
7
|
+
"de": "<h3>Neue Funktionen</h3>\n<h4>Textänderungen des KI-Assistenten absatzweise übernehmen</h4>\n<p>Schlägt der KI-Assistent Änderungen an einem längeren Text vor, müssen Sie nicht\nmehr den gesamten Text übernehmen oder ablehnen: Einzelne Absätze oder\nAufzählungspunkte lassen sich jetzt gezielt übernehmen oder verwerfen – per\nKlick oder mit der Tastatur.</p>\n<h4>Validierungen in der Seitenanalyse</h4>\n<p>Validierungsfehler werden neu direkt in der Seitenanalyse angezeigt – zusammen\nmit den anderen Analyse-Ergebnissen wie Lesbarkeit oder Barrierefreiheit. Die\nseparate Ansicht für Validierungen entfällt, die Seitenanalyse ist dafür immer\nverfügbar.</p>\n<h4>Validierungsfehler beim Speichern/Publizieren</h4>\n<p>Schlägt die Publikation wegen Validierungsfehlern fehl, zeigt der Dialog neu die\nkonkreten Probleme an, damit Sie sie direkt beheben können.</p>\n<h4>Blöcke in Antworten des KI-Assistenten verlinkt</h4>\n<p>Wenn der KI-Assistent in seinen Antworten auf einen Block verweist, erscheint\nneu dessen Bezeichnung als klickbarer Link, der direkt zum Block auf der Seite\nspringt. Bisher wurde an dieser Stelle teilweise eine kryptische ID angezeigt.</p>\n<h3>Verbesserungen</h3>\n<ul>\n<li>Die Farbauswahl im Diagramm-Editor wurde überarbeitet: Alle Farben und ihre\nAbstufungen sind neu übersichtlich als Palette dargestellt.</li>\n</ul>\n<h3>Fehlerbehebungen</h3>\n<ul>\n<li>Ein Klick auf eine Hervorhebung der Seitenanalyse springt jetzt zuverlässig\nzur betroffenen Stelle, auch wenn die Sidebar geschlossen ist. Beim Schliessen\nder Seitenanalyse werden Hervorhebungen korrekt zurückgesetzt.</li>\n<li>Die Textsuche des KI-Assistenten ordnet Texte jetzt dem richtigen Block zu,\nwenn Blöcke ineinander verschachtelt sind.</li>\n</ul>\n"
|
|
8
|
+
}
|
|
9
|
+
},
|
|
2
10
|
{
|
|
3
11
|
"version": "2.0.0-alpha.61",
|
|
4
12
|
"date": "2026-06-03",
|
|
5
13
|
"body": {
|
|
6
|
-
"en": "<h3>Improvements</h3>\n<h4>The AI assistant sees your selection from the very first message</h4>\n<p>When you select a block and immediately ask the AI assistant something like\n"Convert this into an accordion", it now knows right away what you mean.\nPreviously it often had to ask back or look up the selection in a separate
|
|
14
|
+
"en": "<h3>Improvements</h3>\n<h4>The AI assistant sees your selection from the very first message</h4>\n<p>When you select a block and immediately ask the AI assistant something like\n"Convert this into an accordion", it now knows right away what you mean.\nPreviously it often had to ask back or look up the selection in a separate step.</p>\n<h4>The AI assistant handles nested blocks correctly</h4>\n<p>When the AI assistant creates a structure made of several blocks, it now\nreliably understands which blocks sit inside which. Previously it sometimes\nmisread its own additions and partially deleted what it had just created.</p>\n<h4>Other improvements</h4>\n<ul>\n<li>The list of changes that the AI assistant proposes for confirmation can now be\nnavigated entirely with the keyboard.</li>\n</ul>\n",
|
|
7
15
|
"de": "<h3>Verbesserungen</h3>\n<h4>KI-Assistent erkennt markierte Blöcke ab der ersten Nachricht</h4>\n<p>Wenn Sie einen Block markieren und dem KI-Assistenten direkt eine Anweisung wie\n«Wandle das in ein Akkordeon um» geben, weiss er sofort, was gemeint ist. Bisher\nmusste er häufig nachfragen oder die Auswahl in einem separaten Schritt\nnachlesen.</p>\n<h4>KI-Assistent ordnet verschachtelte Blöcke korrekt ein</h4>\n<p>Erstellt der KI-Assistent eine Struktur mit mehreren Blöcken, erkennt er nun\nzuverlässig, welche Blöcke ineinander liegen. Vorher kam es vor, dass er die\ngerade erstellte Struktur falsch interpretierte und teilweise wieder löschte.</p>\n<h4>Weitere Verbesserungen</h4>\n<ul>\n<li>Die Liste der Änderungen, die der KI-Assistent zur Bestätigung vorschlägt,\nlässt sich jetzt vollständig mit der Tastatur durchgehen.</li>\n</ul>\n"
|
|
8
16
|
}
|
|
9
17
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="_bk_flex _bk_items-baseline _bk_gap-3 _bk_flex-wrap _bk_min-w-0 _bk_text-sm _bk_-mt-2">
|
|
3
3
|
<span class="_bk_font-semibold _bk_text-mono-900 _bk_truncate">
|
|
4
|
-
{{ user?.name || $t("
|
|
4
|
+
{{ user?.name || `[${$t("deleted", "deleted")}]` }}
|
|
5
5
|
</span>
|
|
6
6
|
<RelativeTime v-slot="{ formatted }" :timestamp="created">
|
|
7
7
|
<span class="_bk_text-xs _bk_text-mono-500">{{ formatted }}</span>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Validation } from '#blokkli/editor/types/state';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
violations: Validation[];
|
|
4
|
+
errors: string[];
|
|
5
|
+
};
|
|
6
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
7
|
+
close: () => any;
|
|
8
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
9
|
+
onClose?: (() => any) | undefined;
|
|
10
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
11
|
+
declare const _default: typeof __VLS_export;
|
|
12
|
+
export default _default;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<PanelSection
|
|
3
|
+
:title="
|
|
4
|
+
$t('publishValidationErrorsTitle', 'Cannot publish: validation errors')
|
|
5
|
+
"
|
|
6
|
+
padded
|
|
7
|
+
>
|
|
8
|
+
<InfoBox
|
|
9
|
+
:text="
|
|
10
|
+
$t(
|
|
11
|
+
'publishValidationErrorsDescription',
|
|
12
|
+
'Fix the following issues and try publishing again.'
|
|
13
|
+
)
|
|
14
|
+
"
|
|
15
|
+
icon="bk_mdi_error-fill"
|
|
16
|
+
color="red"
|
|
17
|
+
/>
|
|
18
|
+
|
|
19
|
+
<ul
|
|
20
|
+
v-if="resolvedViolations.length"
|
|
21
|
+
class="bk-publish-violations bk-control _bk_mt-15"
|
|
22
|
+
>
|
|
23
|
+
<li
|
|
24
|
+
v-for="(item, i) in resolvedViolations"
|
|
25
|
+
:key="item.violation.message + i"
|
|
26
|
+
>
|
|
27
|
+
<button
|
|
28
|
+
type="button"
|
|
29
|
+
class="bk-validation-item"
|
|
30
|
+
@click.prevent="onClick(item)"
|
|
31
|
+
>
|
|
32
|
+
<div v-if="item.block" class="bk-validation-item-header">
|
|
33
|
+
<ItemIcon :bundle="item.block.bundle" />
|
|
34
|
+
<div>{{ item.bundleLabel }}</div>
|
|
35
|
+
</div>
|
|
36
|
+
<div
|
|
37
|
+
v-if="item.fieldLabel"
|
|
38
|
+
class="_bk_text-xs _bk_text-mono-600 _bk_font-medium _bk_mb-3"
|
|
39
|
+
>
|
|
40
|
+
{{ item.fieldLabel }}
|
|
41
|
+
</div>
|
|
42
|
+
<div v-html="item.violation.message" />
|
|
43
|
+
</button>
|
|
44
|
+
</li>
|
|
45
|
+
</ul>
|
|
46
|
+
|
|
47
|
+
<ul
|
|
48
|
+
v-if="errors.length"
|
|
49
|
+
class="bk-publish-errors _bk_list-disc _bk_pl-20 _bk_mt-15 _bk_text-base"
|
|
50
|
+
>
|
|
51
|
+
<li
|
|
52
|
+
v-for="(error, i) in errors"
|
|
53
|
+
:key="'err' + i"
|
|
54
|
+
class="_bk_text-red-dark"
|
|
55
|
+
>
|
|
56
|
+
{{ error }}
|
|
57
|
+
</li>
|
|
58
|
+
</ul>
|
|
59
|
+
</PanelSection>
|
|
60
|
+
</template>
|
|
61
|
+
|
|
62
|
+
<script setup>
|
|
63
|
+
import { computed, useBlokkli } from "#imports";
|
|
64
|
+
import { InfoBox, ItemIcon } from "#blokkli/editor/components";
|
|
65
|
+
import PanelSection from "#blokkli/editor/components/Panel/Section/index.vue";
|
|
66
|
+
import { itemEntityType } from "#blokkli-build/config";
|
|
67
|
+
const props = defineProps({
|
|
68
|
+
violations: { type: Array, required: true },
|
|
69
|
+
errors: { type: Array, required: true }
|
|
70
|
+
});
|
|
71
|
+
const emit = defineEmits(["close"]);
|
|
72
|
+
const { types, blocks, context, eventBus, $t } = useBlokkli();
|
|
73
|
+
function firstFieldSegment(propertyPath) {
|
|
74
|
+
for (const segment of propertyPath.split(".")) {
|
|
75
|
+
if (segment && !/^\d+$/.test(segment)) {
|
|
76
|
+
return segment;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return void 0;
|
|
80
|
+
}
|
|
81
|
+
function resolveBundle(violation, block) {
|
|
82
|
+
if (block) return block.bundle;
|
|
83
|
+
if (!violation.entityType || violation.entityType === context.value.entityType) {
|
|
84
|
+
return context.value.entityBundle;
|
|
85
|
+
}
|
|
86
|
+
return void 0;
|
|
87
|
+
}
|
|
88
|
+
function resolveFieldLabel(violation, block) {
|
|
89
|
+
if (!violation.propertyPath) return void 0;
|
|
90
|
+
const fieldName = firstFieldSegment(violation.propertyPath);
|
|
91
|
+
if (!fieldName) return void 0;
|
|
92
|
+
const entityType = violation.entityType ?? context.value.entityType;
|
|
93
|
+
const bundle = resolveBundle(violation, block);
|
|
94
|
+
if (!entityType || !bundle) return void 0;
|
|
95
|
+
return types.getFieldConfig(entityType, bundle, fieldName)?.label;
|
|
96
|
+
}
|
|
97
|
+
const resolvedViolations = computed(
|
|
98
|
+
() => props.violations.map((violation) => {
|
|
99
|
+
const block = violation.entityUuid ? blocks.getBlock(violation.entityUuid) ?? null : null;
|
|
100
|
+
const bundleLabel = block ? types.getBlockBundleDefinition(block.bundle)?.label : void 0;
|
|
101
|
+
return {
|
|
102
|
+
violation,
|
|
103
|
+
block,
|
|
104
|
+
bundleLabel,
|
|
105
|
+
fieldLabel: resolveFieldLabel(violation, block)
|
|
106
|
+
};
|
|
107
|
+
})
|
|
108
|
+
);
|
|
109
|
+
function onClick(item) {
|
|
110
|
+
if (item.violation.entityType !== itemEntityType || !item.violation.entityUuid) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
eventBus.emit("select", item.violation.entityUuid);
|
|
114
|
+
eventBus.emit("scrollIntoView", { uuid: item.violation.entityUuid });
|
|
115
|
+
emit("close");
|
|
116
|
+
}
|
|
117
|
+
</script>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Validation } from '#blokkli/editor/types/state';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
violations: Validation[];
|
|
4
|
+
errors: string[];
|
|
5
|
+
};
|
|
6
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
7
|
+
close: () => any;
|
|
8
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
9
|
+
onClose?: (() => any) | undefined;
|
|
10
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
11
|
+
declare const _default: typeof __VLS_export;
|
|
12
|
+
export default _default;
|
|
@@ -116,6 +116,12 @@
|
|
|
116
116
|
</InfoBox>
|
|
117
117
|
</FormItem>
|
|
118
118
|
</PanelSection>
|
|
119
|
+
<Violations
|
|
120
|
+
v-if="hasFailures"
|
|
121
|
+
:violations="failedViolations"
|
|
122
|
+
:errors="failedErrors"
|
|
123
|
+
@close="$emit('close')"
|
|
124
|
+
/>
|
|
119
125
|
<div>
|
|
120
126
|
<FormItem v-if="successItems.length && showTable">
|
|
121
127
|
<h2 class="bk-heading-2">
|
|
@@ -200,6 +206,7 @@ import { emitMessage } from "#blokkli/editor/events";
|
|
|
200
206
|
import Item from "./Item.vue";
|
|
201
207
|
import PublishOption, {} from "./PublishOption.vue";
|
|
202
208
|
import Summary from "./Summary.vue";
|
|
209
|
+
import Violations from "./Violations.vue";
|
|
203
210
|
import PanelSection from "#blokkli/editor/components/Panel/Section/index.vue";
|
|
204
211
|
const showTable = false;
|
|
205
212
|
const { adapter, $t, state, context, ui } = useBlokkli();
|
|
@@ -393,6 +400,17 @@ const selectedToPublishItems = computed(
|
|
|
393
400
|
)
|
|
394
401
|
);
|
|
395
402
|
const isLoading = computed(() => status.value === "pending" || isMutating.value);
|
|
403
|
+
const failedStatuses = computed(
|
|
404
|
+
() => Object.values(mutationStatusItems.value).filter((s) => !s.success)
|
|
405
|
+
);
|
|
406
|
+
const failedViolations = computed(
|
|
407
|
+
() => failedStatuses.value.flatMap((s) => s.violations ?? [])
|
|
408
|
+
);
|
|
409
|
+
const failedErrors = computed(() => {
|
|
410
|
+
const messages = failedStatuses.value.flatMap((s) => s.errors ?? []);
|
|
411
|
+
return Array.from(new Set(messages));
|
|
412
|
+
});
|
|
413
|
+
const hasFailures = computed(() => failedStatuses.value.length > 0);
|
|
396
414
|
const scheduleDateError = computed(() => {
|
|
397
415
|
if (publishMode.value !== "scheduled" || !scheduleDate.value) {
|
|
398
416
|
return "";
|
|
@@ -499,12 +517,19 @@ async function removeScheduledDate() {
|
|
|
499
517
|
}
|
|
500
518
|
isMutating.value = true;
|
|
501
519
|
const previousScheduleDate = scheduleDate.value;
|
|
502
|
-
|
|
503
|
-
|
|
520
|
+
let success = false;
|
|
521
|
+
try {
|
|
522
|
+
const response = await adapter.unscheduleEditState({
|
|
504
523
|
hostEntityType: context.value.entityType,
|
|
505
524
|
hostEntityUuid: context.value.entityUuid
|
|
506
|
-
})
|
|
507
|
-
|
|
525
|
+
});
|
|
526
|
+
success = !!response?.success;
|
|
527
|
+
if (response?.state) {
|
|
528
|
+
state.applyMutationState(response.state);
|
|
529
|
+
}
|
|
530
|
+
} catch {
|
|
531
|
+
success = false;
|
|
532
|
+
}
|
|
508
533
|
if (success) {
|
|
509
534
|
await refresh();
|
|
510
535
|
scheduleDate.value = previousScheduleDate;
|
|
@@ -518,8 +543,7 @@ async function onSubmit() {
|
|
|
518
543
|
}
|
|
519
544
|
isMutating.value = true;
|
|
520
545
|
const items = stateItems.value;
|
|
521
|
-
const
|
|
522
|
-
let mutationResult = false;
|
|
546
|
+
const selectedItems = [];
|
|
523
547
|
for (const item of items) {
|
|
524
548
|
const isSelected = states.value.includes(item.id) || item.hostEntityType === context.value.entityType && item.hostEntityUuid === context.value.entityUuid;
|
|
525
549
|
if (!isSelected) {
|
|
@@ -528,29 +552,41 @@ async function onSubmit() {
|
|
|
528
552
|
if (publishedIds.value.includes(item.id)) {
|
|
529
553
|
continue;
|
|
530
554
|
}
|
|
555
|
+
selectedItems.push(item);
|
|
531
556
|
try {
|
|
557
|
+
let response;
|
|
532
558
|
if (publishMode.value === "scheduled") {
|
|
533
559
|
if (!adapter.scheduleEditState) {
|
|
534
560
|
throw new Error("scheduleEditState method not available");
|
|
535
561
|
}
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
})
|
|
543
|
-
);
|
|
562
|
+
response = await adapter.scheduleEditState({
|
|
563
|
+
hostEntityType: item.hostEntityType,
|
|
564
|
+
hostEntityUuid: item.hostEntityUuid,
|
|
565
|
+
revisionLogMessage: revisionMessage.value,
|
|
566
|
+
date: scheduleDate.value
|
|
567
|
+
});
|
|
544
568
|
} else {
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
569
|
+
response = await adapter.publish({
|
|
570
|
+
hostEntityType: item.hostEntityType,
|
|
571
|
+
hostEntityUuid: item.hostEntityUuid,
|
|
572
|
+
closeAfterPublish: true,
|
|
573
|
+
revisionLogMessage: revisionMessage.value,
|
|
574
|
+
publishIfUnpublished: shouldPublish.value
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
if (response?.success) {
|
|
578
|
+
mutationStatusItems.value[item.id] = { id: item.id, success: true };
|
|
579
|
+
publishedIds.value.push(item.id);
|
|
580
|
+
} else {
|
|
581
|
+
mutationStatusItems.value[item.id] = {
|
|
582
|
+
id: item.id,
|
|
583
|
+
success: false,
|
|
584
|
+
errors: response?.errors,
|
|
585
|
+
violations: response?.violations
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
if (response?.state && item.id === currentId.value) {
|
|
589
|
+
state.applyMutationState(response.state);
|
|
554
590
|
}
|
|
555
591
|
} catch {
|
|
556
592
|
mutationStatusItems.value[item.id] = {
|
|
@@ -563,7 +599,8 @@ async function onSubmit() {
|
|
|
563
599
|
}
|
|
564
600
|
}
|
|
565
601
|
isMutating.value = false;
|
|
566
|
-
|
|
602
|
+
const allSucceeded = selectedItems.length > 0 && selectedItems.every((item) => mutationStatusItems.value[item.id]?.success);
|
|
603
|
+
if (!allSucceeded) {
|
|
567
604
|
return;
|
|
568
605
|
}
|
|
569
606
|
if (publishMode.value === "scheduled") {
|
|
@@ -93,10 +93,8 @@ async function publishCurrent() {
|
|
|
93
93
|
$t("publishSuccess", "Changes published successfully.")
|
|
94
94
|
);
|
|
95
95
|
if (!success) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
eventBus.emit("publish:failed");
|
|
99
|
-
eventBus.emit("sidebar:open", "violations");
|
|
96
|
+
if (state.violations.value.length) {
|
|
97
|
+
eventBus.emit("sidebar:open", "analyze");
|
|
100
98
|
}
|
|
101
99
|
return;
|
|
102
100
|
}
|
|
@@ -101,10 +101,6 @@ declare module '#blokkli/editor/adapter' {
|
|
|
101
101
|
}
|
|
102
102
|
declare module '#blokkli/editor/events' {
|
|
103
103
|
interface EventbusEvents {
|
|
104
|
-
/**
|
|
105
|
-
* Emitted when publishing failed.
|
|
106
|
-
*/
|
|
107
|
-
'publish:failed': undefined;
|
|
108
104
|
/**
|
|
109
105
|
* Show the publish dialog.
|
|
110
106
|
*/
|
|
@@ -3,4 +3,11 @@ export declare function toShaderColor(rgba: RGB): RGB;
|
|
|
3
3
|
export declare const rgbaToString: (color: RGB, alpha?: number) => string;
|
|
4
4
|
export declare function getContrastRatio(color1: RGB, color2: RGB): number;
|
|
5
5
|
export declare function findHighestContrastColor(colors: RGB[], backgroundColor?: RGB): RGB;
|
|
6
|
+
export declare const hexToRgb: (hex: string) => RGB | undefined;
|
|
7
|
+
/**
|
|
8
|
+
* Whether the given hex color is "light" — i.e. dark text on top of it would
|
|
9
|
+
* be more readable than light text. Use this to decide between black/white
|
|
10
|
+
* foreground content on a colored background. Unparseable hex → `false`.
|
|
11
|
+
*/
|
|
12
|
+
export declare const isLightHex: (hex: string) => boolean;
|
|
6
13
|
export declare const parseColorString: (color: string) => RGB | undefined;
|
|
@@ -28,6 +28,20 @@ export function findHighestContrastColor(colors, backgroundColor = [255, 255, 25
|
|
|
28
28
|
}
|
|
29
29
|
return maxContrastColor;
|
|
30
30
|
}
|
|
31
|
+
export const hexToRgb = (hex) => {
|
|
32
|
+
const match = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
33
|
+
if (!match) return;
|
|
34
|
+
return [
|
|
35
|
+
Number.parseInt(match[1], 16),
|
|
36
|
+
Number.parseInt(match[2], 16),
|
|
37
|
+
Number.parseInt(match[3], 16)
|
|
38
|
+
];
|
|
39
|
+
};
|
|
40
|
+
export const isLightHex = (hex) => {
|
|
41
|
+
const rgb = hexToRgb(hex);
|
|
42
|
+
if (!rgb) return false;
|
|
43
|
+
return getContrastRatio(rgb, [0, 0, 0]) > getContrastRatio(rgb, [255, 255, 255]);
|
|
44
|
+
};
|
|
31
45
|
export const parseColorString = (color) => {
|
|
32
46
|
const rgbaRegex = /^rgba?\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})(?:,\s*(0|1|0?\.\d+))?\)$/;
|
|
33
47
|
const match = color.match(rgbaRegex);
|