Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev UI: Migrate Flyway extension #35073

Merged
merged 1 commit into from
Jul 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions extensions/flyway/deployment/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-flyway</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-vertx-http-dev-ui-tests</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5-internal</artifactId>
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package io.quarkus.flyway.devui;

import static io.quarkus.deployment.annotations.ExecutionTime.RUNTIME_INIT;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;

import io.quarkus.agroal.spi.JdbcInitialSQLGeneratorBuildItem;
import io.quarkus.deployment.IsDevelopment;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.annotations.Record;
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;
import io.quarkus.flyway.runtime.FlywayBuildTimeConfig;
import io.quarkus.flyway.runtime.devui.FlywayDevUIRecorder;
import io.quarkus.flyway.runtime.devui.FlywayJsonRpcService;

public class FlywayDevUIProcessor {

@BuildStep(onlyIf = IsDevelopment.class)
@Record(value = RUNTIME_INIT, optional = true)
CardPageBuildItem create(FlywayDevUIRecorder recorder, FlywayBuildTimeConfig buildTimeConfig,
List<JdbcInitialSQLGeneratorBuildItem> generatorBuildItem,
CurateOutcomeBuildItem curateOutcomeBuildItem) {

Map<String, Supplier<String>> initialSqlSuppliers = new HashMap<>();
for (JdbcInitialSQLGeneratorBuildItem buildItem : generatorBuildItem) {
initialSqlSuppliers.put(buildItem.getDatabaseName(), buildItem.getSqlSupplier());
}

String artifactId = curateOutcomeBuildItem.getApplicationModel().getAppArtifact().getArtifactId();

recorder.setInitialSqlSuppliers(initialSqlSuppliers, artifactId);

CardPageBuildItem card = new CardPageBuildItem();

card.addPage(Page.webComponentPageBuilder()
.componentLink("qwc-flyway-datasources.js")
.dynamicLabelJsonRPCMethodName("getNumberOfDatasources")
.icon("font-awesome-solid:database"));
return card;
}

@BuildStep(onlyIf = IsDevelopment.class)
JsonRPCProvidersBuildItem registerJsonRpcBackend() {
return new JsonRPCProvidersBuildItem(FlywayJsonRpcService.class);
}
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
import { QwcHotReloadElement, html, css} from 'qwc-hot-reload-element';
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 'qui-alert';
import { columnBodyRenderer } from '@vaadin/grid/lit.js';
import { dialogRenderer } from '@vaadin/dialog/lit.js';
import '@vaadin/grid/vaadin-grid-sort-column.js';
import '@vaadin/progress-bar';
import { notifier } from 'notifier';

export class QwcFlywayDatasources extends QwcHotReloadElement {

jsonRpc = new JsonRpc(this);

static styles = css`
.button {
cursor: pointer;
}
.clearIcon {
color: var(--lumo-warning-text-color);
}`;

static properties = {
_ds: {state: true},
_selectedDs: {state: true},
_createDialogOpened: {state: true}
}

constructor() {
super();
this._ds = null;
this._selectedDs = null;
this._createDialogOpened = false;
}

connectedCallback() {
super.connectedCallback();
this.hotReload();
}

hotReload(){
this.jsonRpc.getDatasources().then(jsonRpcResponse => {
this._ds = jsonRpcResponse.result;
});
}

render() {
if (this._ds) {
return this._renderDataSourceTable();
} else {
return html`<vaadin-progress-bar class="progress" indeterminate></vaadin-progress-bar>`;
}
}

_renderDataSourceTable() {
return html`${this._renderCreateDialog()}
<vaadin-grid .items="${this._ds}" class="datatable" theme="no-border">
<vaadin-grid-column auto-width
header="Name"
${columnBodyRenderer(this._nameRenderer, [])}>
</vaadin-grid-column>
<vaadin-grid-column auto-width
header="Action"
${columnBodyRenderer(this._actionRenderer, [])}
resizable>
</vaadin-grid-column>
</vaadin-grid>`;
}

_actionRenderer(ds) {
return html`${this._renderMigrationButtons(ds)}
${this._renderCreateButton(ds)}`;
}

_renderMigrationButtons(ds) {
if(ds.hasMigrations){
return html`
<vaadin-button theme="small" @click=${() => this._clean(ds)} class="button">
<vaadin-icon class="clearIcon" icon="font-awesome-solid:broom"></vaadin-icon> Clean
</vaadin-button>
<vaadin-button theme="small" @click=${() => this._migrate(ds)} class="button">
<vaadin-icon icon="font-awesome-solid:arrow-right-arrow-left"></vaadin-icon> Migrate
</vaadin-button>`;
}
}

_renderCreateButton(ds) {
if(ds.createPossible){
return html`
<vaadin-button theme="small" @click=${() => this._showCreateDialog(ds)} class="button" title="Set up basic files for Flyway migrations to work. Initial file in db/migrations will be created and you can then add additional migration files">
<vaadin-icon icon="font-awesome-solid:plus"></vaadin-icon> Create Initial Migration File
</vaadin-button>`;
}
}

_nameRenderer(ds) {
return html`${ds.name}`;
}

_showCreateDialog(ds){
this._selectedDs = ds;
this._createDialogOpened = true;
}

_renderCreateDialog(){
return html`<vaadin-dialog class="createDialog"
header-title="Create"
.opened="${this._createDialogOpened}"
@opened-changed="${(e) => (this._createDialogOpened = e.detail.value)}"
${dialogRenderer(() => this._renderCreateDialogForm(), "Create")}
></vaadin-dialog>`;
}

_renderCreateDialogForm(){
let title = this._selectedDs.name + " Datasource";
return html`<b>${title}</b></br>
Set up an initial file from Hibernate ORM schema generation for Flyway migrations to work.<br/>
If you say yes, an initial file in <code>db/migrations</code> will be <br/>
created and you can then add additional migration files as documented.
${this._renderDialogButtons(this._selectedDs)}
`;
}

_renderDialogButtons(ds){
return html`<div style="display: flex; flex-direction: row-reverse; gap: 10px;">
<vaadin-button theme="secondary" @click=${() => this._create(this._selectedDs)}>Create</vaadin-button>
<vaadin-button theme="secondary error" @click=${this._cancelCreate}>Cancel</vaadin-button>
</div>`;
}

_clean(ds) {
this.jsonRpc.clean({ds: ds.name}).then(jsonRpcResponse => {
this._showResultNotification(jsonRpcResponse.result);
});
}

_migrate(ds) {
this.jsonRpc.migrate({ds: ds.name}).then(jsonRpcResponse => {
this._showResultNotification(jsonRpcResponse.result);
});
}

_create(ds) {
this.jsonRpc.create({ds: ds.name}).then(jsonRpcResponse => {
this._showResultNotification(jsonRpcResponse.result);
this._selectedDs = null;
this._createDialogOpened = false;
this.hotReload();
});
}

_cancelCreate(){
this._selectedDs = null;
this._createDialogOpened = false;
}

_showResultNotification(response){
if(response.type === "success"){
notifier.showInfoMessage(response.message + " (" + response.number + ")");
}else{
notifier.showWarningMessage(response.message);
}
}

}
customElements.define('qwc-flyway-datasources', QwcFlywayDatasources);
Loading