Page History
Info | ||
---|---|---|
| ||
Workshop 23.05.2018
The recordings of the workshop are available at the file server:
- afp://fileserver.magnolia-cms.com/All/Product Development/Knowledge Transfer/2018/20180522-UI-Workshop-part-1.mp4
- afp://fileserver.magnolia-cms.com/All/Product Development/Knowledge Transfer/2018/20180522-UI-workshop-part-2.mp4
Related repos:
Project with UI framework extensions and reference content app implementation: https://git.magnolia-cms.com/users/apchelintcev/repos/content-app-poc/browse
UI fork with necessary minimal changes: https://git.magnolia-cms.com/users/jsimak/repos/ui-bottom-lift/browse
Related JIRA issues:
Jira | ||||||||
---|---|---|---|---|---|---|---|---|
|
Jira | ||||||||
---|---|---|---|---|---|---|---|---|
|
Jira | ||||||||
---|---|---|---|---|---|---|---|---|
|
Jira | ||||||||
---|---|---|---|---|---|---|---|---|
|
Jira | ||||||||
---|---|---|---|---|---|---|---|---|
|
Jira | ||||||||
---|---|---|---|---|---|---|---|---|
|
Main goals
- Adapt UI framework to Vaadin 8 concepts
- Data binding in forms, dialogs and grids - simplify the existing solution
Model View Presenter
Initial investigation concept: Design patterns in UI content app
Reasons to bother | What changes | Benefits |
---|---|---|
|
|
|
Inversion of control (IoC) capabilities in UI
Reasons to bother | What changes | Outcome |
---|---|---|
| ViewProvider API Special factory API that creates the view with all the following additional features. Bean Storages for the views Each framework view gets the bean storage (same as app/sub-app) and can store objects in there. Each view can create sub-views and their storages will form an hierarchy with the parent's which makes it easy to traverse the parent storages from the child ones. Sharing objects between views Each view can bind view contexts (see MVP pattern changes) and publish other objects like definitions so that all the child views can access them effortlessly ComponentProvider for every view Each view gets its own
| Benefits:
|
Questions:
|
ContentConnector
Reasons to bother | What changes | Outcome |
---|---|---|
| Instead of single CC interface we can introduce a concept of a
| Benefits
Concerns
|
Data binding in grids and tree grids
Reasons to bother | What changes | |
---|---|---|
Vaadin 8 brings in new concepts to the data binding
| DataProvider
PropertySet
| Benefits
Concerns
|
Content change events
Reasons to bother | What changes | Outcome |
---|---|---|
Quirky way of communicating the data source changes
| We should try to expose the data source observation utilities and subscribe to them where needed.
| Benefits
Questions
|
Field definitions
Reasons to bother | What changes | Benefits |
---|---|---|
|
| Better compatibility with the new, more type-safe Vaadin data-binding API's |
Form definition
Reasons to bother | What changes | Outcome |
---|---|---|
|
Possibly we introduce an alternative term 'editor' which is more generic than the form | Benefits
Questions
|
I18N support in dialogs
Column definitions
Complex fields
Current state overview
Framework should help the developers to build their apps with Magnolia faster, get access to the components and features, framework though should not be all the time in the way of the developer.
The current offering of the UI framework:
- Content app implementation
- Form framework
- Flexibility via configuration of the content apps
- Dependency injection via Guice and factory capabilities of the ComponentProvider
- EventBus API to share events between the UI parts
The problems:
...
- Solution proposal - let the views drive the process, treat presenters as optional, view-specific detail that merely helps to separate communication with the backend.
...
- As a result - lot's of redundant Listener interfaces between views and presenters.
- Each view and a presenter as a result is a Guice component mapped in the module descriptor, making it hard to override the parts with custom implementations.
- Can we treat views more as custom Vaadin components? Can we rely more on
ComponentProvider#newInstance
more when creating the views and merely using the impl classes coming from e.g. definitions? - Possible solution: provide views with out-of-the-box component provider and
#create()
API, let them create sub-views easily.
...
How to share context and provide injectable components
...
- Views rarely require 'components' with specific lifecycle (typically they just need an instance of smth).
- Views, especially the ones that are bound to generic data, require generic instances to be provided. Guice does not support that easily (and our XML configs completely block that).
...
Code Pro | ||||
---|---|---|---|---|
| ||||
public interface UiFrameworkView extends View {
...
/**
* Wrapper around {@link ComponentProvider} capabilities.
*/
default <T> T create(Class type, Object... args) {
return getComponentProvider().newInstance((Class<T>) type, args);
}
default ViewProvider getViewProvider() {
return new ViewProvider.Impl(getCurrentViewReference());
}
default ComponentProvider getComponentProvider() {
return new ViewComponentProvider(getCurrentViewReference());
}
default UiContextReference getCurrentViewReference() {
return ViewContextKeyRegistry.access()
.lookUp(this)
.orElseGet(() -> CurrentUiContextReference.get().getUiContextReference());
}
default <T extends ViewContext> T bindContext(Class<? extends T> contextClass) {
final T context = new ViewContextProxy().createViewContext(contextClass);
SessionStore.access().getBeanStore(getCurrentViewReference()).put(contextClass, context);
return context;
}
default void bindDatasource(Object definition) {
SessionStore.access().getBeanStore(getCurrentViewReference()).put(DatasourceHolder.class, new DatasourceHolder(definition));
}
}
|
How to bind to different data sources
The following could be a looser and more flexible replacement for the ContentConnector abstraction. Instead of having the monolithic interface, we rather could facilitate a DatasourceSupport
that could provide data-binding implementations based on the exposed configuration by e.g. delegating to the registered reference implementations.
Code Pro | ||
---|---|---|
| ||
@Singleton
public class DatasourceSupport {
private final Map<Class, DatasourceBundle> bundles;
@Inject
public DatasourceSupport(Set<DatasourceBundle> bundles) {
this.bundles = bundles
.stream()
.collect(toMap(
DatasourceBundle::supportedDataSourceType,
identity()));
}
@SuppressWarnings("unchecked")
public <DEF> DatasourceBundle<DEF> getDatasourceBundle(DEF def) {
Objects.requireNonNull(def);
return Optional.ofNullable(bundles.get(def.getClass())).orElseThrow(() -> new IllegalArgumentException("No such bundle for the type " + def.getClass()));
}
}
@Multibinding
public abstract class DatasourceBundle<DEF> {
private final Class<DEF> type;
public DatasourceBundle(Class<DEF> type) {
this.type = type;
}
public Class<DEF> supportedDataSourceType() {
return this.type;
}
public abstract <T> T lookup(Class<T> type, DEF definition);
}
|
Code Pro | ||||
---|---|---|---|---|
| ||||
public class DatasourceComponentParameterResolver implements ParameterResolver {
private final DatasourceSupport datasourceSupport;
private final Object datasourceDefinition;
public DatasourceComponentParameterResolver(DatasourceSupport datasourceSupport, Object datasourceDefinition) {
this.datasourceSupport = datasourceSupport;
this.datasourceDefinition = datasourceDefinition;
}
@Override
public Object resolveParameter(ParameterInfo parameter) {
boolean isDatasourceComponent = Stream.of(parameter.getParameterAnnotations()).anyMatch(DatasourceComponent.class::isInstance);
if (isDatasourceComponent) {
return datasourceSupport
.getDatasourceBundle(datasourceDefinition)
.lookup(parameter.getParameterType(), datasourceDefinition);
}
return UNRESOLVED;
}
}
|
Questions:
- It is pretty clear that DataProvider and PropertySet domain-specific implementaions are required. But what else?
- optional HierarchicalDataProvider and potentially additional Hierarchy support for parent resolution (not covered by HDP interface in Vaadin).
- utilities to "serialise"/"deserialise" items to and from URL fragments.
- utility to "describe" the items (for status purposes and such).
...