Skip to content

Commit 9579d9d

Browse files
Merge pull request #31553 from cescoffier/devui-config
Initial version of the config editor page
2 parents 2767f39 + 8e636e5 commit 9579d9d

File tree

7 files changed

+508
-115
lines changed

7 files changed

+508
-115
lines changed

bom/application/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3331,6 +3331,12 @@
33313331
<version>${vaadin.version}</version>
33323332
<scope>runtime</scope>
33333333
</dependency>
3334+
<dependency>
3335+
<groupId>org.mvnpm.at.vaadin</groupId>
3336+
<artifactId>integer-field</artifactId>
3337+
<version>${vaadin.version}</version>
3338+
<scope>runtime</scope>
3339+
</dependency>
33343340
<dependency>
33353341
<groupId>org.mvnpm.at.vaadin</groupId>
33363342
<artifactId>field-base</artifactId>

extensions/vertx-http/deployment/src/main/java/io/quarkus/devui/deployment/BuildTimeContentProcessor.java

Lines changed: 137 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package io.quarkus.devui.deployment;
22

3+
import static io.quarkus.vertx.http.deployment.devmode.console.ConfigEditorProcessor.cleanUpAsciiDocIfNecessary;
4+
import static io.quarkus.vertx.http.deployment.devmode.console.ConfigEditorProcessor.isSetByDevServices;
5+
36
import java.io.File;
47
import java.io.IOException;
58
import java.io.InputStream;
@@ -13,7 +16,10 @@
1316
import java.util.HashSet;
1417
import java.util.List;
1518
import java.util.Map;
19+
import java.util.Optional;
1620
import java.util.Set;
21+
import java.util.regex.Pattern;
22+
import java.util.stream.Collectors;
1723

1824
import org.eclipse.microprofile.config.Config;
1925
import org.eclipse.microprofile.config.ConfigProvider;
@@ -27,6 +33,8 @@
2733
import io.quarkus.deployment.IsDevelopment;
2834
import io.quarkus.deployment.annotations.BuildProducer;
2935
import io.quarkus.deployment.annotations.BuildStep;
36+
import io.quarkus.deployment.builditem.ConfigDescriptionBuildItem;
37+
import io.quarkus.deployment.builditem.DevServicesLauncherConfigResultBuildItem;
3038
import io.quarkus.deployment.dev.devservices.DevServiceDescriptionBuildItem;
3139
import io.quarkus.deployment.pkg.builditem.CurateOutcomeBuildItem;
3240
import io.quarkus.deployment.util.IoUtil;
@@ -41,6 +49,7 @@
4149
import io.quarkus.devui.spi.page.Page;
4250
import io.quarkus.devui.spi.page.PageBuilder;
4351
import io.quarkus.vertx.http.deployment.NonApplicationRootPathBuildItem;
52+
import io.quarkus.vertx.http.runtime.devmode.ConfigDescription;
4453

4554
/**
4655
* 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<BuildTimeConstBuildItem> buildTimeConstPr
283292
BuildProducer<ThemeVarsBuildItem> themeVarsProducer,
284293
ExtensionsBuildItem extensionsBuildItem,
285294
List<MenuPageBuildItem> menuPageBuildItems,
286-
List<DevServiceDescriptionBuildItem> DevServiceDescriptions) {
295+
List<DevServiceDescriptionBuildItem> devServiceDescriptions,
296+
List<ConfigDescriptionBuildItem> configDescriptionBuildItems,
297+
Optional<DevServicesLauncherConfigResultBuildItem> devServicesLauncherConfig) {
287298

288299
BuildTimeConstBuildItem internalBuildTimeData = new BuildTimeConstBuildItem(AbstractDevUIBuildItem.DEV_UI);
289300

@@ -292,6 +303,101 @@ void createBuildTimeData(BuildProducer<BuildTimeConstBuildItem> buildTimeConstPr
292303
Map<String, String> dark = new HashMap<>();
293304
Map<String, String> light = new HashMap<>();
294305

306+
computeColors(themes, dark, light);
307+
308+
internalBuildTimeData.addBuildTimeData("themes", themes);
309+
310+
// Extensions
311+
Map<ExtensionGroup, List<Extension>> response = Map.of(
312+
ExtensionGroup.active, extensionsBuildItem.getActiveExtensions(),
313+
ExtensionGroup.inactive, extensionsBuildItem.getInactiveExtensions());
314+
315+
internalBuildTimeData.addBuildTimeData("extensions", response);
316+
317+
// Sections Menu
318+
Page extensions = Page.webComponentPageBuilder().internal()
319+
.title("Extensions")
320+
.icon("font-awesome-solid:puzzle-piece")
321+
.componentLink("qwc-extensions.js").build();
322+
323+
Page configuration = Page.webComponentPageBuilder().internal()
324+
.title("Configuration")
325+
.icon("font-awesome-solid:sliders")
326+
.componentLink("qwc-configuration.js").build();
327+
328+
internalBuildTimeData.addBuildTimeData("allConfiguration",
329+
getAllConfig(configDescriptionBuildItems, devServicesLauncherConfig));
330+
331+
Page continuousTesting = Page.webComponentPageBuilder().internal()
332+
.title("Continuous Testing")
333+
.icon("font-awesome-solid:flask-vial")
334+
.componentLink("qwc-continuous-testing.js").build();
335+
336+
internalBuildTimeData.addBuildTimeData("continuousTesting", "TODO: Continuous Testing");
337+
338+
Page devServices = Page.webComponentPageBuilder().internal()
339+
.title("Dev services")
340+
.icon("font-awesome-solid:wand-magic-sparkles")
341+
.componentLink("qwc-dev-services.js").build();
342+
343+
internalBuildTimeData.addBuildTimeData("devServices", devServiceDescriptions);
344+
345+
Page buildSteps = Page.webComponentPageBuilder().internal()
346+
.title("Build steps")
347+
.icon("font-awesome-solid:hammer")
348+
.componentLink("qwc-build-steps.js").build();
349+
350+
internalBuildTimeData.addBuildTimeData("buildSteps", "TODO: Build Steps");
351+
352+
// Add default menu items
353+
@SuppressWarnings("unchecked")
354+
List<Page> sectionMenu = new ArrayList(List.of(extensions, configuration, continuousTesting, devServices, buildSteps));
355+
356+
// Add any Menus from extensions
357+
for (Extension e : extensionsBuildItem.getSectionMenuExtensions()) {
358+
List<Page> pagesFromExtension = e.getMenuPages();
359+
sectionMenu.addAll(pagesFromExtension);
360+
}
361+
362+
internalBuildTimeData.addBuildTimeData("menuItems", sectionMenu);
363+
364+
// Add the Footer tabs
365+
Page serverLog = Page.webComponentPageBuilder().internal()
366+
.title("Server")
367+
.icon("font-awesome-solid:server")
368+
.componentLink("qwc-server-log.js").build();
369+
370+
Page devUiLog = Page.webComponentPageBuilder().internal()
371+
.title("Dev UI")
372+
.icon("font-awesome-solid:satellite-dish")
373+
.componentLink("qwc-jsonrpc-messages.js").build();
374+
375+
@SuppressWarnings("unchecked")
376+
List<Page> footerTabs = new ArrayList(List.of(serverLog, devUiLog));
377+
378+
// Add any Footer tabs from extensions
379+
for (Extension e : extensionsBuildItem.getFooterTabsExtensions()) {
380+
List<Page> tabsFromExtension = e.getFooterPages();
381+
footerTabs.addAll(tabsFromExtension);
382+
}
383+
384+
internalBuildTimeData.addBuildTimeData("footerTabs", footerTabs);
385+
386+
// Add version info
387+
Map<String, String> applicationInfo = new HashMap<>();
388+
applicationInfo.put("quarkusVersion", Version.getVersion());
389+
applicationInfo.put("applicationName", config.getOptionalValue("quarkus.application.name", String.class).orElse(""));
390+
applicationInfo.put("applicationVersion",
391+
config.getOptionalValue("quarkus.application.version", String.class).orElse(""));
392+
internalBuildTimeData.addBuildTimeData("applicationInfo", applicationInfo);
393+
394+
buildTimeConstProducer.produce(internalBuildTimeData);
395+
396+
themeVarsProducer.produce(new ThemeVarsBuildItem(light.keySet(), QUARKUS_BLUE.toString()));
397+
}
398+
399+
private static void computeColors(Map<String, Map<String, String>> themes, Map<String, String> dark,
400+
Map<String, String> light) {
295401
// Quarkus logo colors
296402
light.put("--quarkus-blue", QUARKUS_BLUE.toString());
297403
dark.put("--quarkus-blue", QUARKUS_BLUE.toString());
@@ -382,95 +488,22 @@ void createBuildTimeData(BuildProducer<BuildTimeConstBuildItem> buildTimeConstPr
382488

383489
themes.put("dark", dark);
384490
themes.put("light", light);
491+
}
385492

386-
internalBuildTimeData.addBuildTimeData("themes", themes);
387-
388-
// Extensions
389-
Map<ExtensionGroup, List<Extension>> response = Map.of(
390-
ExtensionGroup.active, extensionsBuildItem.getActiveExtensions(),
391-
ExtensionGroup.inactive, extensionsBuildItem.getInactiveExtensions());
392-
393-
internalBuildTimeData.addBuildTimeData("extensions", response);
394-
395-
// Sections Menu
396-
Page extensions = Page.webComponentPageBuilder().internal()
397-
.title("Extensions")
398-
.icon("font-awesome-solid:puzzle-piece")
399-
.componentLink("qwc-extensions.js").build();
400-
401-
Page configuration = Page.webComponentPageBuilder().internal()
402-
.title("Configuration")
403-
.icon("font-awesome-solid:sliders")
404-
.componentLink("qwc-configuration.js").build();
405-
406-
internalBuildTimeData.addBuildTimeData("allConfiguration", "TODO: Configuration");
407-
408-
Page continuousTesting = Page.webComponentPageBuilder().internal()
409-
.title("Continuous Testing")
410-
.icon("font-awesome-solid:flask-vial")
411-
.componentLink("qwc-continuous-testing.js").build();
412-
413-
internalBuildTimeData.addBuildTimeData("continuousTesting", "TODO: Continuous Testing");
414-
415-
Page devServices = Page.webComponentPageBuilder().internal()
416-
.title("Dev services")
417-
.icon("font-awesome-solid:wand-magic-sparkles")
418-
.componentLink("qwc-dev-services.js").build();
419-
420-
internalBuildTimeData.addBuildTimeData("devServices", DevServiceDescriptions);
421-
422-
Page buildSteps = Page.webComponentPageBuilder().internal()
423-
.title("Build steps")
424-
.icon("font-awesome-solid:hammer")
425-
.componentLink("qwc-build-steps.js").build();
426-
427-
internalBuildTimeData.addBuildTimeData("buildSteps", "TODO: Build Steps");
428-
429-
// Add default menu items
430-
@SuppressWarnings("unchecked")
431-
List<Page> sectionMenu = new ArrayList(List.of(extensions, configuration, continuousTesting, devServices, buildSteps));
432-
433-
// Add any Menus from extensions
434-
for (Extension e : extensionsBuildItem.getSectionMenuExtensions()) {
435-
List<Page> pagesFromExtension = e.getMenuPages();
436-
sectionMenu.addAll(pagesFromExtension);
493+
private List<ConfigDescription> getAllConfig(List<ConfigDescriptionBuildItem> configDescriptionBuildItems,
494+
Optional<DevServicesLauncherConfigResultBuildItem> devServicesLauncherConfig) {
495+
List<ConfigDescription> configDescriptions = new ArrayList<>();
496+
for (ConfigDescriptionBuildItem item : configDescriptionBuildItems) {
497+
configDescriptions.add(
498+
new ConfigDescription(item.getPropertyName(),
499+
formatJavadoc(cleanUpAsciiDocIfNecessary(item.getDocs())),
500+
item.getDefaultValue(),
501+
isSetByDevServices(devServicesLauncherConfig, item.getPropertyName()),
502+
item.getValueTypeName(),
503+
item.getAllowedValues(),
504+
item.getConfigPhase().name()));
437505
}
438-
439-
internalBuildTimeData.addBuildTimeData("menuItems", sectionMenu);
440-
441-
// Add the Footer tabs
442-
Page serverLog = Page.webComponentPageBuilder().internal()
443-
.title("Server")
444-
.icon("font-awesome-solid:server")
445-
.componentLink("qwc-server-log.js").build();
446-
447-
Page devUiLog = Page.webComponentPageBuilder().internal()
448-
.title("Dev UI")
449-
.icon("font-awesome-solid:satellite-dish")
450-
.componentLink("qwc-jsonrpc-messages.js").build();
451-
452-
@SuppressWarnings("unchecked")
453-
List<Page> footerTabs = new ArrayList(List.of(serverLog, devUiLog));
454-
455-
// Add any Footer tabs from extensions
456-
for (Extension e : extensionsBuildItem.getFooterTabsExtensions()) {
457-
List<Page> tabsFromExtension = e.getFooterPages();
458-
footerTabs.addAll(tabsFromExtension);
459-
}
460-
461-
internalBuildTimeData.addBuildTimeData("footerTabs", footerTabs);
462-
463-
// Add version info
464-
Map<String, String> applicationInfo = new HashMap<>();
465-
applicationInfo.put("quarkusVersion", Version.getVersion());
466-
applicationInfo.put("applicationName", config.getOptionalValue("quarkus.application.name", String.class).orElse(""));
467-
applicationInfo.put("applicationVersion",
468-
config.getOptionalValue("quarkus.application.version", String.class).orElse(""));
469-
internalBuildTimeData.addBuildTimeData("applicationInfo", applicationInfo);
470-
471-
buildTimeConstProducer.produce(internalBuildTimeData);
472-
473-
themeVarsProducer.produce(new ThemeVarsBuildItem(light.keySet(), QUARKUS_BLUE.toString()));
506+
return configDescriptions;
474507
}
475508

476509
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) {
531564
return new Color(hue, saturation, lightness, alpha);
532565
}
533566
}
567+
568+
private static final Pattern codePattern = Pattern.compile("(\\{@code )([^}]+)(\\})");
569+
private static final Pattern linkPattern = Pattern.compile("(\\{@link )([^}]+)(\\})");
570+
571+
static String formatJavadoc(String val) {
572+
if (val == null) {
573+
return val;
574+
}
575+
// Replace {@code} and {@link}
576+
val = codePattern.matcher(val).replaceAll("<code>$2</code>");
577+
val = linkPattern.matcher(val).replaceAll("<code>$2</code>");
578+
// Add br before @see and @deprecated
579+
val = val.lines().filter(s -> !s.startsWith("@see")).collect(Collectors.joining("\n"));
580+
val = val.replace("@deprecated", "<br><strong>Deprecated</strong>");
581+
return val;
582+
}
534583
}

extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/devmode/console/ConfigEditorProcessor.java

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444
import io.quarkus.devconsole.runtime.spi.DevConsolePostHandler;
4545
import io.quarkus.devconsole.spi.DevConsoleRouteBuildItem;
4646
import io.quarkus.devconsole.spi.DevConsoleRuntimeTemplateInfoBuildItem;
47+
import io.quarkus.devui.runtime.ConfigJsonRpcService;
48+
import io.quarkus.devui.spi.JsonRPCProvidersBuildItem;
4749
import io.quarkus.vertx.http.runtime.devmode.ConfigDescription;
4850
import io.quarkus.vertx.http.runtime.devmode.ConfigDescriptionsManager;
4951
import io.quarkus.vertx.http.runtime.devmode.ConfigDescriptionsRecorder;
@@ -127,7 +129,7 @@ protected void handlePost(RoutingContext event, MultiMap form) throws Exception
127129

128130
}
129131

130-
private String cleanUpAsciiDocIfNecessary(String docs) {
132+
public static String cleanUpAsciiDocIfNecessary(String docs) {
131133
if (docs == null || !docs.toLowerCase(Locale.ROOT).contains("@asciidoclet")) {
132134
return docs;
133135
}
@@ -152,6 +154,16 @@ void handleRequests(BuildProducer<DevConsoleRouteBuildItem> devConsoleRouteProdu
152154
}));
153155
}
154156

157+
@BuildStep(onlyIf = IsDevelopment.class)
158+
JsonRPCProvidersBuildItem registerJsonRpcService() {
159+
DevConsoleManager.register("config-update-property", map -> {
160+
Map<String, String> values = Collections.singletonMap(map.get("name"), map.get("value"));
161+
updateConfig(values);
162+
return null;
163+
});
164+
return new JsonRPCProvidersBuildItem("ConfigJsonRpcService", ConfigJsonRpcService.class);
165+
}
166+
155167
private Map<String, String> filterAndApplyProfile(Map<String, String> autoconfig, List<String> configFilter,
156168
String profile) {
157169
return autoconfig.entrySet().stream()
@@ -208,7 +220,7 @@ static byte[] getConfig() {
208220
}
209221
}
210222

211-
static void updateConfig(Map<String, String> values) {
223+
public static void updateConfig(Map<String, String> values) {
212224
if (values != null && !values.isEmpty()) {
213225
try {
214226
Path configPath = getConfigPath();
@@ -292,7 +304,7 @@ private static Path getConfigPath() throws IOException {
292304
return configPath;
293305
}
294306

295-
private boolean isSetByDevServices(Optional<DevServicesLauncherConfigResultBuildItem> devServicesLauncherConfig,
307+
public static boolean isSetByDevServices(Optional<DevServicesLauncherConfigResultBuildItem> devServicesLauncherConfig,
296308
String propertyName) {
297309
if (devServicesLauncherConfig.isPresent()) {
298310
return devServicesLauncherConfig.get().getConfig().containsKey(propertyName);

extensions/vertx-http/dev-ui-resources/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,11 @@
131131
<artifactId>number-field</artifactId>
132132
<scope>runtime</scope>
133133
</dependency>
134+
<dependency>
135+
<groupId>org.mvnpm.at.vaadin</groupId>
136+
<artifactId>integer-field</artifactId>
137+
<scope>runtime</scope>
138+
</dependency>
134139
<dependency>
135140
<groupId>org.mvnpm.at.vaadin</groupId>
136141
<artifactId>field-base</artifactId>

0 commit comments

Comments
 (0)