This is an automated email from the ASF dual-hosted git repository.
ahuber pushed a commit to branch spring6
in repository https://gitbox.apache.org/repos/asf/causeway.git
The following commit(s) were added to refs/heads/spring6 by this push:
new d263047a0e CAUSEWAY-3407: populate nav bar
d263047a0e is described below
commit d263047a0ee1d72e591049e3b224d925ccf99923
Author: Andi Huber <[email protected]>
AuthorDate: Fri Apr 7 17:20:40 2023 +0200
CAUSEWAY-3407: populate nav bar
---
.../org/apache/causeway/commons/io/YamlUtils.java | 11 +-
.../thymeflux/test/ThymefluxViewerTests.java | 24 +---
.../resources/templates/nav/topNavSection.html | 58 ++++++++++
.../templates/prototyping/image-solid.svg | 1 +
.../viewer/src/main/resources/templates/root.html | 124 +++++++++++++--------
.../applib/services/header/HeaderUiModel.java | 5 -
6 files changed, 148 insertions(+), 75 deletions(-)
diff --git
a/commons/src/main/java/org/apache/causeway/commons/io/YamlUtils.java
b/commons/src/main/java/org/apache/causeway/commons/io/YamlUtils.java
index f29621ec1e..ef7ebe4db2 100644
--- a/commons/src/main/java/org/apache/causeway/commons/io/YamlUtils.java
+++ b/commons/src/main/java/org/apache/causeway/commons/io/YamlUtils.java
@@ -184,12 +184,11 @@ public class YamlUtils {
private Map<String, Property> postProcessMap(final Map<String,
Property> map) {
//debug
//System.err.printf("%s map: %s%n", type.getName(), map);
- map.replaceAll((k, v)->{
- if(Can.class.isAssignableFrom(v.getType())) {
- return MethodPropertyFromCanToList.wrap((MethodProperty)v);
- }
- return v;
- });
+ map.replaceAll((k, v)->
+ Can.class.isAssignableFrom(v.getType())
+ && v instanceof MethodProperty // no field support yet
+ ? MethodPropertyFromCanToList.wrap((MethodProperty)v)
+ : v);
return map;
}
diff --git
a/incubator/viewers/thymeflux/test/src/test/java/org/apache/causeway/viewer/thymeflux/test/ThymefluxViewerTests.java
b/incubator/viewers/thymeflux/test/src/test/java/org/apache/causeway/viewer/thymeflux/test/ThymefluxViewerTests.java
index 7d4e42f466..4faf069719 100644
---
a/incubator/viewers/thymeflux/test/src/test/java/org/apache/causeway/viewer/thymeflux/test/ThymefluxViewerTests.java
+++
b/incubator/viewers/thymeflux/test/src/test/java/org/apache/causeway/viewer/thymeflux/test/ThymefluxViewerTests.java
@@ -30,8 +30,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import org.apache.causeway.applib.annotation.DomainServiceLayout.MenuBar;
+import org.apache.causeway.commons.io.YamlUtils;
import org.apache.causeway.viewer.commons.applib.services.header.HeaderUiModel;
-import
org.apache.causeway.viewer.commons.applib.services.menu.model.NavbarSection;
import org.apache.causeway.viewer.thymeflux.model.root.ThymefluxRootController;
import
org.apache.causeway.viewer.thymeflux.viewer.CausewayModuleIncViewerThymefluxViewer;
@@ -62,25 +62,13 @@ class ThymefluxViewerTests {
var headerUiModel = (HeaderUiModel)model.getAttribute("headerUiModel");
assertNotNull(headerUiModel);
- var primary = (NavbarSection)headerUiModel.navbar().primary();
- var secondary = (NavbarSection)headerUiModel.navbar().secondary();
- var tertiary = (NavbarSection)headerUiModel.navbar().tertiary();
+ var navbar = headerUiModel.navbar();
- assertEquals(MenuBar.PRIMARY, primary.menuBarSelect());
- assertEquals(MenuBar.SECONDARY, secondary.menuBarSelect());
- assertEquals(MenuBar.TERTIARY, tertiary.menuBarSelect());
-
- System.err.printf("%s%n", headerUiModel.toYaml());
-
-
- primary.topLevelEntries().forEach(top->System.err.printf("prim: %s%n",
top.name()));
- secondary.topLevelEntries().forEach(top->System.err.printf("sec:
%s%n", top.name()));
- tertiary.topLevelEntries().forEach(top->System.err.printf("tert:
%s%n", top.name()));
-
- primary.topLevelEntries().forEach(top->System.err.printf("prim: %s%n",
top));
- secondary.topLevelEntries().forEach(top->System.err.printf("sec:
%s%n", top));
- tertiary.topLevelEntries().forEach(top->System.err.printf("tert:
%s%n", top));
+ assertEquals(MenuBar.PRIMARY, navbar.primary().menuBarSelect());
+ assertEquals(MenuBar.SECONDARY, navbar.secondary().menuBarSelect());
+ assertEquals(MenuBar.TERTIARY, navbar.tertiary().menuBarSelect());
+ System.err.printf("== navbar: %n%s====%n",
YamlUtils.toStringUtf8(navbar.primary()));
}
diff --git
a/incubator/viewers/thymeflux/viewer/src/main/resources/templates/nav/topNavSection.html
b/incubator/viewers/thymeflux/viewer/src/main/resources/templates/nav/topNavSection.html
new file mode 100644
index 0000000000..5885b82b0d
--- /dev/null
+++
b/incubator/viewers/thymeflux/viewer/src/main/resources/templates/nav/topNavSection.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<!--/* 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. */-->
+<html lang="en"
+ xmlns:th="http://www.thymeleaf.org"
+ xmlns:hx="http://www.w3.org/1999/xhtml">
+
+<!-- NAMED MENU DROPDOWN -->
+
+<th:block th:fragment="topNavSection(topNavSection)">
+
+<li th:each="topLevelEntry : ${topNavSection.topLevelEntries()}"
+ class="nav-item dropdown">
+ <a class="nav-link dropdown-toggle"
+ href="#" role="button"
data-bs-toggle="dropdown"><span>[[${topLevelEntry.name()}]]</span>
+ </a>
+ <ul class="dropdown-menu">
+
+ <!-- MENU ENTRIES -->
+ <th:block th:each="menuEntry : ${topLevelEntry.subEntries()}">
+
+ <th:block th:if="${menuEntry.asSpacer().isPresent()}"
+ th:with="menuSpacer =
${menuEntry.asSpacer().get()}">
+
+ <th:block th:if="${menuSpacer.isEmpty()}">
+ <li><hr class="dropdown-divider"></li>
+ </th:block>
+
+ <th:block th:unless="${menuSpacer.isEmpty()}">
+ <li class="list-section-label"><span
class="sectionLabel">[[${menuSpacer.label()}]]</span>
+ </li>
+ </th:block>
+
+ </th:block>
+ <li><a th:if="${menuEntry.asAction().isPresent()}"
+ th:with="menuAction =
${menuEntry.asAction().get()}"
+ class="dropdown-item" href="#">
[[${menuAction.name()}]] </a></li>
+
+ </th:block>
+
+ </ul>
+</li>
+
+</th:block>
\ No newline at end of file
diff --git
a/incubator/viewers/thymeflux/viewer/src/main/resources/templates/prototyping/image-solid.svg
b/incubator/viewers/thymeflux/viewer/src/main/resources/templates/prototyping/image-solid.svg
new file mode 100644
index 0000000000..1b5822d5c0
--- /dev/null
+++
b/incubator/viewers/thymeflux/viewer/src/main/resources/templates/prototyping/image-solid.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font
Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License -
https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons,
Inc. --><path d="M0 96C0 60.7 28.7 32 64 32H448c35.3 0 64 28.7 64 64V416c0
35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V96zM323.8
202.5c-4.5-6.6-11.9-10.5-19.8-10.5s-15.4 3.9-19.8 10.5l-87 127.6L170.7
297c-4.6-5.7-11.5-9-18.7-9s-14.2 3.3-18.7 9l-64 80c-5.8 7.2-6.9 17.1-2 [...]
\ No newline at end of file
diff --git
a/incubator/viewers/thymeflux/viewer/src/main/resources/templates/root.html
b/incubator/viewers/thymeflux/viewer/src/main/resources/templates/root.html
index 64f09c612f..974a4d2ab1 100644
--- a/incubator/viewers/thymeflux/viewer/src/main/resources/templates/root.html
+++ b/incubator/viewers/thymeflux/viewer/src/main/resources/templates/root.html
@@ -1,5 +1,5 @@
<!DOCTYPE html>
-<!-- Licensed to the Apache Software Foundation (ASF) under one
+<!--/* 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
@@ -14,55 +14,80 @@
"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. -->
+ under the License. */-->
+<html lang="en"
+ xmlns:th="http://www.thymeleaf.org"
+ xmlns:hx="http://www.w3.org/1999/xhtml">
+
<head>
<meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+ <!--/* PROTOTYPING -->
+ <link
href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65"
crossorigin="anonymous"/>
+ <link href="../static/css/causeway-thymeflux.css" rel="stylesheet" />
+ <script
src="https://cdn.jsdelivr.net/npm/@popperjs/[email protected]/dist/umd/popper.min.js"
integrity="sha384-oBqDVmMz9ATKxIep9tiCxS/Z9fNfEXiDAYTujMAeBAsjFuCZSmKbSSUnQlmh/jp3"
crossorigin="anonymous" defer></script>
+ <script
src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js"
integrity="sha384-cuYeSxntonz0PPNlHhBs68uyIAVpIIOZZ5JqeqvYYIcEL727kskC66kF92t6Xl2V"
crossorigin="anonymous" defer></script>
+ <!--*/-->
+
+ <!--/*/
+ <link rel="icon" type="image/x-icon" href="/images/favicon.ico">
<link th:rel="stylesheet"
th:href="@{/webjars/bootstrap/5.2.3/css/bootstrap.min.css}" />
- <link data-th-href="@{/css/causeway-thymeflux.css}" rel="stylesheet">
+ <link th:rel="stylesheet" th:href="@{/css/causeway-thymeflux.css}">
+ <script th:src="@{/webjars/popper.js/2.9.3/umd/popper.min.js}"
defer></script>
+ <script th:src="@{/webjars/bootstrap/5.2.3/js/bootstrap.bundle.min.js}"
defer></script>
+ <script th:src="@{/webjars/htmx.org/1.8.6/dist/htmx.min.js}"
defer></script>
+ /*/-->
+
</head>
+
+
<body>
-<div class="container">
+<nav class="navbar navbar-expand-md sticky-top bg-light">
+ <div class="container-fluid">
+
+ <!-- BRANDING -->
+
+ <a th:with="branding = ${headerUiModel.branding()}"
+ class="navbar-brand"
+ href="#">
+ <img class="navbar-brand-logo" alt="Brand"
+ src="prototyping/image-solid.svg" height="48px"/>
+ [[${branding.name.orElse("")}]]
+ </a>
+
+ <!-- NAVBAR COLLAPSE TOGGLER -->
+
+ <button class="navbar-toggler" type="button" data-bs-toggle="collapse"
data-bs-target="#navbarSupportedContent">
+ <span class="navbar-toggler-icon"></span>
+ </button>
+
+ <!-- NAVBAR -->
+
+ <div class="collapse navbar-collapse mr-auto" id="navbarSupportedContent">
+
+ <!-- PRIMARY SECTION -->
+
+ <ul th:insert="nav/topNavSection ::
topNavSection(${headerUiModel.navbar().primary()})"
+ class="navbar-nav me-auto mb-2 mb-lg-0">
+ </ul>
+
+ <!-- SECONDARY AND TERTIARY SECTION -->
+
+ <ul th:insert="nav/topNavSection ::
topNavSection(${headerUiModel.navbar().secondary()})"
+ class="navbar-nav">
+ </ul>
+ <ul th:insert="nav/topNavSection ::
topNavSection(${headerUiModel.navbar().tertiary()})"
+ class="navbar-nav">
+ </ul>
+
+ </div>
- <nav class="navbar navbar-expand-lg bg-light">
- <div class="container-fluid">
- <a class="navbar-brand" href="#">Navbar</a>
- <button class="navbar-toggler" type="button"
data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle
navigation">
- <span class="navbar-toggler-icon"></span>
- </button>
- <div class="collapse navbar-collapse" id="navbarSupportedContent">
- <ul class="navbar-nav me-auto mb-2 mb-lg-0">
- <li class="nav-item">
- <a class="nav-link active" aria-current="page"
href="#">Home</a>
- </li>
- <li class="nav-item">
- <a class="nav-link" href="#">Link</a>
- </li>
- <li class="nav-item dropdown">
- <a class="nav-link dropdown-toggle" href="#" role="button"
data-bs-toggle="dropdown" aria-expanded="false">
- Dropdown
- </a>
- <ul class="dropdown-menu">
- <li><a class="dropdown-item" href="#">Action</a></li>
- <li><a class="dropdown-item" href="#">Another
action</a></li>
- <li><hr class="dropdown-divider"></li>
- <li><a class="dropdown-item" href="#">Something else
here</a></li>
- </ul>
- </li>
- <li class="nav-item">
- <a class="nav-link disabled">Disabled</a>
- </li>
- </ul>
- <form class="d-flex" role="search">
- <input class="form-control me-2" type="search"
placeholder="Search" aria-label="Search">
- <button class="btn btn-outline-success"
type="submit">Search</button>
- </form>
- </div>
- </div>
- </nav>
+</nav>
+<div class="container">
<div class="row">
<div id="title">
@@ -87,20 +112,26 @@
<td>[[${headerUiModel.branding.logoHref}]]</td>
</tr>
- <tr class="result" th:each="topLevelEntry :
${headerUiModel.navbar().primary().topLevelEntries()}">
+ <th:block
th:with="topNavSection=${headerUiModel.navbar().primary()}">
+ <tr class="result" th:each="topLevelEntry :
${topNavSection.topLevelEntries()}">
<td>[[${topLevelEntry.name}]]</td>
<td>[[${topLevelEntry.subEntries}]]</td>
</tr>
</th:block>
- <tr class="result" th:each="topLevelEntry :
${headerUiModel.navbar().secondary().topLevelEntries()}">
+
+ <th:block
th:with="topNavSection=${headerUiModel.navbar().secondary()}">
+ <tr class="result" th:each="topLevelEntry :
${topNavSection.topLevelEntries()}">
<td>[[${topLevelEntry.name}]]</td>
<td>[[${topLevelEntry.subEntries}]]</td>
</tr>
- <tr class="result" th:each="topLevelEntry :
${headerUiModel.navbar().tertiary().topLevelEntries()}">
+ </th:block>
+
+ <th:block
th:with="topNavSection=${headerUiModel.navbar().tertiary()}">
+ <tr class="result" th:each="topLevelEntry :
${topNavSection.topLevelEntries()}">
<td>[[${topLevelEntry.name}]]</td>
<td>[[${topLevelEntry.subEntries}]]</td>
</tr>
-
+ </th:block>
<tr class="result">
<td>User</td>
@@ -118,4 +149,5 @@
</div>
</div>
-</body>
\ No newline at end of file
+</body>
+</html>
\ No newline at end of file
diff --git
a/viewers/commons/applib/src/main/java/org/apache/causeway/viewer/commons/applib/services/header/HeaderUiModel.java
b/viewers/commons/applib/src/main/java/org/apache/causeway/viewer/commons/applib/services/header/HeaderUiModel.java
index 4cb09499d5..faeaf59572 100644
---
a/viewers/commons/applib/src/main/java/org/apache/causeway/viewer/commons/applib/services/header/HeaderUiModel.java
+++
b/viewers/commons/applib/src/main/java/org/apache/causeway/viewer/commons/applib/services/header/HeaderUiModel.java
@@ -18,7 +18,6 @@
*/
package org.apache.causeway.viewer.commons.applib.services.header;
-import org.apache.causeway.commons.io.YamlUtils;
import
org.apache.causeway.viewer.commons.applib.services.branding.BrandingUiModel;
import
org.apache.causeway.viewer.commons.applib.services.menu.model.NavbarUiModel;
import
org.apache.causeway.viewer.commons.applib.services.userprof.UserProfileUiModel;
@@ -30,8 +29,4 @@ public record HeaderUiModel(
@NonNull UserProfileUiModel userProfile,
@NonNull NavbarUiModel navbar) {
- public String toYaml() {
- return YamlUtils.toStringUtf8(this);
- }
-
}