This is an automated email from the ASF dual-hosted git repository. danhaywood pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/isis.git
commit 56d1c22d302311c92b6eb01309df5337c71c7c33 Author: Dan Haywood <[email protected]> AuthorDate: Mon Aug 1 19:02:30 2022 +0100 ISIS-3104: moves Object_clearHints to own module also add a bunch of regression tests for layout. --- core/pom.xml | 5 + examples/demo/wicket/common/pom.xml | 4 + regressiontests/pom.xml | 1 + regressiontests/stable-layouts/log4j2-test.xml | 78 +++ regressiontests/stable-layouts/pom.xml | 87 +++ .../layouts/integtest/Layout_IntegTest.java | 780 +++++++++++++++++++++ .../layouts/integtest/model/Counter.java | 227 ++++++ .../layouts/integtest/model/Counter.layout.xml | 72 ++ .../model/Counter_updateNameUsingMixin.java | 37 + .../integtest/model/LayoutTestDomainModel.java | 24 + viewers/wicket/{ => applib}/pom.xml | 41 +- .../applib/IsisModuleViewerWicketApplibMixins.java | 39 ++ .../wicket/applib}/mixins/Object_clearHints.java | 25 +- viewers/wicket/pom.xml | 5 +- .../viewer/IsisModuleViewerWicketViewer.java | 4 - 15 files changed, 1392 insertions(+), 37 deletions(-) diff --git a/core/pom.xml b/core/pom.xml index 3a6a4507ec..f43d342c73 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -627,6 +627,11 @@ <artifactId>isis-viewer-restfulobjects-jaxrsresteasy4</artifactId> <version>2.0.0-SNAPSHOT</version> </dependency> + <dependency> + <groupId>org.apache.isis.viewer</groupId> + <artifactId>isis-viewer-wicket-applib</artifactId> + <version>2.0.0-SNAPSHOT</version> + </dependency> <dependency> <groupId>org.apache.isis.viewer</groupId> <artifactId>isis-viewer-wicket-model</artifactId> diff --git a/examples/demo/wicket/common/pom.xml b/examples/demo/wicket/common/pom.xml index 0205522416..3d35b0fc9d 100644 --- a/examples/demo/wicket/common/pom.xml +++ b/examples/demo/wicket/common/pom.xml @@ -70,6 +70,10 @@ <artifactId>isis-viewer-wicket-ui</artifactId> </dependency> + <dependency> + <groupId>org.apache.isis.viewer</groupId> + <artifactId>isis-viewer-wicket-applib</artifactId> + </dependency> <dependency> <groupId>org.apache.isis.viewer</groupId> <artifactId>isis-viewer-wicket-viewer</artifactId> diff --git a/regressiontests/pom.xml b/regressiontests/pom.xml index 999079fce4..ab2b35ad81 100644 --- a/regressiontests/pom.xml +++ b/regressiontests/pom.xml @@ -295,6 +295,7 @@ <module>stable-cucumber</module> <module>stable-domainmodel</module> <module>stable-eventhandling</module> + <module>stable-layouts</module> <module>stable-factory</module> <module>stable-interact</module> <module>stable-persistence-jdo</module> diff --git a/regressiontests/stable-layouts/log4j2-test.xml b/regressiontests/stable-layouts/log4j2-test.xml new file mode 100644 index 0000000000..0ed7986e24 --- /dev/null +++ b/regressiontests/stable-layouts/log4j2-test.xml @@ -0,0 +1,78 @@ +<?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. +--> +<Configuration status="WARN"> + <Properties> + <Property name="PID">????</Property> + <Property name="LOG_EXCEPTION_CONVERSION_WORD">%xwEx</Property> + <Property name="LOG_LEVEL_PATTERN">%5p</Property> + <Property name="LOG_DATEFORMAT_PATTERN">yyyy-MM-dd HH:mm:ss.SSS</Property> + <Property name="CONSOLE_LOG_PATTERN">%clr{%d{${LOG_DATEFORMAT_PATTERN}}}{faint} %clr{${LOG_LEVEL_PATTERN}} %clr{${sys:PID}}{magenta} %clr{---}{faint} %clr{[%15.15t]}{faint} %clr{%-40.40c{1.}}{cyan} %clr{:}{faint} %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD}</Property> + <Property name="FILE_LOG_PATTERN">%d{${LOG_DATEFORMAT_PATTERN}} ${LOG_LEVEL_PATTERN} ${sys:PID} --- [%t] %-40.40c{1.} : %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD}</Property> + </Properties> + <Appenders> + <Console name="Console" target="SYSTEM_OUT" follow="true"> + <PatternLayout pattern="${sys:CONSOLE_LOG_PATTERN}" /> + </Console> + </Appenders> + <Loggers> + <Logger name="org.apache.catalina.startup.DigesterFactory" level="error" /> + <Logger name="org.apache.catalina.util.LifecycleBase" level="error" /> + <Logger name="org.apache.coyote.http11.Http11NioProtocol" level="warn" /> + <logger name="org.apache.sshd.common.util.SecurityUtils" level="warn"/> + <Logger name="org.apache.tomcat.util.net.NioSelectorPool" level="warn" /> + <Logger name="org.eclipse.jetty.util.component.AbstractLifeCycle" level="error" /> + <Logger name="org.hibernate.validator.internal.util.Version" level="warn" /> + <logger name="org.springframework.boot.actuate.endpoint.jmx" level="warn"/> + + <logger name="org.apache.directory" level="warn"/> + <logger name="org.apache.directory.api.ldap.model.entry.Value" level="off"/> + + <logger name="DataNucleus.Persistence" level="info"/> + <logger name="DataNucleus.Transaction" level="info"/> + <logger name="DataNucleus.Datastore.Schema" level="info"/> + <logger name="DataNucleus.Datastore.Native" level="info"/> + + <Root level="info"> + <AppenderRef ref="Console" /> + </Root> + </Loggers> +</Configuration> + +<!-- # DataNucleus Logging Categories --> +<!-- DataNucleus.Persistence - All messages relating to the persistence process --> +<!-- DataNucleus.Transaction - All messages relating to transactions --> +<!-- DataNucleus.Connection - All messages relating to Connections. --> +<!-- DataNucleus.Query - All messages relating to queries --> +<!-- DataNucleus.Cache - All messages relating to the DataNucleus Cache --> +<!-- DataNucleus.MetaData - All messages relating to MetaData --> +<!-- DataNucleus.Datastore - All general datastore messages --> +<!-- DataNucleus.Datastore.Schema - All schema related datastore log messages --> +<!-- DataNucleus.Datastore.Persist - All datastore persistence messages --> +<!-- DataNucleus.Datastore.Retrieve - All datastore retrieval messages --> +<!-- DataNucleus.Datastore.Native - Log of all 'native' statements sent to the datastore --> +<!-- DataNucleus.General - All general operational messages --> +<!-- DataNucleus.Lifecycle - All messages relating to object lifecycle changes --> +<!-- DataNucleus.ValueGeneration - All messages relating to value generation --> +<!-- DataNucleus.Enhancer - All messages from the DataNucleus Enhancer. --> +<!-- DataNucleus.SchemaTool - All messages from DataNucleus SchemaTool --> +<!-- DataNucleus.JDO - All messages general to JDO --> +<!-- DataNucleus.JPA - All messages general to JPA --> +<!-- DataNucleus.JCA - All messages relating to Connector JCA. --> +<!-- DataNucleus.IDE - Messages from the DataNucleus IDE. --> \ No newline at end of file diff --git a/regressiontests/stable-layouts/pom.xml b/regressiontests/stable-layouts/pom.xml new file mode 100644 index 0000000000..7c7828abfe --- /dev/null +++ b/regressiontests/stable-layouts/pom.xml @@ -0,0 +1,87 @@ +<?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/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.apache.isis.regressiontests</groupId> + <artifactId>isis-regressiontests</artifactId> + <version>2.0.0-SNAPSHOT</version> + </parent> + + <artifactId>isis-regressiontests-stable-layouts</artifactId> + <name>Apache Isis - Regression Tests (stable) - Layouts</name> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.apache.isis.extensions</groupId> + <artifactId>isis-extensions</artifactId> + <version>2.0.0-SNAPSHOT</version> + <scope>import</scope> + <type>pom</type> + </dependency> + <dependency> + <groupId>org.apache.isis.testing</groupId> + <artifactId>isis-testing</artifactId> + <version>2.0.0-SNAPSHOT</version> + <scope>import</scope> + <type>pom</type> + </dependency> + <dependency> + <groupId>org.apache.isis.viewer</groupId> + <artifactId>isis-viewer-wicket</artifactId> + <version>2.0.0-SNAPSHOT</version> + <scope>import</scope> + <type>pom</type> + </dependency> + + <dependency> + <groupId>org.apache.isis.regressiontests</groupId> + <artifactId>isis-regressiontests-cmdexecauditsess-generic</artifactId> + <version>2.0.0-SNAPSHOT</version> + </dependency> + </dependencies> + </dependencyManagement> + + <dependencies> + + <dependency> + <groupId>org.apache.isis.core</groupId> + <artifactId>isis-applib</artifactId> + </dependency> + + <dependency> + <groupId>org.apache.isis.viewer</groupId> + <artifactId>isis-viewer-wicket-applib</artifactId> + </dependency> + + <dependency> + <groupId>org.apache.isis.core</groupId> + <artifactId>isis-core-config</artifactId> + </dependency> + + <dependency> + <groupId>org.apache.isis.testing</groupId> + <artifactId>isis-testing-fixtures-applib</artifactId> + </dependency> + + <dependency> + <groupId>org.apache.isis.core</groupId> + <artifactId>isis-core-runtimeservices</artifactId> + </dependency> + + + </dependencies> + +</project> diff --git a/regressiontests/stable-layouts/src/main/java/org/apache/isis/regressiontests/layouts/integtest/Layout_IntegTest.java b/regressiontests/stable-layouts/src/main/java/org/apache/isis/regressiontests/layouts/integtest/Layout_IntegTest.java new file mode 100644 index 0000000000..cca8034282 --- /dev/null +++ b/regressiontests/stable-layouts/src/main/java/org/apache/isis/regressiontests/layouts/integtest/Layout_IntegTest.java @@ -0,0 +1,780 @@ +/* + * 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.regressiontests.layouts.integtest; + +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.PropertySource; +import org.springframework.context.annotation.PropertySources; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.TransactionException; +import org.springframework.transaction.TransactionStatus; + +import static org.assertj.core.api.Assertions.*; + +import org.apache.isis.applib.IsisModuleApplibMixins; +import org.apache.isis.applib.annotation.ActionLayout; +import org.apache.isis.applib.id.LogicalType; +import org.apache.isis.applib.layout.LayoutConstants; +import org.apache.isis.applib.services.bookmark.Bookmark; +import org.apache.isis.applib.services.bookmark.BookmarkService; +import org.apache.isis.applib.services.iactnlayer.InteractionService; +import org.apache.isis.applib.services.metamodel.Config; +import org.apache.isis.applib.services.metamodel.MetaModelService; +import org.apache.isis.core.config.beans.IsisBeanTypeRegistry; +import org.apache.isis.core.config.presets.IsisPresets; +import org.apache.isis.core.metamodel.facetapi.Facet; +import org.apache.isis.core.metamodel.facets.actions.position.ActionPositionFacet; +import org.apache.isis.core.metamodel.facets.members.layout.group.LayoutGroupFacet; +import org.apache.isis.core.metamodel.facets.members.layout.order.LayoutOrderFacet; +import org.apache.isis.core.metamodel.spec.feature.MixedIn; +import org.apache.isis.core.metamodel.spec.feature.ObjectAction; +import org.apache.isis.core.metamodel.specloader.SpecificationLoader; +import org.apache.isis.core.runtimeservices.IsisModuleCoreRuntimeServices; +import org.apache.isis.regressiontests.layouts.integtest.model.Counter; +import org.apache.isis.regressiontests.layouts.integtest.model.LayoutTestDomainModel; +import org.apache.isis.schema.metamodel.v2.Action; +import org.apache.isis.schema.metamodel.v2.DomainClassDto; +import org.apache.isis.schema.metamodel.v2.FacetAttr; +import org.apache.isis.schema.metamodel.v2.MetamodelDto; +import org.apache.isis.security.bypass.IsisModuleSecurityBypass; +import org.apache.isis.testing.integtestsupport.applib.IsisIntegrationTestAbstract; +import org.apache.isis.viewer.wicket.applib.IsisModuleViewerWicketApplibMixins; + +import lombok.val; + +@SpringBootTest( + classes = Layout_IntegTest.AppManifest.class +) +@ActiveProfiles("test") +public class Layout_IntegTest extends IsisIntegrationTestAbstract { + + @SpringBootConfiguration + @EnableAutoConfiguration + @Import({ + IsisModuleApplibMixins.class, + IsisModuleViewerWicketApplibMixins.class, + IsisModuleCoreRuntimeServices.class, + IsisModuleSecurityBypass.class, + }) + @PropertySources({ + @PropertySource(IsisPresets.UseLog4j2Test) + }) + @ComponentScan(basePackageClasses = {AppManifest.class, LayoutTestDomainModel.class}) + public static class AppManifest { + + @Bean + @Singleton + public PlatformTransactionManager platformTransactionManager() { + return new PlatformTransactionManager() { + + @Override + public void rollback(final TransactionStatus status) throws TransactionException { + } + + @Override + public TransactionStatus getTransaction(final TransactionDefinition definition) throws TransactionException { + return null; + } + + @Override + public void commit(final TransactionStatus status) throws TransactionException { + } + }; + } + + } + + @BeforeAll + static void beforeAll() { + IsisPresets.forcePrototyping(); + } + + Bookmark target1; + + @BeforeEach + void beforeEach() { + interactionService.nextInteraction(); + + Optional<Bookmark> bookmark = bookmarkService.bookmarkFor(newCounter("counter-1")); + target1 = bookmark.orElseThrow(); + + interactionService.nextInteraction(); + + } + + protected Counter newCounter(String name) { + return Counter.builder().name(name).build(); + } + + + @Test + void actionNoPosition() { + + // given + val objectSpecification = specificationLoader.loadSpecification(Counter.class); + + // when + val action = lookupAction("actionNoPosition"); + + // then + assertThat(action).isNotNull(); + List<Facet> facets = action.getFacetHolder().streamFacets().collect(Collectors.toList()); + + val actionPositionFacet = action.getFacet(ActionPositionFacet.class); + assertThat(actionPositionFacet) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::getPrecedence).isEqualTo(Facet.Precedence.FALLBACK)) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::position).isEqualTo(ActionLayout.Position.BELOW)); + + val layoutOrderFacet = action.getFacet(LayoutOrderFacet.class); + assertThat(layoutOrderFacet) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getSequence).isEqualTo("")) + ; + + val layoutGroupFacet = action.getFacet(LayoutGroupFacet.class); + assertThat(layoutGroupFacet) + .satisfies(f -> assertThat(f).isNull()) + ; + } + + @Test + void actionPositionBelow() { + + // given + val action = lookupAction("actionPositionBelow"); + + // when, then + List<Facet> facets = action.getFacetHolder().streamFacets().collect(Collectors.toList()); + + val actionPositionFacet = action.getFacet(ActionPositionFacet.class); + assertThat(actionPositionFacet) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::position).isEqualTo(ActionLayout.Position.BELOW)); + + val layoutOrderFacet = action.getFacet(LayoutOrderFacet.class); + assertThat(layoutOrderFacet) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getSequence).isEqualTo("")) + ; + + val layoutGroupFacet = action.getFacet(LayoutGroupFacet.class); + assertThat(layoutGroupFacet) + .satisfies(f -> assertThat(f).isNull()) + ; + } + + @Test + void actionPositionPanel() { + + // given + val action = lookupAction("actionPositionPanel"); + + // when, then + List<Facet> facets = action.getFacetHolder().streamFacets().collect(Collectors.toList()); + + val actionPositionFacet = action.getFacet(ActionPositionFacet.class); + assertThat(actionPositionFacet) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::position).isEqualTo(ActionLayout.Position.PANEL)); + + val layoutOrderFacet = action.getFacet(LayoutOrderFacet.class); + assertThat(layoutOrderFacet) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getSequence).isEqualTo("")) + ; + + val layoutGroupFacet = action.getFacet(LayoutGroupFacet.class); + assertThat(layoutGroupFacet) + .satisfies(f -> assertThat(f).isNull()) + ; + } + + @Test + void actionDetailsFieldSetNoPosition() { + + // given + val action = lookupAction("actionDetailsFieldSetNoPosition"); + + // when, then + List<Facet> facets = action.getFacetHolder().streamFacets().collect(Collectors.toList()); + + val actionPositionFacet = action.getFacet(ActionPositionFacet.class); + assertThat(actionPositionFacet) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::getPrecedence).isEqualTo(Facet.Precedence.FALLBACK)) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::position).isEqualTo(ActionLayout.Position.BELOW)); + + val layoutOrderFacet = action.getFacet(LayoutOrderFacet.class); + assertThat(layoutOrderFacet) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getSequence).isEqualTo("1")) + ; + + val layoutGroupFacet = action.getFacet(LayoutGroupFacet.class); + assertThat(layoutGroupFacet) + .satisfies(f -> assertThat(f).isNotNull()) + .satisfies(f -> assertThat(f).extracting(LayoutGroupFacet::getGroupId).isEqualTo("details")) + ; + } + + @Test + void actionDetailsFieldSetPositionBelow() { + + // given + val action = lookupAction("actionDetailsFieldSetPositionBelow"); + + // when, then + List<Facet> facets = action.getFacetHolder().streamFacets().collect(Collectors.toList()); + + val actionPositionFacet = action.getFacet(ActionPositionFacet.class); + assertThat(actionPositionFacet) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::position).isEqualTo(ActionLayout.Position.BELOW)); + + val layoutOrderFacet = action.getFacet(LayoutOrderFacet.class); + assertThat(layoutOrderFacet) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getSequence).isEqualTo("2")) + ; + + val layoutGroupFacet = action.getFacet(LayoutGroupFacet.class); + assertThat(layoutGroupFacet) + .satisfies(f -> assertThat(f).isNotNull()) + .satisfies(f -> assertThat(f).extracting(LayoutGroupFacet::getGroupId).isEqualTo("details")) + ; + } + + @Test + void actionDetailsFieldSetPositionPanel() { + + // given + val action = lookupAction("actionDetailsFieldSetPositionPanel"); + + // when, then + List<Facet> facets = action.getFacetHolder().streamFacets().collect(Collectors.toList()); + + val actionPositionFacet = action.getFacet(ActionPositionFacet.class); + assertThat(actionPositionFacet) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::position).isEqualTo(ActionLayout.Position.PANEL)); + + val layoutOrderFacet = action.getFacet(LayoutOrderFacet.class); + assertThat(layoutOrderFacet) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getSequence).isEqualTo("3")) + ; + + val layoutGroupFacet = action.getFacet(LayoutGroupFacet.class); + assertThat(layoutGroupFacet) + .satisfies(f -> assertThat(f).isNotNull()) + .satisfies(f -> assertThat(f).extracting(LayoutGroupFacet::getGroupId).isEqualTo("details")) + ; + } + + @Test + void actionDetailsFieldSetPositionPanelDropdown() { + + // given + val action = lookupAction("actionDetailsFieldSetPositionPanelDropdown"); + + // when, then + List<Facet> facets = action.getFacetHolder().streamFacets().collect(Collectors.toList()); + + val actionPositionFacet = action.getFacet(ActionPositionFacet.class); + assertThat(actionPositionFacet) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::position).isEqualTo(ActionLayout.Position.PANEL_DROPDOWN)); + + val layoutOrderFacet = action.getFacet(LayoutOrderFacet.class); + assertThat(layoutOrderFacet) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getSequence).isEqualTo("4")) + ; + + val layoutGroupFacet = action.getFacet(LayoutGroupFacet.class); + assertThat(layoutGroupFacet) + .satisfies(f -> assertThat(f).isNotNull()) + .satisfies(f -> assertThat(f).extracting(LayoutGroupFacet::getGroupId).isEqualTo("details")) + ; + } + + @Test + void actionEmptyFieldSetNoPosition() { + + // given + val action = lookupAction("actionEmptyFieldSetNoPosition"); + + // when, then + List<Facet> facets = action.getFacetHolder().streamFacets().collect(Collectors.toList()); + + val actionPositionFacet = action.getFacet(ActionPositionFacet.class); + assertThat(actionPositionFacet) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::getPrecedence).isEqualTo(Facet.Precedence.FALLBACK)) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::position).isEqualTo(ActionLayout.Position.BELOW)); + + val layoutOrderFacet = action.getFacet(LayoutOrderFacet.class); + assertThat(layoutOrderFacet) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getSequence).isEqualTo("1")) + ; + + val layoutGroupFacet = action.getFacet(LayoutGroupFacet.class); + assertThat(layoutGroupFacet) + .satisfies(f -> assertThat(f).extracting(LayoutGroupFacet::getGroupId).isEqualTo("empty")) + ; + } + + @Test + void actionEmptyFieldSetPositionBelow() { + + // given + val action = lookupAction("actionEmptyFieldSetPositionBelow"); + + // when, then + List<Facet> facets = action.getFacetHolder().streamFacets().collect(Collectors.toList()); + + val actionPositionFacet = action.getFacet(ActionPositionFacet.class); + assertThat(actionPositionFacet) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::position).isEqualTo(ActionLayout.Position.BELOW)); + + val layoutOrderFacet = action.getFacet(LayoutOrderFacet.class); + assertThat(layoutOrderFacet) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getSequence).isEqualTo("2")) + ; + + val layoutGroupFacet = action.getFacet(LayoutGroupFacet.class); + assertThat(layoutGroupFacet) + .satisfies(f -> assertThat(f).extracting(LayoutGroupFacet::getGroupId).isEqualTo("empty")) + ; + } + + @Test + void actionEmptyFieldSetPositionPanel() { + + // given + val action = lookupAction("actionEmptyFieldSetPositionPanel"); + + // when, then + List<Facet> facets = action.getFacetHolder().streamFacets().collect(Collectors.toList()); + + val actionPositionFacet = action.getFacet(ActionPositionFacet.class); + assertThat(actionPositionFacet) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::position).isEqualTo(ActionLayout.Position.PANEL)); + + val layoutOrderFacet = action.getFacet(LayoutOrderFacet.class); + assertThat(layoutOrderFacet) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getSequence).isEqualTo("3")) + ; + + val layoutGroupFacet = action.getFacet(LayoutGroupFacet.class); + assertThat(layoutGroupFacet) + .satisfies(f -> assertThat(f).extracting(LayoutGroupFacet::getGroupId).isEqualTo("empty")) + ; + } + + @Test + void actionEmptyFieldSetPositionPanelDropdown() { + + // given + val action = lookupAction("actionEmptyFieldSetPositionPanelDropdown"); + + // when, then + List<Facet> facets = action.getFacetHolder().streamFacets().collect(Collectors.toList()); + + val actionPositionFacet = action.getFacet(ActionPositionFacet.class); + assertThat(actionPositionFacet) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::position).isEqualTo(ActionLayout.Position.PANEL_DROPDOWN)); + + val layoutOrderFacet = action.getFacet(LayoutOrderFacet.class); + assertThat(layoutOrderFacet) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getSequence).isEqualTo("4")) + ; + + val layoutGroupFacet = action.getFacet(LayoutGroupFacet.class); + assertThat(layoutGroupFacet) + .satisfies(f -> assertThat(f).extracting(LayoutGroupFacet::getGroupId).isEqualTo("empty")) + ; + } + + @Test + void actionAssociatedWithNamePropertyNoPosition() { + + // given + val action = lookupAction("actionAssociatedWithNamePropertyNoPosition"); + + // when, then + List<Facet> facets = action.getFacetHolder().streamFacets().collect(Collectors.toList()); + + val actionPositionFacet = action.getFacet(ActionPositionFacet.class); + assertThat(actionPositionFacet) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::getPrecedence).isEqualTo(Facet.Precedence.FALLBACK)) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::position).isEqualTo(ActionLayout.Position.BELOW)); + + val layoutOrderFacet = action.getFacet(LayoutOrderFacet.class); + assertThat(layoutOrderFacet) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getSequence).isEqualTo("")) + ; + + val layoutGroupFacet = action.getFacet(LayoutGroupFacet.class); + assertThat(layoutGroupFacet) + .satisfies(f -> assertThat(f).extracting(LayoutGroupFacet::getGroupId).isEqualTo("name")) // TODO: ?? strange, because 'name' is not a fieldset; should be 'details' ?? + ; + } + + @Test + void actionAssociatedWithNamePropertyBelow() { + + // given + val action = lookupAction("actionAssociatedWithNamePropertyBelow"); + + // when, then + List<Facet> facets = action.getFacetHolder().streamFacets().collect(Collectors.toList()); + + val actionPositionFacet = action.getFacet(ActionPositionFacet.class); + assertThat(actionPositionFacet) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::position).isEqualTo(ActionLayout.Position.BELOW)); + + val layoutOrderFacet = action.getFacet(LayoutOrderFacet.class); + assertThat(layoutOrderFacet) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getSequence).isEqualTo("")) + ; + + val layoutGroupFacet = action.getFacet(LayoutGroupFacet.class); + assertThat(layoutGroupFacet) + .satisfies(f -> assertThat(f).extracting(LayoutGroupFacet::getGroupId).isEqualTo("name")) // TODO: ?? strange, because 'name' is not a fieldset; should be 'details' ?? + ; + } + + @Test + void actionAssociatedWithNamePropertyPanel() { + + // given + val action = lookupAction("actionAssociatedWithNamePropertyPanel"); + + // when, then + List<Facet> facets = action.getFacetHolder().streamFacets().collect(Collectors.toList()); + + val actionPositionFacet = action.getFacet(ActionPositionFacet.class); + assertThat(actionPositionFacet) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::position).isEqualTo(ActionLayout.Position.PANEL)); + + val layoutOrderFacet = action.getFacet(LayoutOrderFacet.class); + assertThat(layoutOrderFacet) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getSequence).isEqualTo("")) + ; + + val layoutGroupFacet = action.getFacet(LayoutGroupFacet.class); + assertThat(layoutGroupFacet) + .satisfies(f -> assertThat(f).extracting(LayoutGroupFacet::getGroupId).isEqualTo("name")) // TODO: ?? strange, because 'name' is not a fieldset; should be 'details' ?? + ; + } + + @Test + void actionAssociatedWithNamePropertyPanelDropdown() { + + // given + val action = lookupAction("actionAssociatedWithNamePropertyPanelDropdown"); + + // when, then + List<Facet> facets = action.getFacetHolder().streamFacets().collect(Collectors.toList()); + + val actionPositionFacet = action.getFacet(ActionPositionFacet.class); + assertThat(actionPositionFacet) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::position).isEqualTo(ActionLayout.Position.PANEL_DROPDOWN)); + + val layoutOrderFacet = action.getFacet(LayoutOrderFacet.class); + assertThat(layoutOrderFacet) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getSequence).isEqualTo("")) + ; + + val layoutGroupFacet = action.getFacet(LayoutGroupFacet.class); + assertThat(layoutGroupFacet) + .satisfies(f -> assertThat(f).extracting(LayoutGroupFacet::getGroupId).isEqualTo("name")) // TODO: ?? strange, because 'name' is not a fieldset; should be 'details' ?? + ; + } + + @Test + void actionAssociatedWithNamePropertyAndDetailsFieldSetNoPosition() { + + // given + val action = lookupAction("actionAssociatedWithNamePropertyAndDetailsFieldSetNoPosition"); + + // when, then + List<Facet> facets = action.getFacetHolder().streamFacets().collect(Collectors.toList()); + + val actionPositionFacet = action.getFacet(ActionPositionFacet.class); + assertThat(actionPositionFacet) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::getPrecedence).isEqualTo(Facet.Precedence.FALLBACK)) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::position).isEqualTo(ActionLayout.Position.BELOW)); + + val layoutOrderFacet = action.getFacet(LayoutOrderFacet.class); + assertThat(layoutOrderFacet) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getSequence).isEqualTo("1")) + ; + + val layoutGroupFacet = action.getFacet(LayoutGroupFacet.class); + assertThat(layoutGroupFacet) + .satisfies(f -> assertThat(f).extracting(LayoutGroupFacet::getGroupId).isEqualTo("details")) + ; + } + + @Test + void actionAssociatedWithNameAndDetailsFieldSetPropertyBelow() { + + // given + val action = lookupAction("actionAssociatedWithNameAndDetailsFieldSetPropertyBelow"); + + // when, then + List<Facet> facets = action.getFacetHolder().streamFacets().collect(Collectors.toList()); + + val actionPositionFacet = action.getFacet(ActionPositionFacet.class); + assertThat(actionPositionFacet) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::position).isEqualTo(ActionLayout.Position.BELOW)); + + val layoutOrderFacet = action.getFacet(LayoutOrderFacet.class); + assertThat(layoutOrderFacet) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getSequence).isEqualTo("2")) + ; + + val layoutGroupFacet = action.getFacet(LayoutGroupFacet.class); + assertThat(layoutGroupFacet) + .satisfies(f -> assertThat(f).extracting(LayoutGroupFacet::getGroupId).isEqualTo("details")) + ; + } + + @Test + void actionAssociatedWithNamePropertyAndDetailsFieldSetPanel() { + + // given + val action = lookupAction("actionAssociatedWithNamePropertyAndDetailsFieldSetPanel"); + + // when, then + List<Facet> facets = action.getFacetHolder().streamFacets().collect(Collectors.toList()); + + val actionPositionFacet = action.getFacet(ActionPositionFacet.class); + assertThat(actionPositionFacet) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::position).isEqualTo(ActionLayout.Position.PANEL)); + + val layoutOrderFacet = action.getFacet(LayoutOrderFacet.class); + assertThat(layoutOrderFacet) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getSequence).isEqualTo("3")) + ; + + val layoutGroupFacet = action.getFacet(LayoutGroupFacet.class); + assertThat(layoutGroupFacet) + .satisfies(f -> assertThat(f).extracting(LayoutGroupFacet::getGroupId).isEqualTo("details")) // because "name" is in this fieldSet + ; + } + + @Test + void actionAssociatedWithNamePropertyAndDetailsFieldSetPanelDropdown() { + + // given + val action = lookupAction("actionAssociatedWithNamePropertyAndDetailsFieldSetPanelDropdown"); + + // when, then + List<Facet> facets = action.getFacetHolder().streamFacets().collect(Collectors.toList()); + + val actionPositionFacet = action.getFacet(ActionPositionFacet.class); + assertThat(actionPositionFacet) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::position).isEqualTo(ActionLayout.Position.PANEL_DROPDOWN)); + + val layoutOrderFacet = action.getFacet(LayoutOrderFacet.class); + assertThat(layoutOrderFacet) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getSequence).isEqualTo("4")) + ; + + val layoutGroupFacet = action.getFacet(LayoutGroupFacet.class); + assertThat(layoutGroupFacet) + .satisfies(f -> assertThat(f).extracting(LayoutGroupFacet::getGroupId).isEqualTo("details")) // because "name" is in this fieldSet + ; + } + + @Test + void actionAssociatedWithNamePropertyButEmptyFieldSetNoPosition() { + + // given + val action = lookupAction("actionAssociatedWithNamePropertyButEmptyFieldSetNoPosition"); + + // when, then + List<Facet> facets = action.getFacetHolder().streamFacets().collect(Collectors.toList()); + + val actionPositionFacet = action.getFacet(ActionPositionFacet.class); + assertThat(actionPositionFacet) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::getPrecedence).isEqualTo(Facet.Precedence.FALLBACK)) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::position).isEqualTo(ActionLayout.Position.BELOW)); + + val layoutOrderFacet = action.getFacet(LayoutOrderFacet.class); + assertThat(layoutOrderFacet) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getSequence).isEqualTo("1")) + ; + + val layoutGroupFacet = action.getFacet(LayoutGroupFacet.class); + assertThat(layoutGroupFacet) + .satisfies(f -> assertThat(f).extracting(LayoutGroupFacet::getGroupId).isEqualTo("empty")) // overrides the 'associateWith' ??? + ; + } + + @Test + void actionAssociatedWithNamePropertyAndSequenceNoPosition() { + + // given + val action = lookupAction("actionAssociatedWithNamePropertyAndSequenceNoPosition"); + + // when, then + List<Facet> facets = action.getFacetHolder().streamFacets().collect(Collectors.toList()); + + val actionPositionFacet = action.getFacet(ActionPositionFacet.class); + assertThat(actionPositionFacet) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::getPrecedence).isEqualTo(Facet.Precedence.FALLBACK)) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::position).isEqualTo(ActionLayout.Position.BELOW)); + + val layoutOrderFacet = action.getFacet(LayoutOrderFacet.class); + assertThat(layoutOrderFacet) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getSequence).isEqualTo("1")) + ; + + val layoutGroupFacet = action.getFacet(LayoutGroupFacet.class); + assertThat(layoutGroupFacet) + .satisfies(f -> assertThat(f).extracting(LayoutGroupFacet::getGroupId).isEqualTo("name")) // TODO: ?? strange, because 'name' is not a fieldset + ; + } + + @Test + void openRestApi() { + + // given + val action = lookupAction("openRestApi"); + + // when, then + List<Facet> facets = action.getFacetHolder().streamFacets().collect(Collectors.toList()); + + val actionPositionFacet = action.getFacet(ActionPositionFacet.class); + assertThat(actionPositionFacet) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::position).isEqualTo(ActionLayout.Position.PANEL_DROPDOWN)); + + val layoutOrderFacet = action.getFacet(LayoutOrderFacet.class); + assertThat(layoutOrderFacet) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getSequence).isEqualTo("750.1")) + ; + + val layoutGroupFacet = action.getFacet(LayoutGroupFacet.class); + assertThat(layoutGroupFacet) + .satisfies(f -> assertThat(f).extracting(LayoutGroupFacet::getGroupId).isEqualTo(LayoutConstants.FieldSetId.METADATA)) + ; + } + + @Test + void clearHints() { + + // given + val action = lookupAction("clearHints"); + + // when, then + List<Facet> facets = action.getFacetHolder().streamFacets().collect(Collectors.toList()); + + val actionPositionFacet = action.getFacet(ActionPositionFacet.class); + assertThat(actionPositionFacet) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(ActionPositionFacet::position).isEqualTo(ActionLayout.Position.PANEL)); + + val layoutOrderFacet = action.getFacet(LayoutOrderFacet.class); + assertThat(layoutOrderFacet) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getPrecedence).isEqualTo(Facet.Precedence.DEFAULT)) + .satisfies(f -> assertThat(f).extracting(LayoutOrderFacet::getSequence).isEqualTo("400.1")) + ; + + val layoutGroupFacet = action.getFacet(LayoutGroupFacet.class); + assertThat(layoutGroupFacet) + .satisfies(f -> assertThat(f).extracting(LayoutGroupFacet::getGroupId).isEqualTo(LayoutConstants.FieldSetId.METADATA)) + ; + } + + private ObjectAction lookupAction(String id) { + val objectSpecification = specificationLoader.loadSpecification(Counter.class); + List<ObjectAction> objectActions = objectSpecification.streamAnyActions(MixedIn.INCLUDED).collect(Collectors.toList()); + return objectSpecification.streamAnyActions(MixedIn.INCLUDED).filter(x -> x.getId().equals(id)).findFirst().orElseThrow(); + } + + + private void extracted(Class<?> cls) { + LogicalType logicalType = metaModelService.lookupLogicalTypeByClass(cls).orElseThrow(); + MetamodelDto metamodelDto = metaModelService.exportMetaModel(new Config().withNamespacePrefix("layouts.test.")); + Map<String, DomainClassDto> metaModelDtoById = metamodelDto.getDomainClassDto().stream().collect(Collectors.toMap(DomainClassDto::getId, Function.identity())); + DomainClassDto domainClassDto = metaModelDtoById.get(cls.getCanonicalName()); + Map<String, Action> actionById = domainClassDto.getActions().getAct().stream().collect(Collectors.toMap(Action::getId, Function.identity())); + List<org.apache.isis.schema.metamodel.v2.Facet> facets = actionById.get("updateNameUsingDeclaredAction").getFacets().getFacet(); + Map<String, org.apache.isis.schema.metamodel.v2.Facet> facetById = facets.stream().collect(Collectors.toMap(org.apache.isis.schema.metamodel.v2.Facet::getId, Function.identity())); + Map<String, String> facetAttrByName = facetById.get(LayoutGroupFacet.class.getCanonicalName()).getAttr().stream().collect(Collectors.toMap(FacetAttr::getName, FacetAttr::getValue)); + facetAttrByName.get("Name"); + } + + + @Inject InteractionService interactionService; + @Inject MetaModelService metaModelService; + @Inject SpecificationLoader specificationLoader; + @Inject BookmarkService bookmarkService; + + @Inject IsisBeanTypeRegistry isisBeanTypeRegistry; + +} diff --git a/regressiontests/stable-layouts/src/main/java/org/apache/isis/regressiontests/layouts/integtest/model/Counter.java b/regressiontests/stable-layouts/src/main/java/org/apache/isis/regressiontests/layouts/integtest/model/Counter.java new file mode 100644 index 0000000000..ab6f5e8837 --- /dev/null +++ b/regressiontests/stable-layouts/src/main/java/org/apache/isis/regressiontests/layouts/integtest/model/Counter.java @@ -0,0 +1,227 @@ +/* + * 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.regressiontests.layouts.integtest.model; + +import javax.inject.Named; +import javax.xml.bind.annotation.XmlAccessorOrder; +import javax.xml.bind.annotation.XmlRootElement; + +import org.apache.isis.applib.annotation.Action; +import org.apache.isis.applib.annotation.ActionLayout; +import org.apache.isis.applib.annotation.DomainObject; +import org.apache.isis.applib.annotation.Nature; +import org.apache.isis.applib.annotation.Property; +import org.apache.isis.applib.annotation.PropertyLayout; +import org.apache.isis.applib.layout.LayoutConstants; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@XmlRootElement() +@XmlAccessorOrder +@Named("layouts.test.Counter") +@DomainObject(nature = Nature.VIEW_MODEL) +@NoArgsConstructor +@Builder +@AllArgsConstructor +public class Counter implements Comparable<Counter> { + + @PropertyLayout(fieldSetId = LayoutConstants.FieldSetId.IDENTITY) + @Getter @Setter + private String name; + + @PropertyLayout(fieldSetId = LayoutConstants.FieldSetId.DETAILS) + @Getter @Setter + private Long num; + + @PropertyLayout(fieldSetId = LayoutConstants.FieldSetId.IDENTITY) + @Getter @Setter + private String propertyInFieldSetIdIdentity; + + @PropertyLayout(fieldSetId = LayoutConstants.FieldSetId.DETAILS) + @Getter @Setter + private String propertyInFieldSetIdDetails; + + @Action() + @ActionLayout() + public Counter actionNoPosition(String newName) { + return doUpdateName(newName); + } + + @Action() + @ActionLayout(position = ActionLayout.Position.BELOW) + public Counter actionPositionBelow(String newName) { + return doUpdateName(newName); + } + + @Action() + @ActionLayout(position = ActionLayout.Position.PANEL) + public Counter actionPositionPanel(String newName) { + return doUpdateName(newName); + } + + @Action() + @ActionLayout(position = ActionLayout.Position.PANEL_DROPDOWN) + public Counter actionPositionPanelDropdown(String newName) { + return doUpdateName(newName); + } + + + // with details fieldset (which contains at least one property) + sequence + + @Action() + @ActionLayout(fieldSetId = LayoutConstants.FieldSetId.DETAILS, sequence = "1") + public Counter actionDetailsFieldSetNoPosition(String newName) { + return doUpdateName(newName); + } + + @Action() + @ActionLayout(fieldSetId = LayoutConstants.FieldSetId.DETAILS, sequence = "2", position = ActionLayout.Position.BELOW) + public Counter actionDetailsFieldSetPositionBelow(String newName) { + return doUpdateName(newName); + } + + @Action() + @ActionLayout(fieldSetId = LayoutConstants.FieldSetId.DETAILS, sequence = "3", position = ActionLayout.Position.PANEL) + public Counter actionDetailsFieldSetPositionPanel(String newName) { + return doUpdateName(newName); + } + + @Action() + @ActionLayout(fieldSetId = LayoutConstants.FieldSetId.DETAILS, sequence = "4", position = ActionLayout.Position.PANEL_DROPDOWN) + public Counter actionDetailsFieldSetPositionPanelDropdown(String newName) { + return doUpdateName(newName); + } + + + // with empty fieldset (that has no properties) + sequence + + @Action() + @ActionLayout(fieldSetId = "empty", sequence = "1") + public Counter actionEmptyFieldSetNoPosition(String newName) { + return doUpdateName(newName); + } + + @Action() + @ActionLayout(fieldSetId = "empty", sequence = "2", position = ActionLayout.Position.BELOW) + public Counter actionEmptyFieldSetPositionBelow(String newName) { + return doUpdateName(newName); + } + + @Action() + @ActionLayout(fieldSetId = "empty", sequence = "3", position = ActionLayout.Position.PANEL) + public Counter actionEmptyFieldSetPositionPanel(String newName) { + return doUpdateName(newName); + } + + @Action() + @ActionLayout(fieldSetId = "empty", sequence = "4", position = ActionLayout.Position.PANEL_DROPDOWN) + public Counter actionEmptyFieldSetPositionPanelDropdown(String newName) { + return doUpdateName(newName); + } + + + // with associateWith + + @Action() + @ActionLayout(associateWith = "name") + public Counter actionAssociatedWithNamePropertyNoPosition(String newName) { + return doUpdateName(newName); + } + + @Action() + @ActionLayout(associateWith = "name", position = ActionLayout.Position.BELOW) + public Counter actionAssociatedWithNamePropertyBelow(String newName) { + return doUpdateName(newName); + } + + @Action() + @ActionLayout(associateWith = "name", position = ActionLayout.Position.PANEL) + public Counter actionAssociatedWithNamePropertyPanel(String newName) { + return doUpdateName(newName); + } + + @Action() + @ActionLayout(associateWith = "name", position = ActionLayout.Position.PANEL_DROPDOWN) + public Counter actionAssociatedWithNamePropertyPanelDropdown(String newName) { + return doUpdateName(newName); + } + + + // with associateWith + correct fieldSet for the associated property + + @Action() + @ActionLayout(associateWith = "name", fieldSetId = "details", sequence = "1") + public Counter actionAssociatedWithNamePropertyAndDetailsFieldSetNoPosition(String newName) { + return doUpdateName(newName); + } + + @Action() + @ActionLayout(associateWith = "name", fieldSetId = "details", sequence = "2", position = ActionLayout.Position.BELOW) + public Counter actionAssociatedWithNameAndDetailsFieldSetPropertyBelow(String newName) { + return doUpdateName(newName); + } + + @Action() + @ActionLayout(associateWith = "name", fieldSetId = "details", sequence = "3", position = ActionLayout.Position.PANEL) + public Counter actionAssociatedWithNamePropertyAndDetailsFieldSetPanel(String newName) { + return doUpdateName(newName); + } + + @Action() + @ActionLayout(associateWith = "name", fieldSetId = "details", sequence = "4", position = ActionLayout.Position.PANEL_DROPDOWN) + public Counter actionAssociatedWithNamePropertyAndDetailsFieldSetPanelDropdown(String newName) { + return doUpdateName(newName); + } + + + // with associateWith + incorrect fieldSet for the associated property + + @Action() + @ActionLayout(associateWith = "name", fieldSetId = "empty", sequence = "1") + public Counter actionAssociatedWithNamePropertyButEmptyFieldSetNoPosition(String newName) { + return doUpdateName(newName); + } + + + // associateWith + only the sequence + + @Action() + @ActionLayout(associateWith = "name", sequence = "1") + public Counter actionAssociatedWithNamePropertyAndSequenceNoPosition(String newName) { + return doUpdateName(newName); + } + + + + Counter doUpdateName(String newName) { + setName(newName); + return this; + } + + @Override + public int compareTo(final Counter o) { + return this.getName().compareTo(o.getName()); + } +} diff --git a/regressiontests/stable-layouts/src/main/java/org/apache/isis/regressiontests/layouts/integtest/model/Counter.layout.xml b/regressiontests/stable-layouts/src/main/java/org/apache/isis/regressiontests/layouts/integtest/model/Counter.layout.xml new file mode 100644 index 0000000000..9ac67c27bc --- /dev/null +++ b/regressiontests/stable-layouts/src/main/java/org/apache/isis/regressiontests/layouts/integtest/model/Counter.layout.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<!-- + 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. +--> +<bs3:grid xsi:schemaLocation="http://isis.apache.org/applib/layout/component http://isis.apache.org/applib/layout/component/component.xsd http://isis.apache.org/applib/layout/grid/bootstrap3 http://isis.apache.org/applib/layout/grid/bootstrap3/bootstrap3.xsd" xmlns:c="http://isis.apache.org/applib/layout/component" xmlns:bs3="http://isis.apache.org/applib/layout/grid/bootstrap3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + + <bs3:row> + <bs3:col span="12" unreferencedActions="true"> + <c:domainObject bookmarking="AS_ROOT"/> + </bs3:col> + </bs3:row> + <bs3:row> + <bs3:col span="4"> + <bs3:row> + <bs3:col span="12"> + <bs3:tabGroup> + <bs3:tab name="Identity"> + <bs3:row> + <bs3:col span="12"> + <c:fieldSet name="Identity" id="identity"/> + </bs3:col> + </bs3:row> + </bs3:tab> + <bs3:tab name="Other"> + <bs3:row> + <bs3:col span="12"> + <c:fieldSet name="Other" id="other" unreferencedProperties="true"/> + </bs3:col> + </bs3:row> + </bs3:tab> + <bs3:tab name="Metadata"> + <bs3:row> + <bs3:col span="12"> + <c:fieldSet name="Metadata" id="metadata"/> + </bs3:col> + </bs3:row> + </bs3:tab> + </bs3:tabGroup> + </bs3:col> + </bs3:row> + <bs3:row> + <bs3:col span="12"> + <c:fieldSet name="Details" id="details"/> + </bs3:col> + </bs3:row> + <bs3:row> + <bs3:col span="12"> + <c:fieldSet name="Empty FieldSet" id="empty"/> + </bs3:col> + </bs3:row> + </bs3:col> + <bs3:col span="8"> + <bs3:tabGroup unreferencedCollections="true"> + </bs3:tabGroup> + </bs3:col> + </bs3:row> +</bs3:grid> diff --git a/regressiontests/stable-layouts/src/main/java/org/apache/isis/regressiontests/layouts/integtest/model/Counter_updateNameUsingMixin.java b/regressiontests/stable-layouts/src/main/java/org/apache/isis/regressiontests/layouts/integtest/model/Counter_updateNameUsingMixin.java new file mode 100644 index 0000000000..e3cee6dd93 --- /dev/null +++ b/regressiontests/stable-layouts/src/main/java/org/apache/isis/regressiontests/layouts/integtest/model/Counter_updateNameUsingMixin.java @@ -0,0 +1,37 @@ +/* + * 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.regressiontests.layouts.integtest.model; + +import org.apache.isis.applib.annotation.Action; +import org.apache.isis.applib.services.wrapper.Mixin; + +import lombok.RequiredArgsConstructor; + +@Action() +@RequiredArgsConstructor +public class Counter_updateNameUsingMixin implements Mixin<Counter> { + + private final Counter counter; + + public Counter act(String name) { + return counter.doUpdateName(name); + } +} diff --git a/regressiontests/stable-layouts/src/main/java/org/apache/isis/regressiontests/layouts/integtest/model/LayoutTestDomainModel.java b/regressiontests/stable-layouts/src/main/java/org/apache/isis/regressiontests/layouts/integtest/model/LayoutTestDomainModel.java new file mode 100644 index 0000000000..79eb334070 --- /dev/null +++ b/regressiontests/stable-layouts/src/main/java/org/apache/isis/regressiontests/layouts/integtest/model/LayoutTestDomainModel.java @@ -0,0 +1,24 @@ +/* + * 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.regressiontests.layouts.integtest.model; + +public class LayoutTestDomainModel { +} diff --git a/viewers/wicket/pom.xml b/viewers/wicket/applib/pom.xml similarity index 57% copy from viewers/wicket/pom.xml copy to viewers/wicket/applib/pom.xml index 1d12d0295e..177f0bacd4 100644 --- a/viewers/wicket/pom.xml +++ b/viewers/wicket/applib/pom.xml @@ -7,9 +7,9 @@ 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 @@ -22,22 +22,35 @@ <modelVersion>4.0.0</modelVersion> <parent> - <groupId>org.apache.isis.core</groupId> - <artifactId>isis-core</artifactId> + <groupId>org.apache.isis.viewer</groupId> + <artifactId>isis-viewer-wicket</artifactId> <version>2.0.0-SNAPSHOT</version> - <relativePath>../../core/pom.xml</relativePath> </parent> - <groupId>org.apache.isis.viewer</groupId> - <artifactId>isis-viewer-wicket</artifactId> - <name>Apache Isis Viewer - Wicket</name> + <artifactId>isis-viewer-wicket-applib</artifactId> + <name>Apache Isis Viewer - Wicket (Applib)</name> + + <properties> + <jar-plugin.automaticModuleName>org.apache.isis.viewer.wicket.applib</jar-plugin.automaticModuleName> + <git-plugin.propertiesDir>org/apache/isis/viewer/wicket/applib</git-plugin.propertiesDir> + </properties> + + <dependencies> + + <dependency> + <groupId>org.apache.isis.core</groupId> + <artifactId>isis-applib</artifactId> + </dependency> + + <!-- TESTING --> + + <dependency> + <groupId>org.apache.isis.core</groupId> + <artifactId>isis-core-internaltestsupport</artifactId> + <scope>test</scope> + </dependency> - <packaging>pom</packaging> + </dependencies> - <modules> - <module>model</module> - <module>viewer</module> - <module>ui</module> - </modules> </project> diff --git a/viewers/wicket/applib/src/main/java/org/apache/isis/viewer/wicket/applib/IsisModuleViewerWicketApplibMixins.java b/viewers/wicket/applib/src/main/java/org/apache/isis/viewer/wicket/applib/IsisModuleViewerWicketApplibMixins.java new file mode 100644 index 0000000000..16125e90cf --- /dev/null +++ b/viewers/wicket/applib/src/main/java/org/apache/isis/viewer/wicket/applib/IsisModuleViewerWicketApplibMixins.java @@ -0,0 +1,39 @@ +/* + * 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.viewer.wicket.applib; + +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +import org.apache.isis.viewer.wicket.applib.mixins.Object_clearHints; + + +/** + * @since 1.x {@index} + */ +@Configuration +@Import({ + + // @Mixin's + Object_clearHints.class, + +}) +public class IsisModuleViewerWicketApplibMixins { + +} diff --git a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/mixins/Object_clearHints.java b/viewers/wicket/applib/src/main/java/org/apache/isis/viewer/wicket/applib/mixins/Object_clearHints.java similarity index 80% rename from viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/mixins/Object_clearHints.java rename to viewers/wicket/applib/src/main/java/org/apache/isis/viewer/wicket/applib/mixins/Object_clearHints.java index c5f5a4fd37..f98fe618d0 100644 --- a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/mixins/Object_clearHints.java +++ b/viewers/wicket/applib/src/main/java/org/apache/isis/viewer/wicket/applib/mixins/Object_clearHints.java @@ -15,11 +15,14 @@ * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. + * */ -package org.apache.isis.viewer.wicket.viewer.mixins; +package org.apache.isis.viewer.wicket.applib.mixins; import javax.inject.Inject; +import org.springframework.beans.factory.annotation.Autowired; + import org.apache.isis.applib.annotation.Action; import org.apache.isis.applib.annotation.ActionLayout; import org.apache.isis.applib.annotation.MemberSupport; @@ -28,10 +31,8 @@ import org.apache.isis.applib.annotation.SemanticsOf; import org.apache.isis.applib.layout.LayoutConstants; import org.apache.isis.applib.services.bookmark.BookmarkService; import org.apache.isis.applib.services.hint.HintStore; -import org.apache.isis.viewer.wicket.viewer.services.HintStoreUsingWicketSession; import lombok.RequiredArgsConstructor; -import lombok.val; /** * Provides the ability for the end-user to discard UI hints so that the @@ -71,7 +72,7 @@ import lombok.val; @RequiredArgsConstructor public class Object_clearHints { - @Inject HintStore hintStore; + @Autowired(required = false) HintStore hintStore; @Inject BookmarkService bookmarkService; private final Object holder; @@ -79,26 +80,16 @@ public class Object_clearHints { public static class ActionDomainEvent extends org.apache.isis.applib.events.domain.ActionDomainEvent<Object> {} @MemberSupport public Object act() { - if (getHintStoreUsingWicketSession() != null) { - val bookmark = bookmarkService.bookmarkForElseFail(holder); - val hintStore = getHintStoreUsingWicketSession(); - if(hintStore!=null) { // just in case - hintStore.removeAll(bookmark); - } + if (hintStore != null) { + bookmarkService.bookmarkFor(holder).ifPresent(bookmark -> this.hintStore.removeAll(bookmark)); } return holder; } @MemberSupport public boolean hideAct() { - return getHintStoreUsingWicketSession() == null; + return hintStore == null; } // -- HELPER - private HintStoreUsingWicketSession getHintStoreUsingWicketSession() { - return hintStore instanceof HintStoreUsingWicketSession - ? (HintStoreUsingWicketSession) hintStore - : null; - } - } diff --git a/viewers/wicket/pom.xml b/viewers/wicket/pom.xml index 1d12d0295e..00228165fd 100644 --- a/viewers/wicket/pom.xml +++ b/viewers/wicket/pom.xml @@ -7,9 +7,9 @@ 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 @@ -35,6 +35,7 @@ <packaging>pom</packaging> <modules> + <module>applib</module> <module>model</module> <module>viewer</module> <module>ui</module> diff --git a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisModuleViewerWicketViewer.java b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisModuleViewerWicketViewer.java index a3dacf59a8..bc8f7d2124 100644 --- a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisModuleViewerWicketViewer.java +++ b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisModuleViewerWicketViewer.java @@ -22,7 +22,6 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.apache.isis.viewer.wicket.ui.IsisModuleViewerWicketUi; -import org.apache.isis.viewer.wicket.viewer.mixins.Object_clearHints; import org.apache.isis.viewer.wicket.viewer.registries.components.ComponentFactoryRegistrarDefault; import org.apache.isis.viewer.wicket.viewer.registries.components.ComponentFactoryRegistryDefault; import org.apache.isis.viewer.wicket.viewer.registries.pages.PageClassListDefault; @@ -72,9 +71,6 @@ import org.apache.isis.viewer.wicket.viewer.wicketapp.config.WicketViewerCssBund WebModuleWicket.class, WicketViewerSettingsDefault.class, - // @Mixin's - Object_clearHints.class, - }) public class IsisModuleViewerWicketViewer {
