You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by th...@apache.org on 2023/01/28 19:20:06 UTC
[tapestry-5] 02/02: TAP5-2744: finished Graphviz component and PageDependencyGraph page
This is an automated email from the ASF dual-hosted git repository.
thiagohp pushed a commit to branch better-page-invalidation
in repository https://gitbox.apache.org/repos/asf/tapestry-5.git
commit 14e2243ca5e4fa65e7c391e09564cb1aafb57fb7
Author: Thiago H. de Paula Figueiredo <th...@arsmachina.com.br>
AuthorDate: Sat Jan 28 16:19:21 2023 -0300
TAP5-2744: finished Graphviz component and PageDependencyGraph page
---
.../META-INF/modules/t5/core/graphviz.coffee | 29 ++++++
.../tapestry5/corelib/components/Graphviz.java | 104 +++++++++++++++++++++
.../tapestry5/corelib/pages/PageCatalog.java | 18 +---
.../corelib/pages/PageDependencyGraph.java | 71 ++++++++++++++
.../ComponentDependencyGraphvizGeneratorImpl.java | 4 +-
.../apache/tapestry5/modules/DashboardModule.java | 6 +-
.../META-INF/assets/tapestry5/PageCatalog.js | 9 --
.../resources/org/apache/tapestry5/core.properties | 3 +
.../apache/tapestry5/corelib/pages/PageCatalog.tml | 4 +-
.../corelib/pages/PageDependencyGraph.tml | 13 +++
10 files changed, 231 insertions(+), 30 deletions(-)
diff --git a/tapestry-core/src/main/coffeescript/META-INF/modules/t5/core/graphviz.coffee b/tapestry-core/src/main/coffeescript/META-INF/modules/t5/core/graphviz.coffee
new file mode 100644
index 000000000..e1fbe3ee2
--- /dev/null
+++ b/tapestry-core/src/main/coffeescript/META-INF/modules/t5/core/graphviz.coffee
@@ -0,0 +1,29 @@
+# Copyright 2023 The Apache Software Foundation
+#
+# Licensed 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.
+
+# ## t5/core/graphviz
+#
+# Support to the core/Graphviz Tapestry component.
+define ["https://cdn.jsdelivr.net/npm/@hpcc-js/wasm/dist/graphviz.umd.js"],
+ (hpccWasm) ->
+ render = (value, id, showDownloadLink) ->
+ hpccWasm.Graphviz.load().then (graphviz) ->
+ svg = graphviz.dot value
+ div = document.getElementById id
+ layout = graphviz.layout(value, "svg", "dot")
+ div.innerHTML = layout
+ if showDownloadLink
+ link = document.getElementById (id + "-download")
+ link.setAttribute "href", "data:image/svg+xml;charset=utf-8," + encodeURIComponent(layout)
+ return render
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Graphviz.java b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Graphviz.java
new file mode 100644
index 000000000..8fd74f4c8
--- /dev/null
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Graphviz.java
@@ -0,0 +1,104 @@
+// Copyright 2023 The Apache Software Foundation
+//
+// Licensed 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.tapestry5.corelib.components;
+
+import org.apache.tapestry5.BindingConstants;
+import org.apache.tapestry5.ComponentResources;
+import org.apache.tapestry5.MarkupWriter;
+import org.apache.tapestry5.annotations.Environmental;
+import org.apache.tapestry5.annotations.Parameter;
+import org.apache.tapestry5.annotations.Property;
+import org.apache.tapestry5.commons.Messages;
+import org.apache.tapestry5.ioc.annotations.Inject;
+import org.apache.tapestry5.services.ajax.AjaxResponseRenderer;
+import org.apache.tapestry5.services.javascript.JavaScriptSupport;
+
+/**
+ * Component that renders a <a href="http://graphviz.org">Graphviz</a> graph using
+ * <a href="https://www.npmjs.com/package/@hpcc-js/wasm">@hpcc-js/wasm</a>. It's mostly
+ * intended to be used internally at Tapestry, hence the lack of options.
+ *
+ * @tapestrydoc
+ */
+public class Graphviz
+{
+
+ /**
+ * A Graphviz graph described in its DOT language.
+ */
+ @Parameter(required = true, allowNull = false)
+ @Property
+ private String value;
+
+ /**
+ * Defines whether a link to download the graph as an SVG file should be provided.
+ */
+ @Parameter(defaultPrefix = BindingConstants.LITERAL, value = "false")
+ private boolean showDownloadLink;
+
+ /**
+ * Defines whether a the Graphviz source should be shown.
+ */
+ @Parameter(defaultPrefix = BindingConstants.LITERAL, value = "false")
+ private boolean showSource;
+
+ @Environmental
+ private JavaScriptSupport javaScriptSupport;
+
+ @Inject
+ private AjaxResponseRenderer ajaxResponseRenderer;
+
+ @Inject
+ private ComponentResources resources;
+
+ @Inject
+ private Messages messages;
+
+ // Read value only once if showSource = true
+ private String cachedValue;
+
+ void setupRender(MarkupWriter writer)
+ {
+
+ cachedValue = value;
+ String elementName = resources.getElementName();
+ if (elementName == null)
+ {
+ elementName = "div";
+ }
+
+ final String id = javaScriptSupport.allocateClientId(resources);
+ writer.element(elementName, "id", id);
+ writer.end();
+
+ javaScriptSupport.require("t5/core/graphviz").with(cachedValue, id, showDownloadLink);
+
+ if (showDownloadLink)
+ {
+ writer.element("a", "href", "#", "id", id + "-download", "download", id + ".svg");
+ writer.write(messages.get("download-graphviz-image"));
+ writer.end();
+ }
+
+ if (showSource)
+ {
+ writer.element("pre", "id", id + "-source");
+ writer.write(cachedValue);
+ writer.end();
+ }
+
+ }
+
+}
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/PageCatalog.java b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/PageCatalog.java
index 0728b6fe2..74479881d 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/PageCatalog.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/PageCatalog.java
@@ -21,11 +21,9 @@ import java.util.Collections;
import java.util.List;
import java.util.Set;
-import org.apache.tapestry5.Asset;
import org.apache.tapestry5.MarkupWriter;
import org.apache.tapestry5.alerts.AlertManager;
import org.apache.tapestry5.annotations.InjectComponent;
-import org.apache.tapestry5.annotations.Path;
import org.apache.tapestry5.annotations.Persist;
import org.apache.tapestry5.annotations.Property;
import org.apache.tapestry5.annotations.UnknownActivationContextCheck;
@@ -152,10 +150,6 @@ public class PageCatalog
@Inject
private AjaxResponseRenderer ajaxResponseRenderer;
- @Inject
- @Path("classpath:/META-INF/assets/tapestry5/PageCatalog.js")
- private Asset pageCatalogJs;
-
void pageLoaded()
{
model = beanModelSource.createDisplayModel(Page.class, messages);
@@ -372,14 +366,6 @@ public class PageCatalog
{
selectedPage = pageSource.getPage(pageName);
ajaxResponseRenderer.addRender("pageStructureZone", pageStructureZone.getBody());
- ajaxResponseRenderer.addCallback((JavaScriptSupport js) -> {
- js.importJavaScriptLibrary(pageCatalogJs);
- js.importJavaScriptLibrary("https://cdn.jsdelivr.net/npm/@hpcc-js/wasm/dist/graphviz.umd.js");
- final String graphvizSource = getGraphvizSource(getSelectedPageClassName());
- System.out.println(graphvizSource);
- js.addScript("showGraphviz('%s', '%s');", pageName,
- graphvizSource.replace("\n", " "));
- });
}
public String getDisplayLogicalName()
@@ -462,9 +448,9 @@ public class PageCatalog
return resolver.getLogicalName(className);
}
- private String getGraphvizSource(String className)
+ public String getGraphvizValue()
{
- return componentDependencyGraphvizGenerator.generate(className);
+ return componentDependencyGraphvizGenerator.generate(getClassName(selectedPage));
}
}
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/PageDependencyGraph.java b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/PageDependencyGraph.java
new file mode 100644
index 000000000..134b87e2c
--- /dev/null
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/PageDependencyGraph.java
@@ -0,0 +1,71 @@
+// Copyright 2023 The Apache Software Foundation
+//
+// Licensed 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.tapestry5.corelib.pages;
+
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.apache.tapestry5.annotations.Property;
+import org.apache.tapestry5.annotations.UnknownActivationContextCheck;
+import org.apache.tapestry5.annotations.WhitelistAccessOnly;
+import org.apache.tapestry5.internal.services.ComponentDependencyGraphvizGenerator;
+import org.apache.tapestry5.internal.services.PageSource;
+import org.apache.tapestry5.internal.structure.Page;
+import org.apache.tapestry5.ioc.annotations.Inject;
+import org.apache.tapestry5.services.ComponentClassResolver;
+import org.apache.tapestry5.services.ajax.AjaxResponseRenderer;
+
+/**
+ * Shows graph showing the dependencies of all already loaded pages and its compnoents, mixins and base classes.
+ */
+@UnknownActivationContextCheck(false)
+@WhitelistAccessOnly
+public class PageDependencyGraph
+{
+
+ @Inject
+ private ComponentClassResolver resolver;
+
+ @Inject
+ private ComponentDependencyGraphvizGenerator componentDependencyGraphvizGenerator;
+
+ @Inject
+ private PageSource pageSource;
+
+ @Inject
+ private ComponentClassResolver componentClassResolver;
+
+ @Inject
+ private AjaxResponseRenderer ajaxResponseRenderer;
+
+ @Property
+ private Page page;
+
+ private String getClassName(Page page)
+ {
+ return page.getRootComponent().getComponentResources().getComponentModel().getComponentClassName();
+ }
+
+ public String getGraphvizValue()
+ {
+ final Set<Page> allPages = pageSource.getAllPages();
+ return componentDependencyGraphvizGenerator.generate(
+ allPages.stream()
+ .map(this::getClassName)
+ .collect(Collectors.toList())
+ .toArray(new String[allPages.size()]));
+ }
+
+}
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentDependencyGraphvizGeneratorImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentDependencyGraphvizGeneratorImpl.java
index f53816687..81a179e46 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentDependencyGraphvizGeneratorImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentDependencyGraphvizGeneratorImpl.java
@@ -42,8 +42,8 @@ public class ComponentDependencyGraphvizGeneratorImpl implements ComponentDepend
dotFile.append("\trankdir=LR;\n");
dotFile.append("\tfontname=\"Helvetica,Arial,sans-serif\";\n");
-// dotFile.append("\tnode [fontname=\"Helvetica,Arial,sans-serif\",fontsize=\"8pt\"];\n");
- dotFile.append("\tedge [fontname=\"Helvetica,Arial,sans-serif\"];\n");
+ dotFile.append("\tsplines=ortho;\n\n");
+ dotFile.append("\tnode [fontname=\"Helvetica,Arial,sans-serif\",fontsize=\"10pt\"];\n");
dotFile.append("\tnode [shape=rect];\n\n");
final Set<String> allClasses = new HashSet<>();
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/modules/DashboardModule.java b/tapestry-core/src/main/java/org/apache/tapestry5/modules/DashboardModule.java
index 002fea71d..c4985b510 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/modules/DashboardModule.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/modules/DashboardModule.java
@@ -1,4 +1,4 @@
-// Copyright 2013, 2014 The Apache Software Foundation
+// Copyright 2013, 2014, 2023 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
package org.apache.tapestry5.modules;
import org.apache.tapestry5.commons.OrderedConfiguration;
+import org.apache.tapestry5.internal.services.ComponentDependencyGraphvizGenerator;
+import org.apache.tapestry5.internal.services.ComponentDependencyGraphvizGeneratorImpl;
import org.apache.tapestry5.internal.services.dashboard.DashboardManagerImpl;
import org.apache.tapestry5.ioc.ServiceBinder;
import org.apache.tapestry5.ioc.annotations.Contribute;
@@ -26,6 +28,7 @@ public class DashboardModule
public static void bind(ServiceBinder binder)
{
binder.bind(DashboardManager.class, DashboardManagerImpl.class);
+ binder.bind(ComponentDependencyGraphvizGenerator.class, ComponentDependencyGraphvizGeneratorImpl.class);
}
@Contribute(DashboardManager.class)
@@ -34,5 +37,6 @@ public class DashboardModule
configuration.add("Pages", new DashboardTab("Pages", "core/PageCatalog"));
configuration.add("Services", new DashboardTab("Services", "core/ServiceStatus"));
configuration.add("Libraries", new DashboardTab("ComponentLibraries", "core/ComponentLibraries"));
+ configuration.add("PageDependencyGraph", new DashboardTab("PageDependencyGraph", "core/PageDependencyGraph"));
}
}
diff --git a/tapestry-core/src/main/resources/META-INF/assets/tapestry5/PageCatalog.js b/tapestry-core/src/main/resources/META-INF/assets/tapestry5/PageCatalog.js
deleted file mode 100644
index c3be055a5..000000000
--- a/tapestry-core/src/main/resources/META-INF/assets/tapestry5/PageCatalog.js
+++ /dev/null
@@ -1,9 +0,0 @@
-console.log("PageCatalog.js");
-function showGraphviz(pageName, dot) {
- var hpccWasm = require("https://cdn.jsdelivr.net/npm/@hpcc-js/wasm/dist/graphviz.umd.js");
- hpccWasm.Graphviz.load().then(graphviz => {
- const svg = graphviz.dot(dot);
- const div = document.getElementById(pageName + "-graphviz");
- div.innerHTML = graphviz.layout(dot, "svg", "dot");
- });
-};
\ No newline at end of file
diff --git a/tapestry-core/src/main/resources/org/apache/tapestry5/core.properties b/tapestry-core/src/main/resources/org/apache/tapestry5/core.properties
index 61cac585b..bda821d34 100644
--- a/tapestry-core/src/main/resources/org/apache/tapestry5/core.properties
+++ b/tapestry-core/src/main/resources/org/apache/tapestry5/core.properties
@@ -140,6 +140,9 @@ private-default-localdate-format=lll
# see ComponentLibraries page
not-informed=Not informed
+# see Graphviz
+download-graphviz-image = Download graph as SVG
+
# OpenAPI generation
openapi.viewer-title=OpenAPI definition viewer
openapi-title=OpenAPI description
diff --git a/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/pages/PageCatalog.tml b/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/pages/PageCatalog.tml
index 688f8bd05..cc7ae7056 100644
--- a/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/pages/PageCatalog.tml
+++ b/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/pages/PageCatalog.tml
@@ -67,8 +67,8 @@
</div>
<div class="panel panel-default vert-offset" t:type="If" t:test="selectedPage">
<div class="panel-heading">${selectedPage.name}'s dependency tree</div>
-<!-- <pre id="${selectedPage.name}-graphviz-source">${getGraphVizSource(selectedPageClassName)}</pre> -->
- <div class="panel-body" id="${selectedPage.name}-graphviz">
+ <div class="panel-body">
+ <t:graphviz value="graphvizValue"/>
</div>
</div>
</t:zone>
diff --git a/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/pages/PageDependencyGraph.tml b/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/pages/PageDependencyGraph.tml
new file mode 100644
index 000000000..21a6ec7c1
--- /dev/null
+++ b/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/pages/PageDependencyGraph.tml
@@ -0,0 +1,13 @@
+<t:block id="content" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd"
+ xmlns:p="tapestry:parameter">
+
+ <p>
+ This page provides a graph, generated with <a href="http://graphviz.org">Graphviz</a>
+ and <a href="https://www.npmjs.com/package/@hpcc-js/wasm">@hpcc-js/wasm</a>,
+ showing the dependencies of all already loaded
+ pages and its components, mixins and base classes.
+ </p>
+
+ <t:Graphviz value="graphvizValue" showDownloadLink="true" showSource="true"/>
+
+</t:block>
\ No newline at end of file