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();
+ }
+
}