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 2023/01/26 09:48:17 UTC
[isis] branch master updated: ISIS-3328: create a help system where multiple pages can be added
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 dc09821e3c ISIS-3328: create a help system where multiple pages can be added
dc09821e3c is described below
commit dc09821e3ca79c6324b9d8bd70532d3da8a7f1f0
Author: Andi Huber <ah...@apache.org>
AuthorDate: Thu Jan 26 10:48:10 2023 +0100
ISIS-3328: create a help system where multiple pages can be added
- reuses the previous DocumentationService as WelcomeHelpPage
---
.../causeway/applib/graph/tree/TreePath.java | 51 ++++-
.../applib/graph/tree/TreePath_Default.java | 44 +++-
.../causeway/applib/graph/tree/TreePathTest.java | 33 ++-
.../extensions/docgen/CausewayModuleExtDocgen.java | 28 ++-
.../extensions/docgen/applib/HelpNode.java | 245 +++++++++++++++++++++
.../HelpPage.java} | 18 +-
.../extensions/docgen/help/DefaultHelpVm.java | 63 ------
.../docgen/help/DefaultHelpVm.layout.xml | 37 ----
.../extensions/docgen/helptree/HelpNodeVm-PAGE.svg | 44 ++++
.../docgen/helptree/HelpNodeVm-TOPIC.svg | 44 ++++
.../extensions/docgen/helptree/HelpNodeVm.java | 127 +++++++++++
.../docgen/helptree/HelpNodeVm.layout.xml | 39 ++++
.../HelpTreeAdapter.java} | 36 +--
.../extensions/docgen/menu/DocumentationMenu.java | 16 +-
.../welcome/WelcomeHelpPage.java} | 43 ++--
15 files changed, 703 insertions(+), 165 deletions(-)
diff --git a/api/applib/src/main/java/org/apache/causeway/applib/graph/tree/TreePath.java b/api/applib/src/main/java/org/apache/causeway/applib/graph/tree/TreePath.java
index 958ea40833..e3b660a859 100644
--- a/api/applib/src/main/java/org/apache/causeway/applib/graph/tree/TreePath.java
+++ b/api/applib/src/main/java/org/apache/causeway/applib/graph/tree/TreePath.java
@@ -19,9 +19,19 @@
package org.apache.causeway.applib.graph.tree;
import java.io.Serializable;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
import org.springframework.lang.Nullable;
+import org.apache.causeway.commons.functional.IndexedConsumer;
+import org.apache.causeway.commons.internal.assertions._Assert;
+import org.apache.causeway.commons.internal.base._Strings;
+import org.apache.causeway.commons.internal.exceptions._Exceptions;
+import org.apache.causeway.commons.internal.primitives._Ints;
+
/**
* Provides an unambiguous way to address nodes by position within a tree-structure. Examples:
* <ul>
@@ -40,13 +50,19 @@ public interface TreePath extends Serializable {
public TreePath append(int indexWithinSiblings);
/**
- *
- * @return a new TreePath instance that represents the parent path of this
+ * Returns a TreePath instance that represents the parent path of this TreePath,
+ * if this is not the root.
*/
public @Nullable TreePath getParentIfAny();
public boolean isRoot();
+ public IntStream streamPathElements();
+
+ public String stringify(String delimiter);
+
+ public Stream<TreePath> streamUpTheHierarchyStartingAtSelf();
+
// -- CONSTRUCTION
public static TreePath of(final int ... canonicalPath) {
@@ -57,4 +73,35 @@ public interface TreePath extends Serializable {
return of(0);
}
+ /**
+ * Parses stringified tree path of format {@code <delimiter>0<delimiter>3<delimiter>1} ...,
+ * as returned by {@link TreePath#stringify(String)}.
+ * <p>
+ * For null or empty input the root is returned.
+ * @throws IllegalArgumentException if parsing fails
+ */
+ public static TreePath parse(final @Nullable String treePathStringified, final String delimiter) {
+ if(_Strings.isNullOrEmpty(treePathStringified)) {
+ return root();
+ }
+ _Assert.assertTrue(_Strings.isNotEmpty(delimiter), ()->"non-empty delimiter required");
+
+ // parse the input String into a list of integers
+ final List<Integer> pathElementsAsList =
+ _Strings.splitThenStream(treePathStringified, delimiter)
+ .filter(_Strings::isNotEmpty)
+ .map(pathElement->
+ _Ints.parseInt(pathElement, 10)
+ .orElseThrow(()->
+ _Exceptions.illegalArgument("illformed treePath '%s' while parsing element '%s' using delimiter '%s'",
+ treePathStringified, pathElement, delimiter)))
+ .collect(Collectors.toList());
+
+ // convert the list of integers into an array of int
+ final int[] canonicalPath = new int[pathElementsAsList.size()];
+ pathElementsAsList.forEach(IndexedConsumer.zeroBased((index, value)->canonicalPath[index] = value));
+
+ return of(canonicalPath);
+ }
+
}
diff --git a/api/applib/src/main/java/org/apache/causeway/applib/graph/tree/TreePath_Default.java b/api/applib/src/main/java/org/apache/causeway/applib/graph/tree/TreePath_Default.java
index b6549f38a5..e5b2993ea1 100644
--- a/api/applib/src/main/java/org/apache/causeway/applib/graph/tree/TreePath_Default.java
+++ b/api/applib/src/main/java/org/apache/causeway/applib/graph/tree/TreePath_Default.java
@@ -22,6 +22,14 @@ import java.util.Arrays;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+import org.apache.causeway.commons.internal.assertions._Assert;
+import org.apache.causeway.commons.internal.base._Refs;
+import org.apache.causeway.commons.internal.base._Strings;
+
+import lombok.NonNull;
+import lombok.val;
/**
* Package private mixin for TreePath.
@@ -32,7 +40,7 @@ class TreePath_Default implements TreePath {
private final int[] canonicalPath;
private final int hashCode;
- TreePath_Default(int[] canonicalPath) {
+ TreePath_Default(final int[] canonicalPath) {
Objects.requireNonNull(canonicalPath, "canonicalPath is required");
if(canonicalPath.length<1) {
throw new IllegalArgumentException("canonicalPath must not be empty");
@@ -42,7 +50,7 @@ class TreePath_Default implements TreePath {
}
@Override
- public TreePath append(int indexWithinSiblings) {
+ public TreePath append(final int indexWithinSiblings) {
final int[] newCanonicalPath = new int[canonicalPath.length+1];
System.arraycopy(canonicalPath, 0, newCanonicalPath, 0, canonicalPath.length);
newCanonicalPath[canonicalPath.length] = indexWithinSiblings;
@@ -64,10 +72,36 @@ class TreePath_Default implements TreePath {
return canonicalPath.length==1;
}
+ @Override
+ public String stringify(@NonNull final String delimiter) {
+ _Assert.assertTrue(_Strings.isNotEmpty(delimiter), ()->"non-empty delimiter required");
+ return delimiter + streamPathElements()
+ .mapToObj(i->""+i)
+ .collect(Collectors.joining(delimiter));
+ }
+
+ @Override
+ public IntStream streamPathElements() {
+ return IntStream.of(canonicalPath);
+ }
+
+ @Override
+ public Stream<TreePath> streamUpTheHierarchyStartingAtSelf() {
+ val hasMore = _Refs.booleanRef(true);
+ return Stream.iterate((TreePath)this, __->hasMore.isTrue(), TreePath::getParentIfAny)
+ .filter(x->{
+ if(x.isRoot()) {
+ hasMore.setValue(false); // stop the stream only after we have included the root
+ }
+ return true;
+ });
+
+ }
+
// -- OBJECT CONTRACTS
@Override
- public boolean equals(Object obj) {
+ public boolean equals(final Object obj) {
if(obj instanceof TreePath_Default) {
final TreePath_Default other = (TreePath_Default) obj;
return Arrays.equals(canonicalPath, other.canonicalPath);
@@ -82,9 +116,7 @@ class TreePath_Default implements TreePath {
@Override
public String toString() {
- return "/" + IntStream.of(canonicalPath)
- .mapToObj(i->""+i)
- .collect(Collectors.joining("/"));
+ return stringify("/");
}
}
diff --git a/api/applib/src/test/java/org/apache/causeway/applib/graph/tree/TreePathTest.java b/api/applib/src/test/java/org/apache/causeway/applib/graph/tree/TreePathTest.java
index ee348a9379..8669e5501e 100644
--- a/api/applib/src/test/java/org/apache/causeway/applib/graph/tree/TreePathTest.java
+++ b/api/applib/src/test/java/org/apache/causeway/applib/graph/tree/TreePathTest.java
@@ -18,23 +18,27 @@
*/
package org.apache.causeway.applib.graph.tree;
+import java.util.List;
+
import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import org.apache.causeway.commons.collections.Can;
+
class TreePathTest {
@Test
- public void rootConstructor() {
+ void rootConstructor() {
final TreePath treePath = TreePath.root();
assertThat(treePath.isRoot(), Matchers.is(true));
assertThat(treePath.toString(), Matchers.is("/0"));
}
@Test
- public void samePathsShouldBeEqual() {
+ void samePathsShouldBeEqual() {
final TreePath treePath1 = TreePath.of(0, 1, 2, 3);
final TreePath treePath2 = TreePath.of(0, 1, 2, 3);
assertEquals(treePath1, treePath2);
@@ -45,4 +49,29 @@ class TreePathTest {
assertThat(treePath1.toString(), Matchers.is("/0/1/2/3"));
}
+ @Test
+ void hierarchyStreamingOfRoot() {
+ assertEquals(
+ Can.ofCollection(List.of("/0")),
+ TreePath.root()
+ .streamUpTheHierarchyStartingAtSelf()
+ .map(TreePath::toString)
+ .collect(Can.toCan()));
+ }
+
+ @Test
+ void hierarchyStreamingOfNonRoot() {
+ assertEquals(
+ Can.ofCollection(
+ List.of(
+ "/0/1/2/3",
+ "/0/1/2",
+ "/0/1",
+ "/0")),
+ TreePath.of(0, 1, 2, 3)
+ .streamUpTheHierarchyStartingAtSelf()
+ .map(TreePath::toString)
+ .collect(Can.toCan()));
+ }
+
}
diff --git a/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/CausewayModuleExtDocgen.java b/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/CausewayModuleExtDocgen.java
index e3fb969bce..9228bb1aed 100644
--- a/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/CausewayModuleExtDocgen.java
+++ b/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/CausewayModuleExtDocgen.java
@@ -18,11 +18,17 @@
*/
package org.apache.causeway.extensions.docgen;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
-import org.apache.causeway.extensions.docgen.help.DocumentationServiceDefault;
+import org.apache.causeway.extensions.docgen.applib.HelpNode.HelpTopic;
import org.apache.causeway.extensions.docgen.menu.DocumentationMenu;
+import org.apache.causeway.extensions.docgen.topics.welcome.WelcomeHelpPage;
+
+import lombok.val;
/**
* Adds the {@link DocumentationMenu} with its auto-configured menu entries.
@@ -30,11 +36,29 @@ import org.apache.causeway.extensions.docgen.menu.DocumentationMenu;
*/
@Configuration
@Import({
+ // menu providers
DocumentationMenu.class,
- DocumentationServiceDefault.class,
+
+ // help pages, as required by the default rootHelpTopic below (in case when to be managed by Spring)
+ WelcomeHelpPage.class
+
})
public class CausewayModuleExtDocgen {
public static final String NAMESPACE = "causeway.ext.docgen";
+ @Bean(NAMESPACE + "RootHelpTopic")
+ @ConditionalOnMissingBean(HelpTopic.class)
+ @Qualifier("Default")
+ public HelpTopic rootHelpTopic(final WelcomeHelpPage welcomeHelpPage) {
+ val root = HelpTopic.root("Topics");
+
+ root.addPage(welcomeHelpPage);
+
+// root.subTopic("Legacy")
+// .addPage(legacyHelpPage);
+
+ return root;
+ }
+
}
diff --git a/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/applib/HelpNode.java b/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/applib/HelpNode.java
new file mode 100644
index 0000000000..684926224a
--- /dev/null
+++ b/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/applib/HelpNode.java
@@ -0,0 +1,245 @@
+/*
+ * 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.causeway.extensions.docgen.applib;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.Stack;
+import java.util.stream.Stream;
+
+import org.springframework.lang.Nullable;
+
+import org.apache.causeway.applib.graph.tree.TreePath;
+import org.apache.causeway.valuetypes.asciidoc.applib.value.AsciiDoc;
+
+import lombok.Getter;
+import lombok.NonNull;
+import lombok.RequiredArgsConstructor;
+import lombok.val;
+
+/**
+ * Represents a node in the tree made of topics and {@link HelpPage}s.
+ *
+ * @since 2.x {@index}
+ */
+public interface HelpNode {
+
+ public enum HelpNodeType {
+ TOPIC,
+ PAGE;
+ }
+
+ TreePath getPath();
+ String getTitle();
+ HelpNodeType getHelpNodeType();
+ AsciiDoc getContent();
+
+ // -- PARENT CHILD RELATIONS
+
+ Optional<HelpTopic> getParent();
+ int childCount();
+ Stream<HelpNode> streamChildNodes();
+
+ Optional<HelpNode> getChildNode(int index);
+
+ // -- IMPLEMENTATIONS
+
+ /**
+ * Topic node of the tree, which may contain sub-{@link HelpTopic}s or {@link HelpPageNode}s.
+ */
+ @RequiredArgsConstructor
+ public static final class HelpTopic
+ implements HelpNode {
+
+ public static HelpTopic root(final String topic) {
+ return parented(null, topic);
+ }
+
+ public static HelpTopic parented(final @Nullable HelpTopic parentTopic, final String topic) {
+ return new HelpTopic(parentTopic, nextChildPathOf(parentTopic), new ArrayList<>(), topic);
+ }
+
+ private final @Nullable HelpTopic parentTopic;
+
+ @Getter(onMethod_={@Override})
+ private final @NonNull TreePath path;
+
+ @Getter
+ private final List<HelpNode> childNodes;
+
+ @Getter(onMethod_={@Override})
+ private final String title;
+
+ public HelpTopic subTopic(final String topic) {
+ val childTopic = HelpTopic.parented(this, topic);
+ childNodes.add(childTopic);
+ return childTopic;
+ }
+
+ @Override
+ public HelpNodeType getHelpNodeType() {
+ return HelpNodeType.TOPIC;
+ }
+
+ @Override
+ public AsciiDoc getContent() {
+ return AsciiDoc.valueOf("todo: summarize children"); // TODO
+ }
+
+ public <T extends HelpPage> HelpTopic addPage(final T helpPage) {
+ childNodes.add(new HelpPageNode(this, nextChildPathOf(this), helpPage));
+ return this;
+ }
+
+ @Override
+ public Optional<HelpTopic> getParent() {
+ return Optional.ofNullable(parentTopic);
+ }
+
+ @Override
+ public int childCount() {
+ return childNodes.size();
+ }
+
+ @Override
+ public Stream<HelpNode> streamChildNodes() {
+ return childNodes.stream();
+ }
+
+ /**
+ * Resolves given {@link TreePath} to its corresponding {@link HelpNode} if possible.
+ */
+ public Optional<HelpNode> lookup(final TreePath treePath) {
+ val root = rootTopic();
+ if(treePath.isRoot()) {
+ return Optional.of(root);
+ }
+
+ val stack = new Stack<HelpNode>();
+ stack.push(root);
+
+ treePath.streamPathElements()
+ .skip(1) // skip first path element which is always '0' and corresponds to the root, which we already handled above
+ .forEach(pathElement->{
+ if(stack.isEmpty()) return; // an empty stack corresponds to a not found state
+
+ val currentNode = stack.peek();
+ val child = currentNode.getChildNode(pathElement).orElse(null);
+
+ if(child!=null) {
+ stack.push(child);
+ } else {
+ stack.clear(); // not found
+ }
+ });
+
+ return stack.isEmpty()
+ ? Optional.empty()
+ : Optional.of(stack.peek());
+ }
+
+ @Override
+ public String toString() {
+ return String.format("HelpTopic[%s, childCount=%s]", getTitle(), childCount());
+ }
+
+ // -- HELPER
+
+ private HelpTopic rootTopic() {
+ var node = this;
+ while(node.getParent().isPresent()) {
+ node = node.getParent().get();
+ }
+ return node;
+ }
+
+ private static @NonNull TreePath nextChildPathOf(final @Nullable HelpTopic parentTopic) {
+ if(parentTopic==null) {
+ return TreePath.root();
+ }
+ return parentTopic.getPath().append(parentTopic.childCount());
+ }
+
+ @Override
+ public Optional<HelpNode> getChildNode(final int index) {
+ return index<childCount()
+ ? Optional.of(getChildNodes().get(index))
+ : Optional.empty();
+ }
+ }
+
+ /**
+ * Leaf node of the tree, referencing a {@link HelpPage}.
+ */
+ @RequiredArgsConstructor
+ public static final class HelpPageNode
+ implements HelpNode {
+
+ private final @NonNull HelpTopic parentTopic;
+
+ @Getter(onMethod_={@Override})
+ private final @NonNull TreePath path;
+
+ @Getter
+ private final HelpPage helpPage;
+
+ @Override
+ public HelpNodeType getHelpNodeType() {
+ return HelpNodeType.PAGE;
+ }
+
+ @Override
+ public String getTitle() {
+ return helpPage.getTitle();
+ }
+
+ @Override
+ public AsciiDoc getContent() {
+ return helpPage.getContent();
+ }
+
+ @Override
+ public Optional<HelpTopic> getParent() {
+ return Optional.of(parentTopic);
+ }
+
+ @Override
+ public int childCount() {
+ return 0;
+ }
+
+ @Override
+ public Stream<HelpNode> streamChildNodes() {
+ return Stream.empty();
+ }
+
+ @Override
+ public Optional<HelpNode> getChildNode(final int index) {
+ return Optional.empty();
+ }
+
+ @Override
+ public String toString() {
+ return String.format("HelpPageNode[%s]", getTitle());
+ }
+
+ }
+
+}
diff --git a/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/help/DocumentationService.java b/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/applib/HelpPage.java
similarity index 64%
rename from extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/help/DocumentationService.java
rename to extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/applib/HelpPage.java
index 35e105d291..b74945f9d1 100644
--- a/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/help/DocumentationService.java
+++ b/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/applib/HelpPage.java
@@ -16,21 +16,13 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.causeway.extensions.docgen.help;
+package org.apache.causeway.extensions.docgen.applib;
-import org.apache.causeway.extensions.docgen.menu.DocumentationMenu;
+import org.apache.causeway.valuetypes.asciidoc.applib.value.AsciiDoc;
-/**
- * Provides the content for the {@link DocumentationMenu} entries.
- * <p>
- * Currently there is only one, namely (<i>help</i>).
- *
- * @see DocumentationMenu
- * @since 2.x {@index}
- */
-public interface DocumentationService {
+public interface HelpPage {
- /** Returns a view-model or value that represents the application's primary help page. */
- Object getHelp();
+ String getTitle();
+ AsciiDoc getContent();
}
diff --git a/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/help/DefaultHelpVm.java b/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/help/DefaultHelpVm.java
deleted file mode 100644
index 7294b520a0..0000000000
--- a/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/help/DefaultHelpVm.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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.causeway.extensions.docgen.help;
-
-import javax.inject.Inject;
-import javax.inject.Named;
-
-import org.apache.causeway.applib.ViewModel;
-import org.apache.causeway.applib.annotation.DomainObject;
-import org.apache.causeway.applib.annotation.DomainObjectLayout;
-import org.apache.causeway.applib.annotation.LabelPosition;
-import org.apache.causeway.applib.annotation.Nature;
-import org.apache.causeway.applib.annotation.ObjectSupport;
-import org.apache.causeway.applib.annotation.Property;
-import org.apache.causeway.applib.annotation.PropertyLayout;
-import org.apache.causeway.applib.value.Markup;
-import org.apache.causeway.extensions.docgen.CausewayModuleExtDocgen;
-
-import lombok.Getter;
-import lombok.RequiredArgsConstructor;
-
-@Named(CausewayModuleExtDocgen.NAMESPACE + ".DefaultHelpVm")
-@DomainObject(nature = Nature.VIEW_MODEL)
-@DomainObjectLayout(
- named = "Application Help",
- cssClassFa = "fa-regular fa-circle-question")
-@RequiredArgsConstructor(onConstructor_ = {@Inject})
-public class DefaultHelpVm implements ViewModel {
-
- private final DocumentationServiceDefault documentationServiceDefault;
- private final String title;
-
- @ObjectSupport
- public String title() {
- return title;
- }
-
- @Property
- @PropertyLayout(labelPosition = LabelPosition.NONE)
- @Getter(lazy = true)
- private final Markup helpContent = new Markup(documentationServiceDefault.getDocumentationAsHtml());
-
- @Override
- public String viewModelMemento() {
- return title;
- }
-}
diff --git a/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/help/DefaultHelpVm.layout.xml b/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/help/DefaultHelpVm.layout.xml
deleted file mode 100644
index 1c25442981..0000000000
--- a/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/help/DefaultHelpVm.layout.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?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. -->
-<bs:grid
- xmlns:cpt="http://causeway.apache.org/applib/layout/component"
- xmlns:bs="http://causeway.apache.org/applib/layout/grid/bootstrap3"
- xmlns:lnk="http://causeway.apache.org/applib/layout/links"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://causeway.apache.org/applib/layout/component http://causeway.apache.org/applib/layout/component/component.xsd http://causeway.apache.org/applib/layout/links http://causeway.apache.org/applib/layout/links/links.xsd http://causeway.apache.org/applib/layout/grid/bootstrap3 http://causeway.apache.org/applib/layout/grid/bootstrap3/bootstrap3.xsd">
- <bs:row>
- <bs:col span="12" unreferencedActions="true">
- <cpt:domainObject />
- </bs:col>
- </bs:row>
- <bs:row>
- <bs:col span="12">
- <bs:row>
- <bs:col span="12">
- <cpt:fieldSet name=""
- unreferencedProperties="true"
- id="details" />
- </bs:col>
- </bs:row>
- </bs:col>
- <bs:col span="8">
- <bs:tabGroup unreferencedCollections="true" />
- </bs:col>
- </bs:row>
-</bs:grid>
\ No newline at end of file
diff --git a/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/helptree/HelpNodeVm-PAGE.svg b/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/helptree/HelpNodeVm-PAGE.svg
new file mode 100644
index 0000000000..b788c7ff81
--- /dev/null
+++ b/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/helptree/HelpNodeVm-PAGE.svg
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
+ viewBox="0 0 58 58" style="enable-background:new 0 0 58 58;" xml:space="preserve">
+<polygon style="fill:#EDEADA;" points="51.5,14 37.5,0 6.5,0 6.5,58 51.5,58 "/>
+<g>
+ <path style="fill:#CEC9AE;" d="M16.5,23h25c0.552,0,1-0.447,1-1s-0.448-1-1-1h-25c-0.552,0-1,0.447-1,1S15.948,23,16.5,23z"/>
+ <path style="fill:#CEC9AE;" d="M16.5,15h10c0.552,0,1-0.447,1-1s-0.448-1-1-1h-10c-0.552,0-1,0.447-1,1S15.948,15,16.5,15z"/>
+ <path style="fill:#CEC9AE;" d="M41.5,29h-25c-0.552,0-1,0.447-1,1s0.448,1,1,1h25c0.552,0,1-0.447,1-1S42.052,29,41.5,29z"/>
+ <path style="fill:#CEC9AE;" d="M41.5,37h-25c-0.552,0-1,0.447-1,1s0.448,1,1,1h25c0.552,0,1-0.447,1-1S42.052,37,41.5,37z"/>
+ <path style="fill:#CEC9AE;" d="M41.5,45h-25c-0.552,0-1,0.447-1,1s0.448,1,1,1h25c0.552,0,1-0.447,1-1S42.052,45,41.5,45z"/>
+</g>
+<polygon style="fill:#CEC9AE;" points="37.5,0 37.5,14 51.5,14 "/>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>
diff --git a/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/helptree/HelpNodeVm-TOPIC.svg b/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/helptree/HelpNodeVm-TOPIC.svg
new file mode 100644
index 0000000000..5f1cdc96fd
--- /dev/null
+++ b/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/helptree/HelpNodeVm-TOPIC.svg
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
+ viewBox="0 0 58 58" style="enable-background:new 0 0 58 58;" xml:space="preserve">
+<path style="fill:#EFCE4A;" d="M55.981,54.5H2.019C0.904,54.5,0,53.596,0,52.481V20.5h58v31.981C58,53.596,57.096,54.5,55.981,54.5z
+ "/>
+<path style="fill:#EBBA16;" d="M26.019,11.5V5.519C26.019,4.404,25.115,3.5,24,3.5H2.019C0.904,3.5,0,4.404,0,5.519V10.5v10h58
+ v-6.981c0-1.115-0.904-2.019-2.019-2.019H26.019z"/>
+<g>
+ <path style="fill:#EB7937;" d="M18,32.5h14c0.552,0,1-0.447,1-1s-0.448-1-1-1H18c-0.552,0-1,0.447-1,1S17.448,32.5,18,32.5z"/>
+ <path style="fill:#EB7937;" d="M18,38.5h22c0.552,0,1-0.447,1-1s-0.448-1-1-1H18c-0.552,0-1,0.447-1,1S17.448,38.5,18,38.5z"/>
+ <path style="fill:#EB7937;" d="M40,42.5H18c-0.552,0-1,0.447-1,1s0.448,1,1,1h22c0.552,0,1-0.447,1-1S40.552,42.5,40,42.5z"/>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>
diff --git a/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/helptree/HelpNodeVm.java b/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/helptree/HelpNodeVm.java
new file mode 100644
index 0000000000..0e1f428900
--- /dev/null
+++ b/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/helptree/HelpNodeVm.java
@@ -0,0 +1,127 @@
+/*
+ * 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.causeway.extensions.docgen.helptree;
+
+import java.util.Optional;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.apache.causeway.applib.ViewModel;
+import org.apache.causeway.applib.annotation.DomainObject;
+import org.apache.causeway.applib.annotation.DomainObjectLayout;
+import org.apache.causeway.applib.annotation.LabelPosition;
+import org.apache.causeway.applib.annotation.Nature;
+import org.apache.causeway.applib.annotation.Navigable;
+import org.apache.causeway.applib.annotation.ObjectSupport;
+import org.apache.causeway.applib.annotation.Programmatic;
+import org.apache.causeway.applib.annotation.Property;
+import org.apache.causeway.applib.annotation.PropertyLayout;
+import org.apache.causeway.applib.annotation.Where;
+import org.apache.causeway.applib.graph.tree.TreeNode;
+import org.apache.causeway.applib.graph.tree.TreePath;
+import org.apache.causeway.extensions.docgen.CausewayModuleExtDocgen;
+import org.apache.causeway.extensions.docgen.applib.HelpNode;
+import org.apache.causeway.extensions.docgen.applib.HelpNode.HelpTopic;
+import org.apache.causeway.valuetypes.asciidoc.applib.value.AsciiDoc;
+
+import lombok.Getter;
+import lombok.val;
+import lombok.extern.log4j.Log4j2;
+
+@Named(CausewayModuleExtDocgen.NAMESPACE + ".HelpNodeVm")
+@DomainObject(
+ nature=Nature.VIEW_MODEL)
+@DomainObjectLayout(
+ named = "Application Help")
+@Log4j2
+public class HelpNodeVm implements ViewModel {
+
+ public final static String PATH_DELIMITER = "|"; // required to be URL-safe
+
+ public static HelpNodeVm forRootTopic(final HelpTopic rootTopic) {
+ return new HelpNodeVm(rootTopic, rootTopic);
+ }
+
+ @Getter @Programmatic
+ private final HelpTopic rootTopic;
+
+ @Getter @Programmatic
+ private final HelpNode helpNode;
+
+ @Inject
+ public HelpNodeVm(final HelpTopic rootTopic, final String rootPathMemento) {
+ this(rootTopic, TreePath.parse(rootPathMemento, PATH_DELIMITER));
+ }
+
+ HelpNodeVm(final HelpTopic rootTopic, final TreePath treePath) {
+ this(rootTopic, rootTopic
+ .lookup(treePath)
+ .orElseGet(()->{
+ log.warn("could not resolve help node {}", treePath);
+ return rootTopic;
+ }));
+ }
+
+ HelpNodeVm(final HelpTopic rootTopic, final HelpNode helpNode) {
+ this.rootTopic = rootTopic;
+ this.helpNode = helpNode;
+ }
+
+ @ObjectSupport public String title() {
+ return helpNode.getTitle();
+ }
+
+ @ObjectSupport public String iconName() {
+ val type = helpNode.getHelpNodeType();
+ return type!=null ? type.name() : "";
+ }
+
+ @Property
+ @PropertyLayout(labelPosition = LabelPosition.NONE, fieldSetId = "tree", sequence = "1")
+ public TreeNode<HelpNodeVm> getTree() {
+ final TreeNode<HelpNodeVm> tree = TreeNode.lazy(HelpNodeVm.forRootTopic(rootTopic), HelpTreeAdapter.class);
+
+ // expand the current node
+ helpNode.getPath().streamUpTheHierarchyStartingAtSelf()
+ .forEach(tree::expand);
+
+ return tree;
+ }
+
+ @Property
+ @PropertyLayout(navigable=Navigable.PARENT, hidden=Where.EVERYWHERE, fieldSetId = "detail", sequence = "1")
+ public HelpNodeVm getParent() {
+ return Optional.ofNullable(helpNode.getPath().getParentIfAny())
+ .map(parentPath->new HelpNodeVm(rootTopic, parentPath.toString()))
+ .orElse(null);
+ }
+
+ @Property
+ @PropertyLayout(labelPosition = LabelPosition.NONE, fieldSetId = "detail", sequence = "2")
+ @Getter(lazy = true)
+ private final AsciiDoc helpContent = helpNode.getContent();
+
+
+ @Override
+ public String viewModelMemento() {
+ return helpNode.getPath().stringify(PATH_DELIMITER);
+ }
+
+}
diff --git a/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/helptree/HelpNodeVm.layout.xml b/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/helptree/HelpNodeVm.layout.xml
new file mode 100644
index 0000000000..7253e3f50a
--- /dev/null
+++ b/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/helptree/HelpNodeVm.layout.xml
@@ -0,0 +1,39 @@
+<?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://causeway.apache.org/applib/layout/component http://causeway.apache.org/applib/layout/component/component.xsd http://causeway.apache.org/applib/layout/grid/bootstrap3 http://causeway.apache.org/applib/layout/grid/bootstrap3/bootstrap3.xsd"
+ xmlns:bs3="http://causeway.apache.org/applib/layout/grid/bootstrap3"
+ xmlns:cpt="http://causeway.apache.org/applib/layout/component"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+
+ <bs3:row>
+ <bs3:col span="10" unreferencedActions="true">
+ <cpt:domainObject />
+ </bs3:col>
+ <bs3:col span="2">
+ <cpt:fieldSet name="" id="sources" />
+ </bs3:col>
+ </bs3:row>
+
+ <bs3:row>
+ <bs3:col span="3">
+ <cpt:fieldSet name="Index" id="tree"/>
+ </bs3:col>
+ <bs3:col span="9">
+ <cpt:fieldSet name="" id="detail"/>
+ <cpt:fieldSet name="Other" id="other" unreferencedProperties="true"/>
+ </bs3:col>
+ </bs3:row>
+ <bs3:row>
+ <bs3:col span="12" unreferencedCollections="true"/>
+ </bs3:row>
+</bs3:grid>
diff --git a/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/CausewayModuleExtDocgen.java b/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/helptree/HelpTreeAdapter.java
similarity index 53%
copy from extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/CausewayModuleExtDocgen.java
copy to extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/helptree/HelpTreeAdapter.java
index e3fb969bce..733035ef96 100644
--- a/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/CausewayModuleExtDocgen.java
+++ b/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/helptree/HelpTreeAdapter.java
@@ -16,25 +16,29 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.causeway.extensions.docgen;
+package org.apache.causeway.extensions.docgen.helptree;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.Import;
+import java.util.Optional;
+import java.util.stream.Stream;
-import org.apache.causeway.extensions.docgen.help.DocumentationServiceDefault;
-import org.apache.causeway.extensions.docgen.menu.DocumentationMenu;
+import org.apache.causeway.applib.graph.tree.TreeAdapter;
-/**
- * Adds the {@link DocumentationMenu} with its auto-configured menu entries.
- * @since 2.0 {@index}
- */
-@Configuration
-@Import({
- DocumentationMenu.class,
- DocumentationServiceDefault.class,
-})
-public class CausewayModuleExtDocgen {
+public class HelpTreeAdapter implements TreeAdapter<HelpNodeVm> {
+
+ @Override
+ public Optional<HelpNodeVm> parentOf(final HelpNodeVm value) {
+ return Optional.ofNullable(value.getParent());
+ }
+
+ @Override
+ public int childCountOf(final HelpNodeVm value) {
+ return value.getHelpNode().childCount();
+ }
- public static final String NAMESPACE = "causeway.ext.docgen";
+ @Override
+ public Stream<HelpNodeVm> childrenOf(final HelpNodeVm value) {
+ return value.getHelpNode().streamChildNodes()
+ .map(childNode->new HelpNodeVm(value.getRootTopic(), childNode));
+ }
}
diff --git a/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/menu/DocumentationMenu.java b/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/menu/DocumentationMenu.java
index 83b92a5719..58517941b7 100644
--- a/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/menu/DocumentationMenu.java
+++ b/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/menu/DocumentationMenu.java
@@ -31,16 +31,17 @@ import org.apache.causeway.applib.annotation.NatureOfService;
import org.apache.causeway.applib.annotation.PriorityPrecedence;
import org.apache.causeway.applib.annotation.SemanticsOf;
import org.apache.causeway.extensions.docgen.CausewayModuleExtDocgen;
-import org.apache.causeway.extensions.docgen.help.DocumentationService;
+import org.apache.causeway.extensions.docgen.applib.HelpNode.HelpTopic;
+import org.apache.causeway.extensions.docgen.helptree.HelpNodeVm;
import lombok.RequiredArgsConstructor;
/**
- * Provides entries for a <i>Documentation</i> sub-menu section utilizing the {@link DocumentationService}.
+ * Provides entries for a <i>Documentation</i> sub-menu section.
* <p>
- * Currently there is only one, namely (<i>help</i>).
+ * Currently there is only one, namely (<i>help</i>), utilizing the {@link HelpTopic}.
*
- * @see DocumentationService
+ * @see HelpTopic
* @since 2.x {@index}
*/
@Named(CausewayModuleExtDocgen.NAMESPACE + ".DocumentationMenu")
@@ -54,8 +55,9 @@ public class DocumentationMenu {
public static abstract class ActionDomainEvent<T> extends CausewayModuleApplib.ActionDomainEvent<T> {}
- private final DocumentationService documentationService;
+ private final HelpTopic rootHelpTopic;
+ /** Returns a view-model that represents the application's primary help page. */
@Action(
domainEvent = help.ActionDomainEvent.class,
semantics = SemanticsOf.NON_IDEMPOTENT //disable client-side caching
@@ -68,8 +70,8 @@ public class DocumentationMenu {
public class ActionDomainEvent extends DocumentationMenu.ActionDomainEvent<help> {}
- @MemberSupport public Object act() {
- return documentationService.getHelp();
+ @MemberSupport public HelpNodeVm act() {
+ return HelpNodeVm.forRootTopic(rootHelpTopic);
}
}
diff --git a/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/help/DocumentationServiceDefault.java b/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/topics/welcome/WelcomeHelpPage.java
similarity index 93%
rename from extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/help/DocumentationServiceDefault.java
rename to extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/topics/welcome/WelcomeHelpPage.java
index 843366d171..b1d49e3e11 100644
--- a/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/help/DocumentationServiceDefault.java
+++ b/extensions/core/docgen/src/main/java/org/apache/causeway/extensions/docgen/topics/welcome/WelcomeHelpPage.java
@@ -16,22 +16,18 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.causeway.extensions.docgen.help;
+package org.apache.causeway.extensions.docgen.topics.welcome;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
-import javax.annotation.Priority;
import javax.inject.Inject;
import javax.inject.Named;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.stereotype.Service;
+import org.springframework.stereotype.Component;
-import org.apache.causeway.applib.ViewModel;
import org.apache.causeway.applib.annotation.DomainObject;
-import org.apache.causeway.applib.annotation.PriorityPrecedence;
import org.apache.causeway.applib.layout.component.ActionLayoutData;
import org.apache.causeway.applib.layout.component.CollectionLayoutData;
import org.apache.causeway.applib.layout.component.FieldSet;
@@ -54,29 +50,39 @@ import org.apache.causeway.core.metamodel.spec.ObjectSpecification;
import org.apache.causeway.core.metamodel.spec.feature.ObjectAction;
import org.apache.causeway.core.metamodel.specloader.SpecificationLoader;
import org.apache.causeway.extensions.docgen.CausewayModuleExtDocgen;
+import org.apache.causeway.extensions.docgen.applib.HelpPage;
+import org.apache.causeway.valuetypes.asciidoc.applib.value.AsciiDoc;
-import lombok.Getter;
import lombok.RequiredArgsConstructor;
-@Service
-@Named(CausewayModuleExtDocgen.NAMESPACE + ".DocumentationServiceDefault")
-@Priority(PriorityPrecedence.MIDPOINT)
-@Qualifier("Default")
+@Component
+@Named(CausewayModuleExtDocgen.NAMESPACE + ".WelcomeHelpPage")
@RequiredArgsConstructor(onConstructor_ = {@Inject})
-//@Log4j2
-public class DocumentationServiceDefault implements DocumentationService {
+public class WelcomeHelpPage implements HelpPage {
private final SpecificationLoader specificationLoader;
private final MenuBarsService menuBarsService;
private final HomePageResolverService homePageResolverService;
private final TranslationService translationService;
- @Getter(onMethod_={@Override}, lazy = true)
- private final ViewModel help = new DefaultHelpVm(this, "Application Help");
+ @Override
+ public String getTitle() {
+ return "Welcome";
+ }
+
+ @Override
+ public AsciiDoc getContent() {
+ // uses a HTML passthrough block (https://docs.asciidoctor.org/asciidoc/latest/pass/pass-block/)
+ return AsciiDoc.valueOf(
+ "== Welcome\n\n"
+ + "++++\n"
+ + getDocumentationAsHtml()
+ + "++++\n");
+ }
// -- HELPER
- String getDocumentationAsHtml() {
+ private String getDocumentationAsHtml() {
final StringBuilder html = new StringBuilder();
Object homePage = homePageResolverService.getHomePage();
if (homePage != null) {
@@ -236,7 +242,8 @@ public class DocumentationServiceDefault implements DocumentationService {
html.append(String.format("<li><b>%s</b>: %s.",
member.getCanonicalFriendlyName(),
describedAs));
- if (member.getElementType().getLogicalType().getCorrespondingClass().isAnnotationPresent(DomainObject.class)) {
+ if (member.getElementType().getLogicalType().getCorrespondingClass()
+ .isAnnotationPresent(DomainObject.class)) {
html.append(String.format(" <i> See: <a href='#%s'>%s</a></i>",
member.getElementType().getLogicalTypeName(),
member.getElementType().getSingularName()));
@@ -271,4 +278,6 @@ public class DocumentationServiceDefault implements DocumentationService {
.orElse(null);
}
+
}
+