Skip to content

Commit

Permalink
Merge pull request #32063 from mkouba/qute-new-dev-ui
Browse files Browse the repository at this point in the history
Qute - the new Dev UI
  • Loading branch information
mkouba authored Mar 24, 2023
2 parents 2647d64 + a69d930 commit 34d7f86
Show file tree
Hide file tree
Showing 13 changed files with 523 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -645,7 +645,7 @@ public void beforeParsing(ParserHelper parserHelper) {
}

analysis.add(new TemplateAnalysis(null, template.getGeneratedId(), template.getExpressions(),
parameterDeclarations, path.getPath()));
parameterDeclarations, path.getPath(), template.getFragmentIds()));
}
}

Expand All @@ -661,7 +661,8 @@ public void beforeParsing(ParserHelper parserHelper) {
analysis.add(new TemplateAnalysis(messageBundleMethod.getTemplateId(), template.getGeneratedId(),
template.getExpressions(), paramDeclarations,
messageBundleMethod.getMethod().declaringClass().name() + "#" + messageBundleMethod.getMethod().name()
+ "()"));
+ "()",
template.getFragmentIds()));
}

LOGGER.debugf("Finished analysis of %s templates in %s ms", analysis.size(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import io.quarkus.qute.TemplateData;
import io.quarkus.qute.generator.ValueResolverGenerator;

final class TemplateDataBuildItem extends MultiBuildItem {
public final class TemplateDataBuildItem extends MultiBuildItem {

private final ClassInfo targetClass;
private final String namespace;
Expand Down Expand Up @@ -55,35 +55,36 @@ final class TemplateDataBuildItem extends MultiBuildItem {
this.properties = propertiesValue != null ? propertiesValue.asBoolean() : false;
}

boolean isTargetAnnotatedType() {
return targetClass.asClass().name().equals(ValueResolverGenerator.TEMPLATE_DATA);
public boolean isTargetAnnotatedType() {
AnnotationValue targetValue = annotationInstance.value(ValueResolverGenerator.TARGET);
return targetValue == null || targetValue.asClass().name().equals(ValueResolverGenerator.TEMPLATE_DATA);
}

ClassInfo getTargetClass() {
public ClassInfo getTargetClass() {
return targetClass;
}

boolean hasNamespace() {
public boolean hasNamespace() {
return namespace != null;
}

String getNamespace() {
public String getNamespace() {
return namespace;
}

String[] getIgnore() {
public String[] getIgnore() {
return ignore;
}

boolean isIgnoreSuperclasses() {
public boolean isIgnoreSuperclasses() {
return ignoreSuperclasses;
}

boolean isProperties() {
public boolean isProperties() {
return properties;
}

AnnotationInstance getAnnotationInstance() {
public AnnotationInstance getAnnotationInstance() {
return annotationInstance;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.List;
import java.util.Objects;
import java.util.Set;

import io.quarkus.builder.item.SimpleBuildItem;
import io.quarkus.qute.Expression;
Expand Down Expand Up @@ -40,13 +41,16 @@ public static final class TemplateAnalysis {
// File path, e.g. hello.html or ItemResource/items.html
public final String path;

public final Set<String> fragmentIds;

public TemplateAnalysis(String id, String generatedId, List<Expression> expressions,
List<ParameterDeclaration> parameterDeclarations, String path) {
List<ParameterDeclaration> parameterDeclarations, String path, Set<String> fragmentIds) {
this.id = id;
this.generatedId = generatedId;
this.expressions = expressions;
this.parameterDeclarations = parameterDeclarations;
this.path = path;
this.fragmentIds = fragmentIds;
}

Expression findExpression(int id) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ static Info create(String typeInfo, Expression.Part part, IndexView index, Funct
rawClass = null;
} else {
rawClass = getClassInfo(classStr, index, templateIdToPathFun, expressionOrigin);
// Comparable<Integer> -> java.lang.Comparable<Integer>
if (rawClass.name().packagePrefix().equals("java.lang")
&& !classStr.contains(Types.JAVA_LANG_PREFIX)) {
classStr = Types.JAVA_LANG_PREFIX + classStr;
}
resolvedType = resolveType(classStr);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
package io.quarkus.qute.deployment.devui;

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map.Entry;
import java.util.stream.Collectors;

import org.jboss.jandex.DotName;

import io.quarkus.deployment.IsDevelopment;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.devui.spi.page.CardPageBuildItem;
import io.quarkus.devui.spi.page.Page;
import io.quarkus.qute.ParameterDeclaration;
import io.quarkus.qute.deployment.CheckedTemplateBuildItem;
import io.quarkus.qute.deployment.TemplateDataBuildItem;
import io.quarkus.qute.deployment.TemplateExtensionMethodBuildItem;
import io.quarkus.qute.deployment.TemplatePathBuildItem;
import io.quarkus.qute.deployment.TemplateVariantsBuildItem;
import io.quarkus.qute.deployment.TemplatesAnalysisBuildItem;
import io.quarkus.qute.deployment.TemplatesAnalysisBuildItem.TemplateAnalysis;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;

public class QuteDevUIProcessor {

@BuildStep(onlyIf = IsDevelopment.class)
public void pages(
List<TemplatePathBuildItem> templatePaths,
List<CheckedTemplateBuildItem> checkedTemplates,
TemplateVariantsBuildItem variants,
TemplatesAnalysisBuildItem templatesAnalysis,
List<TemplateExtensionMethodBuildItem> templateExtensionMethods,
List<TemplateDataBuildItem> templateDatas,
BuildProducer<CardPageBuildItem> cardPages) {

CardPageBuildItem pageBuildItem = new CardPageBuildItem("Qute");

List<TemplatePathBuildItem> sortedTemplatePaths = templatePaths.stream()
.sorted(Comparator.comparing(tp -> tp.getPath().toLowerCase())).collect(Collectors.toList());
JsonArray templates = createTemplatesJson(sortedTemplatePaths, checkedTemplates, templatesAnalysis, variants);

List<TemplateExtensionMethodBuildItem> sortedExtensionMethods = templateExtensionMethods.stream()
.sorted(new Comparator<TemplateExtensionMethodBuildItem>() {

@Override
public int compare(TemplateExtensionMethodBuildItem m1, TemplateExtensionMethodBuildItem m2) {
DotName m1Class = m1.getMethod().declaringClass().name();
DotName m2Class = m2.getMethod().declaringClass().name();
int ret = m1Class.compareTo(m2Class);
return ret == 0 ? m1.getMethod().name().compareTo(m2.getMethod().name()) : ret;
}
}).collect(Collectors.toList());
JsonArray extensionMethods = createExtensionMethodsJson(sortedExtensionMethods);

List<TemplateDataBuildItem> sortedTemplateData = templateDatas.stream()
.sorted(Comparator.comparing(td -> td.getTargetClass().name())).collect(Collectors.toList());
JsonArray templateData = createTemplateDataJson(sortedTemplateData);

pageBuildItem.addBuildTimeData("templates", templates);
pageBuildItem.addBuildTimeData("extensionMethods", extensionMethods);
pageBuildItem.addBuildTimeData("templateData", templateData);

pageBuildItem.addPage(Page.webComponentPageBuilder()
.title("Templates")
.icon("font-awesome-solid:file-code")
.componentLink("qwc-qute-templates.js")
.staticLabel(String.valueOf(templates.size())));

pageBuildItem.addPage(Page.webComponentPageBuilder()
.title("Extension Methods")
.icon("font-awesome-solid:puzzle-piece")
.componentLink("qwc-qute-extension-methods.js")
.staticLabel(String.valueOf(extensionMethods.size())));

pageBuildItem.addPage(Page.webComponentPageBuilder()
.title("@TemplateData")
.icon("font-awesome-solid:database")
.componentLink("qwc-qute-template-data.js")
.staticLabel(String.valueOf(templateData.size())));

cardPages.produce(pageBuildItem);
}

private JsonArray createTemplateDataJson(List<TemplateDataBuildItem> sortedTemplateData) {
JsonArray data = new JsonArray();
for (TemplateDataBuildItem templateData : sortedTemplateData) {
JsonObject json = new JsonObject();
json.put("target", templateData.getTargetClass().name().toString());
if (templateData.hasNamespace()) {
json.put("namespace", templateData.getNamespace());
}
if (templateData.getIgnore() != null && templateData.getIgnore().length > 0) {
json.put("ignores", Arrays.toString(templateData.getIgnore()));
}
if (templateData.isProperties()) {
json.put("properties", true);
}
data.add(json);
}
return data;
}

private JsonArray createExtensionMethodsJson(List<TemplateExtensionMethodBuildItem> sortedExtensionMethods) {
JsonArray extensionMethods = new JsonArray();
for (TemplateExtensionMethodBuildItem templateExtensionMethod : sortedExtensionMethods) {
JsonObject extensionMethod = new JsonObject();
extensionMethod.put("name", templateExtensionMethod.getMethod().declaringClass().name() + "#"
+ templateExtensionMethod.getMethod().name() + "()");
if (templateExtensionMethod.getMatchRegex() != null && !templateExtensionMethod.getMatchRegex().isEmpty()) {
extensionMethod.put("matchRegex", templateExtensionMethod.getMatchRegex());
} else if (!templateExtensionMethod.getMatchNames().isEmpty()) {
extensionMethod.put("matchNames", templateExtensionMethod.getMatchNames().toString());
} else {
extensionMethod.put("matchName", templateExtensionMethod.getMatchName());
}
if (templateExtensionMethod.hasNamespace()) {
extensionMethod.put("namespace", templateExtensionMethod.getNamespace());
} else {
extensionMethod.put("matchType", templateExtensionMethod.getMatchType().toString());
}
extensionMethods.add(extensionMethod);
}
return extensionMethods;
}

private JsonArray createTemplatesJson(List<TemplatePathBuildItem> sortedTemplatePaths,
List<CheckedTemplateBuildItem> checkedTemplates, TemplatesAnalysisBuildItem templatesAnalysis,
TemplateVariantsBuildItem variants) {
JsonArray templates = new JsonArray();
for (TemplatePathBuildItem templatePath : sortedTemplatePaths) {
JsonObject template = new JsonObject();
template.put("path", templatePath.getPath());

CheckedTemplateBuildItem checkedTemplate = findCheckedTemplate(getBasePath(templatePath.getPath(), variants),
checkedTemplates);
if (checkedTemplate != null) {
template.put("checkedTemplateMethod",
checkedTemplate.method.declaringClass().name() + "#" + checkedTemplate.method.name() + "()");
}

TemplateAnalysis analysis = templatesAnalysis.getAnalysis().stream()
.filter(ta -> ta.path.equals(templatePath.getPath())).findFirst().orElse(null);
if (analysis != null) {
if (!analysis.fragmentIds.isEmpty()) {
JsonArray fragmentIds = new JsonArray();
analysis.fragmentIds.forEach(fragmentIds::add);
template.put("fragmentIds", fragmentIds);
}
if (!analysis.parameterDeclarations.isEmpty()) {
JsonArray paramDeclarations = new JsonArray();
for (ParameterDeclaration pd : analysis.parameterDeclarations) {
paramDeclarations.add(String.format("{@%s %s%s}",
pd.getTypeInfo().substring(1, pd.getTypeInfo().length() - 1), pd.getKey(),
pd.getDefaultValue() != null ? "=" + pd.getDefaultValue().toOriginalString() : ""));
}
template.put("paramDeclarations", paramDeclarations);
}
}
templates.add(template);
}
return templates;
}

private String getBasePath(String path, TemplateVariantsBuildItem variants) {
for (Entry<String, List<String>> e : variants.getVariants().entrySet()) {
if (e.getValue().contains(path)) {
return e.getKey();
}
}
return null;
}

private CheckedTemplateBuildItem findCheckedTemplate(String basePath, List<CheckedTemplateBuildItem> checkedTemplates) {
if (basePath != null) {
for (CheckedTemplateBuildItem checkedTemplate : checkedTemplates) {
if (checkedTemplate.isFragment()) {
continue;
}
if (checkedTemplate.templateId.equals(basePath)) {
return checkedTemplate;
}
}
}
return null;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@

import { LitElement, html, css} from 'lit';
import { columnBodyRenderer } from '@vaadin/grid/lit.js';
import '@vaadin/grid';
import '@vaadin/text-field';
import { extensionMethods } from 'qute-data';


/**
* This component shows the extension methods.
*/
export class QwcQuteExtensionMethods extends LitElement {

static styles = css`
:host {
display: flex;
flex-direction: column;
gap: 10px;
}
.templates-table {
padding-bottom: 10px;
height: 100%;
}
code {
font-size: 85%;
}
.annotation {
color: var(--lumo-contrast-50pct);
}
`;


render() {
return html`
<vaadin-grid .items="${extensionMethods}" class="templates-table" theme="no-border" all-rows-visible>
<vaadin-grid-column auto-width
header="Extension Method"
${columnBodyRenderer(this._renderMethod, [])}
resizable>
</vaadin-grid-column>
<vaadin-grid-column auto-width
header="Match name"
${columnBodyRenderer(this._renderMatchName, [])}
resizable>
</vaadin-grid-column>
<vaadin-grid-column auto-width
header="Match type"
${columnBodyRenderer(this._renderMatchType, [])}
resizable>
</vaadin-grid-column>
<vaadin-grid-column auto-width
header="Namespace"
${columnBodyRenderer(this._renderNamespace, [])}
resizable>
</vaadin-grid-column>
</vaadin-grid>
`;
}

_renderMethod(method) {
return html`
<code>${method.name}</code>
`;
}

_renderMatchName(method) {
if (method.matchRegex) {
return html`
Regex: <code>${method.matchRegex}</code>
`;
} else if(method.matchNames) {
return html`
Names: <code>${method.matchNames}</code>
`;
} else {
return html`
Name: <code>${method.matchName}</code>
`;
}
}

_renderMatchType(method) {
return method.matchType ? html`
<code>${method.matchType}</code>
` : html``;
}

_renderNamespace(method) {
return method.namespace ? html`
<code>${method.namespace}</code>
` : html``;
}

}
customElements.define('qwc-qute-extension-methods', QwcQuteExtensionMethods);
Loading

0 comments on commit 34d7f86

Please sign in to comment.