Vaadin Flow Components V25.2.0-beta2
Pre-releaseVaadin Flow Components 25.2.0-beta2
This is a release of the Java integration for Vaadin Components to be used from the Java server side with Vaadin Flow.
Changes in Flow Components from 25.2.0-beta1
Changes in All Components
- Chore:
- ⧉ Increase Web-Component version
Changes in vaadin-ai-components-flow
-
Breaking Changes:
-
⧉ Use config class for form ai controller value options (#9372) (CP: 25.2). PR:9408
This PR cherry-picks changes from the original PR #9372 to branch 25.2. --- #### Original PR description > ## Description > > This PR adds a
ValueOptionsbuilder for configuring per-field options onFormAIController. A registration carries the field together with the label set the LLM may pick from; the controller pairs it with a label-to-value converter (implicit forString-valued fields, required for any other value type). > > ###ValueOptionsAPI > > -ValueOptions.forField(HasValue<?, V> field)— single-value field. > -ValueOptions.forField(MultiSelect<C, T> field)— multi-select field; picked by the compiler whenever the reference is statically typed asMultiSelect. > -options(Collection<String>)— fixed label list. > -options(BiFunction<String, Integer, List<String>>)— queryable label callback (filter + limit → labels). > >options(...)overloads are mutually exclusive; calling one clears the other so the last setter wins. > > ###FormAIController.valueOptionsoverloads > > -valueOptions(ValueOptions<String> config)— forString-valued fields. The converter is implicitlyFunction.identity(): the chosen label is the value. > -<V> valueOptions(ValueOptions<V> config, Function<String, V> toValue)— for any other value type. The compiler requires the converter — a non-Stringregistration without one does not compile. > > For multi-select fields the controller aggregates the resolved per-label elements into aLinkedHashSetbeforeHasValue#setValue. > > ### Sample uses > >Stringsingle-value field (no converter — identity implicit): >java > controller.valueOptions( > ValueOptions.forField(currencyCombo) > .options(List.of("EUR", "USD", "GBP"))); >> > Non-Stringsingle-value field (explicit converter): >java > controller.valueOptions( > ValueOptions.forField(projectSelect) > .options((filter, limit) -> projectService.search(filter, limit)), > label -> projectService.findByName(label)); >> >Stringmulti-select field (no converter): >java > controller.valueOptions( > ValueOptions.forField(tagsCheckboxGroup) > .options(List.of("AI", "Cloud", "Security"))); >> > Non-Stringmulti-select field (per-element converter): >java > controller.valueOptions( > ValueOptions.forField(projectsMultiSelect) > .options(List.of("Apollo", "Vega")), > label -> projectService.findByName(label)); >> > ### Multi-value support contract > > Multi-value components are only supported if they implement theMultiSelectinterface. The controller's runtime checks enforce this at registration time: > > - AMultiSelectfield registered through the single-valueforFieldoverload (upcast reference) is rejected with a message that steers the developer to declare the reference asMultiSelect. > - A field whose value type is aCollectionbut does not implementMultiSelectis rejected — Collection-valued fields must implementMultiSelectto be registered viavalueOptions(...). > > Fixes https://github.com/orgs/vaadin/projects/103/views/1?filterQuery=&pane=issue&itemId=190875414 > > ## Type of change > > - [ ] Bugfix > - [ ] Feature > - [x] Refactor > > ## Checklist > > - [x] I have read the contribution guide: https://vaadin.com/docs/latest/contributing/overview > - [x] I have added a description following the guideline. > - [x] The issue is created in the corresponding repository and I have referenced it. > - [x] I have added tests to ensure my change is effective and works as intended. > - [x] New and existing tests are passing locally with my change. > - [x] I have performed self-review and corrected misspellings. >
-
-
New Features:
-
⧉ Add field highlighting for ai updated fields (#9413) (CP: 25.2). PR:9440
This PR cherry-picks changes from the original PR #9413 to branch 25.2. --- #### Original PR description > ## Description > > This PR: > - Adds
withFieldValuesChanged(Consumer<Map<HasValue, FieldValueChange>>), which fires once per successful turn. Ignored fields are excluded. Skipped when the turn ended in error or when no field changed. > - AddsshowHighlight(HasValue)andhideHighlight(HasValue)to control the highlighter. Each controller carries a per-instance UUID id (vaadin-ai-<uuid>) and usesaddUser/removeUser, so the AI highlight coexists with any other field-highlighter user the application keeps on the same field. The highlight is not retained across detach/re-attach. > > Fixes https://github.com/orgs/vaadin/projects/103/views/1?filterQuery=&pane=issue&itemId=193540699 > > ## Type of change > > - [ ] Bugfix > - [x] Feature > > ## Checklist > > - [x] I have read the contribution guide: https://vaadin.com/docs/latest/contributing/overview > - [x] I have added a description following the guideline. > - [x] The issue is created in the corresponding repository and I have referenced it. > - [x] I have added tests to ensure my change is effective and works as intended. > - [x] New and existing tests are passing locally with my change. > - [x] I have performed self-review and corrected misspellings. > - [x] Enhancement / new feature was discussed in a corresponding GitHub issue and Acceptance Criteria were created. -
⧉ Expose per-turn session metadata to the LLM (#9399) (CP: 25.2). PR:9410
This PR cherry-picks changes from the original PR #9399 to branch 25.2. --- #### Original PR description > ## Summary > - The LLM needs ambient session context — current date/time, and optionally tenant, locale, or view state — to interpret relative references like "sales from the past two months" instead of guessing. Putting that in the system prompt would invalidate its cache every turn, so it rides on a built-in get_session_context tool whose description carries the content, keeping the (potentially large) system prompt cacheable. > - The orchestrator installs a default supplier that provides the current server date and time; withMetadata lets apps replace or extend it with their own context, or pass null to disable the tool entirely. > > Closes https://github.com/orgs/vaadin/projects/103/views/3?pane=issue&itemId=193058102 > > 🤖 Generated with Claude Code
-
⧉ Expose form workflow via get_form_instructions tool (#9371) (CP: 25.2). PR:9407
This PR cherry-picks changes from the original PR #9371 to branch 25.2. --- #### Original PR description > ## Summary > - Applications no longer have to repeat the form-fill workflow in their own system prompts — the controller carries its own contract, so adopters only supply domain context. > - Mirrors the existing
get_chart_instructions/get_grid_instructionspattern so behaviour is consistent across AI-component controllers. > > Fixes https://github.com/orgs/vaadin/projects/103/views/3?pane=issue&itemId=189954324 > > 🤖 Generated with Claude Code -
⧉ Surface validation in fill_form response. PR:9341
## Summary - Wires
Binder.Binding/HasValidatorrejections into thefill_formtool result so the LLM can self-correct in the same turn instead of silently leaving the form in an invalid state. Validation runs atfill_formexecution time only, per the RFC's validation-feedback flow. - Per RFC,fill_formnow mirrorsget_form_state's shape — returning the full post-writefieldsblock plusrejected— so value-change listener cascades and other downstream shifts are visible without an extra round-trip. (Breaking: the previoussuccess/writtenkeys are gone; derive success fromrejected.isEmpty().) - The schema is otherwise intentionally kept shape-only (type / format / value / enum / queryable / array / items); JSR-303 and component-side constraints reach the LLM through the validator feedback path onfill_form. Surfacing those constraints proactively inget_form_state(e.g. viajakarta.validation.Validatorintrospection, paired withBeanValidationBinder) is deferred until later. Closes https://github.com/orgs/vaadin/projects/103/views/3?pane=issue&itemId=186557546 🤖 Generated with Claude Code --------- -
⧉ Add prompt overload accepting attachments. PR:9339
## Description This PR adds
prompt(String, List<AIAttachment>)overload toAIOrchestrator. The overload uses only the supplied list and does not drain a configuredAIFileReceiver; pending uploads stay in the receiver for the next call toprompt(String)or the user's next submit. An empty list is still "explicit" — it does not fall back to the receiver. Fixes https://github.com/orgs/vaadin/projects/103/views/1?filterQuery=&pane=issue&itemId=189945711 ## Type of change - [ ] Bugfix - [x] Feature ## Checklist - [x] I have read the contribution guide: https://vaadin.com/docs/latest/contributing/overview - [x] I have added a description following the guideline. - [x] The issue is created in the corresponding repository and I have referenced it. - [x] I have added tests to ensure my change is effective and works as intended. - [x] New and existing tests are passing locally with my change. - [x] I have performed self-review and corrected misspellings. - [x] Enhancement / new feature was discussed in a corresponding GitHub issue and Acceptance Criteria were created.
-
-
Fixes:
-
⧉ Surface binder cross-field rejections in fill_form (#9406) (CP: 25.2). PR:9412
This PR cherry-picks changes from the original PR #9406 to branch 25.2. --- #### Original PR description > ## Summary > - Bean-level cross-field rules registered with
binder.withValidator((bean, ctx) -> ...)never ran duringfill_form, so a value combination that violated such a rule came back as success and the model had no way to correct it. > - These failures now appear as rejections keyed on a__form__sentinel id, since a cross-field rule is not tied to a single field. > -fill_formnow writes every value before it validates, so each field's verdict is based on the fully-written form and no longer depends on the order the values arrived in. > - Validation only reads each verdict; it does not change the UI. Fields the current fill did not write are not marked invalid, so required fields the user has not reached yet stay clean. > > 🤖 Generated with Claude Code > -
⧉ Respect visibility, enabled, and read-only state in the form AI (#9398) (CP: 25.2). PR:9411
This PR cherry-picks changes from the original PR #9398 to branch 25.2. --- #### Original PR description > ## Description > The form AI controller discovered every
HasValuein the form and offered all of them to the model throughget_form_state, no matter their state. A field the application had hidden, disabled, or set read-only was still readable — and writable throughfill_form. So the AI could read values off fields the user cannot see and overwrite fields the user cannot edit. > > For example, an expense form shows a read-only, computed "Total" and a "Cost center" field enabled only for business trips. Before this change, a prompt like "set the total to 0 and the cost center to X" was carried out even though the user can neither edit the total nor reach the cost center. > > Changes: > > - Hidden fields are excluded fromget_form_stateandfill_form. > - Disabled and read-only fields stay inget_form_stateas read-only context, each carrying a"disabled"or"readOnly"flag alongside its description and current value.fill_formrejects writes to them with a reason. This keeps context the model may need to fill other fields, while preventing edits. > - During a fill turn the controller sets every writable field read-only so the user cannot race the AI. That turn lock is excluded from the"readOnly"flag, so a field the controller locked is never reported as read-only to the model — only application-set read-only is. > - The model instructions explain the flags and tell the model to set a controlling field first to unlock a disabled or read-only field. > > --- > > 🤖 Generated with Claude Code -
⧉ Resolve eager-items selects without explicit valueOptions. PR:9357
## Summary - An eager
setItems(...)ComboBox/Select/RadioButtonGroup/CheckboxGroup/MultiSelectComboBox was unwritable fromfill_formunless the app also calledFormAIController.valueOptions(...), even though the schema already surfaces those items asenum. - The converter now resolves an LLM-supplied label against the field's in-memory items viarenderItemfor both single- and multi-select, so both halves of the tool protocol agree on the label set without forcing a second registration. 🤖 Generated with Claude Code ---------
-
Changes in vaadin-grid-flow
- Fixes:
-
⧉ Do not include flow-server packages from OSGI manifest (#9414) (CP: 25.2). PR:9416
This PR cherry-picks changes from the original PR #9414 to branch 25.2. --- #### Original PR description > ## Description > > Fixes the
vaadin-boardOSGI manifest to not exportcom.vaadin.flow.component.clipboardfromflow-server: > - Change the exported package pattern to not use a wildcard before the component name > - Introduce aosgi.export.package.additionalvariable, so thatvaadin-gridcan still exportcom.vaadin.flow.component.treegrid, which is otherwise not exported anymore with the new pattern > - Remove the-noimport:=truedirective to simplify the implementation, which doesn't seem to make any difference as the same manifests are generated without it > - Remove some demo related instructions, which should not be relevant since demo modules have been removed > > Fixes #9392 > > ## Type of change > > - Bugfix >
-
Changes in vaadin-spreadsheet-flow
- Fixes:
-
⧉ Make spreadsheet overlays native popover, per instance (#9303) (CP: 25.2). PR:9495
This PR cherry-picks changes from the original PR #9303 to branch 25.2. --- #### Original PR description > The spreadsheet attaches a
<div id="spreadsheet-overlays">to host its overlay widgets (context menu, tooltips, comment overlays, popup buttons). It has historically lived in<body>to escape clipping by ancestoroverflow/transformrules and as a singleton shared by all spreadsheet instances on the page. Switching the overlays to native popover changes the picture: every overlay enters the top layer regardless of DOM position, so neither the body-attachment nor the singleton are load-bearing anymore. > > This PR includes the native popover changes proposed in #9270 and adds the structural changes that the popover approach enables: > > - the container moves into the<vaadin-spreadsheet>light DOM, projected into the shadow root via a newoverlaysslot, with one container per instance; > - the reference is threaded from JS into the GWT widget chain instead of being looked up by id; > -SpreadsheetConnector— notApplicationConnection— now owns theSpreadsheetContextMenu. > > Tooltips and the cell-comment overlay are created inSheetWidget's constructor (before the host is known), so the container is wired in via a setter rather than a constructor argument. > > A side benefit: spreadsheet overlays inside a modalDialogare interactive again. The modal setsbody { pointer-events: none }to disable everything outside the dialog overlay; with the container now inside the dialog's slotted content, the overlays inheritpointer-events: autofrom the dialog's overlay part instead ofpointer-events: nonefrom<body>. > > Intended to replace #9270. > > Related to #9270 > > --- > > 🤖 Generated with Claude Code -
⧉ Defer Spreadsheet.selectCellRange until sheet widget layout is ready (#9381) (CP: 25.2). PR:9484
This PR cherry-picks changes from the original PR #9381 to branch 25.2. --- > > Follow-up to #9333. When a Spreadsheet inside a closed Dialog is opened, Flow > flushes the property writes and the
setSelectedCellAndRangeRPC in the same > task. The api receives the call before the deferred init scheduled in >SheetWidget.resetFromModelhas run — soSheetWidget.getRowHeightreads an > uninitializeddefinedRowHeightsand throws > >> Uncaught TypeError: Cannot read properties of undefined (reading 'length') >> > That throw drops the selection and trips the*_noErrors/*_noConsoleErrors> console-log assertions. > > #9333's connector-side guard masked this by probingdefinedRowHeights> through the api's private GWT fields — names that only survive >-Dgwt.style=pretty(local/dev). CI compiles the GWT client with >-Dgwt.style=OBF, where those private names are renamed andapi.spreadsheetWidget> isundefined. The guard itself then threw, producing the same SEVERE log and > the same ~20 spreadsheet IT failures on the cherry-pick PRs. > > > Move the layout-readiness handling into the widget that owns the operation: > > -SheetWidget.isLoaded()(package-private) — exposes the already-existing >loadedflag that flips at the end ofresetFromModel's deferred command. > -SpreadsheetWidget.selectCellRange— if!sheetWidget.isLoaded(), store the > latest args andScheduler.scheduleDeferred(this::applyPendingSelectCellRange). > The deferred re-checks, applies, or re-schedules. Latest-wins (rapid successive > calls collapse to the final selection). Bounded at 100 hops as a safety net; > in the typical case the layout init has already been scheduled before us, so > GWT's FIFO scheduler resolves us in 0–1 hops. > -vaadin-spreadsheet.js—setSelectedCellAndRangegoes back to a one-liner > (this._flush(); this.api.setSelectedCellAndRange(...args)). No try/catch, > no pending state, no constants. > > OnlyselectCellRangeis deferred — it's the only RPC that touches row/column > metrics. Other RPCs (cellsUpdated, popup ops, etc.) don't need this and > didn't fail in the original CI runs. > > > Reproduce locally by compiling the client with-Dgwt.style=OBF(matching CI) > and running the merged ITs in production mode: > >> mvn clean install -DskipTests -Dgwt.style=OBF \ > -pl vaadin-spreadsheet-flow-parent/vaadin-spreadsheet-flow-client,vaadin-spreadsheet-flow-parent/vaadin-spreadsheet-flow > node scripts/mergeITs.js spreadsheet > mvn verify -Drun-it -pl integration-tests -Dvaadin.productionMode=true \ > -Dit.test='NavigationIT,SpreadsheetDialogIT' -DskipUnitTests >> > - With this PR → NavigationIT 26/0, SpreadsheetDialogIT 1/0. > - Reverting only the GWT-side change → SpreadsheetDialogIT fails with the > underlyingCannot read properties of undefined (reading 'length')in >FlowClient-…js— the actualdefinedRowHeightsNPE. > > Follow-up to #9333. > > --- > > 🤖 Generated with Claude Code -
⧉ Defer setSelectedCellAndRange until sheet layout is ready. PR:9373
Follow-up to #9333. The connector's
setSelectedCellAndRangesilently dropped calls when the sheet widget'sdefinedRowHeightswasn't yet populated, on the assumption that Flow would reissue the call. That assumption only holds for the reload cycle path (initialSheetSelectionset on the server, thenonSheetScrollfrom the client triggeringreloadCurrentSelection). For any other path — most notably the selection RPC sent when the user types a range into the address field — there is no reissue, so a call that loses the race against GWT's deferred initial relayout is lost permanently. This caused the cherry-pick PRs (#9365, #9366, #9367) to consistently fail 20 selection-related tests (NavigationIT,NamedRangeIT,ChartsIT,SheetTabSheetIT,PreserveOnRefreshIT, and the newSpreadsheetDialogIT). The original PR happened to pass on main's CI agent timing, but the failure is deterministic on the cherry-pick branches' GWT 2.9 / older-Flow-SNAPSHOT environment. Queue the latest call as_pendingSelectionand polldefinedRowHeightsevery 10 ms until it's set or the element is disconnected. Rapid successive calls collapse to the final selection (the array is overwritten, only one retry loop runs at a time). Follow-up to #9333. --- 🤖 Generated with Claude Code
-
Changes in vaadin-upload-flow
- Fixes:
-
⧉ Avoid serializing full File instance for determining uploading state (#9444) (CP: 25.2). PR:9449
This PR cherry-picks changes from the original PR #9444 to branch 25.2. --- #### Original PR description > ## Description > > The Flow Upload component currently listens to several web component events to determine whether the component is still processing any upload or not. To facilitate that it sends fully serialized instances of all JS
Fileobjects to the server in order to access theuploadingproperty of each. Serializing the full File object can lead to circular serialization issues as reported in #9434. > > This changes the respective event listeners to determine the uploading state on the client via a JS expression and then only sends a single boolean with the event, rather than the full File object. This avoids serializing File objects completely and also reduces the payload of the event. > > Fixes #9434 > > ## Type of change > > - Bugfix >
-
Compatibility
- This release use Web Components listed in Vaadin Platform 25.2.0-beta2
- Tested with Vaadin Flow version 25.2.0-beta2