From 8e636e5d3655f8fe1f7b2647cade110233d35133 Mon Sep 17 00:00:00 2001 From: Clement Escoffier Date: Thu, 2 Mar 2023 15:46:42 +0100 Subject: [PATCH] Initial version of the config editor page Incomplete: - Missing the wildcard support - Missing the filter per extension support - Missing the application.properties editor --- bom/application/pom.xml | 6 + .../deployment/BuildTimeContentProcessor.java | 225 +++++++----- .../console/ConfigEditorProcessor.java | 18 +- .../vertx-http/dev-ui-resources/pom.xml | 5 + .../resources/dev-ui/qwc/qwc-configuration.js | 336 ++++++++++++++++-- .../devui/runtime/ConfigJsonRpcService.java | 31 ++ .../runtime/config/VertxConfiguration.java | 2 +- 7 files changed, 508 insertions(+), 115 deletions(-) create mode 100644 extensions/vertx-http/runtime/src/main/java/io/quarkus/devui/runtime/ConfigJsonRpcService.java diff --git a/bom/application/pom.xml b/bom/application/pom.xml index d41300b3b26d8..89bf5065227d5 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -3331,6 +3331,12 @@ ${vaadin.version} runtime + + org.mvnpm.at.vaadin + integer-field + ${vaadin.version} + runtime + org.mvnpm.at.vaadin field-base diff --git a/extensions/vertx-http/deployment/src/main/java/io/quarkus/devui/deployment/BuildTimeContentProcessor.java b/extensions/vertx-http/deployment/src/main/java/io/quarkus/devui/deployment/BuildTimeContentProcessor.java index 3d2e0a462714b..ea83ad71d668b 100644 --- a/extensions/vertx-http/deployment/src/main/java/io/quarkus/devui/deployment/BuildTimeContentProcessor.java +++ b/extensions/vertx-http/deployment/src/main/java/io/quarkus/devui/deployment/BuildTimeContentProcessor.java @@ -1,5 +1,8 @@ package io.quarkus.devui.deployment; +import static io.quarkus.vertx.http.deployment.devmode.console.ConfigEditorProcessor.cleanUpAsciiDocIfNecessary; +import static io.quarkus.vertx.http.deployment.devmode.console.ConfigEditorProcessor.isSetByDevServices; + import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -13,7 +16,10 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; +import java.util.regex.Pattern; +import java.util.stream.Collectors; import org.eclipse.microprofile.config.Config; import org.eclipse.microprofile.config.ConfigProvider; @@ -27,6 +33,8 @@ import io.quarkus.deployment.IsDevelopment; import io.quarkus.deployment.annotations.BuildProducer; import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.builditem.ConfigDescriptionBuildItem; +import io.quarkus.deployment.builditem.DevServicesLauncherConfigResultBuildItem; import io.quarkus.deployment.dev.devservices.DevServiceDescriptionBuildItem; import io.quarkus.deployment.pkg.builditem.CurateOutcomeBuildItem; import io.quarkus.deployment.util.IoUtil; @@ -41,6 +49,7 @@ import io.quarkus.devui.spi.page.Page; import io.quarkus.devui.spi.page.PageBuilder; import io.quarkus.vertx.http.deployment.NonApplicationRootPathBuildItem; +import io.quarkus.vertx.http.runtime.devmode.ConfigDescription; /** * This creates static content that is used in dev UI. For example the index.html and any other data (json) available on build @@ -283,7 +292,9 @@ void createBuildTimeData(BuildProducer buildTimeConstPr BuildProducer themeVarsProducer, ExtensionsBuildItem extensionsBuildItem, List menuPageBuildItems, - List DevServiceDescriptions) { + List devServiceDescriptions, + List configDescriptionBuildItems, + Optional devServicesLauncherConfig) { BuildTimeConstBuildItem internalBuildTimeData = new BuildTimeConstBuildItem(AbstractDevUIBuildItem.DEV_UI); @@ -292,6 +303,101 @@ void createBuildTimeData(BuildProducer buildTimeConstPr Map dark = new HashMap<>(); Map light = new HashMap<>(); + computeColors(themes, dark, light); + + internalBuildTimeData.addBuildTimeData("themes", themes); + + // Extensions + Map> response = Map.of( + ExtensionGroup.active, extensionsBuildItem.getActiveExtensions(), + ExtensionGroup.inactive, extensionsBuildItem.getInactiveExtensions()); + + internalBuildTimeData.addBuildTimeData("extensions", response); + + // Sections Menu + Page extensions = Page.webComponentPageBuilder().internal() + .title("Extensions") + .icon("font-awesome-solid:puzzle-piece") + .componentLink("qwc-extensions.js").build(); + + Page configuration = Page.webComponentPageBuilder().internal() + .title("Configuration") + .icon("font-awesome-solid:sliders") + .componentLink("qwc-configuration.js").build(); + + internalBuildTimeData.addBuildTimeData("allConfiguration", + getAllConfig(configDescriptionBuildItems, devServicesLauncherConfig)); + + Page continuousTesting = Page.webComponentPageBuilder().internal() + .title("Continuous Testing") + .icon("font-awesome-solid:flask-vial") + .componentLink("qwc-continuous-testing.js").build(); + + internalBuildTimeData.addBuildTimeData("continuousTesting", "TODO: Continuous Testing"); + + Page devServices = Page.webComponentPageBuilder().internal() + .title("Dev services") + .icon("font-awesome-solid:wand-magic-sparkles") + .componentLink("qwc-dev-services.js").build(); + + internalBuildTimeData.addBuildTimeData("devServices", devServiceDescriptions); + + Page buildSteps = Page.webComponentPageBuilder().internal() + .title("Build steps") + .icon("font-awesome-solid:hammer") + .componentLink("qwc-build-steps.js").build(); + + internalBuildTimeData.addBuildTimeData("buildSteps", "TODO: Build Steps"); + + // Add default menu items + @SuppressWarnings("unchecked") + List sectionMenu = new ArrayList(List.of(extensions, configuration, continuousTesting, devServices, buildSteps)); + + // Add any Menus from extensions + for (Extension e : extensionsBuildItem.getSectionMenuExtensions()) { + List pagesFromExtension = e.getMenuPages(); + sectionMenu.addAll(pagesFromExtension); + } + + internalBuildTimeData.addBuildTimeData("menuItems", sectionMenu); + + // Add the Footer tabs + Page serverLog = Page.webComponentPageBuilder().internal() + .title("Server") + .icon("font-awesome-solid:server") + .componentLink("qwc-server-log.js").build(); + + Page devUiLog = Page.webComponentPageBuilder().internal() + .title("Dev UI") + .icon("font-awesome-solid:satellite-dish") + .componentLink("qwc-jsonrpc-messages.js").build(); + + @SuppressWarnings("unchecked") + List footerTabs = new ArrayList(List.of(serverLog, devUiLog)); + + // Add any Footer tabs from extensions + for (Extension e : extensionsBuildItem.getFooterTabsExtensions()) { + List tabsFromExtension = e.getFooterPages(); + footerTabs.addAll(tabsFromExtension); + } + + internalBuildTimeData.addBuildTimeData("footerTabs", footerTabs); + + // Add version info + Map applicationInfo = new HashMap<>(); + applicationInfo.put("quarkusVersion", Version.getVersion()); + applicationInfo.put("applicationName", config.getOptionalValue("quarkus.application.name", String.class).orElse("")); + applicationInfo.put("applicationVersion", + config.getOptionalValue("quarkus.application.version", String.class).orElse("")); + internalBuildTimeData.addBuildTimeData("applicationInfo", applicationInfo); + + buildTimeConstProducer.produce(internalBuildTimeData); + + themeVarsProducer.produce(new ThemeVarsBuildItem(light.keySet(), QUARKUS_BLUE.toString())); + } + + private static void computeColors(Map> themes, Map dark, + Map light) { // Quarkus logo colors light.put("--quarkus-blue", QUARKUS_BLUE.toString()); dark.put("--quarkus-blue", QUARKUS_BLUE.toString()); @@ -382,95 +488,22 @@ void createBuildTimeData(BuildProducer buildTimeConstPr themes.put("dark", dark); themes.put("light", light); + } - internalBuildTimeData.addBuildTimeData("themes", themes); - - // Extensions - Map> response = Map.of( - ExtensionGroup.active, extensionsBuildItem.getActiveExtensions(), - ExtensionGroup.inactive, extensionsBuildItem.getInactiveExtensions()); - - internalBuildTimeData.addBuildTimeData("extensions", response); - - // Sections Menu - Page extensions = Page.webComponentPageBuilder().internal() - .title("Extensions") - .icon("font-awesome-solid:puzzle-piece") - .componentLink("qwc-extensions.js").build(); - - Page configuration = Page.webComponentPageBuilder().internal() - .title("Configuration") - .icon("font-awesome-solid:sliders") - .componentLink("qwc-configuration.js").build(); - - internalBuildTimeData.addBuildTimeData("allConfiguration", "TODO: Configuration"); - - Page continuousTesting = Page.webComponentPageBuilder().internal() - .title("Continuous Testing") - .icon("font-awesome-solid:flask-vial") - .componentLink("qwc-continuous-testing.js").build(); - - internalBuildTimeData.addBuildTimeData("continuousTesting", "TODO: Continuous Testing"); - - Page devServices = Page.webComponentPageBuilder().internal() - .title("Dev services") - .icon("font-awesome-solid:wand-magic-sparkles") - .componentLink("qwc-dev-services.js").build(); - - internalBuildTimeData.addBuildTimeData("devServices", DevServiceDescriptions); - - Page buildSteps = Page.webComponentPageBuilder().internal() - .title("Build steps") - .icon("font-awesome-solid:hammer") - .componentLink("qwc-build-steps.js").build(); - - internalBuildTimeData.addBuildTimeData("buildSteps", "TODO: Build Steps"); - - // Add default menu items - @SuppressWarnings("unchecked") - List sectionMenu = new ArrayList(List.of(extensions, configuration, continuousTesting, devServices, buildSteps)); - - // Add any Menus from extensions - for (Extension e : extensionsBuildItem.getSectionMenuExtensions()) { - List pagesFromExtension = e.getMenuPages(); - sectionMenu.addAll(pagesFromExtension); + private List getAllConfig(List configDescriptionBuildItems, + Optional devServicesLauncherConfig) { + List configDescriptions = new ArrayList<>(); + for (ConfigDescriptionBuildItem item : configDescriptionBuildItems) { + configDescriptions.add( + new ConfigDescription(item.getPropertyName(), + formatJavadoc(cleanUpAsciiDocIfNecessary(item.getDocs())), + item.getDefaultValue(), + isSetByDevServices(devServicesLauncherConfig, item.getPropertyName()), + item.getValueTypeName(), + item.getAllowedValues(), + item.getConfigPhase().name())); } - - internalBuildTimeData.addBuildTimeData("menuItems", sectionMenu); - - // Add the Footer tabs - Page serverLog = Page.webComponentPageBuilder().internal() - .title("Server") - .icon("font-awesome-solid:server") - .componentLink("qwc-server-log.js").build(); - - Page devUiLog = Page.webComponentPageBuilder().internal() - .title("Dev UI") - .icon("font-awesome-solid:satellite-dish") - .componentLink("qwc-jsonrpc-messages.js").build(); - - @SuppressWarnings("unchecked") - List footerTabs = new ArrayList(List.of(serverLog, devUiLog)); - - // Add any Footer tabs from extensions - for (Extension e : extensionsBuildItem.getFooterTabsExtensions()) { - List tabsFromExtension = e.getFooterPages(); - footerTabs.addAll(tabsFromExtension); - } - - internalBuildTimeData.addBuildTimeData("footerTabs", footerTabs); - - // Add version info - Map applicationInfo = new HashMap<>(); - applicationInfo.put("quarkusVersion", Version.getVersion()); - applicationInfo.put("applicationName", config.getOptionalValue("quarkus.application.name", String.class).orElse("")); - applicationInfo.put("applicationVersion", - config.getOptionalValue("quarkus.application.version", String.class).orElse("")); - internalBuildTimeData.addBuildTimeData("applicationInfo", applicationInfo); - - buildTimeConstProducer.produce(internalBuildTimeData); - - themeVarsProducer.produce(new ThemeVarsBuildItem(light.keySet(), QUARKUS_BLUE.toString())); + return configDescriptions; } private static final Color QUARKUS_BLUE = Color.from(211, 63, 54); @@ -531,4 +564,20 @@ static Color from(int hue, int saturation, int lightness, double alpha) { return new Color(hue, saturation, lightness, alpha); } } + + private static final Pattern codePattern = Pattern.compile("(\\{@code )([^}]+)(\\})"); + private static final Pattern linkPattern = Pattern.compile("(\\{@link )([^}]+)(\\})"); + + static String formatJavadoc(String val) { + if (val == null) { + return val; + } + // Replace {@code} and {@link} + val = codePattern.matcher(val).replaceAll("$2"); + val = linkPattern.matcher(val).replaceAll("$2"); + // Add br before @see and @deprecated + val = val.lines().filter(s -> !s.startsWith("@see")).collect(Collectors.joining("\n")); + val = val.replace("@deprecated", "
Deprecated"); + return val; + } } diff --git a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/devmode/console/ConfigEditorProcessor.java b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/devmode/console/ConfigEditorProcessor.java index abb3c93e65cc6..fc28b82441960 100644 --- a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/devmode/console/ConfigEditorProcessor.java +++ b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/devmode/console/ConfigEditorProcessor.java @@ -44,6 +44,8 @@ import io.quarkus.devconsole.runtime.spi.DevConsolePostHandler; import io.quarkus.devconsole.spi.DevConsoleRouteBuildItem; import io.quarkus.devconsole.spi.DevConsoleRuntimeTemplateInfoBuildItem; +import io.quarkus.devui.runtime.ConfigJsonRpcService; +import io.quarkus.devui.spi.JsonRPCProvidersBuildItem; import io.quarkus.vertx.http.runtime.devmode.ConfigDescription; import io.quarkus.vertx.http.runtime.devmode.ConfigDescriptionsManager; import io.quarkus.vertx.http.runtime.devmode.ConfigDescriptionsRecorder; @@ -127,7 +129,7 @@ protected void handlePost(RoutingContext event, MultiMap form) throws Exception } - private String cleanUpAsciiDocIfNecessary(String docs) { + public static String cleanUpAsciiDocIfNecessary(String docs) { if (docs == null || !docs.toLowerCase(Locale.ROOT).contains("@asciidoclet")) { return docs; } @@ -152,6 +154,16 @@ void handleRequests(BuildProducer devConsoleRouteProdu })); } + @BuildStep(onlyIf = IsDevelopment.class) + JsonRPCProvidersBuildItem registerJsonRpcService() { + DevConsoleManager.register("config-update-property", map -> { + Map values = Collections.singletonMap(map.get("name"), map.get("value")); + updateConfig(values); + return null; + }); + return new JsonRPCProvidersBuildItem("ConfigJsonRpcService", ConfigJsonRpcService.class); + } + private Map filterAndApplyProfile(Map autoconfig, List configFilter, String profile) { return autoconfig.entrySet().stream() @@ -208,7 +220,7 @@ static byte[] getConfig() { } } - static void updateConfig(Map values) { + public static void updateConfig(Map values) { if (values != null && !values.isEmpty()) { try { Path configPath = getConfigPath(); @@ -292,7 +304,7 @@ private static Path getConfigPath() throws IOException { return configPath; } - private boolean isSetByDevServices(Optional devServicesLauncherConfig, + public static boolean isSetByDevServices(Optional devServicesLauncherConfig, String propertyName) { if (devServicesLauncherConfig.isPresent()) { return devServicesLauncherConfig.get().getConfig().containsKey(propertyName); diff --git a/extensions/vertx-http/dev-ui-resources/pom.xml b/extensions/vertx-http/dev-ui-resources/pom.xml index 3340d14edca2e..ccb78699d4b24 100644 --- a/extensions/vertx-http/dev-ui-resources/pom.xml +++ b/extensions/vertx-http/dev-ui-resources/pom.xml @@ -131,6 +131,11 @@ number-field runtime
+ + org.mvnpm.at.vaadin + integer-field + runtime + org.mvnpm.at.vaadin field-base diff --git a/extensions/vertx-http/dev-ui-resources/src/main/resources/dev-ui/qwc/qwc-configuration.js b/extensions/vertx-http/dev-ui-resources/src/main/resources/dev-ui/qwc/qwc-configuration.js index 23f97335d38fc..6a5282d615949 100644 --- a/extensions/vertx-http/dev-ui-resources/src/main/resources/dev-ui/qwc/qwc-configuration.js +++ b/extensions/vertx-http/dev-ui-resources/src/main/resources/dev-ui/qwc/qwc-configuration.js @@ -1,30 +1,320 @@ -import { LitElement, html, css} from 'lit'; -import { allConfiguration } from 'devui-data'; +import {LitElement, html, css} from 'lit'; +import {allConfiguration} from 'devui-data'; +import { JsonRpc } from 'jsonrpc'; +import {until} from 'lit/directives/until.js'; +import '@vaadin/grid'; +import 'qui/qui-alert.js'; +import {columnBodyRenderer} from '@vaadin/grid/lit.js'; +import '@vaadin/grid/vaadin-grid-sort-column.js'; +import '@vaadin/icon'; +import '@vaadin/tooltip'; +import '@vaadin/checkbox'; +import '@vaadin/number-field'; +import '@vaadin/integer-field'; +import '@vaadin/text-field'; +import '@vaadin/select'; +import '@vaadin/vertical-layout'; +import '@vaadin/horizontal-layout'; +import '@vaadin/details'; +import { QuiAlert} from "qui/qui-alert.js"; +import { unsafeHTML } from 'lit/directives/unsafe-html.js'; +import {gridRowDetailsRenderer} from '@vaadin/grid/lit.js'; /** * This component allows users to change the configuration */ export class QwcConfiguration extends LitElement { - static styles = css` - .todo { - padding-left: 10px; - height: 100%; - }`; - - static properties = { - _configurations: {state: true} - }; - - constructor() { - super(); - this._configurations = allConfiguration; - } - - render() { - if(this._configurations){ - return html`
${this._configurations}
`; - } - } - + + jsonRpc = new JsonRpc("ConfigJsonRpcService"); + + static styles = css` + vaadin-grid { + height: 100%; + } + + vaadin-grid-cell-content { + vertical-align: top; + width: 100%; + } + + .description { + padding: 1em; + } + + .input-column { + width: 100%; + vertical-align: top; + } + + .top-align { + vertical-align: top; + } + + .full-height { + height: 100%; + } + + .save-button { + background-color: transparent; + cursor: pointer; + color: var(--lumo-primary-color); + } + + .lock-icon { + color: var(--lumo-error-color-50pct); + font-size: small; + } + .unlock-icon { + color: var(--lumo-success-color-50pct); + font-size: small; + } + `; + + static properties = { + _configurations: {state: true, type: Array}, + _filtered: {state: true, type: Array}, + _values: {state: true}, + _message: {state: true}, + _detailsOpenedItem: {state: true, type: Array} + }; + + constructor() { + super(); + this._configurations = allConfiguration; + this._filtered = allConfiguration; + this.jsonRpc.getAllValues().then(e => { + this._values = e.result; + }); + this._detailsOpenedItem = []; + } + + render() { + return html`${until(this._render(), html`Loading configuration properties...`)}`; + } + + _match(value, term) { + if (! value) { + return false; + } + return value.toLowerCase().includes(term.toLowerCase()); + } + + _filter(e) { + const searchTerm = (e.detail.value || '').trim(); + if (searchTerm === '') { + this._filtered = this._configurations; + return; + } + + this._filtered = this._configurations.filter((prop) => { + return this._match(prop.name, searchTerm) || this._match(prop.description, searchTerm) + }); + } + + _render() { + if (this._filtered && this._values) { + return html` + ${this._message} + + + + + + + + + + + + + `; + } + } + + _lockRenderer(prop) { + if (prop.configPhase === "BUILD_AND_RUN_TIME_FIXED" || prop.configPhase === "BUILD_TIME") { + return html` + + + ` + } else { + return html` + + + ` + } + } + + _nameRenderer(prop) { + let devservice = ""; + let wildcard = ""; + if (prop.autoFromDevServices) { + devservice = html` + + + ` + } + + if (prop.wildcardEntry) { + wildcard = html` + + + ` + } + + return html` + ${devservice}${wildcard}`; + } + + _valueRenderer(prop) { + let def = ''; + if (prop.defaultValue) { + def = "Default value: " + prop.defaultValue; + } else { + def = "No default value"; + } + + let actualValue = this._values[prop.name]; + if (!actualValue) { + actualValue = prop.defaultValue; + } + + if (prop.wildcardEntry) { + // TODO + } else if (prop.typeName === "java.lang.Boolean") { + return html` + + + ` + } else if (prop.typeName === "java.lang.Integer" || prop.typeName === "java.lang.Long") { + return html` + + + ` + } else if (prop.typeName === "java.lang.Float" || prop.typeName === "java.lang.Double") { + return html` + + + ` + } else if (prop.typeName === "java.lang.Enum" || prop.typeName === "java.util.logging.Level") { + let items = []; + let defaultValue = ''; + for (let idx in prop.allowedValues) { + if (prop.allowedValues[idx] === actualValue) { + defaultValue = prop.allowedValues[idx]; + } + items.push({ + 'label': prop.allowedValues[idx], + 'value': prop.allowedValues[idx], + }); + } + if (! defaultValue) { + defaultValue = prop.defaultValue; + } + return html` + + + ` + } else { + return html` + + + + + ` + } + } + + _descriptionRenderer(prop) { + let val = prop.name; + let res = ""; + for (let i = 0; i < val.length; i++) { + let c = val.charAt(i); + if ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9') { + res = res + c; + } else { + res = res + '_'; + if (c === '"' && i + 1 === val.length) { + res = res + '_'; + } + } + } + res = res.toUpperCase(); + let env = html` +
+ Environment variable: ${res} +
` + return html`

${unsafeHTML(prop.description)}

${env}
`; + } + + _updateTextProperty(property, event, val) { + event.preventDefault(); + let value = val; + if (!val) { + const input = this.shadowRoot.getElementById("input-" + property.name); + value = input.value; + } + this.jsonRpc.updateProperty({ + 'name': property.name, + 'value': value + }).then(e => { + this._values[property.name] = value; + this._message = html`` + }) + } + _updateBooleanProperty(property, event, value) { + event.preventDefault(); + this.jsonRpc.updateProperty({ + 'name': property.name, + 'value': value.toString() + }).then(e => { + this._values[property.name] = value; + this._message = html`` + }); + } + } + customElements.define('qwc-configuration', QwcConfiguration); \ No newline at end of file diff --git a/extensions/vertx-http/runtime/src/main/java/io/quarkus/devui/runtime/ConfigJsonRpcService.java b/extensions/vertx-http/runtime/src/main/java/io/quarkus/devui/runtime/ConfigJsonRpcService.java new file mode 100644 index 0000000000000..d344840787698 --- /dev/null +++ b/extensions/vertx-http/runtime/src/main/java/io/quarkus/devui/runtime/ConfigJsonRpcService.java @@ -0,0 +1,31 @@ +package io.quarkus.devui.runtime; + +import java.util.Map; + +import jakarta.enterprise.context.ApplicationScoped; + +import org.eclipse.microprofile.config.Config; +import org.eclipse.microprofile.config.ConfigProvider; + +import io.quarkus.dev.console.DevConsoleManager; +import io.vertx.core.json.JsonObject; + +@ApplicationScoped +public class ConfigJsonRpcService { + + public boolean updateProperty(String name, String value) { + System.out.println("setting " + name + " to " + value); + DevConsoleManager.invoke("config-update-property", Map.of("name", name, "value", value)); + return true; + } + + public JsonObject getAllValues() { + JsonObject values = new JsonObject(); + Config config = ConfigProvider.getConfig(); + for (String name : config.getPropertyNames()) { + values.put(name, config.getConfigValue(name).getValue()); + } + return values; + } + +} diff --git a/extensions/vertx/runtime/src/main/java/io/quarkus/vertx/core/runtime/config/VertxConfiguration.java b/extensions/vertx/runtime/src/main/java/io/quarkus/vertx/core/runtime/config/VertxConfiguration.java index 375dbcf200228..64956933fa62f 100644 --- a/extensions/vertx/runtime/src/main/java/io/quarkus/vertx/core/runtime/config/VertxConfiguration.java +++ b/extensions/vertx/runtime/src/main/java/io/quarkus/vertx/core/runtime/config/VertxConfiguration.java @@ -83,7 +83,7 @@ public class VertxConfiguration { /** * Prefill thread pool when creating a new Executor. - * When {@see io.vertx.core.spi.ExecutorServiceFactory.createExecutor} is called, + * When {@link io.vertx.core.spi.ExecutorServiceFactory#createExecutor} is called, * initialise with the number of defined threads at startup */ @ConfigItem(defaultValue = "false")