Skip to content

Commit

Permalink
Qute - the new Dev UI
Browse files Browse the repository at this point in the history
- the preview page was intentionally not migrated
  • Loading branch information
mkouba committed Mar 23, 2023
1 parent ac6f162 commit a69d930
Show file tree
Hide file tree
Showing 5 changed files with 458 additions and 1 deletion.
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);
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@

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


/**
* This component shows the TemplateData.
*/
export class QwcQuteTemplateData 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="${templateData}" class="templates-table" theme="no-border" all-rows-visible>
<vaadin-grid-column auto-width
header="Target Class"
${columnBodyRenderer(this._renderTarget, [])}
resizable>
</vaadin-grid-column>
<vaadin-grid-column auto-width
header="Namespace"
${columnBodyRenderer(this._renderNamespace, [])}
resizable>
</vaadin-grid-column>
<vaadin-grid-column auto-width
header="Ignore"
${columnBodyRenderer(this._renderIgnores, [])}
resizable>
</vaadin-grid-column>
<vaadin-grid-column auto-width
header="Only properties"
${columnBodyRenderer(this._renderProperties, [])}
resizable>
</vaadin-grid-column>
</vaadin-grid>
`;
}

_renderTarget(data) {
return html`
<code>${data.target}</code>
`;
}

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

_renderIgnores(data) {
return data.ignores ? html`
<code>${data.ignores}</code>
` : html``;
}

_renderProperties(data) {
return data.properties ? html`
<code>${data.properties}</code>
` : html``;
}

}
customElements.define('qwc-qute-template-data', QwcQuteTemplateData);

0 comments on commit a69d930

Please sign in to comment.