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 <[email protected]> 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
