@Override
public Sequence<ApplicationMenuItemDefinition> getMenuItemDefinitions() {
return Sequence.of(
new ApplicationMenuItemDefinition("Playground", 0) {
@Override
protected MenuItem internalCreateItem(ApplicationMenu menu) {
return menu.addItem(getName(), item -> LinkkiUi.getCurrentNavigator()
.navigateTo(PlaygroundView.NAME));
}
});
}
Vaadin 8 to Flow Migration
Application Framework
Messages
-
Deprecated
Message*
classes have been removed-
MessageListPanel
has been replaced byMessageUiComponents#createMessageTable
-
MessagePmo
has been replaced byMessageRowPmo
-
MessageRow
has been replaced byMessageUiComponents#createMessageComponent
-
LinkkiUi and navigation
Navigation has been replaced by Routing, using the @Route
annotation at the corresponding Component
itself. With the new changes, it is no longer necessary to extend the UI as the tasks of LinkkiUi
either became oblivious or is overtaken by ApplicationLayout
.
- LinkkiUi
-
Change Migration The class
LinkkiUi
is removed.Remove sub-classes of
LinkkiUi
.
- ApplicationLayout
-
Change Migration -
The constructor now takes
ApplicationConfig
as a parameter. -
#getApplicationConfig` has been removed.
-
Create a new sub-class of
ApplicationLayout
(e.g.MyApplicationLayout
) -
In the new subclass, pass an instance of the customized
ApplicationConfig
to the super constructor. ThisApplicationConfig
was previously used in the implementation ofLinkkiUi
.
#createApplicationNavigator
has been removed.No migration needed
ApplicationLayout
itself implementsRouterLayout
which make it possible to use theApplicationLayout
as the layout for routes, previously known as views. -
- ApplicationConfig
-
Change Migration The class is moved from
org.linkki.framework.state
toorg.linkki.framework.ui.application
.Reorganize import in the project where
ApplicationConfig
is used.ApplicationConfig#createApplicationLayout
has been removed.Move the implementation of
#createApplicationLayout
to the implementation ofApplicationLayout
.Name, version, description and copyright are moved to
ApplicationInfo
.-
Create a new implementation of
ApplicationInfo
that contains the existing implementation for name, version, description and copyright.
If additional information needs to be stored to be displayed in the header and footer, follow the migration steps for theApplicationHeader
and theApplicationFooter
. -
Return a instance of the new implementation in `ApplicationConfig#getApplicationInfo.
The return type
ApplicationHeaderDefinition
ofApplicationConfig#ApplicationHeaderDefinition
has changed:-
Until now: creates a
ApplicationHeader
from anApplicationMenu
-
New: creates an
ApplicationHeader
from anApplicationInfo
and a sequence ofApplicationMenuItemDefinitions
.
-
If
getHeaderDefinition
was not overridden, no migration is needed. -
If a custom implementation of
ApplicationHeader
was used, consult migration steps of theApplicationHeader
.
ApplicationConfig#ApplicationFooterDefinition
has changed: * Until now: creates aApplicationFooter
from anApplicationConfig
* New: creates anApplicationFooter
from anApplicationInfo
-
If
getFooterDefinition
was not overridden, no migration is needed. -
If a custom implementation of
ApplicationFooter
was used, consult migration steps of theApplicationFooter
.
-
- ApplicationHeader
-
If no custom implementation of
ApplicationHeader
is used, no migration is needed.
In custom implementations:Change Migration ApplicationHeader#addUserMenu
The user menu has been completely removed. This has to be implemented by yourself.If you want to create a user menu, then overwrite
ApplicationHeader#createRightMenuBar
and add aMenuItem
to theMenuBar
ApplicationHeader
uses anApplicationInfo
andSequence<ApplicationMenuItem>
as arguments instead ofApplicationMenu
.Adjust the constructor and the super constructor call within with the new parameters.
ApplicationHeader
now extendsComposite<HorizontalLayout>
instead ofHorizontalLayout
directly.Whenever components are added, add the components to
getContent()
instead.ApplicationInfoPmo
usesApplicationInfo
as constructor argument instead ofApplicationConfig
In a custom
ApplicationInfoPmo
implementation is used:-
In subclasses of
ApplicationInfoPmo
, adjust the constructor and the super constructor call within with the new parameters. -
If
ApplicationHeader#getApplicationInfo
, change the return type to the custom subclass. -
In
ApplicationHeader#createApplicationInfoPmo
, use the adjusted constructor with#getApplicationInfo
.
ApplicationHeader#addRightComponents()
visibility has changed fromprotected
toprivate
due to deprecation.In the subclasses, override and move the code to
addRightComponents(HorizontalLayout)
.API of
ApplicationMenuItemDefinition
has changed, resulting in changes ingetMenuItemDefinitions
.See migration steps of the ApplicationMenuItemDefinition.
-
- ApplicationMenuItemDefinition
-
The API of
ApplicationMenuItemDefinition
is completely reworked. Instead of extending the class for customization, the new API is intended to be easily composable for customization.Change Migration Argument
position
is removed from the constructor as it was not necessary.Remove the attribute. To ensure the position of the menu item, make sure to put it at the right position in
ApplicationConfig#getMenuItemDefinitions
.getName
is removed.Pass the name to the constructor directly instead.
The methods
createItem
andinternalCreateItem
are removed. Instead, new constructors are introduced:-
with name, id and a
Handler
that is executed on click. -
with name, id and a list of
ApplicationMenuItemDefinitions
as sub-menu items -
with name, id and a URL String to navigate to on click. This method handles both external and internal links.
-
with name, id and a
Class
to navigate to. The given class should be a route component.
Use the existing implementation of
internalCreateItem
andcreateItem
to directly create new instances ofApplicationMenuItemDefinition
. A few examples are provided below.The following code snippet shows a simple
ApplicationMenuItem
before and after migration:Table 1. Migration of a simple ApplicationMenuItem Before migration After migration new ApplicationMenuItemDefinition("Playground", "playground", TestScenarioView.class)
For more complex menu items that used to extend from
ApplicationMenuItem
, consider create menu item definitions directly instead of inheriting. If the implementation need to be customizable, it can be easily done by composingApplicationMenuItems
.
Here is an example of a more complexApplicationMenuItem
. This menu item contains one sub-menu item with caption "New". If only one sub-sub-menu item is given, the sub-menu-item shows a notification on click (caption → New). If multiple sub-sub-menu items are given, those are shown in the sub-menu item (caption → New → sub-sub-menu items).Table 2. Migration of a complex ApplicationMenuItem Before migration After migration public class CustomMenuItemDefinition extends ApplicationMenuItemDefinition { private List<MySubSubMenuItem> subSubMenuItems; public CustomMenuItemDefinition(String name, int position, List<MySubSubMenuItem> subSubMenuItems) { super(name, position); this.subSubMenuItems = subSubMenuItems; } private List<MySubSubMenuItem> getSubSubMenuItems() { return subSubMenuItems; } @Override protected MenuItem internalCreateItem(ApplicationMenu menu) { MenuItem newApplicationMenuItem = menu.addItem(getName(), null, null); MenuItem newMenuItem = newApplicationMenuItem.addItem("New", null); if (getSubSubMenuItems().size() > 1) { getSubSubMenuItems().forEach(i -> newMenuItem.addItem(i.getName(), i.getCommand())); } else if (getSubSubMenuItems().size() == 1) { MySubSubMenuItem onlyItem = getSubSubMenuItems().get(0); newMenuItem.addItem(onlyItem.getName(), onlyItem.getCommand()); } return newApplicationMenuItem; } public static class MySubSubMenuItem { private String name; public MySubSubMenuItem(String name) { this.name = name; } public String getName() { return name; } public Command getCommand() { return i -> Notification.show(name); } } }
public class CustomMenuItemDefinitionCreator { public static ApplicationMenuItemDefinition createMenuItem(String name, String id, List<MySubSubMenuItem> subSubMenuItems) { return new ApplicationMenuItemDefinition(name, id, Collections.singletonList(createSubMenuItem(subSubMenuItems))); } private static ApplicationMenuItemDefinition createSubMenuItem(List<MySubSubMenuItem> subSubMenuItems) { String subMenuName = "New"; if (subSubMenuItems.size() > 1) { return new ApplicationMenuItemDefinition(subMenuName, "new", subSubMenuItems.stream() .map(i -> new ApplicationMenuItemDefinition(i.getName(), i.getId(), () -> i.getCommand().apply())) .collect(Collectors.toList())); } else if (subSubMenuItems.size() == 1) { MySubSubMenuItem onlyItem = subSubMenuItems.get(0); return new ApplicationMenuItemDefinition(onlyItem.getName(), onlyItem.getId(), onlyItem.getCommand()); } else { return new ApplicationMenuItemDefinition(subMenuName, "new", Handler.NOP_HANDLER); } } public static class MySubSubMenuItem { private String name; private String id; public MySubSubMenuItem(String name, String id) { this.name = name; this.id = id; } public String getName() { return name; } public String getId() { return id; } public Handler getCommand() { return () -> Notification.show(name); } } }
-
Change | Migration |
---|---|
|
Adjust the constructor and the super constructor call within with the new parameters. |
|
Whenever components are added, add the components to |
|
Adjust the implementation of |
|
In subclasses, override and move the code to |
Visibility of |
This method should not be called externally anymore. Remove external calls. |
- Views
Change | Migration |
---|---|
|
Remove the interface in all implementations. |
Views must be annotated with |
Annotate all views with |
- Other changes
-
-
ApplicationNavigator
has been removed
-
Components
-
Dialogs are now extending
Composite<Dialog>
instead ofWindow
. -
MessageUiComponents
are now displayed usingGrid
instead ofTable
TabSheetArea has been replaced by LinkkiTabLayout
-
TabSheetArea#addTab
→LinkkiTabLayout#addTabSheet
-
TabSheetArea#createContent
to add tabs usingTabSheetArea#addTab
has been removed. Instead,LinkkiTabLayout#addTabSheet
should be used -
TabSheetArea#updateContent
has been removed.
SidebarLayout has been replaced by LinkkiTabLayout
Before migration | After migration |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Tab visibility can be controlled using LinkkiTabSheetBuilder#visibleWhen
and LinkkiTabLayout#updateSheetVisibility
.
SidebarSheet has been replaced by LinkkiTabSheet
For performance reasons, components must be created via a supplier and can no longer be set directly.
Before migration | After migration |
---|---|
|
|
|
|
|
|
*UiUpdateObserver
has been replaced by AfterTabSelectedObserver
. For more information see AfterTabSelectedObserver.
@UIButton
-
styleNames()
has been replaced byvariants()
, which now returns an Array ofButtonVariant
-
shortcutKeyCode
now returnsString[]
. Commonly usedKeyCodes
in linkki are defined inKeyCode
. An overview of all supported keys can be found in Vaadin’sKey
class. -
shortcutModifierKeys
now returns an Array ofKeyModifier
. For a list of available modifiers, see Vaadin’s enum classKeyModifier
.
@UIDateField
The date format of a @UIDateField is now controlled by DateFormats
and the locale, the attribute dateFormat
has been removed.
@UITextArea
Attribute rows
does not exists anymore. It has been replaced by height
, which returns a String
, specifying the height of the component using a number and a CSS unit, for example "5em".
ComponentFactory
Following *Label
methods have been removed, as Label
has been replaced by LinkkiText
:
-
newLabelWidth100(parent, caption)
-
sizedLabel(parent, caption, contentMode)
-
sizedLabel(parent, caption)
-
newLabelWidthUndefined(parent, caption)
-
labelIcon(parent, fontIcon)
-
newEmptyLabel(layout)
-
newLabelIcon(fontIcon)
-
newLabelFullWidth(caption, contentMode)
-
newLabelFullWidth(caption)
-
newLabelUndefinedWidth(caption, contentMode)
-
newLabelUndefinedWidth(caption)
Component#setIcon
The setIcon
method for Component
has been deleted. It is only available for @UIButton
and components, that are implementing the HasIcon
interface, like the ones created by @UILabel
and @UILink
.
Resource / Icon
com.vaadin.server.Resource
for icons in Vaadin 8 has been replaced by VaadinIcon#create
Tables have been replaced by Grids
In Vaadin Flow, Table
has been replaced by Grid
-
PmoBasedTablefactory
has been replaced byGridComponentCreator
-
@UITableColumn
:expandRatio
replaced byflexGrow
. TheflexGrow
specifies what amount of the available space inside the table the column should take up and grow (if resized), proportionally to the other columns. IfflexGrow
is set to 0, the column has a fixedwidth
.
Notifications
In Vaadin 8, there used to be four types of notification: humanized, warning, error and tray. This categorization does not exist anymore. To display notifications based on the severity, linkki provides a new class NotificationUtil
. See the documentation on notifications for more detail.
Aspect annotations
@BindIcon
The @BindIcon
annotation is available for @UIButton
and all components, that are implementing the HasIcon
interface. At the moment, these are @UILabel
and @UILink
. Using htmlContent
of the @UILabel
will override any icon.
@BindTooltip
HTML content is no longer support for tooltips.
NLS
TextProvider
It is recommended to provide an implementation of I18NProvider
as following, to ensure UI#getLocale
returns the best matching Locale
corresponding to the user agent’s preferences (i.e. the Accept-Language
header). If no I18NProvider
is available, the default JVM Locale
is used.
@Component
public class MyI18NProvider implements I18NProvider {
...
}
Styling
In general, the the Sass precompiler is no longer used by default, which means that any existing styling code that utilized SCSS functionalities needs to be adjusted to work in CSS.
In addition, all applications need to either apply the "linkki"
theme or a theme that extends from it to make sure that the linkki components work properly. Detailed instructions are provided in the chapter "Styling".
As the generated HTML has changed drastically, existing styling customizations have to be checked for necessity and, if still necessary, adjusted for the new DOM structure. As Vaadin components are now mostly web components, existing styles that apply to Vaadin components most likely do not work any more. Consult the Vaadin documentation on component styling to adjust the selectors and the documentation on theming for how to include them in the custom theme.
ComponentStyles
In Vaadin 8, sections created with @UISection
have a dynamic label width by default, i.e. the labels are as long as the longest label.
For @UIFormSection
, LinkkiTheme
offered style names to set a fixed width.
This behavior has changed with Vaadin Flow. All sections now have a fixed label width by default. It is not possible to have dynamic label width anymore.
To set a custom label width, you can use ComponentStyles.setFormItemLabelWidth(Component, String)
.
This replaces the class names LinkkiTheme.LABEL_FIXED_WIDTH
and LinkkiTheme.LABEL_FIXED_WIDTH_LONG
.
Before migration | After migration |
---|---|
|
|
To apply a custom label width to all sections inside a Component
, the surrounding layout such as AbstractPage
can be passed as the Component
-Parameter.
For more information see ComponentStyles.
Views
PageTitle
In order to set a page title for a view, the View
class has to be annotated with either @PageTitle
or has to implement the HasDynamicTitle
interface.
For more Information see Updating the Page Title During Navigation