Skip to content

Commit

Permalink
Merge pull request #104 from ia3andy/link-support
Browse files Browse the repository at this point in the history
Add link support to QuteWebTemplateBuildItem
  • Loading branch information
mkouba committed Aug 27, 2024
2 parents b9957b8 + 36ba844 commit ce245c2
Show file tree
Hide file tree
Showing 10 changed files with 244 additions and 55 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package io.quarkiverse.qute.web.deployment;

import static java.util.function.Predicate.not;

import java.util.List;
import java.util.Optional;
import java.util.regex.Pattern;
Expand Down Expand Up @@ -42,7 +44,7 @@ AdditionalBeanBuildItem beans() {

@BuildStep
public void collectTemplatePaths(TemplateFilePathsBuildItem templateFilePaths,
QuteWebBuildTimeConfig config, BuildProducer<QuteWebTemplatePathBuildItem> paths) {
QuteWebBuildTimeConfig config, BuildProducer<QuteWebTemplateBuildItem> paths) {
String publicPathPrefix = "";
String publicDir = config.publicDir();
if (!publicDir.equals("/") && !publicDir.isBlank()) {
Expand All @@ -60,24 +62,28 @@ public void collectTemplatePaths(TemplateFilePathsBuildItem templateFilePaths,
continue;
}
LOG.debugf("Web template found: %s", path);
paths.produce(new QuteWebTemplatePathBuildItem(path));
paths.produce(new QuteWebTemplateBuildItem(path, null));
}
}

@BuildStep
@Record(ExecutionTime.RUNTIME_INIT)
@Consume(SyntheticBeansRuntimeInitBuildItem.class)
public RouteBuildItem produceTemplatesRoute(QuteWebRecorder recorder, List<QuteWebTemplatePathBuildItem> templatePaths,
public RouteBuildItem produceTemplatesRoute(QuteWebRecorder recorder, List<QuteWebTemplateBuildItem> templates,
HttpRootPathBuildItem httpRootPath, QuteWebBuildTimeConfig config) {
if (templatePaths.isEmpty()) {
if (templates.isEmpty()) {
// There are no templates to serve
return null;
}
final var templateLinks = templates.stream().filter(QuteWebTemplateBuildItem::hasLink)
.collect(Collectors.toMap(QuteWebTemplateBuildItem::link, QuteWebTemplateBuildItem::templatePath));
final var templatePaths = templates.stream().filter(not(QuteWebTemplateBuildItem::hasLink))
.map(QuteWebTemplateBuildItem::templatePath)
.collect(Collectors.toSet());
return httpRootPath.routeBuilder()
.routeFunction(httpRootPath.relativePath(config.rootPath() + "/*"), recorder.initializeRoute())
.handlerType(config.useBlockingHandler() ? HandlerType.BLOCKING : HandlerType.NORMAL)
.handler(recorder.handler(httpRootPath.relativePath(config.rootPath()),
templatePaths.stream().map(QuteWebTemplatePathBuildItem::getPath).collect(Collectors.toSet())))
.handler(recorder.handler(httpRootPath.relativePath(config.rootPath()), templatePaths, templateLinks))
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package io.quarkiverse.qute.web.deployment;

import static io.quarkiverse.qute.web.runtime.PathUtils.removeExtension;
import static io.quarkiverse.qute.web.runtime.PathUtils.removeLeadingSlash;
import static io.quarkiverse.qute.web.runtime.PathUtils.removeTrailingSlash;

import io.quarkus.builder.item.MultiBuildItem;

public final class QuteWebTemplateBuildItem extends MultiBuildItem {

/**
* templatePath is used also as path if link is null (e.g. "my-blog-post")
*/
private final String templatePath;

/**
* The link to use for this template or null to use the template path (e.g "posts/my-blog-post")
*
* If two links are identical, an exception is thrown
* If a link and a path are identical for different items, the link has priority
*/
private final String link;

public QuteWebTemplateBuildItem(String templatePath, String link) {
this.templatePath = removeExtension(templatePath);
this.link = normalizeLink(link);
}

public String templatePath() {
return templatePath;
}

public String link() {
return link;
}

public boolean hasLink() {
return link != null;
}

private static String normalizeLink(String link) {
if (link == null) {
return null;
}
return removeTrailingSlash(removeLeadingSlash(link));
}

}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

import io.quarkiverse.qute.web.deployment.QuteWebTemplatePathBuildItem;
import io.quarkiverse.qute.web.deployment.QuteWebTemplateBuildItem;
import io.quarkiverse.qute.web.runtime.PathUtils;
import io.quarkiverse.qute.web.runtime.QuteWebBuildTimeConfig;
import io.quarkus.deployment.IsDevelopment;
import io.quarkus.deployment.annotations.BuildProducer;
Expand All @@ -13,23 +13,25 @@
import io.quarkus.devui.spi.page.Page;
import io.quarkus.vertx.http.deployment.HttpRootPathBuildItem;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;

public class QuteWebDevUIProcessor {

@BuildStep(onlyIf = IsDevelopment.class)
public void pages(List<QuteWebTemplatePathBuildItem> templatePaths, HttpRootPathBuildItem httpRootPath,
public void pages(List<QuteWebTemplateBuildItem> templatePaths, HttpRootPathBuildItem httpRootPath,
QuteWebBuildTimeConfig config, BuildProducer<CardPageBuildItem> cardPages) {

CardPageBuildItem pageBuildItem = new CardPageBuildItem();

final String publicDir = config.publicDir();
JsonArray paths = new JsonArray();
for (String path : templatePaths.stream().map(QuteWebTemplatePathBuildItem::getPath)
.sorted(Comparator.comparing(p -> p.toLowerCase())).collect(Collectors.toList())) {
paths.add(path);
for (QuteWebTemplateBuildItem item : templatePaths.stream()
.sorted(Comparator.comparing(p -> p.templatePath().toLowerCase())).toList()) {
var link = item.link() == null ? PathUtils.removeLeadingSlash(item.templatePath().replace(publicDir, ""))
: item.link();
link = PathUtils.join(httpRootPath.relativePath(config.rootPath()), link);
paths.add(new JsonObject().put("templateId", item.templatePath()).put("link", link));
}

pageBuildItem.addBuildTimeData("paths", paths);
pageBuildItem.addBuildTimeData("rootPrefix", httpRootPath.relativePath(config.rootPath()) + "/");

pageBuildItem.addPage(Page.webComponentPageBuilder()
.title("Pages")
Expand Down
15 changes: 9 additions & 6 deletions deployment/src/main/resources/dev-ui/qwc-qsp-paths.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { columnBodyRenderer } from '@vaadin/grid/lit.js';
import '@vaadin/grid';
import '@vaadin/text-field';
import { paths } from 'build-time-data';
import { rootPrefix } from 'build-time-data';


/**
Expand Down Expand Up @@ -33,18 +32,22 @@ export class QwcQspPaths extends LitElement {
render() {
return html`
<vaadin-grid .items="${paths}" class="paths-table" theme="no-border" all-rows-visible>
<vaadin-grid-column auto-width
header="Path"
${columnBodyRenderer(this._renderPath, [])}
<vaadin-grid-column auto-width
path="templateId"
resizable>
</vaadin-grid-column>
<vaadin-grid-column auto-width
header="Link"
${columnBodyRenderer(this._renderLink, [])}
resizable>
</vaadin-grid-column>
</vaadin-grid>
`;
}

_renderPath(path) {
_renderLink(item) {
return html`
<a href="${rootPrefix}${path}" target="_blank" class="path-link">${rootPrefix}${path}</a>
<a href="${item.link}" target="_blank" class="path-link">${item.link}</a>
`;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package io.quarkiverse.qute.web.test;

import org.jboss.shrinkwrap.api.asset.StringAsset;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkiverse.qute.web.deployment.QuteWebTemplateBuildItem;
import io.quarkus.builder.BuildContext;
import io.quarkus.builder.BuildStep;
import io.quarkus.builder.BuildStepBuilder;
import io.quarkus.test.QuarkusUnitTest;

public class LinkedDuplicateTemplateTest {

@RegisterExtension
static final QuarkusUnitTest config = new QuarkusUnitTest().withApplicationRoot(root -> {
root.addAsResource(new StringAsset(
"Hello {name ?: 'world'}!"),
"templates/pub/hello.txt");
}).addBuildChainCustomizer(buildChainBuilder -> {
final BuildStepBuilder stepBuilder = buildChainBuilder.addBuildStep(new BuildStep() {
@Override
public void execute(BuildContext context) {
context.produce(new QuteWebTemplateBuildItem("pub/hello.txt", "/foo/bar"));
context.produce(new QuteWebTemplateBuildItem("pub/hello.txt", "/foo/bar"));
}
});
stepBuilder.produces(QuteWebTemplateBuildItem.class).build();
}).assertException(throwable -> {
Assertions.assertInstanceOf(IllegalStateException.class, throwable);
});

@Test
public void testDuplicateLink() {

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package io.quarkiverse.qute.web.test;

import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.containsString;

import org.jboss.shrinkwrap.api.asset.StringAsset;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkiverse.qute.web.deployment.QuteWebTemplateBuildItem;
import io.quarkus.builder.BuildContext;
import io.quarkus.builder.BuildStep;
import io.quarkus.builder.BuildStepBuilder;
import io.quarkus.test.QuarkusUnitTest;

public class LinkedTemplateTest {

@RegisterExtension
static final QuarkusUnitTest config = new QuarkusUnitTest().withApplicationRoot(root -> {
root.addAsResource(new StringAsset(
"Hello {name ?: 'world'}!"),
"templates/pub/hello.txt");
root.addAsResource(new StringAsset(
"Linked Hello {name ?: 'world'}!"),
"templates/linked.txt");
}).addBuildChainCustomizer(buildChainBuilder -> {
final BuildStepBuilder stepBuilder = buildChainBuilder.addBuildStep(new BuildStep() {
@Override
public void execute(BuildContext context) {
context.produce(new QuteWebTemplateBuildItem("pub/hello.txt", "/foo/bar"));
context.produce(new QuteWebTemplateBuildItem("pub/hello.txt", "/"));
context.produce(new QuteWebTemplateBuildItem("linked.txt", "/hello.txt"));
}
});
stepBuilder.produces(QuteWebTemplateBuildItem.class).build();
});

@Test
public void testFixedLink() {
given()
.when().get("/hello")
.then()
.statusCode(200)
.body(containsString("Hello world!"));
given()
.when().get("/foo/bar")
.then()
.statusCode(200)
.body(containsString("Hello world!"));
given()
.when().get("/hello.txt")
.then()
.statusCode(200)
.body(containsString("Linked Hello world!"));

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package io.quarkiverse.qute.web.runtime;

public final class PathUtils {

public static String toUnixPath(String path) {
return path.replaceAll("\\\\", "/");
}

public static String prefixWithSlash(String path) {
return path.startsWith("/") ? path : "/" + path;
}

public static String surroundWithSlashes(String path) {
return prefixWithSlash(addTrailingSlash(path));
}

public static String addTrailingSlash(String path) {
return path.endsWith("/") ? path : path + "/";
}

public static String join(String path1, String path2) {
return addTrailingSlash(path1) + removeLeadingSlash(path2);
}

public static String removeLeadingSlash(String path) {
return path.startsWith("/") ? path.substring(1) : path;
}

public static String removeTrailingSlash(String path) {
return path.endsWith("/") ? path.substring(0, path.length() - 1) : path;
}

public static String removeExtension(String path) {
final int i = path.lastIndexOf(".");
return i > 0 ? path.substring(0, i) : path;
}
}
Loading

0 comments on commit ce245c2

Please sign in to comment.