diff --git a/deployment/src/main/java/io/quarkiverse/statiq/deployment/StatiqProcessor.java b/deployment/src/main/java/io/quarkiverse/statiq/deployment/StatiqProcessor.java index e88f3070..acf63e9c 100644 --- a/deployment/src/main/java/io/quarkiverse/statiq/deployment/StatiqProcessor.java +++ b/deployment/src/main/java/io/quarkiverse/statiq/deployment/StatiqProcessor.java @@ -7,11 +7,13 @@ import jakarta.inject.Singleton; +import io.quarkiverse.statiq.runtime.FixedStaticPagesProvider; import io.quarkiverse.statiq.runtime.StatiqGenerator; import io.quarkiverse.statiq.runtime.StatiqGeneratorConfig; import io.quarkiverse.statiq.runtime.StatiqRecorder; import io.quarkus.arc.deployment.AdditionalBeanBuildItem; import io.quarkus.arc.deployment.SyntheticBeanBuildItem; +import io.quarkus.deployment.annotations.BuildProducer; import io.quarkus.deployment.annotations.BuildStep; import io.quarkus.deployment.annotations.ExecutionTime; import io.quarkus.deployment.annotations.Record; @@ -19,9 +21,8 @@ import io.quarkus.deployment.pkg.builditem.OutputTargetBuildItem; import io.quarkus.vertx.http.deployment.NonApplicationRootPathBuildItem; import io.quarkus.vertx.http.deployment.RouteBuildItem; -import io.quarkus.vertx.http.deployment.VertxWebRouterBuildItem; import io.quarkus.vertx.http.deployment.devmode.NotFoundPageDisplayableEndpointBuildItem; -import io.quarkus.vertx.http.runtime.VertxHttpRecorder; +import io.quarkus.vertx.http.deployment.spi.StaticResourcesBuildItem; class StatiqProcessor { @@ -45,32 +46,38 @@ SyntheticBeanBuildItem produceGeneratorConfig(StatiqConfig config, OutputTargetB } @BuildStep - AdditionalBeanBuildItem produceStatiqGenerator() { - return AdditionalBeanBuildItem.unremovableOf(StatiqGenerator.class); + void produceBeans(BuildProducer additionalBeanProducer) { + additionalBeanProducer.produce(AdditionalBeanBuildItem.unremovableOf(StatiqGenerator.class)); + additionalBeanProducer.produce(AdditionalBeanBuildItem.unremovableOf(FixedStaticPagesProvider.class)); } @BuildStep @Record(ExecutionTime.RUNTIME_INIT) - void initHandler( - VertxWebRouterBuildItem router, + void initHandler(List notFoundPageDisplayableEndpoints, + StaticResourcesBuildItem staticResourcesBuildItem, + StatiqRecorder recorder) { + + Set staticPaths = new HashSet<>(staticResourcesBuildItem.getPaths()); + staticPaths.addAll(notFoundPageDisplayableEndpoints.stream() + .filter(not(NotFoundPageDisplayableEndpointBuildItem::isAbsolutePath)) + .map(NotFoundPageDisplayableEndpointBuildItem::getEndpoint) + .toList()); + recorder.setStatiqPages(staticPaths); + } + + @BuildStep + @Record(ExecutionTime.RUNTIME_INIT) + void initHandler(BuildProducer routes, NonApplicationRootPathBuildItem nonApplicationRootPath, - List notFoundPageDisplayableEndpoints, - StatiqRecorder recorder, - VertxHttpRecorder vertxHttpRecorder) { + StatiqRecorder recorder) { final RouteBuildItem route = nonApplicationRootPath.routeBuilder() .management() .route("statiq/generate") - .handler(recorder.createGenerateHandler(notFoundPageDisplayableEndpoints.stream() - .filter(not(NotFoundPageDisplayableEndpointBuildItem::isAbsolutePath)) - .map(NotFoundPageDisplayableEndpointBuildItem::getEndpoint) - .toList())) + .handler(recorder.createGenerateHandler()) .build(); - // Can't use RouteBuildItem because of cycles - if (router.getFrameworkRouter() != null) { - vertxHttpRecorder.addRoute(router.getFrameworkRouter(), route.getRouteFunction(), route.getHandler(), - route.getType()); - } + + routes.produce(route); } diff --git a/deployment/src/main/java/io/quarkiverse/statiq/deployment/devui/StatiqDevUIProcessor.java b/deployment/src/main/java/io/quarkiverse/statiq/deployment/devui/StatiqDevUIProcessor.java new file mode 100644 index 00000000..788b5142 --- /dev/null +++ b/deployment/src/main/java/io/quarkiverse/statiq/deployment/devui/StatiqDevUIProcessor.java @@ -0,0 +1,28 @@ +package io.quarkiverse.statiq.deployment.devui; + +import io.quarkiverse.statiq.runtime.devui.StatiqJsonRPCService; +import io.quarkus.deployment.IsDevelopment; +import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.pkg.builditem.CurateOutcomeBuildItem; +import io.quarkus.devui.spi.JsonRPCProvidersBuildItem; +import io.quarkus.devui.spi.page.CardPageBuildItem; +import io.quarkus.devui.spi.page.Page; + +public class StatiqDevUIProcessor { + @BuildStep(onlyIf = IsDevelopment.class) + CardPageBuildItem create(CurateOutcomeBuildItem bi) { + CardPageBuildItem pageBuildItem = new CardPageBuildItem(); + pageBuildItem.addPage(Page.webComponentPageBuilder() + .title("Pages") + .componentLink("qwc-statiq.js") + .icon("font-awesome-solid:link")); + + return pageBuildItem; + } + + @BuildStep(onlyIf = IsDevelopment.class) + JsonRPCProvidersBuildItem createJsonRPCServiceForCache() { + return new JsonRPCProvidersBuildItem(StatiqJsonRPCService.class); + } + +} diff --git a/deployment/src/main/resources/dev-ui/qwc-statiq.js b/deployment/src/main/resources/dev-ui/qwc-statiq.js new file mode 100644 index 00000000..a3da37eb --- /dev/null +++ b/deployment/src/main/resources/dev-ui/qwc-statiq.js @@ -0,0 +1,117 @@ +import { LitElement, html, css} from 'lit'; +import { JsonRpc } from 'jsonrpc'; +import '@vaadin/icon'; +import '@vaadin/button'; +import '@vaadin/text-field'; +import '@vaadin/text-area'; +import '@vaadin/form-layout'; +import '@vaadin/progress-bar'; +import '@vaadin/checkbox'; +import '@vaadin/grid'; +import { columnBodyRenderer } from '@vaadin/grid/lit.js'; +import '@vaadin/grid/vaadin-grid-sort-column.js'; + +export class QwcStatiq extends LitElement { + + jsonRpc = new JsonRpc(this); + + // Component style + static styles = css` + .button { + background-color: transparent; + cursor: pointer; + } + .clearIcon { + color: orange; + } + `; + + // Component properties + static properties = { + "_pages": {state: true}, + } + + constructor() { + super(); + } + + // Components callbacks + + /** + * Called when displayed + */ + connectedCallback() { + super.connectedCallback(); + this.jsonRpc.getPages().then(jsonRpcResponse => { + this._pages = []; + jsonRpcResponse.result.forEach(c => { + this._pages.push(c); + }); + }); + } + + /** + * Called when it needs to render the components + * @returns {*} + */ + render() { + if (this._pages) { + return this._renderTable(); + } else { + return html`Loading pages...`; + } + } + + // View / Templates + + _renderTable() { + return html` + + + + + + + + + + + + + + `; + } + + _fileRenderer(page) { + return html`${page.outputPath}`; + } + + _pathRenderer(page) { + return html`${page.path}`; + } + + _linkRenderer(page) { + return html``; + } + + + +} +customElements.define('qwc-statiq', QwcStatiq); \ No newline at end of file diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 0b5f08f4..5b592e82 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -17,7 +17,17 @@ io.quarkus - quarkus-resteasy-reactive + quarkus-rest + + + io.quarkiverse.web-bundler + quarkus-web-bundler + 999-SNAPSHOT + + + io.quarkiverse.qute.web + quarkus-qute-web + 3.0.0 io.quarkiverse.statiq diff --git a/integration-tests/src/main/java/io/quarkiverse/statiq/it/StatiqResource.java b/integration-tests/src/main/java/io/quarkiverse/statiq/it/StatiqResource.java index bbf7f4cd..939af33c 100644 --- a/integration-tests/src/main/java/io/quarkiverse/statiq/it/StatiqResource.java +++ b/integration-tests/src/main/java/io/quarkiverse/statiq/it/StatiqResource.java @@ -1,24 +1,34 @@ /* -* Licensed to the Apache Software Foundation (ASF) under one or more -* contributor license agreements. See the NOTICE file distributed with -* this work for additional information regarding copyright ownership. -* The ASF licenses this file to You 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. -*/ + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 io.quarkiverse.statiq.it; +import java.util.List; + import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Singleton; +import jakarta.transaction.Transactional; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.MediaType; + +import io.quarkiverse.statiq.runtime.StatiqPage; +import io.quarkiverse.statiq.runtime.StatiqPages; @Path("/statiq") @ApplicationScoped @@ -26,7 +36,18 @@ public class StatiqResource { // add some rest methods here @GET - public String hello() { - return "Hello statiq"; + @Produces(MediaType.TEXT_PLAIN) + public String hello(@QueryParam("name") String name) { + return "Hello " + name; } + + @Produces + @Singleton + @Transactional + StatiqPages produce() { + return new StatiqPages(List.of( + new StatiqPage("/statiq?name=foo"), + new StatiqPage("/statiq?name=bar"))); + } + } diff --git a/integration-tests/src/main/resources/META-INF/resources/assets/vector.svg b/integration-tests/src/main/resources/META-INF/resources/assets/vector.svg new file mode 100644 index 00000000..b1da66af --- /dev/null +++ b/integration-tests/src/main/resources/META-INF/resources/assets/vector.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/integration-tests/src/main/resources/application.properties b/integration-tests/src/main/resources/application.properties index e69de29b..08fba159 100644 --- a/integration-tests/src/main/resources/application.properties +++ b/integration-tests/src/main/resources/application.properties @@ -0,0 +1 @@ +quarkus.statiq.fixed=/,/static/**,/assets/**,/some-page \ No newline at end of file diff --git a/integration-tests/src/main/resources/templates/pub/some-page.html b/integration-tests/src/main/resources/templates/pub/some-page.html new file mode 100644 index 00000000..039f59be --- /dev/null +++ b/integration-tests/src/main/resources/templates/pub/some-page.html @@ -0,0 +1,2 @@ +

Hello

+ \ No newline at end of file diff --git a/integration-tests/src/main/resources/web/index.html b/integration-tests/src/main/resources/web/index.html new file mode 100644 index 00000000..b45834c5 --- /dev/null +++ b/integration-tests/src/main/resources/web/index.html @@ -0,0 +1,2 @@ +

Hello

+ \ No newline at end of file diff --git a/integration-tests/src/main/resources/web/static/logo.svg b/integration-tests/src/main/resources/web/static/logo.svg new file mode 100644 index 00000000..938db5b4 --- /dev/null +++ b/integration-tests/src/main/resources/web/static/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/integration-tests/src/test/java/io/quarkiverse/statiq/it/StatiqResourceTest.java b/integration-tests/src/test/java/io/quarkiverse/statiq/it/StatiqResourceTest.java index c993bd45..9b658b61 100644 --- a/integration-tests/src/test/java/io/quarkiverse/statiq/it/StatiqResourceTest.java +++ b/integration-tests/src/test/java/io/quarkiverse/statiq/it/StatiqResourceTest.java @@ -1,7 +1,11 @@ package io.quarkiverse.statiq.it; import static io.restassured.RestAssured.given; -import static org.hamcrest.Matchers.is; +import static java.nio.file.Files.exists; +import static org.hamcrest.Matchers.*; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.nio.file.Path; import org.junit.jupiter.api.Test; @@ -13,9 +17,27 @@ public class StatiqResourceTest { @Test public void testHelloEndpoint() { given() - .when().get("/statiq") + .when().get("/statiq?name=statiq") .then() .statusCode(200) .body(is("Hello statiq")); } + + @Test + public void testGenerate() { + given() + .baseUri("http://localhost:9001") + .when().get("/q/statiq/generate") + .then() + .statusCode(200) + .body(startsWith("Generated in:")) + .body(endsWith("/target/statiq")); + + assertTrue(exists(Path.of("target/statiq/index.html"))); + assertTrue(exists(Path.of("target/statiq/some-page"))); + assertTrue(exists(Path.of("target/statiq/statiq-name-bar"))); + assertTrue(exists(Path.of("target/statiq/statiq-name-foo"))); + assertTrue(exists(Path.of("target/statiq/assets/vector.svg"))); + assertTrue(exists(Path.of("target/statiq/static/logo.svg"))); + } } diff --git a/integration-tests/src/test/resources/application.properties b/integration-tests/src/test/resources/application.properties new file mode 100644 index 00000000..882657a8 --- /dev/null +++ b/integration-tests/src/test/resources/application.properties @@ -0,0 +1 @@ +quarkus.management.enabled=true \ No newline at end of file diff --git a/runtime/src/main/java/io/quarkiverse/statiq/runtime/FixedStaticPagesProvider.java b/runtime/src/main/java/io/quarkiverse/statiq/runtime/FixedStaticPagesProvider.java new file mode 100644 index 00000000..5871a8e3 --- /dev/null +++ b/runtime/src/main/java/io/quarkiverse/statiq/runtime/FixedStaticPagesProvider.java @@ -0,0 +1,52 @@ +package io.quarkiverse.statiq.runtime; + +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.PathMatcher; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import jakarta.enterprise.inject.Produces; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; + +@Singleton +public class FixedStaticPagesProvider { + @Inject + StatiqGeneratorConfig config; + + private static volatile Set staticPaths; + + public static void setStaticPaths(Set staticPaths) { + FixedStaticPagesProvider.staticPaths = staticPaths; + } + + @Produces + @Singleton + StatiqPages produce() { + List statiqPages = new ArrayList<>(); + for (String p : config.fixedPaths) { + + if (!isGlobPattern(p) && p.startsWith("/")) { + // fixed paths are directly added + statiqPages.add(new StatiqPage(p, PageType.FIXED)); + continue; + } + // Try to detect fixed paths from glob pattern + for (String staticPath : staticPaths) { + PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:" + p); + if (matcher.matches(Path.of(staticPath))) { + statiqPages.add(new StatiqPage(staticPath, PageType.FIXED)); + } + } + } + return new StatiqPages(statiqPages); + } + + private static boolean isGlobPattern(String s) { + // Check if the string contains any glob pattern special characters + return s.contains("*") || s.contains("?") || s.contains("{") || s.contains("}") || s.contains("[") || s.contains("]") + || s.contains("**"); + } +} diff --git a/runtime/src/main/java/io/quarkiverse/statiq/runtime/PageType.java b/runtime/src/main/java/io/quarkiverse/statiq/runtime/PageType.java new file mode 100644 index 00000000..9b3520c8 --- /dev/null +++ b/runtime/src/main/java/io/quarkiverse/statiq/runtime/PageType.java @@ -0,0 +1,6 @@ +package io.quarkiverse.statiq.runtime; + +public enum PageType { + FIXED, + PROVIDED +} diff --git a/runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqGenerator.java b/runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqGenerator.java index 210bc56d..afb6f510 100644 --- a/runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqGenerator.java +++ b/runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqGenerator.java @@ -1,15 +1,12 @@ package io.quarkiverse.statiq.runtime; -import java.nio.file.FileSystems; import java.nio.file.Path; -import java.nio.file.PathMatcher; -import java.util.ArrayList; -import java.util.List; +import java.util.*; import java.util.concurrent.CompletionStage; +import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.inject.Instance; import jakarta.inject.Inject; -import jakarta.inject.Singleton; import io.quarkus.arc.All; import io.smallrye.mutiny.Uni; @@ -23,19 +20,20 @@ import io.vertx.ext.web.client.HttpResponse; import io.vertx.ext.web.client.WebClient; -@Singleton +@ApplicationScoped public class StatiqGenerator implements Handler { private final Instance vertx; private final StatiqGeneratorConfig config; private WebClient client; - private final List statiqPages = new ArrayList<>(); + private final List statiqPages; @Inject public StatiqGenerator(final Instance vertx, final StatiqGeneratorConfig config, @All final List statiqPages) { this.vertx = vertx; this.config = config; - this.statiqPages.addAll(statiqPages.stream().map(StatiqPages::pages).flatMap(List::stream).toList()); + this.statiqPages = statiqPages.stream().map(StatiqPages::pages).flatMap(List::stream) + .sorted(Comparator.comparing(StatiqPage::outputPath)).toList(); } private WebClient client() { @@ -45,33 +43,15 @@ private WebClient client() { return client; } - public void addFixedStaticPages(List staticPaths) { - for (String p : config.fixedPaths) { - if (!isGlobPattern(p) && p.startsWith("/")) { - // fixed paths are directly added - this.statiqPages.add(new StatiqPage(p)); - continue; - } - // Try to detect fixed paths from glob pattern - for (String staticPath : staticPaths) { - PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:" + p); - if (matcher.matches(Path.of(staticPath))) { - this.statiqPages.add(new StatiqPage(staticPath)); - } - } - } - } - @Override public void handle(RoutingContext event) { final FileSystem fs = vertx.get().fileSystem(); final List> all = new ArrayList<>(); final Path outputDir = Path.of(config.outputDir).toAbsolutePath(); - final List paths = this.statiqPages.stream().map(StatiqPage::path).toList(); - for (String path : paths) { - all.add(Uni.createFrom().completionStage(() -> fetchContent(event.request(), path)) + for (StatiqPage page : this.statiqPages) { + all.add(Uni.createFrom().completionStage(() -> fetchContent(event.request(), page.path())) .chain(r -> { - final Path targetPath = computeStatiqPath(outputDir, path); + final Path targetPath = outputDir.resolve(page.outputPath()); return Uni.createFrom() .completionStage(() -> fs.mkdirs(targetPath.getParent().toString()).toCompletionStage()) .chain(() -> Uni.createFrom().completionStage(fs @@ -95,26 +75,9 @@ public void handle(RoutingContext event) { } - private static Path computeStatiqPath(Path outputDir, String path) { - String statiqPath = path; - if (statiqPath.endsWith("/")) { - statiqPath += "index.html"; - } - if (statiqPath.startsWith("/")) { - statiqPath = statiqPath.substring(1); - } - return outputDir.resolve(statiqPath).toAbsolutePath(); - } - private CompletionStage> fetchContent(HttpServerRequest request, String path) { return client().get(request.localAddress().port(), "localhost", path) .send().toCompletionStage(); } - private static boolean isGlobPattern(String s) { - // Check if the string contains any glob pattern special characters - return s.contains("*") || s.contains("?") || s.contains("{") || s.contains("}") || s.contains("[") || s.contains("]") - || s.contains("**"); - } - } diff --git a/runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqPage.java b/runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqPage.java index 1cd895b0..c59d001f 100644 --- a/runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqPage.java +++ b/runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqPage.java @@ -1,4 +1,34 @@ package io.quarkiverse.statiq.runtime; -public record StatiqPage(String path) { +import java.util.regex.Pattern; + +public record StatiqPage(String path, PageType type, String outputPath) { + + private static final Pattern NON_FILE_CHARS = Pattern.compile("[^a-zA-Z0-9\\\\/.]"); + + public StatiqPage(String path, PageType type) { + this(path, type, defaultOutputPath(path)); + } + + public StatiqPage(String path) { + this(path, PageType.PROVIDED); + } + + public static String defaultOutputPath(String path) { + String statiqPath = path; + if (statiqPath.endsWith("/")) { + statiqPath = cleanPath(statiqPath) + "index.html"; + } else if (NON_FILE_CHARS.matcher(path).find()) { + statiqPath = cleanPath(statiqPath); + } + if (statiqPath.startsWith("/")) { + statiqPath = statiqPath.substring(1); + } + return statiqPath; + } + + private static String cleanPath(String statiqPath) { + return NON_FILE_CHARS.matcher(statiqPath).replaceAll("-"); + } + } diff --git a/runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqPages.java b/runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqPages.java index 958cc96e..6fce1218 100644 --- a/runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqPages.java +++ b/runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqPages.java @@ -1,6 +1,12 @@ package io.quarkiverse.statiq.runtime; +import java.util.Comparator; import java.util.List; public record StatiqPages(List pages) { + + public static List merge(List statiqPages) { + return statiqPages.stream().map(StatiqPages::pages).flatMap(List::stream) + .sorted(Comparator.comparing(StatiqPage::outputPath)).toList(); + } } \ No newline at end of file diff --git a/runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqRecorder.java b/runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqRecorder.java index 2ed05642..261f79c9 100644 --- a/runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqRecorder.java +++ b/runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqRecorder.java @@ -1,6 +1,7 @@ package io.quarkiverse.statiq.runtime; import java.util.List; +import java.util.Set; import io.quarkus.arc.Arc; import io.quarkus.arc.InstanceHandle; @@ -21,10 +22,12 @@ public StatiqGeneratorConfig getValue() { }; } - public Handler createGenerateHandler(List staticPaths) { + public void setStatiqPages(Set staticPaths) { + FixedStaticPagesProvider.setStaticPaths(staticPaths); + } + + public Handler createGenerateHandler() { final InstanceHandle generatorInstanceHandle = Arc.container().instance(StatiqGenerator.class); - final StatiqGenerator statiqGenerator = generatorInstanceHandle.get(); - statiqGenerator.addFixedStaticPages(staticPaths); - return statiqGenerator; + return generatorInstanceHandle.get(); } } diff --git a/runtime/src/main/java/io/quarkiverse/statiq/runtime/devui/StatiqJsonRPCService.java b/runtime/src/main/java/io/quarkiverse/statiq/runtime/devui/StatiqJsonRPCService.java new file mode 100644 index 00000000..ea381af0 --- /dev/null +++ b/runtime/src/main/java/io/quarkiverse/statiq/runtime/devui/StatiqJsonRPCService.java @@ -0,0 +1,29 @@ +package io.quarkiverse.statiq.runtime.devui; + +import java.util.List; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import io.quarkiverse.statiq.runtime.StatiqGenerator; +import io.quarkiverse.statiq.runtime.StatiqPage; +import io.quarkiverse.statiq.runtime.StatiqPages; +import io.quarkus.arc.All; +import io.smallrye.common.annotation.NonBlocking; + +@ApplicationScoped +public class StatiqJsonRPCService { + + @All + @Inject + List statiqPages; + + @Inject + StatiqGenerator generator; + + @NonBlocking + public List getPages() { + return StatiqPages.merge(statiqPages); + } + +}