You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2020/02/24 10:50:52 UTC

[isis] branch master updated: ISIS-2298: initial working vaadin demo mapped to url /vaadin

This is an automated email from the ASF dual-hosted git repository.

ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git


The following commit(s) were added to refs/heads/master by this push:
     new 0ccd359  ISIS-2298: initial working vaadin demo mapped to url /vaadin
0ccd359 is described below

commit 0ccd359107643e009eadf2da80be5111608a649e
Author: Andi Huber <ah...@apache.org>
AuthorDate: Mon Feb 24 11:50:09 2020 +0100

    ISIS-2298: initial working vaadin demo mapped to url /vaadin
---
 .../demo/src/main/java/demoapp/webapp/DemoApp.java |   1 +
 examples/demo/src/main/resources/application.yml   |   6 +
 .../viewer/vaadin/model/entity/EntityUiModel.java  |  91 ++++++++
 .../vaadin/model/menu/MenuSectionUiModel.java}     |  33 ++-
 .../vaadin/model/menu/ServiceAndActionUiModel.java |  47 +++++
 incubator/viewers/vaadin/ui/pom.xml                |  95 ++++++---
 .../vaadin/ui/IsisModuleIncViewerVaadinUi.java     |   3 +
 .../viewer/vaadin/ui/collection/TableView.java     |  44 ++++
 .../incubator/viewer/vaadin/ui/main/MainView.java  | 231 +++++++++++++++++++++
 .../viewer/vaadin/ui/object/ObjectFormView.java    | 209 +++++++++++++++++++
 incubator/viewers/vaadin/viewer/pom.xml            |   1 +
 .../viewer/IsisModuleIncViewerVaadinViewer.java    |  85 ++++++++
 12 files changed, 795 insertions(+), 51 deletions(-)

diff --git a/examples/demo/src/main/java/demoapp/webapp/DemoApp.java b/examples/demo/src/main/java/demoapp/webapp/DemoApp.java
index 3e73104..980ad29 100644
--- a/examples/demo/src/main/java/demoapp/webapp/DemoApp.java
+++ b/examples/demo/src/main/java/demoapp/webapp/DemoApp.java
@@ -90,6 +90,7 @@ public class DemoApp extends SpringBootServletInitializer {
         @PropertySource(IsisPresets.NoTranslations),
         @PropertySource(IsisPresets.SilenceWicket),
         @PropertySource(IsisPresets.DataNucleusAutoCreate),
+        @PropertySource(IsisPresets.DebugVaadin),
     })
     @Import({
         IsisModuleCoreRuntimeServices.class,
diff --git a/examples/demo/src/main/resources/application.yml b/examples/demo/src/main/resources/application.yml
index 672f9e6..678e57c 100644
--- a/examples/demo/src/main/resources/application.yml
+++ b/examples/demo/src/main/resources/application.yml
@@ -113,4 +113,10 @@ resteasy:
 spring:
   banner:
     location: banner.txt
+    
+vaadin:
+  whitelisted-packages: com.vaadin
+  urlMapping: "/vaadin/*"
+  servlet:
+      productionMode: true
 
diff --git a/incubator/viewers/vaadin/model/src/main/java/org/apache/isis/incubator/viewer/vaadin/model/entity/EntityUiModel.java b/incubator/viewers/vaadin/model/src/main/java/org/apache/isis/incubator/viewer/vaadin/model/entity/EntityUiModel.java
new file mode 100644
index 0000000..c255c0e
--- /dev/null
+++ b/incubator/viewers/vaadin/model/src/main/java/org/apache/isis/incubator/viewer/vaadin/model/entity/EntityUiModel.java
@@ -0,0 +1,91 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.incubator.viewer.vaadin.model.entity;
+
+import org.apache.isis.applib.annotation.Where;
+import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.webapp.context.IsisWebAppCommonContext;
+
+import lombok.Data;
+
+@Data
+public class EntityUiModel {
+
+    private final IsisWebAppCommonContext commonContext;
+    private final ManagedObject managedObject;
+
+    ManagedObject load() {
+        return null;
+    }
+
+    public enum Mode {
+        VIEW, EDIT
+    }
+
+    public enum RenderingHint {
+        // normal form
+        REGULAR(Where.OBJECT_FORMS),
+
+        // inside parent table
+        PARENTED_PROPERTY_COLUMN(Where.PARENTED_TABLES),
+        PARENTED_TITLE_COLUMN(Where.PARENTED_TABLES),
+
+        // stand alone table
+        STANDALONE_PROPERTY_COLUMN(Where.STANDALONE_TABLES),
+        STANDALONE_TITLE_COLUMN(Where.STANDALONE_TABLES);
+
+        private final Where where;
+
+        RenderingHint(final Where where) {
+            this.where = where;
+        }
+
+        public boolean isRegular() {
+            return this == REGULAR;
+        }
+
+        public boolean isInParentedTable() {
+            return this == PARENTED_PROPERTY_COLUMN;
+        }
+
+        public boolean isInStandaloneTable() {
+            return this == STANDALONE_PROPERTY_COLUMN;
+        }
+
+        public boolean isInTable() {
+            return isInParentedTable() || isInStandaloneTable() || isInTableTitleColumn();
+        }
+
+        public boolean isInTableTitleColumn() {
+            return isInParentedTableTitleColumn() || isInStandaloneTableTitleColumn();
+        }
+
+        public boolean isInParentedTableTitleColumn() {
+            return this == PARENTED_TITLE_COLUMN;
+        }
+
+        public boolean isInStandaloneTableTitleColumn() {
+            return this == STANDALONE_TITLE_COLUMN;
+        }
+
+        public Where asWhere() {
+            return this.where;
+        }
+    }
+}
diff --git a/incubator/viewers/vaadin/viewer/src/main/java/org/apache/isis/incubator/viewer/vaadin/viewer/IsisModuleIncViewerVaadinViewer.java b/incubator/viewers/vaadin/model/src/main/java/org/apache/isis/incubator/viewer/vaadin/model/menu/MenuSectionUiModel.java
similarity index 61%
copy from incubator/viewers/vaadin/viewer/src/main/java/org/apache/isis/incubator/viewer/vaadin/viewer/IsisModuleIncViewerVaadinViewer.java
copy to incubator/viewers/vaadin/model/src/main/java/org/apache/isis/incubator/viewer/vaadin/model/menu/MenuSectionUiModel.java
index 5931075..7fd88b7 100644
--- a/incubator/viewers/vaadin/viewer/src/main/java/org/apache/isis/incubator/viewer/vaadin/viewer/IsisModuleIncViewerVaadinViewer.java
+++ b/incubator/viewers/vaadin/model/src/main/java/org/apache/isis/incubator/viewer/vaadin/model/menu/MenuSectionUiModel.java
@@ -16,30 +16,25 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
+package org.apache.isis.incubator.viewer.vaadin.model.menu;
 
-package org.apache.isis.incubator.viewer.vaadin.viewer;
+import java.util.ArrayList;
+import java.util.List;
 
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.Import;
+import lombok.Data;
 
-import org.apache.isis.incubator.viewer.vaadin.ui.IsisModuleIncViewerVaadinUi;
-
-/**
- * 
- * @since 2.0
- */
-@Configuration
-@Import({
-        // modules
-        IsisModuleIncViewerVaadinUi.class,
-
-        // @Service's
+@Data
+public class MenuSectionUiModel {
 
+    final String name;
 
-        // @Mixin's
-       
+    public boolean hasSubMenuItems() {
+        return !serviceAndActionUiModels.isEmpty();
+    }
 
-})
-public class IsisModuleIncViewerVaadinViewer {
+    final List<ServiceAndActionUiModel> serviceAndActionUiModels = new ArrayList<>();
 
+    public void addAction(final ServiceAndActionUiModel serviceAndActionUiModel) {
+        serviceAndActionUiModels.add(serviceAndActionUiModel);
+    }
 }
diff --git a/incubator/viewers/vaadin/model/src/main/java/org/apache/isis/incubator/viewer/vaadin/model/menu/ServiceAndActionUiModel.java b/incubator/viewers/vaadin/model/src/main/java/org/apache/isis/incubator/viewer/vaadin/model/menu/ServiceAndActionUiModel.java
new file mode 100644
index 0000000..e3d8375
--- /dev/null
+++ b/incubator/viewers/vaadin/model/src/main/java/org/apache/isis/incubator/viewer/vaadin/model/menu/ServiceAndActionUiModel.java
@@ -0,0 +1,47 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.incubator.viewer.vaadin.model.menu;
+
+import java.util.Optional;
+
+import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAction.Util;
+import org.apache.isis.incubator.viewer.vaadin.model.entity.EntityUiModel;
+
+import lombok.Data;
+
+@Data
+public class ServiceAndActionUiModel {
+
+    final EntityUiModel entityUiModel;
+    final String serviceName;
+    // TODO final ServiceActionLinkFactory linkAndLabelFactory;
+    // TODO final EntityModel serviceEntityModel;
+    final ObjectAction objectAction;
+    final boolean isFirstSection;
+
+    Optional<String> cssClassFa() {
+        return Optional.ofNullable(Util.cssClassFaFor(objectAction));
+    }
+
+    Optional<String> cssClass(final ManagedObject managedObject) {
+        return Optional.ofNullable(Util.cssClassFor(objectAction, managedObject));
+    }
+}
diff --git a/incubator/viewers/vaadin/ui/pom.xml b/incubator/viewers/vaadin/ui/pom.xml
index 72c7f6c..28d8650 100644
--- a/incubator/viewers/vaadin/ui/pom.xml
+++ b/incubator/viewers/vaadin/ui/pom.xml
@@ -1,45 +1,76 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!--
-  Licensed to the Apache Software Foundation (ASF) under one
-  or more contributor license agreements.  See the NOTICE file
-  distributed with this work for additional information
-  regarding copyright ownership.  The ASF licenses this file
-  to you under the Apache License, Version 2.0 (the
-  "License"); you may not use this file except in compliance
-  with the License.  You may obtain a copy of the License at
-  
-         http://www.apache.org/licenses/LICENSE-2.0
-         
-  Unless required by applicable law or agreed to in writing,
-  software distributed under the License is distributed on an
-  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-  KIND, either express or implied.  See the License for the
-  specific language governing permissions and limitations
-  under the License.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-
-    <modelVersion>4.0.0</modelVersion>
-	
+<!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor 
+	license agreements. See the NOTICE file distributed with this work for additional 
+	information regarding copyright ownership. The ASF licenses this file to 
+	you under the Apache License, Version 2.0 (the "License"); you may not use 
+	this file except in compliance with the License. You may obtain a copy of 
+	the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required 
+	by applicable law or agreed to in writing, software distributed under the 
+	License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS 
+	OF ANY KIND, either express or implied. See the License for the specific 
+	language governing permissions and limitations under the License. -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+	<modelVersion>4.0.0</modelVersion>
+
 	<parent>
-        <groupId>org.apache.isis.incubator.viewer</groupId>
-        <artifactId>isis-viewer-vaadin</artifactId>
-        <version>2.0.0-M3-SNAPSHOT</version>
-    </parent>
+		<groupId>org.apache.isis.incubator.viewer</groupId>
+		<artifactId>isis-viewer-vaadin</artifactId>
+		<version>2.0.0-M3-SNAPSHOT</version>
+	</parent>
+
+	<artifactId>isis-viewer-vaadin-ui</artifactId>
+	<name>Apache Isis Inc - Viewer Vaadin (UI Components)</name>
+
+	<properties>
+		<jar-plugin.automaticModuleName>org.apache.isis.incubator.viewer.vaadin.ui</jar-plugin.automaticModuleName>
+		<git-plugin.propertiesDir>org/apache/isis/incubator/viewer/vaadin/ui</git-plugin.propertiesDir>
+	</properties>
 
-    <artifactId>isis-viewer-vaadin-ui</artifactId>
-    <name>Apache Isis Inc - Viewer Vaadin (UI Components)</name>
+<!-- 	<build> -->
+<!-- 		<plugins> -->
 
-    <properties>
-        <jar-plugin.automaticModuleName>org.apache.isis.incubator.viewer.vaadin.ui</jar-plugin.automaticModuleName>
-        <git-plugin.propertiesDir>org/apache/isis/incubator/viewer/vaadin/ui</git-plugin.propertiesDir>
-    </properties>
+<!-- 			<plugin> -->
+<!-- 				<groupId>com.vaadin</groupId> -->
+<!-- 				<artifactId>vaadin-maven-plugin</artifactId> -->
+<!-- 				<version>${vaadin.version}</version> -->
+<!-- 				<executions> -->
+<!-- 					<execution> -->
+<!-- 						<goals> -->
+<!-- 							<goal>prepare-frontend</goal> -->
+<!-- 							<goal>build-frontend</goal> -->
+<!-- 						</goals> -->
+<!-- 					</execution> -->
+<!-- 				</executions> -->
+<!-- 			</plugin> -->
+
+<!-- 		</plugins> -->
+<!-- 	</build> -->
 
 	<dependencies>
+
 		<dependency>
 			<groupId>org.apache.isis.incubator.viewer</groupId>
 			<artifactId>isis-viewer-vaadin-model</artifactId>
 		</dependency>
+
+		<dependency>
+			<groupId>org.apache.isis.core</groupId>
+			<artifactId>isis-core-runtimeservices</artifactId>
+		</dependency>
+
+		<dependency>
+			<groupId>com.vaadin</groupId>
+			<artifactId>vaadin</artifactId>
+		</dependency>
+
+		<dependency>
+			<groupId>com.vaadin</groupId>
+			<artifactId>vaadin-spring</artifactId>
+		</dependency>
+
 	</dependencies>
 
 </project>
diff --git a/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/IsisModuleIncViewerVaadinUi.java b/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/IsisModuleIncViewerVaadinUi.java
index d840155..2ee5e89 100644
--- a/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/IsisModuleIncViewerVaadinUi.java
+++ b/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/IsisModuleIncViewerVaadinUi.java
@@ -18,6 +18,8 @@
  */
 package org.apache.isis.incubator.viewer.vaadin.ui;
 
+import com.vaadin.flow.spring.annotation.EnableVaadin;
+
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Import;
 
@@ -32,5 +34,6 @@ import org.apache.isis.incubator.viewer.vaadin.model.IsisModuleIncViewerVaadinMo
         // @Service's
         
 })
+@EnableVaadin("org.apache.isis.incubator.viewer.vaadin.ui") // scan for vaadin annotations
 public class IsisModuleIncViewerVaadinUi {
 }
diff --git a/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/collection/TableView.java b/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/collection/TableView.java
new file mode 100644
index 0000000..3711151
--- /dev/null
+++ b/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/collection/TableView.java
@@ -0,0 +1,44 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.incubator.viewer.vaadin.ui.collection;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import com.vaadin.flow.component.grid.Grid;
+import com.vaadin.flow.component.orderedlayout.VerticalLayout;
+
+import org.apache.isis.core.metamodel.facets.collections.CollectionFacet;
+import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+
+public class TableView extends VerticalLayout {
+
+    private static final long serialVersionUID = 1L;
+
+    public TableView(final ManagedObject collection) {
+        final ObjectSpecification assocObjectSpecification = collection.getSpecification();
+        final CollectionFacet facet = assocObjectSpecification.getFacet(CollectionFacet.class);
+        final List<ManagedObject> objects = facet.stream(collection).collect(Collectors.toList());
+
+        final Grid<ManagedObject> objectGrid = new Grid<>();
+        objectGrid.setItems(objects);
+        add(objectGrid);
+    }
+}
diff --git a/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/main/MainView.java b/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/main/MainView.java
new file mode 100644
index 0000000..74e523c
--- /dev/null
+++ b/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/main/MainView.java
@@ -0,0 +1,231 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.incubator.viewer.vaadin.ui.main;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import com.vaadin.flow.component.ClickEvent;
+import com.vaadin.flow.component.ComponentEventListener;
+import com.vaadin.flow.component.Text;
+import com.vaadin.flow.component.button.Button;
+import com.vaadin.flow.component.contextmenu.MenuItem;
+import com.vaadin.flow.component.contextmenu.SubMenu;
+import com.vaadin.flow.component.dependency.JsModule;
+import com.vaadin.flow.component.html.Div;
+import com.vaadin.flow.component.menubar.MenuBar;
+import com.vaadin.flow.component.orderedlayout.VerticalLayout;
+import com.vaadin.flow.router.Route;
+import com.vaadin.flow.theme.Theme;
+import com.vaadin.flow.theme.lumo.Lumo;
+
+import org.apache.logging.log4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import org.apache.isis.applib.layout.component.ServiceActionLayoutData;
+import org.apache.isis.applib.layout.menubars.MenuSection;
+import org.apache.isis.applib.layout.menubars.bootstrap3.BS3Menu;
+import org.apache.isis.applib.layout.menubars.bootstrap3.BS3MenuBar;
+import org.apache.isis.applib.layout.menubars.bootstrap3.BS3MenuBars;
+import org.apache.isis.applib.services.menu.MenuBarsService.Type;
+import org.apache.isis.core.config.IsisConfiguration;
+import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
+import org.apache.isis.core.metamodel.context.MetaModelContext;
+import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
+import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
+import org.apache.isis.core.runtime.session.IsisSessionFactory;
+import org.apache.isis.core.runtimeservices.menubars.bootstrap3.MenuBarsServiceBS3;
+import org.apache.isis.core.webapp.context.IsisWebAppCommonContext;
+import org.apache.isis.incubator.viewer.vaadin.model.entity.EntityUiModel;
+import org.apache.isis.incubator.viewer.vaadin.model.menu.MenuSectionUiModel;
+import org.apache.isis.incubator.viewer.vaadin.model.menu.ServiceAndActionUiModel;
+import org.apache.isis.incubator.viewer.vaadin.ui.collection.TableView;
+import org.apache.isis.incubator.viewer.vaadin.ui.object.ObjectFormView;
+
+import lombok.val;
+import lombok.extern.log4j.Log4j2;
+
+@Route()
+@JsModule("@vaadin/vaadin-lumo-styles/presets/compact.js")
+//@Theme(value = Material.class, variant = Material.DARK)
+@Theme(value = Lumo.class)
+@Log4j2
+public class MainView extends VerticalLayout {
+
+    private static final long serialVersionUID = 1L;
+
+    public MainView(
+            @Autowired final IsisSessionFactory isisSessionFactory,
+            @Autowired final SpecificationLoader specificationLoader,
+            @Autowired final MetaModelContext metaModelContext,
+            @Autowired final IsisConfiguration isisConfiguration
+    ) {
+        final IsisWebAppCommonContext isisWebAppCommonContext = IsisWebAppCommonContext.of(metaModelContext);
+
+        final MenuBarsServiceBS3 menuBarsService = metaModelContext.getServiceRegistry()
+                .lookupServiceElseFail(MenuBarsServiceBS3.class);
+        final BS3MenuBars bs3MenuBars = menuBarsService.menuBars(Type.DEFAULT);
+
+        final MenuBar menuBar = new MenuBar();
+        final Text selectedMenuItem = new Text("");
+        final VerticalLayout actionResult = new VerticalLayout();
+        final Div message = new Div(new Text("Selected: "), selectedMenuItem);
+
+        add(menuBar);
+        add(message);
+        add(actionResult);
+
+        final List<MenuSectionUiModel> menuSectionUiModels = buildMenuModel(log, isisWebAppCommonContext, bs3MenuBars);
+        log.warn("menu model:\n ");
+        menuSectionUiModels.forEach(m -> log.warn("\t{}", m));
+
+        menuSectionUiModels.forEach(sectionUiModel -> {
+                    final MenuItem menuItem = menuBar.addItem(sectionUiModel.getName());
+                    final SubMenu subMenu = menuItem.getSubMenu();
+                    sectionUiModel.getServiceAndActionUiModels().forEach(a ->
+                            createActionOverviewAndBindRunAction(selectedMenuItem, actionResult, subMenu, a));
+                }
+        );
+        setWidthFull();
+    }
+
+    private void createActionOverviewAndBindRunAction(
+            final Text selected,
+            final VerticalLayout actionResultDiv,
+            final SubMenu subMenu,
+            final ServiceAndActionUiModel a
+    ) {
+        final ObjectAction objectAction = a.getObjectAction();
+        subMenu.addItem(objectAction.getName(),
+                e -> {
+                    actionResultDiv.removeAll();
+
+                    selected.setText(objectAction.toString());
+                    objectAction.getParameters();
+                    actionResultDiv.add(new Div(new Text("Name: " + objectAction.getName())));
+                    actionResultDiv.add(new Div(new Text("Description: " + objectAction.getDescription())));
+                    actionResultDiv.add(new Div(new Text("Parameters: " + objectAction.getParameters())));
+                    final Div actionResult = new Div();
+                    actionResult.setWidthFull();
+
+                    if (objectAction.isAction() && objectAction.getParameters().isEmpty()) {
+                        actionResultDiv.add(new Button("run", executeAndHandleResultAction(a, objectAction, actionResult)));
+                        actionResultDiv.add(actionResult);
+                    }
+                    actionResultDiv.setWidthFull();
+                }
+        );
+    }
+
+    private ComponentEventListener<ClickEvent<Button>> executeAndHandleResultAction(
+            final ServiceAndActionUiModel a,
+            final ObjectAction objectAction,
+            final Div actionResult
+    ) {
+        return buttonClickEvent -> {
+            final ManagedObject actionOwner = a.getEntityUiModel().getManagedObject();
+            final ManagedObject result = objectAction
+                    .execute(
+                            actionOwner,
+                            null,
+                            Collections.emptyList(),
+                            InteractionInitiatedBy.USER
+                    );
+            actionResult.removeAll();
+            if (result.getSpecification().isParentedOrFreeCollection()) {
+                actionResult.add(new TableView(result));
+            } else {
+                actionResult.add(new ObjectFormView(result));
+            }
+        };
+    }
+
+    // copied from org.apache.isis.viewer.wicket.ui.components.actionmenu.serviceactions.ServiceActionUtil.buildMenu
+    public static List<MenuSectionUiModel> buildMenuModel(
+            final Logger log,
+            final IsisWebAppCommonContext commonContext,
+            final BS3MenuBars menuBars
+    ) {
+
+        // TODO handle menuBars.getSecondary(), menuBars.getTertiary()
+        final BS3MenuBar menuBar = menuBars.getPrimary();
+
+        // we no longer use ServiceActionsModel#getObject() because the model only holds the services for the
+        // menuBar in question, whereas the "Other" menu may reference a service which is defined for some other menubar
+
+        final List<MenuSectionUiModel> menuSections = new ArrayList<>();
+        for (final BS3Menu menu : menuBar.getMenus()) {
+
+            final MenuSectionUiModel menuSectionUiModel = new MenuSectionUiModel(menu.getNamed());
+
+            for (final MenuSection menuSection : menu.getSections()) {
+
+                boolean isFirstSection = true;
+
+                for (final ServiceActionLayoutData actionLayoutData : menuSection.getServiceActions()) {
+                    val serviceSpecId = actionLayoutData.getObjectType();
+
+                    final ManagedObject serviceAdapter = commonContext.lookupServiceAdapterById(serviceSpecId);
+                    if (serviceAdapter == null) {
+                        // service not recognized, presumably the menu layout is out of sync
+                        // with actual configured modules
+                        continue;
+                    }
+                    // TODO Wicket final EntityModel entityModel = EntityModel.ofAdapter(commonContext, serviceAdapter);
+                    final EntityUiModel entityUiModel =
+                            new EntityUiModel(commonContext, serviceAdapter);
+
+                    final ObjectAction objectAction =
+                            serviceAdapter
+                                    .getSpecification()
+                                    .getObjectAction(actionLayoutData.getId())
+                                    .orElse(null);
+                    if (objectAction == null) {
+                        log.warn("No such action {}", actionLayoutData.getId());
+                        continue;
+                    }
+                    final ServiceAndActionUiModel serviceAndActionUiModel =
+                            new ServiceAndActionUiModel(
+                                    entityUiModel,
+                                    actionLayoutData.getNamed(),
+                                    objectAction,
+                                    isFirstSection);
+
+                    menuSectionUiModel.addAction(serviceAndActionUiModel);
+                    isFirstSection = false;
+
+                    // TODO Wicket
+                    //                    final CssMenuItem.Builder subMenuItemBuilder = menuSectionModel.newSubMenuItem(serviceAndAction);
+                    //                    if (subMenuItemBuilder == null) {
+                    //                        // either service or this action is not visible
+                    //                        continue;
+                    //                    }
+                    //                    subMenuItemBuilder.build();
+                }
+            }
+            if (menuSectionUiModel.hasSubMenuItems()) {
+                menuSections.add(menuSectionUiModel);
+            }
+        }
+        return menuSections;
+    }
+
+}
\ No newline at end of file
diff --git a/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/object/ObjectFormView.java b/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/object/ObjectFormView.java
new file mode 100644
index 0000000..b91e0a5
--- /dev/null
+++ b/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/object/ObjectFormView.java
@@ -0,0 +1,209 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.incubator.viewer.vaadin.ui.object;
+
+import java.io.ByteArrayInputStream;
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import com.vaadin.flow.component.Component;
+import com.vaadin.flow.component.formlayout.FormLayout;
+import com.vaadin.flow.component.grid.Grid;
+import com.vaadin.flow.component.html.H1;
+import com.vaadin.flow.component.html.H3;
+import com.vaadin.flow.component.html.Image;
+import com.vaadin.flow.component.html.Label;
+import com.vaadin.flow.component.orderedlayout.VerticalLayout;
+import com.vaadin.flow.component.textfield.TextField;
+import com.vaadin.flow.server.InputStreamFactory;
+import com.vaadin.flow.server.StreamResource;
+
+import org.apache.isis.core.metamodel.facets.collections.CollectionFacet;
+import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.feature.Contributed;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.isis.core.metamodel.spec.feature.ObjectMember;
+
+public class ObjectFormView extends VerticalLayout {
+
+    private static final long serialVersionUID = 1L;
+    
+    public static final String NULL = "<NULL>";
+
+    public ObjectFormView(final ManagedObject managedObject) {
+        final ObjectSpecification specification = managedObject.getSpecification();
+        final String title = specification.getTitle(null, managedObject);
+        add(new H1(title));
+
+        final List<? extends ObjectAssociation> objectAssociations = specification
+                .streamAssociations(Contributed.INCLUDED)
+                .filter(ObjectMember::isPropertyOrCollection)
+                .collect(Collectors.toList());
+        final FormLayout formLayout = new FormLayout();
+        final VerticalLayout tables = new VerticalLayout();
+        objectAssociations.forEach(objectAssociation -> {
+            final ManagedObject assocObject = objectAssociation.get(managedObject);
+            if (assocObject == null) {
+                formLayout.add(createErrorField(objectAssociation, "assoc. object is null: "));
+                return;
+            }
+            final ObjectSpecification propSpec = assocObject.getSpecification();
+            switch (propSpec.getBeanSort()) {
+            case VALUE: {
+                formLayout.add(createValueField(objectAssociation, assocObject));
+                break;
+            }
+            case COLLECTION: {
+                tables.add(new Label(objectAssociation.getName()));
+                tables.add(createCollectionComponent(objectAssociation, assocObject));
+                break;
+            }
+            case VIEW_MODEL:
+            case ENTITY:
+            case MANAGED_BEAN_CONTRIBUTING:
+            case MANAGED_BEAN_NOT_CONTRIBUTING:
+            case MIXIN:
+            case UNKNOWN:
+            default: {
+                final String value = propSpec.toString();
+                final TextField textField = new TextField(value);
+                textField.setLabel(
+                        "Unhandled kind assoc.: " + propSpec.getBeanSort() + " " + objectAssociation.getName());
+                textField.setValue(propSpec.toString());
+                textField.setInvalid(true);
+                formLayout.add(textField);
+                break;
+            }
+            }
+        });
+
+        add(formLayout);
+        add(new H3("Tables"));
+        add(tables);
+        setWidthFull();
+
+    }
+
+    private Component createErrorField(final ObjectAssociation objectAssociation, final String error) {
+        return createErrorField("Error:" + objectAssociation.getName(),
+                error + objectAssociation.toString());
+    }
+
+    private Component createErrorField(final String s, final String s2) {
+        final TextField textField = new TextField();
+        textField.setLabel(s);
+        textField.setValue(s2);
+        return textField;
+    }
+
+    private Component createCollectionComponent(
+            final ObjectAssociation objectAssociation,
+            final ManagedObject assocObject
+    ) {
+        final ObjectSpecification assocObjectSpecification = assocObject.getSpecification();
+        final CollectionFacet collectionFacet = assocObjectSpecification.getFacet(CollectionFacet.class);
+
+        final String label = "Collection:" + objectAssociation.getName();
+        final Object pojo = assocObject.getPojo();
+        if (pojo instanceof Collection) {
+
+            final List<ManagedObject> objects = collectionFacet.stream(assocObject).collect(Collectors.toList());
+
+            //            final ComboBox<ManagedObject> listBox = new ComboBox<>();
+            //            listBox.setLabel(label + " #" + objects.size());
+            //            listBox.setItems(objects);
+            //            if (!objects.isEmpty()) {
+            //                listBox.setValue(objects.get(0));
+            //            }
+            //            listBox.setItemLabelGenerator(o -> o.titleString(null));
+
+            final Grid<ManagedObject> objectGrid = new Grid<>();
+            if (objects.isEmpty()) {
+                return objectGrid;
+            }
+            final ManagedObject firstObject = objects.get(0);
+            final List<ObjectAssociation> properties = firstObject.getSpecification()
+                    .streamAssociations(Contributed.INCLUDED)
+                    .filter(m -> m.getFeatureType().isProperty())
+                    .collect(Collectors.toList());
+            properties.forEach(p -> {
+                final Grid.Column<ManagedObject> column = objectGrid.addColumn(managedObject -> {
+                    final ManagedObject managedObject1 = p.get(managedObject);
+                    if (managedObject1 == null) {
+                        return NULL;
+                    }
+                    return managedObject1.titleString();
+                });
+                column.setHeader(p.getName());
+            });
+            objectGrid.setItems(objects);
+            objectGrid.recalculateColumnWidths();
+            objectGrid.setColumnReorderingAllowed(true);
+            return objectGrid;
+        }
+
+        if (pojo == null) {
+            final TextField textField = new TextField();
+            textField.setLabel(label);
+
+            textField.setValue("<NULL>");
+            return textField;
+        }
+
+        final TextField textField = new TextField();
+        textField.setLabel(label);
+
+        textField.setValue("Unknown collection type:" + pojo.getClass());
+        return textField;
+    }
+
+    private Component createValueField(final ObjectAssociation association, final ManagedObject assocObject) {
+        // TODO how to handle object type / id
+
+        // How to handle blobs?
+        //        final BlobValueSemanticsProvider blobValueFacet = association.getFacet(BlobValueSemanticsProvider.class);
+        //        if (blobValueFacet != null) {
+        //            final java.awt.Image aByte = blobValueFacet.getParser(assocObject);
+        //            new Image(aByte);
+        //            return null;
+        //        }
+        final String description = assocObject.getSpecification().streamFacets()
+                .map(facet -> facet.getClass().getName())
+                .collect(Collectors.joining("\n"));
+
+        final TextField textField = createTextField(association, assocObject);
+        //        Tooltips.getCurrent().setTooltip(textField, description);
+        return textField;
+    }
+
+    private Image convertToImage(final byte[] imageData) {
+        final StreamResource streamResource = new StreamResource("isr",
+                (InputStreamFactory) () -> new ByteArrayInputStream(imageData));
+        return new Image(streamResource, "photo");
+    }
+
+    private TextField createTextField(final ObjectAssociation association, final ManagedObject assocObject) {
+        final TextField textField = new TextField();
+        textField.setLabel(association.getName());
+        textField.setValue(assocObject.titleString(null));
+        return textField;
+    }
+}
diff --git a/incubator/viewers/vaadin/viewer/pom.xml b/incubator/viewers/vaadin/viewer/pom.xml
index 7ad28ab..159e64d 100644
--- a/incubator/viewers/vaadin/viewer/pom.xml
+++ b/incubator/viewers/vaadin/viewer/pom.xml
@@ -34,6 +34,7 @@
 			<groupId>org.apache.isis.incubator.viewer</groupId>
 			<artifactId>isis-viewer-vaadin-ui</artifactId>
 		</dependency>
+
 	</dependencies>
 
 
diff --git a/incubator/viewers/vaadin/viewer/src/main/java/org/apache/isis/incubator/viewer/vaadin/viewer/IsisModuleIncViewerVaadinViewer.java b/incubator/viewers/vaadin/viewer/src/main/java/org/apache/isis/incubator/viewer/vaadin/viewer/IsisModuleIncViewerVaadinViewer.java
index 5931075..6bc05d4 100644
--- a/incubator/viewers/vaadin/viewer/src/main/java/org/apache/isis/incubator/viewer/vaadin/viewer/IsisModuleIncViewerVaadinViewer.java
+++ b/incubator/viewers/vaadin/viewer/src/main/java/org/apache/isis/incubator/viewer/vaadin/viewer/IsisModuleIncViewerVaadinViewer.java
@@ -19,8 +19,28 @@
 
 package org.apache.isis.incubator.viewer.vaadin.viewer;
 
+import java.util.HashMap;
+import java.util.Map;
+
+import com.vaadin.flow.server.Constants;
+import com.vaadin.flow.spring.RootMappedCondition;
+import com.vaadin.flow.spring.SpringBootAutoConfiguration;
+import com.vaadin.flow.spring.SpringServlet;
+import com.vaadin.flow.spring.VaadinConfigurationProperties;
+import com.vaadin.flow.spring.VaadinServletContextInitializer;
+import com.vaadin.flow.spring.VaadinWebsocketEndpointExporter;
+import com.vaadin.flow.spring.annotation.EnableVaadin;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.web.servlet.ServletContextInitializer;
+import org.springframework.boot.web.servlet.ServletRegistrationBean;
+import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Import;
+import org.springframework.util.ClassUtils;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.socket.server.standard.ServerEndpointExporter;
 
 import org.apache.isis.incubator.viewer.vaadin.ui.IsisModuleIncViewerVaadinUi;
 
@@ -32,6 +52,8 @@ import org.apache.isis.incubator.viewer.vaadin.ui.IsisModuleIncViewerVaadinUi;
 @Import({
         // modules
         IsisModuleIncViewerVaadinUi.class,
+        
+        VaadinConfigurationProperties.class
 
         // @Service's
 
@@ -40,6 +62,69 @@ import org.apache.isis.incubator.viewer.vaadin.ui.IsisModuleIncViewerVaadinUi;
        
 
 })
+//disable standard vaadin spring boot bootstrapping
+@EnableAutoConfiguration(exclude = { SpringBootAutoConfiguration.class })
 public class IsisModuleIncViewerVaadinViewer {
+    
+    
+    @Autowired
+    private WebApplicationContext context;
+    @Autowired
+    private VaadinConfigurationProperties configurationProperties;
+
+    static String makeContextRelative(String url) {
+        // / -> context://
+        // foo -> context://foo
+        // /foo -> context://foo
+        if (url.startsWith("/")) {
+            url = url.substring(1);
+        }
+        return "context://" + url;
+    }
+
+    /**
+     * Creates a {@link ServletContextInitializer} instance.
+     *
+     * @return a custom ServletContextInitializer instance
+     */
+    @Bean
+    public ServletContextInitializer contextInitializer() {
+        return new VaadinServletContextInitializer(context);
+    }
+
+    /**
+     * Creates a {@link ServletRegistrationBean} instance with Spring aware Vaadin servlet.
+     *
+     * @return a custom ServletRegistrationBean instance
+     */
+    @Bean
+    public ServletRegistrationBean<SpringServlet> servletRegistrationBean() {
+        String mapping = configurationProperties.getUrlMapping();
+        final Map<String, String> initParameters = new HashMap<>();
+        final boolean rootMapping = RootMappedCondition.isRootMapping(mapping);
+        if (rootMapping) {
+            mapping = "/vaadinServlet/*";
+            initParameters.put(Constants.SERVLET_PARAMETER_PUSH_URL,
+                    makeContextRelative(mapping.replace("*", "")));
+        }
+        final ServletRegistrationBean<SpringServlet> registration = new ServletRegistrationBean<>(
+                new SpringServlet(context, rootMapping), mapping);
+        registration.setInitParameters(initParameters);
+        registration
+                .setAsyncSupported(configurationProperties.isAsyncSupported());
+        registration.setName(
+                ClassUtils.getShortNameAsProperty(SpringServlet.class));
+        return registration;
+    }
 
+    /**
+     * Deploys JSR-356 websocket endpoints when Atmosphere is available.
+     *
+     * @return the server endpoint exporter which does the actual work.
+     */
+    @Bean
+    public ServerEndpointExporter websocketEndpointDeployer() {
+        return new VaadinWebsocketEndpointExporter();
+    }
+    
 }