Skip to content

Commit a65d609

Browse files
authored
Merge pull request #37039 from phillip-kruger/dev-ui-endpoints
2 parents ea40376 + 1fa6022 commit a65d609

File tree

7 files changed

+290
-2
lines changed

7 files changed

+290
-2
lines changed

extensions/info/deployment/src/main/resources/dev-ui/qwc-info.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ export class QwcInfo extends LitElement {
5656
}
5757

5858
async load() {
59-
const response = await fetch(this._infoUrl)
59+
const response = await fetch(this._infoUrl);
6060
const data = await response.json();
6161
this._info = data;
6262
}
@@ -72,7 +72,7 @@ export class QwcInfo extends LitElement {
7272
}else{
7373
return html`
7474
<div style="color: var(--lumo-secondary-text-color);width: 95%;" >
75-
<div>Fetching infomation...</div>
75+
<div>Fetching information...</div>
7676
<vaadin-progress-bar indeterminate></vaadin-progress-bar>
7777
</div>
7878
`;

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,13 @@ void registerDevUiHandlers(
201201
.build());
202202
}
203203

204+
Handler<RoutingContext> endpointInfoHandler = recorder.endpointInfoHandler(basepath);
205+
206+
routeProducer.produce(
207+
nonApplicationRootPathBuildItem.routeBuilder().route(DEVUI + SLASH + "endpoints.json")
208+
.handler(endpointInfoHandler)
209+
.build());
210+
204211
// For the Vaadin router (So that bookmarks/url refreshes work)
205212
for (DevUIRoutesBuildItem devUIRoutesBuildItem : devUIRoutesBuildItems) {
206213
String route = devUIRoutesBuildItem.getPath();
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package io.quarkus.devui.deployment.menu;
2+
3+
import static io.quarkus.deployment.annotations.ExecutionTime.STATIC_INIT;
4+
5+
import java.util.List;
6+
import java.util.stream.Collectors;
7+
8+
import io.quarkus.deployment.IsDevelopment;
9+
import io.quarkus.deployment.annotations.BuildStep;
10+
import io.quarkus.deployment.annotations.Record;
11+
import io.quarkus.devui.deployment.InternalPageBuildItem;
12+
import io.quarkus.devui.runtime.DevUIRecorder;
13+
import io.quarkus.devui.runtime.EndpointInfo;
14+
import io.quarkus.devui.spi.page.Page;
15+
import io.quarkus.vertx.http.deployment.HttpRootPathBuildItem;
16+
import io.quarkus.vertx.http.deployment.NonApplicationRootPathBuildItem;
17+
import io.quarkus.vertx.http.deployment.devmode.NotFoundPageDisplayableEndpointBuildItem;
18+
19+
/**
20+
* This creates Endpoints Page
21+
*/
22+
public class EndpointsProcessor {
23+
private static final String DEVUI = "dev-ui";
24+
25+
@Record(STATIC_INIT)
26+
@BuildStep(onlyIf = IsDevelopment.class)
27+
void addEndpointInfos(List<NotFoundPageDisplayableEndpointBuildItem> displayableEndpoints,
28+
DevUIRecorder recorder, HttpRootPathBuildItem httpRoot) {
29+
30+
List<EndpointInfo> endpoints = displayableEndpoints
31+
.stream()
32+
.map(v -> new EndpointInfo(v.getEndpoint(httpRoot), v.getDescription()))
33+
.sorted()
34+
.collect(Collectors.toList());
35+
36+
recorder.setEndpoints(endpoints);
37+
}
38+
39+
@BuildStep(onlyIf = IsDevelopment.class)
40+
InternalPageBuildItem createEndpointsPage(NonApplicationRootPathBuildItem nonApplicationRootPathBuildItem) {
41+
42+
String basepath = nonApplicationRootPathBuildItem.resolvePath(DEVUI);
43+
44+
InternalPageBuildItem endpointsPage = new InternalPageBuildItem("Endpoints", 25);
45+
46+
endpointsPage.addBuildTimeData("basepath", basepath);
47+
48+
// Page
49+
endpointsPage.addPage(Page.webComponentPageBuilder()
50+
.namespace("devui-endpoints")
51+
.title("Endpoints")
52+
.icon("font-awesome-solid:plug")
53+
.componentLink("qwc-endpoints.js"));
54+
55+
return endpointsPage;
56+
}
57+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import { LitElement, html, css} from 'lit';
2+
import { basepath } from 'devui-data';
3+
import '@vaadin/progress-bar';
4+
import '@vaadin/grid';
5+
import { columnBodyRenderer } from '@vaadin/grid/lit.js';
6+
import '@vaadin/grid/vaadin-grid-sort-column.js';
7+
8+
/**
9+
* This component show all available endpoints
10+
*/
11+
export class QwcEndpoints extends LitElement {
12+
13+
static styles = css`
14+
.infogrid {
15+
width: 99%;
16+
height: 99%;
17+
}
18+
a {
19+
cursor: pointer;
20+
color: var(--lumo-body-text-color);
21+
}
22+
a:link {
23+
text-decoration: none;
24+
color: var(--lumo-body-text-color);
25+
}
26+
a:visited {
27+
text-decoration: none;
28+
color: var(--lumo-body-text-color);
29+
}
30+
a:active {
31+
text-decoration: none;
32+
color: var(--lumo-body-text-color);
33+
}
34+
a:hover {
35+
color: var(--quarkus-red);
36+
}
37+
`;
38+
39+
static properties = {
40+
_info: {state: true},
41+
}
42+
43+
constructor() {
44+
super();
45+
this._info = null;
46+
}
47+
48+
async connectedCallback() {
49+
super.connectedCallback();
50+
await this.load();
51+
}
52+
53+
async load() {
54+
const response = await fetch(basepath + "/endpoints.json");
55+
const data = await response.json();
56+
this._info = data;
57+
}
58+
59+
render() {
60+
if (this._info) {
61+
const items = [];
62+
for (const [key, value] of Object.entries(this._info)) {
63+
items.push({"uri" : key, "description": value});
64+
}
65+
66+
return html`<vaadin-grid .items="${items}" class="infogrid">
67+
<vaadin-grid-sort-column header='URL'
68+
path="uri"
69+
${columnBodyRenderer(this._uriRenderer, [])}>
70+
</vaadin-grid-sort-column>
71+
72+
<vaadin-grid-sort-column
73+
header="Description"
74+
path="description"
75+
${columnBodyRenderer(this._descriptionRenderer, [])}>
76+
</vaadin-grid-sort-column>
77+
</vaadin-grid>`;
78+
}else{
79+
return html`
80+
<div style="color: var(--lumo-secondary-text-color);width: 95%;" >
81+
<div>Fetching information...</div>
82+
<vaadin-progress-bar indeterminate></vaadin-progress-bar>
83+
</div>
84+
`;
85+
}
86+
}
87+
88+
_uriRenderer(endpoint) {
89+
if (endpoint.uri) {
90+
return html`<a href="${endpoint.uri}" target="_blank">${endpoint.uri}</a>`;
91+
}
92+
}
93+
94+
_descriptionRenderer(endpoint) {
95+
if (endpoint.description) {
96+
return html`<span>${endpoint.description}</span>`;
97+
}
98+
}
99+
100+
}
101+
customElements.define('qwc-endpoints', QwcEndpoints);

extensions/vertx-http/runtime/src/main/java/io/quarkus/devui/runtime/DevUIRecorder.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,14 @@ public Handler<RoutingContext> buildTimeStaticHandler(String basePath, Map<Strin
8787
return new DevUIBuildTimeStaticHandler(basePath, urlAndPath);
8888
}
8989

90+
public Handler<RoutingContext> endpointInfoHandler(String basePath) {
91+
return new EndpointInfoHandler(basePath);
92+
}
93+
94+
public void setEndpoints(List<EndpointInfo> endpointInfos) {
95+
EndpointInfoHandler.setEndpoints(endpointInfos);
96+
}
97+
9098
public Handler<RoutingContext> vaadinRouterHandler(String basePath) {
9199
return new VaadinRouterHandler(basePath);
92100
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package io.quarkus.devui.runtime;
2+
3+
public class EndpointInfo implements Comparable<EndpointInfo> {
4+
private String uri;
5+
private String description;
6+
7+
// for bytecode recorder
8+
public EndpointInfo() {
9+
}
10+
11+
public EndpointInfo(String uri, String description) {
12+
this.uri = uri;
13+
this.description = description;
14+
}
15+
16+
public String getDescription() {
17+
return description;
18+
}
19+
20+
public String getUri() {
21+
return uri;
22+
}
23+
24+
public void setDescription(String description) {
25+
this.description = description;
26+
}
27+
28+
public void setUri(String uri) {
29+
this.uri = uri;
30+
}
31+
32+
@Override
33+
public int compareTo(EndpointInfo o) {
34+
return uri.compareTo(o.uri);
35+
}
36+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package io.quarkus.devui.runtime;
2+
3+
import java.util.HashMap;
4+
import java.util.List;
5+
import java.util.Map;
6+
7+
import io.vertx.core.Handler;
8+
import io.vertx.core.json.Json;
9+
import io.vertx.core.json.JsonObject;
10+
import io.vertx.ext.web.RoutingContext;
11+
12+
/**
13+
* Handler to return the endpoint info
14+
*/
15+
public class EndpointInfoHandler implements Handler<RoutingContext> {
16+
private static volatile List<EndpointInfo> endpointInfos;
17+
18+
static void setEndpoints(List<EndpointInfo> endpointInfos) {
19+
EndpointInfoHandler.endpointInfos = endpointInfos;
20+
}
21+
22+
private String basePath; // Like /q/dev-ui
23+
24+
public EndpointInfoHandler() {
25+
26+
}
27+
28+
public EndpointInfoHandler(String basePath) {
29+
this.basePath = basePath;
30+
}
31+
32+
public String getBasePath() {
33+
return basePath;
34+
}
35+
36+
public void setBasePath(String basePath) {
37+
this.basePath = basePath;
38+
}
39+
40+
@Override
41+
public void handle(RoutingContext event) {
42+
String normalizedPath = event.normalizedPath();
43+
if (normalizedPath.contains(SLASH)) {
44+
int si = normalizedPath.lastIndexOf(SLASH) + 1;
45+
String path = normalizedPath.substring(0, si);
46+
String fileName = normalizedPath.substring(si);
47+
if (path.startsWith(basePath) && fileName.equals("endpoints.json")) {
48+
49+
event.response()
50+
.setStatusCode(STATUS)
51+
.setStatusMessage(OK)
52+
.putHeader(CONTENT_TYPE, "application/json")
53+
.end(Json.encodePrettily(getContent()));
54+
55+
} else {
56+
event.next();
57+
}
58+
} else {
59+
event.next();
60+
}
61+
}
62+
63+
private JsonObject getContent() {
64+
65+
Map<String, Object> info = new HashMap<>();
66+
67+
for (EndpointInfo endpoint : EndpointInfoHandler.endpointInfos) {
68+
info.put(endpoint.getUri(), endpoint.getDescription());
69+
}
70+
71+
return new JsonObject(info);
72+
73+
}
74+
75+
private static final int STATUS = 200;
76+
private static final String OK = "OK";
77+
private static final String SLASH = "/";
78+
private static final String CONTENT_TYPE = "Content-Type";
79+
}

0 commit comments

Comments
 (0)