Skip to content

Commit 758e770

Browse files
authored
Merge pull request #31427 from cescoffier/devui-datasource
Add the data source card + qwc-alert
2 parents c0b9b32 + 87118e2 commit 758e770

File tree

5 files changed

+325
-0
lines changed

5 files changed

+325
-0
lines changed

extensions/datasource/deployment/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@
3333
<groupId>io.quarkus</groupId>
3434
<artifactId>quarkus-kubernetes-service-binding-spi</artifactId>
3535
</dependency>
36+
<dependency>
37+
<groupId>io.quarkus</groupId>
38+
<artifactId>quarkus-vertx-http-dev-ui-spi</artifactId>
39+
</dependency>
3640
<dependency>
3741
<groupId>io.quarkus</groupId>
3842
<artifactId>quarkus-devservices-deployment</artifactId>

extensions/datasource/deployment/src/main/java/io/quarkus/datasource/deployment/devservices/DevUIDatasourceProcessor.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,15 @@
88

99
import io.quarkus.datasource.runtime.DataSourcesBuildTimeConfig;
1010
import io.quarkus.datasource.runtime.DatabaseRecorder;
11+
import io.quarkus.datasource.runtime.DatasourceJsonRpcService;
1112
import io.quarkus.deployment.IsDevelopment;
1213
import io.quarkus.deployment.annotations.BuildStep;
1314
import io.quarkus.deployment.annotations.Record;
1415
import io.quarkus.devconsole.spi.DevConsoleRouteBuildItem;
1516
import io.quarkus.devconsole.spi.DevConsoleTemplateInfoBuildItem;
17+
import io.quarkus.devui.spi.JsonRPCProvidersBuildItem;
18+
import io.quarkus.devui.spi.page.CardPageBuildItem;
19+
import io.quarkus.devui.spi.page.Page;
1620

1721
public class DevUIDatasourceProcessor {
1822

@@ -31,4 +35,26 @@ public DevConsoleTemplateInfoBuildItem devConsoleInfo(
3135
DevConsoleRouteBuildItem devConsoleCleanDatabaseHandler(DatabaseRecorder recorder) {
3236
return new DevConsoleRouteBuildItem("reset", "POST", recorder.devConsoleResetDatabaseHandler());
3337
}
38+
39+
@BuildStep(onlyIf = IsDevelopment.class)
40+
CardPageBuildItem create(DataSourcesBuildTimeConfig dataSourceBuildTimeConfig) {
41+
CardPageBuildItem card = new CardPageBuildItem("Datasources");
42+
43+
List<String> names = new ArrayList<>();
44+
names.add("<default>");
45+
names.addAll(dataSourceBuildTimeConfig.namedDataSources.keySet());
46+
Collections.sort(names);
47+
card.addBuildTimeData("datasources", names);
48+
49+
card.addPage(Page.webComponentPageBuilder().title("Reset")
50+
.componentLink("qwc-datasources-reset.js")
51+
.icon("font-awesome-solid:broom"));
52+
return card;
53+
}
54+
55+
@BuildStep(onlyIf = IsDevelopment.class)
56+
JsonRPCProvidersBuildItem registerJsonRpcBackend() {
57+
return new JsonRPCProvidersBuildItem("Datasources", DatasourceJsonRpcService.class);
58+
}
59+
3460
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import { LitElement, html, css} from 'lit';
2+
import { JsonRpc } from 'jsonrpc';
3+
import '@vaadin/icon';
4+
import '@vaadin/button';
5+
import '@vaadin/text-field';
6+
import '@vaadin/text-area';
7+
import '@vaadin/form-layout';
8+
import '@vaadin/progress-bar';
9+
import '@vaadin/checkbox';
10+
import { until } from 'lit/directives/until.js';
11+
import '@vaadin/grid';
12+
import 'qui/qui-alert.js';
13+
import { columnBodyRenderer } from '@vaadin/grid/lit.js';
14+
import '@vaadin/grid/vaadin-grid-sort-column.js';
15+
16+
import {datasources} from 'datasources-data';
17+
18+
19+
export class QwcDatasourcesReset extends LitElement {
20+
21+
jsonRpc = new JsonRpc("Datasources");
22+
23+
static styles = css`
24+
.button {
25+
background-color: transparent;
26+
cursor: pointer;
27+
}
28+
.clearIcon {
29+
color: orange;
30+
}
31+
.message {
32+
padding: 15px;
33+
text-align: center;
34+
margin-left: 20%;
35+
margin-right: 20%;
36+
border: 2px solid orange;
37+
border-radius: 10px;
38+
font-size: large;
39+
}
40+
`;
41+
42+
static properties = {
43+
"_ds": {state: true},
44+
"_message": {state: true}
45+
}
46+
47+
connectedCallback() {
48+
super.connectedCallback();
49+
this._ds = datasources;
50+
}
51+
52+
render() {
53+
return html`${until(this._renderDataSourceTable(), html`<span>Loading datasources...</span>`)}`;
54+
}
55+
56+
57+
_renderDataSourceTable() {
58+
if (this._ds) {
59+
return html`
60+
${this._message}
61+
<vaadin-grid .items="${this._ds}" class="datatable" theme="no-border">
62+
<vaadin-grid-column auto-width
63+
header="Name"
64+
${columnBodyRenderer(this._nameRenderer, [])}>
65+
</vaadin-grid-column>
66+
67+
<vaadin-grid-column auto-width
68+
header="Action"
69+
${columnBodyRenderer(this._actionRenderer, [])}
70+
resizable>
71+
</vaadin-grid-column>
72+
</vaadin-grid>`;
73+
}
74+
}
75+
76+
_actionRenderer(ds) {
77+
return html`
78+
<vaadin-button theme="small" @click=${() => this._reset(ds)} class="button">
79+
<vaadin-icon class="clearIcon" icon="font-awesome-solid:broom"></vaadin-icon> Reset
80+
</vaadin-button>`;
81+
}
82+
83+
_nameRenderer(ds) {
84+
return html`${ds}`;
85+
}
86+
87+
_reset(ds) {
88+
this._message = '';
89+
this.jsonRpc.reset({ds: ds}).then(jsonRpcResponse => {
90+
if (ds === "<default>") {
91+
ds = "default"
92+
}
93+
this._message = html`<qui-alert theme="success" content="The datasource <code>${ds}</code> has been cleared." dismissible icon></qui-alert>`
94+
});
95+
}
96+
97+
98+
}
99+
customElements.define('qwc-datasources-reset', QwcDatasourcesReset);
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package io.quarkus.datasource.runtime;
2+
3+
import java.util.ServiceLoader;
4+
5+
import jakarta.enterprise.context.ApplicationScoped;
6+
7+
@ApplicationScoped
8+
public class DatasourceJsonRpcService {
9+
10+
public boolean reset(String ds) {
11+
ServiceLoader<DatabaseSchemaProvider> dbs = ServiceLoader.load(DatabaseSchemaProvider.class,
12+
Thread.currentThread().getContextClassLoader());
13+
for (DatabaseSchemaProvider i : dbs) {
14+
i.resetDatabase(ds);
15+
}
16+
return true;
17+
}
18+
}
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
import {LitElement, html, css} from 'lit';
2+
import {unsafeHTML} from 'lit-html/directives/unsafe-html.js';
3+
4+
5+
export class QuiAlert extends LitElement {
6+
7+
static styles = css`
8+
.alert {
9+
background-color: transparent;
10+
padding: 1rem 1rem;
11+
margin: 1rem;
12+
color: inherit;
13+
border: 1px solid transparent;
14+
border-radius: 0.375rem;
15+
position: relative;
16+
}
17+
18+
a {
19+
font-weight: 700;
20+
}
21+
22+
.icon {
23+
width: 1em;
24+
height: 1em;
25+
vertical-align: -0.125em;
26+
fill: currentColor;
27+
margin-right: .5rem !important;
28+
flex-shrink: 0 !important;
29+
}
30+
31+
.alert-header {
32+
font-size: calc(1.275rem + .3vw);
33+
}
34+
35+
36+
.alert-primary {
37+
color: var(--lumo-primary-contrast-color);
38+
background-color: var(--lumo-primary-color);
39+
}
40+
41+
.alert-primary a {
42+
color: #6ea8fe;
43+
}
44+
45+
.alert-success {
46+
color: var(--lumo-success-contrast-color);
47+
background-color: var(--lumo-success-color);
48+
}
49+
50+
51+
.alert-success a {
52+
color: #75b798;
53+
}
54+
55+
.alert-danger {
56+
color: var(--lumo-error-contrast-color);
57+
background-color: var(--lumo-error-color);
58+
59+
}
60+
61+
.alert-danger a {
62+
color: #ea868f;
63+
}
64+
65+
.alert-warning {
66+
color: var(--lumo-warning-contrast-color);
67+
background-color: var(--lumo-warning-color);
68+
border-color: #664d03;
69+
}
70+
71+
.alert-warning a {
72+
color: #ffda6a;
73+
}
74+
75+
.alert-info {
76+
color: var(--lumo-info-contrast-color);
77+
background-color: var(--lumo-info-color);
78+
}
79+
80+
.alert-info a {
81+
color: #6edff6;
82+
}
83+
84+
.close {
85+
cursor: pointer;
86+
}
87+
88+
.alert-dismissible .close {
89+
position: absolute;
90+
top: 0;
91+
right: 0;
92+
padding: .75rem 1.25rem;
93+
color: inherit;
94+
font-size: x-large;
95+
}
96+
97+
button.close {
98+
padding: 0;
99+
background-color: transparent;
100+
border: 0;
101+
-webkit-appearance: none;
102+
}
103+
`
104+
105+
106+
static properties = {
107+
// Tag attributes
108+
title: {type: String},
109+
content: {type: String},
110+
theme: {type: String},
111+
icon: {type: Boolean},
112+
dismissible: {type: Boolean},
113+
// Internal state
114+
_dismissed: {type: Boolean, state: true}
115+
};
116+
117+
render() {
118+
if (this._dismissed) {
119+
return '';
120+
}
121+
122+
let title = '';
123+
let close = '';
124+
let classes = '';
125+
if (this.title) {
126+
title = html`<h4 class="alert-heading alert-heading-${this.theme}">${title}</h4>`
127+
}
128+
if (this.dismissible) {
129+
classes = "alert-dismissible";
130+
close = html`
131+
<button type="button" @click="${this._dismiss}" class="close" aria-label="Close">
132+
<span>&times;</span>
133+
</button>`
134+
}
135+
let icon = this._getIcon();
136+
return html`
137+
<div class="alert alert-${this.theme} ${classes}" role="alert">
138+
${icon}
139+
${title}
140+
${unsafeHTML(this.content)}
141+
${close}
142+
</div>`;
143+
}
144+
145+
_dismiss() {
146+
this._dismissed = true;
147+
}
148+
149+
_getIcon() {
150+
if (this.icon) {
151+
switch (this.type) {
152+
case "warning":
153+
case "danger":
154+
return html`
155+
<svg class="icon" role="img" aria-label="Danger:">
156+
<path d="M8.982 1.566a1.13 1.13 0 0 0-1.96 0L.165 13.233c-.457.778.091 1.767.98 1.767h13.713c.889 0 1.438-.99.98-1.767L8.982 1.566zM8 5c.535 0 .954.462.9.995l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 5.995A.905.905 0 0 1 8 5zm.002 6a1 1 0 1 1 0 2 1 1 0 0 1 0-2z"></path>
157+
</svg>`
158+
case "info":
159+
return html`
160+
<svg class="icon" role="img" aria-label="Info:">
161+
<path d="M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16zm.93-9.412-1 4.705c-.07.34.029.533.304.533.194 0 .487-.07.686-.246l-.088.416c-.287.346-.92.598-1.465.598-.703 0-1.002-.422-.808-1.319l.738-3.468c.064-.293.006-.399-.287-.47l-.451-.081.082-.381 2.29-.287zM8 5.5a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"></path>
162+
</svg>`
163+
case "success":
164+
return html`
165+
<svg class="icon" role="img" aria-label="Success:">
166+
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zm-3.97-3.03a.75.75 0 0 0-1.08.022L7.477 9.417 5.384 7.323a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-.01-1.05z"></path>
167+
</svg>`
168+
default:
169+
return '';
170+
}
171+
} else {
172+
return '';
173+
}
174+
}
175+
176+
}
177+
178+
customElements.define('qui-alert', QuiAlert);

0 commit comments

Comments
 (0)