From 952950ade78442b3f67ceab20d85219993b4d340 Mon Sep 17 00:00:00 2001 From: Tomi Virkki Date: Fri, 21 Aug 2026 10:31:11 +0300 Subject: [PATCH 1/2] docs: document custom AI field marker popover content Co-Authored-By: Claude Fable 5 --- articles/flow/ai-support/ai-powered-form.adoc | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/articles/flow/ai-support/ai-powered-form.adoc b/articles/flow/ai-support/ai-powered-form.adoc index 1dc1e4c99c..a70125938f 100644 --- a/articles/flow/ai-support/ai-powered-form.adoc +++ b/articles/flow/ai-support/ai-powered-form.adoc @@ -252,6 +252,7 @@ The marker needs no application code: * The marker clears itself as soon as the user edits or reverts the field, so a stale cue never lingers over a value the user changed. * The marker survives detaching and re-attaching the field. +[[disabling-the-marker]] === Disabling the Marker Call [methodname]`setFieldMarkerEnabled(false)` for a form that should carry no trace of the AI's edits: @@ -285,6 +286,26 @@ Each text has a specific role: The texts are applied to every marker the controller puts on a field, so set them before the first turn to localize them all. Texts left `null` fall back to the built-in defaults. +[role="since:com.vaadin:vaadin@V25.3"] +=== Custom Popover Content + +By default the marker's popover holds the explanation message and the revert control. To show what the AI based a value on -- for example the source snippets reported when <<#source-tracking,source tracking>> is enabled -- set a content provider with [methodname]`setFieldMarkerContentProvider()`. The component it returns is shown in the popover between the message and the revert control: + +[source,java] +---- +controller.setSourceTrackingEnabled(true); +controller.setFieldMarkerContentProvider(change -> + change.getFieldSource() + .map(source -> new Div(source.extracts().stream() + .map(extract -> new Paragraph(extract.text())) + .toArray(Component[]::new))) + .orElse(null)); +---- + +The provider is called once per field whose value changed during a successful turn, with the same event the <<#reacting-to-ai-changes,change listeners>> receive, before those listeners run. Returning `null` leaves that field's popover without extra content. Return a fresh component on every call; a component that already has a parent is rejected. + +The controller owns the returned component's lifecycle: the content stays in the popover as long as the mark it belongs to, is replaced when a later turn fills the field again, and goes away with the mark when the user edits or reverts the field. Like the mark itself, the content survives detaching and re-attaching the field. When the marker is <<#disabling-the-marker,disabled>>, the provider is never called. + [[reacting-to-ai-changes]] == Reacting to AI Changes From 5cacde118a382f3145a22619e95071cebbf8b908 Mon Sep 17 00:00:00 2001 From: Tomi Virkki Date: Wed, 26 Aug 2026 15:21:36 +0300 Subject: [PATCH 2/2] docs: align field marker popover content docs with updated API Co-Authored-By: Claude Fable 5 --- articles/flow/ai-support/ai-powered-form.adoc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/articles/flow/ai-support/ai-powered-form.adoc b/articles/flow/ai-support/ai-powered-form.adoc index a70125938f..bb66c288f5 100644 --- a/articles/flow/ai-support/ai-powered-form.adoc +++ b/articles/flow/ai-support/ai-powered-form.adoc @@ -289,12 +289,12 @@ The texts are applied to every marker the controller puts on a field, so set the [role="since:com.vaadin:vaadin@V25.3"] === Custom Popover Content -By default the marker's popover holds the explanation message and the revert control. To show what the AI based a value on -- for example the source snippets reported when <<#source-tracking,source tracking>> is enabled -- set a content provider with [methodname]`setFieldMarkerContentProvider()`. The component it returns is shown in the popover between the message and the revert control: +By default the marker's popover holds the explanation message and the revert control. To show what the AI based a value on -- for example the source snippets reported when <<#source-tracking,source tracking>> is enabled -- set a content provider with [methodname]`setFieldMarkerPopoverContentProvider()`. The component it returns is shown in the popover between the message and the revert control: [source,java] ---- controller.setSourceTrackingEnabled(true); -controller.setFieldMarkerContentProvider(change -> +controller.setFieldMarkerPopoverContentProvider(change -> change.getFieldSource() .map(source -> new Div(source.extracts().stream() .map(extract -> new Paragraph(extract.text())) @@ -302,7 +302,7 @@ controller.setFieldMarkerContentProvider(change -> .orElse(null)); ---- -The provider is called once per field whose value changed during a successful turn, with the same event the <<#reacting-to-ai-changes,change listeners>> receive, before those listeners run. Returning `null` leaves that field's popover without extra content. Return a fresh component on every call; a component that already has a parent is rejected. +The provider is called once per field whose value changed during a successful turn, with the same event the <<#reacting-to-ai-changes,change listeners>> receive, before those listeners run. Returning `null` leaves that field's popover without extra content. Return a fresh component on every call; a component that already has a parent is rejected -- the controller logs a warning and marks the field without the extra content, without failing the turn. The controller owns the returned component's lifecycle: the content stays in the popover as long as the mark it belongs to, is replaced when a later turn fills the field again, and goes away with the mark when the user edits or reverts the field. Like the mark itself, the content survives detaching and re-attaching the field. When the marker is <<#disabling-the-marker,disabled>>, the provider is never called.