nicer dialogs

This commit is contained in:
f43nd1r 2019-12-06 02:02:11 +01:00
parent 0580a25047
commit 46f9569ca8
17 changed files with 269 additions and 207 deletions

1
.gitignore vendored
View file

@ -39,3 +39,4 @@ webpack.generated.js
### Maven ### ### Maven ###
**/target **/target
/target /target
.flattened-pom.xml

View file

@ -0,0 +1,40 @@
import {html, PolymerElement} from '@polymer/polymer/polymer-element.js';
import '@vaadin/vaadin-dialog/vaadin-dialog.js';
import '@vaadin/vaadin-button/vaadin-button.js';
class AcrariumDialogContent extends PolymerElement {
static get template() {
// language=HTML
return html`
<style>
.footer {
background-color: var(--lumo-contrast-5pct);
display: flex;
margin: calc(var(--lumo-space-l) * -1);
margin-top: var(--lumo-space-l);
padding: var(--lumo-space-s) var(--lumo-space-l);
}
.spacer {
flex: 1;
}
slot[name="header"]::slotted(*) {
margin-top: var(--lumo-space-s) !important;
}
</style>
<div class="header">
<slot name="header"></slot>
</div>
<slot></slot>
<div class="footer">
<slot name="negative"></slot>
<div class="spacer"></div>
<slot name="positive"></slot>
</div>
`
}
}
customElements.define("acrarium-dialog-content", AcrariumDialogContent);

View file

@ -24,7 +24,7 @@ import com.faendir.acra.model.QReport;
import com.faendir.acra.model.Report; import com.faendir.acra.model.Report;
import com.faendir.acra.security.SecurityUtils; import com.faendir.acra.security.SecurityUtils;
import com.faendir.acra.service.AvatarService; import com.faendir.acra.service.AvatarService;
import com.faendir.acra.ui.base.popup.Popup; import com.faendir.acra.ui.component.dialog.FluentDialog;
import com.faendir.acra.ui.view.report.ReportView; import com.faendir.acra.ui.view.report.ReportView;
import com.faendir.acra.util.TimeSpanRenderer; import com.faendir.acra.util.TimeSpanRenderer;
import com.vaadin.flow.component.button.Button; import com.vaadin.flow.component.button.Button;
@ -54,10 +54,10 @@ public class ReportList extends MyGrid<Report>{
addColumn(report -> report.getStacktrace().getStacktrace().split("\n", 2)[0], QReport.report.stacktrace.stacktrace, Messages.STACKTRACE).setAutoWidth(false).setFlexGrow(1); addColumn(report -> report.getStacktrace().getStacktrace().split("\n", 2)[0], QReport.report.stacktrace.stacktrace, Messages.STACKTRACE).setAutoWidth(false).setFlexGrow(1);
if (SecurityUtils.hasPermission(app, Permission.Level.EDIT)) { if (SecurityUtils.hasPermission(app, Permission.Level.EDIT)) {
addColumn(new ComponentRenderer<>(report -> new Button(new Icon(VaadinIcon.TRASH), addColumn(new ComponentRenderer<>(report -> new Button(new Icon(VaadinIcon.TRASH),
event -> new Popup().setTitle(Messages.DELETE_REPORT_CONFIRM).addYesNoButtons(p -> { event -> new FluentDialog().addText(Messages.DELETE_REPORT_CONFIRM).addConfirmButtons(p -> {
reportDeleter.accept(report); reportDeleter.accept(report);
getDataProvider().refreshAll(); getDataProvider().refreshAll();
}, true).show()))); }).show())));
} }
addOnClickNavigation(ReportView.class, Report::getId); addOnClickNavigation(ReportView.class, Report::getId);
} }

View file

@ -1,80 +0,0 @@
/*
* (C) Copyright 2019 Lukas Morawietz (https://github.com/F43nd1r)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.faendir.acra.ui.component;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.dialog.Dialog;
import com.vaadin.flow.component.html.Div;
/**
* @author lukas
* @since 24.04.19
*/
public class CardDialog extends Dialog implements HasSize, HasStyle {
private final Div header;
private final Div content;
public CardDialog() {
header = new Div();
header.getStyle().set("padding", "1rem");
header.getStyle().set("box-sizing", "border-box");
header.getStyle().set("background-color", "var(--lumo-contrast-5pct)");
header.getStyle().set("display", "inline-block");
header.setWidth("100%");
content = new Div();
content.getStyle().set("padding", "1rem");
content.getStyle().set("box-sizing", "border-box");
content.getStyle().set("display", "inline-block");
content.setSizeFull();
super.add(header, content);
}
public CardDialog(Component... components) {
this();
add(components);
}
public void removeAll() {
content.removeAll();
}
public void addComponentAtIndex(int index, Component component) {
content.addComponentAtIndex(index, component);
}
public void addComponentAsFirst(Component component) {
content.addComponentAsFirst(component);
}
public void add(Component... components) {
content.add(components);
}
public void remove(Component... components) {
content.remove(components);
}
public void setHeader(Component... components) {
header.removeAll();
header.add(components);
}
public void setHeaderColor(String textColor, String backgroundColor) {
header.getStyle().set("color",textColor);
header.getStyle().set("background-color", backgroundColor);
}
}

View file

@ -30,6 +30,7 @@ import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.checkbox.Checkbox; import com.vaadin.flow.component.checkbox.Checkbox;
import com.vaadin.flow.component.combobox.ComboBox; import com.vaadin.flow.component.combobox.ComboBox;
import com.vaadin.flow.component.html.Div; import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.html.H3;
import com.vaadin.flow.component.html.Image; import com.vaadin.flow.component.html.Image;
import com.vaadin.flow.component.select.Select; import com.vaadin.flow.component.select.Select;
import com.vaadin.flow.component.textfield.NumberField; import com.vaadin.flow.component.textfield.NumberField;
@ -148,6 +149,10 @@ public class Translatable<T extends Component> extends Composite<T> implements L
return create(new Label(), captionId, params); return create(new Label(), captionId, params);
} }
public static Translatable<H3> createH3(@NonNull String captionId, @NonNull Object... params) {
return create(new H3(), captionId, params);
}
public static Translatable<Image> createImage(@NonNull String src, @NonNull String captionId, @NonNull Object... params) { public static Translatable<Image> createImage(@NonNull String src, @NonNull String captionId, @NonNull Object... params) {
return new Translatable<>(new Image(src, ""), image -> image.setAlt(image.getTranslation(captionId, params))); return new Translatable<>(new Image(src, ""), image -> image.setAlt(image.getTranslation(captionId, params)));
} }

View file

@ -0,0 +1,84 @@
package com.faendir.acra.ui.component.dialog;
import com.faendir.acra.ui.component.Translatable;
import com.vaadin.flow.component.ClickEvent;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.ComponentEventListener;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.dialog.Dialog;
import com.vaadin.flow.dom.Element;
import java.util.Optional;
public class AcrariumDialog extends Dialog {
private final DialogContent content;
public AcrariumDialog() {
this.content = new DialogContent();
super.add(content);
}
public void setHeader(String captionId, Object... params) {
content.setHeader(Translatable.createH3(captionId, params));
}
public void setPositive(ComponentEventListener<ClickEvent<Button>> clickListener, String captionId, Object... params) {
Translatable<Button> button = Translatable.createButton(event -> {
close();
clickListener.onComponentEvent(event);
}, captionId, params);
content.setPositive(button);
}
public Optional<Translatable<Button>> getPositive() {
//noinspection unchecked
return content.getElement().getChildren().filter(e -> "positive".equals(e.getAttribute("slot"))).findAny().flatMap(Element::getComponent).map(c -> (Translatable<Button>) c);
}
public void setNegative(String captionId, Object... params) {
setNegative(e -> {
}, captionId, params);
}
public void setNegative(ComponentEventListener<ClickEvent<Button>> clickListener, String captionId, Object... params) {
Translatable<Button> button = Translatable.createButton(event -> {
close();
clickListener.onComponentEvent(event);
}, captionId, params).with(b -> {
b.removeThemeVariants(ButtonVariant.LUMO_PRIMARY);
b.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
});
content.setNegative(button);
}
@Override
public void add(Component... components) {
content.add(components);
}
@Override
public void add(String text) {
content.add(text);
}
@Override
public void remove(Component... components) {
content.remove(components);
}
@Override
public void removeAll() {
content.removeAll();
}
@Override
public void addComponentAtIndex(int index, Component component) {
content.addComponentAtIndex(index, component);
}
@Override
public void addComponentAsFirst(Component component) {
content.addComponentAsFirst(component);
}
}

View file

@ -0,0 +1,47 @@
/*
* (C) Copyright 2019 Lukas Morawietz (https://github.com/F43nd1r)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.faendir.acra.ui.component.dialog;
import com.faendir.acra.ui.component.Card;
import com.vaadin.flow.component.*;
import com.vaadin.flow.component.HasStyle;
import com.vaadin.flow.component.dependency.JsModule;
import com.vaadin.flow.component.polymertemplate.PolymerTemplate;
/**
* @author lukas
* @since 24.04.19
*/
@Tag("acrarium-dialog-content")
@JsModule("./elements/dialog-content.js")
public class DialogContent extends PolymerTemplate<Card.CardModel> implements com.faendir.acra.ui.component.HasSize, HasStyle, HasOrderedComponents<DialogContent> {
public void setHeader(HasElement header) {
header.getElement().setAttribute("slot", "header");
getElement().appendChild(header.getElement());
}
public void setNegative(HasElement negative) {
negative.getElement().setAttribute("slot", "negative");
getElement().appendChild(negative.getElement());
}
public void setPositive(HasElement positive) {
positive.getElement().setAttribute("slot", "positive");
getElement().appendChild(positive.getElement());
}
}

View file

@ -14,16 +14,13 @@
* limitations under the License. * limitations under the License.
*/ */
package com.faendir.acra.ui.base.popup; package com.faendir.acra.ui.component.dialog;
import com.faendir.acra.i18n.Messages; import com.faendir.acra.i18n.Messages;
import com.faendir.acra.ui.component.FlexLayout; import com.faendir.acra.ui.component.FlexLayout;
import com.faendir.acra.ui.component.Translatable; import com.faendir.acra.ui.component.Translatable;
import com.vaadin.flow.component.Component; import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.HasSize; import com.vaadin.flow.component.HasSize;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.dialog.Dialog;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import org.springframework.data.util.Pair; import org.springframework.data.util.Pair;
import org.springframework.lang.NonNull; import org.springframework.lang.NonNull;
@ -37,73 +34,66 @@ import java.util.function.Consumer;
* @author Lukas * @author Lukas
* @since 19.12.2017 * @since 19.12.2017
*/ */
public class Popup extends Dialog { public class FluentDialog extends AcrariumDialog {
private final List<Component> components; private final List<Component> components;
private final Map<ValidatedField<?, ?>, Pair<Boolean, ValidatedField.Listener>> fields; private final Map<ValidatedField<?, ?>, Pair<Boolean, ValidatedField.Listener>> fields;
private final List<Translatable<Button>> buttons;
public Popup() { public FluentDialog() {
components = new ArrayList<>(); components = new ArrayList<>();
fields = new HashMap<>(); fields = new HashMap<>();
buttons = new ArrayList<>();
} }
@NonNull @NonNull
public Popup setTitle(@NonNull String titleId, Object... params) { public FluentDialog setTitle(@NonNull String titleId, Object... params) {
components.add(0, Translatable.createText(titleId, params)); setHeader(titleId, params);
return this; return this;
} }
@NonNull @NonNull
public Popup addCreateButton(@NonNull Consumer<Popup> onCreateAction) { public FluentDialog addCreateButton(@NonNull Consumer<FluentDialog> onCreateAction) {
return addCreateButton(onCreateAction, false); setPositive(event -> onCreateAction.accept(this), Messages.CREATE);
} setNegative(Messages.CANCEL);
@NonNull
public Popup addCreateButton(@NonNull Consumer<Popup> onCreateAction, boolean closeAfter) {
buttons.add(Translatable.createButton(event -> {
onCreateAction.accept(this);
if (closeAfter) {
close();
}
}, Messages.CREATE));
return this; return this;
} }
@NonNull @NonNull
public Popup addCloseButton() { public FluentDialog addCloseButton() {
buttons.add(Translatable.createButton(event -> close(), Messages.CLOSE)); setPositive(e -> {
}, Messages.CLOSE);
return this; return this;
} }
@NonNull @NonNull
public Popup addYesNoButtons(@NonNull Consumer<Popup> onYesAction) { public FluentDialog addYesNoButtons(@NonNull Consumer<FluentDialog> onYesAction) {
return addYesNoButtons(onYesAction, false); setPositive(event -> onYesAction.accept(this), Messages.YES);
} setNegative(Messages.NO);
@NonNull
public Popup addYesNoButtons(@NonNull Consumer<Popup> onYesAction, boolean closeAfter) {
buttons.add(Translatable.createButton(event -> {
onYesAction.accept(this);
if (closeAfter) {
close();
}
}, Messages.YES));
buttons.add(Translatable.createButton(event -> close(), Messages.NO));
return this; return this;
} }
@NonNull @NonNull
public Popup addComponent(@NonNull Component component) { public FluentDialog addConfirmButtons(@NonNull Consumer<FluentDialog> onYesAction) {
setPositive(event -> onYesAction.accept(this), Messages.CONFIRM);
setNegative(Messages.CANCEL);
return this;
}
@NonNull
public FluentDialog addComponent(@NonNull Component component) {
components.add(component); components.add(component);
return this; return this;
} }
public Popup addValidatedField(@NonNull ValidatedField<?, ?> validatedField) { @NonNull
public FluentDialog addText(String captionId, Object... params) {
components.add(Translatable.createText(captionId, params));
return this;
}
public FluentDialog addValidatedField(@NonNull ValidatedField<?, ?> validatedField) {
return addValidatedField(validatedField, false); return addValidatedField(validatedField, false);
} }
public Popup addValidatedField(@NonNull ValidatedField<?, ?> validatedField, boolean isInitialValid) { public FluentDialog addValidatedField(@NonNull ValidatedField<?, ?> validatedField, boolean isInitialValid) {
ValidatedField.Listener listener = value -> updateField(validatedField, value); ValidatedField.Listener listener = value -> updateField(validatedField, value);
validatedField.addListener(listener); validatedField.addListener(listener);
fields.put(validatedField, Pair.of(isInitialValid, listener)); fields.put(validatedField, Pair.of(isInitialValid, listener));
@ -115,23 +105,7 @@ public class Popup extends Dialog {
checkValid(); checkValid();
} }
public Popup clear() {
components.clear();
fields.forEach((field, booleanListenerPair) -> field.removeListener(booleanListenerPair.getSecond()));
fields.clear();
buttons.clear();
return this;
}
public void show() { public void show() {
if (buttons.size() == 1) {
components.add(buttons.get(0));
} else if (buttons.size() > 1) {
HorizontalLayout buttonLayout = new HorizontalLayout();
components.add(buttonLayout);
buttons.forEach(buttonLayout::add);
buttons.forEach(com.faendir.acra.ui.component.HasSize::setWidthFull);
}
components.forEach(component -> { components.forEach(component -> {
if (component instanceof HasSize) { if (component instanceof HasSize) {
try { try {
@ -144,7 +118,6 @@ public class Popup extends Dialog {
layout.setFlexDirection(FlexLayout.FlexDirection.COLUMN); layout.setFlexDirection(FlexLayout.FlexDirection.COLUMN);
components.forEach(layout::add); components.forEach(layout::add);
checkValid(); checkValid();
removeAll();
add(layout); add(layout);
if (!isOpened()) { if (!isOpened()) {
open(); open();
@ -153,6 +126,6 @@ public class Popup extends Dialog {
private void checkValid() { private void checkValid() {
boolean valid = fields.values().stream().map(Pair::getFirst).reduce(Boolean::logicalAnd).orElse(true); boolean valid = fields.values().stream().map(Pair::getFirst).reduce(Boolean::logicalAnd).orElse(true);
buttons.forEach(button -> button.getContent().setEnabled(valid)); getPositive().ifPresent(button -> button.getContent().setEnabled(valid));
} }
} }

View file

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.faendir.acra.ui.base.popup; package com.faendir.acra.ui.component.dialog;
import com.vaadin.flow.component.Component; import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.HasValidation; import com.vaadin.flow.component.HasValidation;

View file

@ -14,13 +14,16 @@
* limitations under the License. * limitations under the License.
*/ */
package com.faendir.acra.ui.component; package com.faendir.acra.ui.component.dialog;
import com.faendir.acra.i18n.Messages; import com.faendir.acra.i18n.Messages;
import com.faendir.acra.model.App; import com.faendir.acra.model.App;
import com.faendir.acra.model.Version; import com.faendir.acra.model.Version;
import com.faendir.acra.service.DataService; import com.faendir.acra.service.DataService;
import com.vaadin.flow.component.button.Button; import com.faendir.acra.ui.component.FlexLayout;
import com.faendir.acra.ui.component.Translatable;
import com.faendir.acra.ui.component.UploadField;
import com.faendir.acra.ui.component.dialog.AcrariumDialog;
import com.vaadin.flow.component.textfield.NumberField; import com.vaadin.flow.component.textfield.NumberField;
import com.vaadin.flow.component.textfield.TextField; import com.vaadin.flow.component.textfield.TextField;
import org.springframework.lang.NonNull; import org.springframework.lang.NonNull;
@ -30,10 +33,10 @@ import org.springframework.lang.Nullable;
* @author lukas * @author lukas
* @since 24.04.19 * @since 24.04.19
*/ */
public class VersionEditorDialog extends CardDialog { public class VersionEditorDialog extends AcrariumDialog {
public VersionEditorDialog(@NonNull DataService dataService, @NonNull App app, @Nullable Runnable onUpdate, @Nullable Version old) { public VersionEditorDialog(@NonNull DataService dataService, @NonNull App app, @Nullable Runnable onUpdate, @Nullable Version old) {
boolean isNew = old == null; boolean isNew = old == null;
setHeader(Translatable.createText(isNew ? Messages.NEW_VERSION : Messages.EDIT_VERSION)); setHeader(isNew ? Messages.NEW_VERSION : Messages.EDIT_VERSION);
Translatable.Value<NumberField, Double> code = Translatable.createNumberField(isNew ? dataService.getMaxVersion(app).map(i -> i + 1d).orElse(1d) : old.getCode(), Messages.VERSION_CODE).with(n -> { Translatable.Value<NumberField, Double> code = Translatable.createNumberField(isNew ? dataService.getMaxVersion(app).map(i -> i + 1d).orElse(1d) : old.getCode(), Messages.VERSION_CODE).with(n -> {
n.setStep(1d); n.setStep(1d);
n.setMin(1d); n.setMin(1d);
@ -55,7 +58,7 @@ public class VersionEditorDialog extends CardDialog {
n.setValue(old.getMappings()); n.setValue(old.getMappings());
} }
}); });
Translatable<Button> button = Translatable.createButton(e -> { setPositive(e -> {
if(isNew) { if(isNew) {
dataService.store(new Version(app, code.getValue().intValue(), name.getValue(), upload.getValue())); dataService.store(new Version(app, code.getValue().intValue(), name.getValue(), upload.getValue()));
} else { } else {
@ -68,7 +71,8 @@ public class VersionEditorDialog extends CardDialog {
onUpdate.run(); onUpdate.run();
} }
}, isNew ? Messages.CREATE : Messages.SAVE); }, isNew ? Messages.CREATE : Messages.SAVE);
FlexLayout layout = new FlexLayout(code, name, upload, button); setNegative(Messages.CANCEL);
FlexLayout layout = new FlexLayout(code, name, upload);
layout.setFlexDirection(FlexLayout.FlexDirection.COLUMN); layout.setFlexDirection(FlexLayout.FlexDirection.COLUMN);
add(layout); add(layout);
} }

View file

@ -28,8 +28,8 @@ import com.faendir.acra.ui.base.ConfigurationLabel;
import com.faendir.acra.ui.base.HasAcrariumTitle; import com.faendir.acra.ui.base.HasAcrariumTitle;
import com.faendir.acra.ui.base.MyGrid; import com.faendir.acra.ui.base.MyGrid;
import com.faendir.acra.ui.base.TranslatableText; import com.faendir.acra.ui.base.TranslatableText;
import com.faendir.acra.ui.base.popup.Popup; import com.faendir.acra.ui.component.dialog.FluentDialog;
import com.faendir.acra.ui.base.popup.ValidatedField; import com.faendir.acra.ui.component.dialog.ValidatedField;
import com.faendir.acra.ui.component.Translatable; import com.faendir.acra.ui.component.Translatable;
import com.faendir.acra.ui.view.app.tabs.BugTab; import com.faendir.acra.ui.view.app.tabs.BugTab;
import com.faendir.acra.util.ImportResult; import com.faendir.acra.util.ImportResult;
@ -74,8 +74,8 @@ public class Overview extends VerticalLayout implements ComponentEventListener<A
if (SecurityUtils.hasRole(User.Role.ADMIN)) { if (SecurityUtils.hasRole(User.Role.ADMIN)) {
grid.appendFooterRow().getCell(appColumn).setComponent(new HorizontalLayout(Translatable.createButton(e -> { grid.appendFooterRow().getCell(appColumn).setComponent(new HorizontalLayout(Translatable.createButton(e -> {
Translatable<TextField> name = Translatable.createTextField("", Messages.NAME); Translatable<TextField> name = Translatable.createTextField("", Messages.NAME);
new Popup().setTitle(Messages.NEW_APP).addComponent(name).addCreateButton(popup -> { new FluentDialog().setTitle(Messages.NEW_APP).addComponent(name).addCreateButton(popup -> {
popup.clear().addComponent(new ConfigurationLabel(dataService.createNewApp(name.getContent().getValue()))).addCloseButton().show(); new FluentDialog().addComponent(new ConfigurationLabel(dataService.createNewApp(name.getContent().getValue()))).addCloseButton().show();
grid.getDataProvider().refreshAll(); grid.getDataProvider().refreshAll();
}).show(); }).show();
}, Messages.NEW_APP), Translatable.createButton(e -> { }, Messages.NEW_APP), Translatable.createButton(e -> {
@ -86,15 +86,14 @@ public class Overview extends VerticalLayout implements ComponentEventListener<A
}); });
Translatable<Checkbox> ssl = Translatable.createCheckbox(false, Messages.SSL); Translatable<Checkbox> ssl = Translatable.createCheckbox(false, Messages.SSL);
Translatable.Value<TextField, String> databaseName = Translatable.createTextField("acra-myapp", Messages.DATABASE_NAME); Translatable.Value<TextField, String> databaseName = Translatable.createTextField("acra-myapp", Messages.DATABASE_NAME);
new Popup().setTitle(Messages.IMPORT_ACRALYZER) new FluentDialog().setTitle(Messages.IMPORT_ACRALYZER)
.addComponent(host) .addComponent(host)
.addComponent(port) .addComponent(port)
.addComponent(ssl) .addComponent(ssl)
.addValidatedField(ValidatedField.of(databaseName), true) .addValidatedField(ValidatedField.of(databaseName), true)
.addCreateButton(popup -> { .addCreateButton(popup -> {
ImportResult importResult = dataService.importFromAcraStorage(host.getContent().getValue(), port.getValue().intValue(), ssl.getContent().getValue(), databaseName.getContent().getValue()); ImportResult importResult = dataService.importFromAcraStorage(host.getContent().getValue(), port.getValue().intValue(), ssl.getContent().getValue(), databaseName.getContent().getValue());
popup.clear() new FluentDialog().addComponent(Translatable.createLabel(Messages.IMPORT_SUCCESS, importResult.getSuccessCount(), importResult.getTotalCount()))
.addComponent(Translatable.createLabel(Messages.IMPORT_SUCCESS, importResult.getSuccessCount(), importResult.getTotalCount()))
.addComponent(new ConfigurationLabel(importResult.getUser())) .addComponent(new ConfigurationLabel(importResult.getUser()))
.addCloseButton() .addCloseButton()
.show(); .show();

View file

@ -29,7 +29,7 @@ import com.faendir.acra.service.DataService;
import com.faendir.acra.service.UserService; import com.faendir.acra.service.UserService;
import com.faendir.acra.ui.base.ConfigurationLabel; import com.faendir.acra.ui.base.ConfigurationLabel;
import com.faendir.acra.ui.base.MyGrid; import com.faendir.acra.ui.base.MyGrid;
import com.faendir.acra.ui.base.popup.Popup; import com.faendir.acra.ui.component.dialog.FluentDialog;
import com.faendir.acra.ui.component.Box; import com.faendir.acra.ui.component.Box;
import com.faendir.acra.ui.component.Card; import com.faendir.acra.ui.component.Card;
import com.faendir.acra.ui.component.CssGrid; import com.faendir.acra.ui.component.CssGrid;
@ -38,7 +38,7 @@ import com.faendir.acra.ui.component.FlexLayout;
import com.faendir.acra.ui.component.HasSize; import com.faendir.acra.ui.component.HasSize;
import com.faendir.acra.ui.component.RangeField; import com.faendir.acra.ui.component.RangeField;
import com.faendir.acra.ui.component.Translatable; import com.faendir.acra.ui.component.Translatable;
import com.faendir.acra.ui.component.VersionEditorDialog; import com.faendir.acra.ui.component.dialog.VersionEditorDialog;
import com.faendir.acra.ui.view.Overview; import com.faendir.acra.ui.view.Overview;
import com.faendir.acra.ui.view.app.AppView; import com.faendir.acra.ui.view.app.AppView;
import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.core.types.dsl.BooleanExpression;
@ -103,10 +103,12 @@ public class AdminTab extends AppTab<Div> {
versionGrid.addColumn(new IconRenderer<>(v -> new Icon(v.getMappings() != null ? VaadinIcon.CHECK : VaadinIcon.CLOSE), v -> ""), QVersion.version.mappings.isNotNull(), Messages.PROGUARD_MAPPINGS); versionGrid.addColumn(new IconRenderer<>(v -> new Icon(v.getMappings() != null ? VaadinIcon.CHECK : VaadinIcon.CLOSE), v -> ""), QVersion.version.mappings.isNotNull(), Messages.PROGUARD_MAPPINGS);
if (SecurityUtils.hasPermission(app, Permission.Level.EDIT)) { if (SecurityUtils.hasPermission(app, Permission.Level.EDIT)) {
versionGrid.addColumn(new ComponentRenderer<>(v -> new Button(new Icon(VaadinIcon.EDIT), e -> new VersionEditorDialog(getDataService(), app, () -> versionGrid.getDataProvider().refreshAll(), v).open()))); versionGrid.addColumn(new ComponentRenderer<>(v -> new Button(new Icon(VaadinIcon.EDIT), e -> new VersionEditorDialog(getDataService(), app, () -> versionGrid.getDataProvider().refreshAll(), v).open())));
versionGrid.addColumn(new ComponentRenderer<>(v -> new Button(new Icon(VaadinIcon.TRASH), e -> new Popup().addComponent(Translatable.createText(Messages.DELETE_VERSION_CONFIRM, v.getCode())).addYesNoButtons(p -> { versionGrid.addColumn(new ComponentRenderer<>(v -> new Button(new Icon(VaadinIcon.TRASH), e -> new FluentDialog()
.addComponent(Translatable.createText(Messages.DELETE_VERSION_CONFIRM, v.getCode()))
.addConfirmButtons(p -> {
getDataService().delete(v); getDataService().delete(v);
versionGrid.getDataProvider().refreshAll(); versionGrid.getDataProvider().refreshAll();
}, true).show()))); }).show())));
versionGrid.appendFooterRow().getCell(versionGrid.getColumns().get(0)).setComponent(Translatable.createButton(e -> new VersionEditorDialog(getDataService(), app, () -> versionGrid.getDataProvider().refreshAll(), null).open(), Messages.NEW_VERSION)); versionGrid.appendFooterRow().getCell(versionGrid.getColumns().get(0)).setComponent(Translatable.createButton(e -> new VersionEditorDialog(getDataService(), app, () -> versionGrid.getDataProvider().refreshAll(), null).open(), Messages.NEW_VERSION));
} }
@ -169,8 +171,8 @@ public class AdminTab extends AppTab<Div> {
exportCard.setHeader(Translatable.createLabel(Messages.EXPORT)); exportCard.setHeader(Translatable.createLabel(Messages.EXPORT));
Box configBox = new Box(Translatable.createLabel(Messages.NEW_ACRA_CONFIG), Translatable.createLabel(Messages.NEW_ACRA_CONFIG_DETAILS), Box configBox = new Box(Translatable.createLabel(Messages.NEW_ACRA_CONFIG), Translatable.createLabel(Messages.NEW_ACRA_CONFIG_DETAILS),
Translatable.createButton(e -> new Popup().setTitle(Messages.NEW_ACRA_CONFIG_CONFIRM) Translatable.createButton(e -> new FluentDialog().addText(Messages.NEW_ACRA_CONFIG_CONFIRM)
.addYesNoButtons(popup -> popup.clear().addComponent(new ConfigurationLabel(getDataService().recreateReporterUser(app))).addCloseButton().show()) .addConfirmButtons(popup -> new FluentDialog().addComponent(new ConfigurationLabel(getDataService().recreateReporterUser(app))).addCloseButton().show())
.show(), Messages.CREATE)); .show(), Messages.CREATE));
Box matchingBox = new Box(Translatable.createLabel(Messages.NEW_BUG_CONFIG), Translatable.createLabel(Messages.NEW_BUG_CONFIG_DETAILS), Box matchingBox = new Box(Translatable.createLabel(Messages.NEW_BUG_CONFIG), Translatable.createLabel(Messages.NEW_BUG_CONFIG_DETAILS),
Translatable.createButton(e -> { Translatable.createButton(e -> {
@ -180,9 +182,9 @@ public class AdminTab extends AppTab<Div> {
it.setMax(100); it.setMax(100);
it.setValue((double) configuration.getMinScore()); it.setValue((double) configuration.getMinScore());
}); });
new Popup().addComponent(score) new FluentDialog().addComponent(score)
.setTitle(Messages.NEW_BUG_CONFIG_CONFIRM) .addText(Messages.NEW_BUG_CONFIG_CONFIRM)
.addYesNoButtons(p -> getDataService().changeConfiguration(app, new App.Configuration(score.getValue().intValue())), true) .addConfirmButtons(p -> getDataService().changeConfiguration(app, new App.Configuration(score.getValue().intValue())))
.show(); .show();
}, Messages.CONFIGURE)); }, Messages.CONFIGURE));
Box purgeAgeBox = new Box(Translatable.createLabel(Messages.PURGE_OLD), Translatable.createLabel(Messages.PURGE_OLD_DETAILS), Translatable.createButton(e -> { Box purgeAgeBox = new Box(Translatable.createLabel(Messages.PURGE_OLD), Translatable.createLabel(Messages.PURGE_OLD_DETAILS), Translatable.createButton(e -> {
@ -195,42 +197,27 @@ public class AdminTab extends AppTab<Div> {
it.setSuffixComponent(Translatable.createLabel(Messages.REPORTS_OLDER_THAN2)); it.setSuffixComponent(Translatable.createLabel(Messages.REPORTS_OLDER_THAN2));
} }
); );
new Popup().addComponent(age) new FluentDialog().addComponent(age)
.addYesNoButtons(popup -> { .setTitle(Messages.PURGE)
.addConfirmButtons(popup -> {
getDataService().deleteReportsOlderThanDays(app, age.getValue().intValue()); getDataService().deleteReportsOlderThanDays(app, age.getValue().intValue());
}, true).show(); }).show();
}, Messages.PURGE)); }, Messages.PURGE));
Box purgeVersionBox = new Box(Translatable.createLabel(Messages.PURGE_VERSION), Translatable.createLabel(Messages.PURGE_VERSION_DETAILS), Translatable.createButton(e -> { Box purgeVersionBox = new Box(Translatable.createLabel(Messages.PURGE_VERSION), Translatable.createLabel(Messages.PURGE_VERSION_DETAILS), Translatable.createButton(e -> {
Translatable.Value<ComboBox<Integer>, Integer> versionBox = Translatable.createComboBox(getDataService().getFromReports(app, null, report.stacktrace.version.code), Messages.REPORTS_BEFORE_VERSION); Translatable.Value<ComboBox<Integer>, Integer> versionBox = Translatable.createComboBox(getDataService().getFromReports(app, null, report.stacktrace.version.code), Messages.REPORTS_BEFORE_VERSION);
new Popup().addComponent(versionBox) new FluentDialog().addComponent(versionBox)
.addYesNoButtons(popup -> { .setTitle(Messages.PURGE)
.addConfirmButtons(popup -> {
if (versionBox.getValue() != null) { if (versionBox.getValue() != null) {
getDataService().deleteReportsBeforeVersion(app, versionBox.getValue()); getDataService().deleteReportsBeforeVersion(app, versionBox.getValue());
} }
}, true).show(); }).show();
}, Messages.PURGE)); }, Messages.PURGE));
Box deleteBox = new Box(Translatable.createLabel(Messages.DELETE_APP), Translatable.createLabel(Messages.DELETE_APP_DETAILS), Translatable.createButton(e -> Box deleteBox = new Box(Translatable.createLabel(Messages.DELETE_APP), Translatable.createLabel(Messages.DELETE_APP_DETAILS), Translatable.createButton(e ->
new Popup().setTitle(Messages.DELETE_APP_CONFIRM).addYesNoButtons(popup -> { new FluentDialog().addText(Messages.DELETE_APP_CONFIRM).addConfirmButtons(popup -> {
getDataService().delete(app); getDataService().delete(app);
UI.getCurrent().navigate(Overview.class); UI.getCurrent().navigate(Overview.class);
}, true).show(), Messages.DELETE)); }).show(), Messages.DELETE));
ComboBox<Integer> versionBox = new ComboBox<>(null, getDataService().getFromReports(app, null, QReport.report.stacktrace.version.code));
versionBox.setWidth("100%");
FlexLayout purgeVersion = new FlexLayout();
purgeVersion.setWidthFull();
purgeVersion.preventWhiteSpaceBreaking();
purgeVersion.setAlignItems(FlexComponent.Alignment.CENTER);
purgeVersion.add(Translatable.createButton(e -> {
if (versionBox.getValue() != null) {
getDataService().deleteReportsBeforeVersion(app, versionBox.getValue());
}
}, Messages.PURGE), Translatable.createLabel(Messages.REPORTS_BEFORE_VERSION), versionBox);
purgeVersion.expand(versionBox);
Translatable<Button> deleteButton = Translatable.createButton(e -> new Popup().setTitle(Messages.DELETE_APP_CONFIRM).addYesNoButtons(popup -> {
getDataService().delete(app);
UI.getCurrent().navigate(Overview.class);
}, true).show(), Messages.DELETE_APP);
deleteButton.setWidthFull();
Card dangerCard = createCard(configBox, matchingBox, purgeAgeBox, purgeVersionBox, deleteBox); Card dangerCard = createCard(configBox, matchingBox, purgeAgeBox, purgeVersionBox, deleteBox);
dangerCard.setHeader(Translatable.createLabel(Messages.DANGER_ZONE)); dangerCard.setHeader(Translatable.createLabel(Messages.DANGER_ZONE));
dangerCard.enableDivider(); dangerCard.enableDivider();

View file

@ -27,7 +27,7 @@ import com.faendir.acra.security.SecurityUtils;
import com.faendir.acra.service.BugMerger; import com.faendir.acra.service.BugMerger;
import com.faendir.acra.service.DataService; import com.faendir.acra.service.DataService;
import com.faendir.acra.ui.base.MyGrid; import com.faendir.acra.ui.base.MyGrid;
import com.faendir.acra.ui.base.popup.Popup; import com.faendir.acra.ui.component.dialog.FluentDialog;
import com.faendir.acra.ui.component.Translatable; import com.faendir.acra.ui.component.Translatable;
import com.faendir.acra.ui.view.app.AppView; import com.faendir.acra.ui.view.app.AppView;
import com.faendir.acra.ui.view.bug.tabs.ReportTab; import com.faendir.acra.ui.view.bug.tabs.ReportTab;
@ -84,11 +84,11 @@ public class BugTab extends AppTab<VerticalLayout> {
RadioButtonGroup<String> titles = new RadioButtonGroup<>(); RadioButtonGroup<String> titles = new RadioButtonGroup<>();
titles.setItems(selectedItems.stream().map(bug -> bug.getBug().getTitle()).collect(Collectors.toList())); titles.setItems(selectedItems.stream().map(bug -> bug.getBug().getTitle()).collect(Collectors.toList()));
titles.setValue(selectedItems.get(0).getBug().getTitle()); titles.setValue(selectedItems.get(0).getBug().getTitle());
new Popup().setTitle(Messages.CHOOSE_BUG_GROUP_TITLE).addComponent(titles).addCreateButton(p -> { new FluentDialog().setTitle(Messages.CHOOSE_BUG_GROUP_TITLE).addComponent(titles).addCreateButton(p -> {
bugMerger.mergeBugs(selectedItems.stream().map(VBug::getBug).collect(Collectors.toList()), titles.getValue()); bugMerger.mergeBugs(selectedItems.stream().map(VBug::getBug).collect(Collectors.toList()), titles.getValue());
bugs.deselectAll(); bugs.deselectAll();
bugs.getDataProvider().refreshAll(); bugs.getDataProvider().refreshAll();
}, true).show(); }).show();
} else { } else {
Notification.show(Messages.ONLY_ONE_BUG_SELECTED); Notification.show(Messages.ONLY_ONE_BUG_SELECTED);
} }

View file

@ -19,7 +19,7 @@ package com.faendir.acra.ui.view.bug.tabs;
import com.faendir.acra.i18n.Messages; import com.faendir.acra.i18n.Messages;
import com.faendir.acra.model.Bug; import com.faendir.acra.model.Bug;
import com.faendir.acra.service.DataService; import com.faendir.acra.service.DataService;
import com.faendir.acra.ui.base.popup.Popup; import com.faendir.acra.ui.component.dialog.FluentDialog;
import com.faendir.acra.ui.component.Card; import com.faendir.acra.ui.component.Card;
import com.faendir.acra.ui.component.FlexLayout; import com.faendir.acra.ui.component.FlexLayout;
import com.faendir.acra.ui.component.HasSize; import com.faendir.acra.ui.component.HasSize;
@ -69,15 +69,15 @@ public class AdminTab extends BugTab<Div> {
layout.add(propertiesCard); layout.add(propertiesCard);
layout.expand(propertiesCard); layout.expand(propertiesCard);
Translatable<Button> unmergeButton = Translatable.createButton(e -> new Popup().setTitle(Messages.UNMERGE_BUG_CONFIRM).addYesNoButtons(p -> { Translatable<Button> unmergeButton = Translatable.createButton(e -> new FluentDialog().addText(Messages.UNMERGE_BUG_CONFIRM).addConfirmButtons(p -> {
getDataService().unmergeBug(bug); getDataService().unmergeBug(bug);
UI.getCurrent().navigate(Overview.class); UI.getCurrent().navigate(Overview.class);
}, true), Messages.UNMERGE_BUG); }), Messages.UNMERGE_BUG);
unmergeButton.setWidthFull(); unmergeButton.setWidthFull();
Translatable<Button> deleteButton = Translatable.createButton(e -> new Popup().setTitle(Messages.DELETE_BUG_CONFIRM).addYesNoButtons(popup -> { Translatable<Button> deleteButton = Translatable.createButton(e -> new FluentDialog().addText(Messages.DELETE_BUG_CONFIRM).addConfirmButtons(popup -> {
getDataService().delete(bug); getDataService().delete(bug);
UI.getCurrent().navigate(Overview.class); UI.getCurrent().navigate(Overview.class);
}, true).show(), Messages.DELETE_BUG); }).show(), Messages.DELETE_BUG);
deleteButton.setWidthFull(); deleteButton.setWidthFull();
Card dangerCard = new Card(unmergeButton, deleteButton); Card dangerCard = new Card(unmergeButton, deleteButton);
dangerCard.setHeader(Translatable.createLabel(Messages.DANGER_ZONE)); dangerCard.setHeader(Translatable.createLabel(Messages.DANGER_ZONE));

View file

@ -27,8 +27,8 @@ import com.faendir.acra.service.UserService;
import com.faendir.acra.ui.base.HasAcrariumTitle; import com.faendir.acra.ui.base.HasAcrariumTitle;
import com.faendir.acra.ui.base.MyGrid; import com.faendir.acra.ui.base.MyGrid;
import com.faendir.acra.ui.base.TranslatableText; import com.faendir.acra.ui.base.TranslatableText;
import com.faendir.acra.ui.base.popup.Popup; import com.faendir.acra.ui.component.dialog.FluentDialog;
import com.faendir.acra.ui.base.popup.ValidatedField; import com.faendir.acra.ui.component.dialog.ValidatedField;
import com.faendir.acra.ui.component.FlexLayout; import com.faendir.acra.ui.component.FlexLayout;
import com.faendir.acra.ui.component.Translatable; import com.faendir.acra.ui.component.Translatable;
import com.faendir.acra.ui.view.MainView; import com.faendir.acra.ui.view.MainView;
@ -106,14 +106,14 @@ public class UserManager extends Composite<FlexLayout> implements HasAcrariumTit
Translatable<Button> newUser = Translatable.createButton(e -> { Translatable<Button> newUser = Translatable.createButton(e -> {
Translatable.Value<TextField, String> name = Translatable.createTextField("", Messages.USERNAME); Translatable.Value<TextField, String> name = Translatable.createTextField("", Messages.USERNAME);
Translatable.Value<PasswordField, String> password = Translatable.createPasswordField(Messages.PASSWORD); Translatable.Value<PasswordField, String> password = Translatable.createPasswordField(Messages.PASSWORD);
new Popup().setTitle(Messages.NEW_USER) new FluentDialog().setTitle(Messages.NEW_USER)
.addValidatedField(ValidatedField.of(name).addValidator(s -> !s.isEmpty(), Messages.USERNAME_EMPTY)) .addValidatedField(ValidatedField.of(name).addValidator(s -> !s.isEmpty(), Messages.USERNAME_EMPTY))
.addValidatedField(ValidatedField.of(password).addValidator(s -> !s.isEmpty(), Messages.PASSWORD_EMPTY)) .addValidatedField(ValidatedField.of(password).addValidator(s -> !s.isEmpty(), Messages.PASSWORD_EMPTY))
.addValidatedField(ValidatedField.of(Translatable.createPasswordField(Messages.REPEAT_PASSWORD)).addValidator(s -> s.equals(password.getContent().getValue()), Messages.PASSWORDS_NOT_MATCHING)) .addValidatedField(ValidatedField.of(Translatable.createPasswordField(Messages.REPEAT_PASSWORD)).addValidator(s -> s.equals(password.getContent().getValue()), Messages.PASSWORDS_NOT_MATCHING))
.addCreateButton(popup -> { .addCreateButton(popup -> {
userService.createUser(name.getContent().getValue().toLowerCase(), password.getContent().getValue()); userService.createUser(name.getContent().getValue().toLowerCase(), password.getContent().getValue());
userGrid.getDataProvider().refreshAll(); userGrid.getDataProvider().refreshAll();
}, true) })
.show(); .show();
}, Messages.NEW_USER); }, Messages.NEW_USER);
userGrid.appendFooterRow().getCell(userGrid.getColumns().get(0)).setComponent(newUser); userGrid.appendFooterRow().getCell(userGrid.getColumns().get(0)).setComponent(newUser);

View file

@ -176,3 +176,4 @@ purgeVersion=Lösche Berichte aus alten Versionen
purgeVersionDetails=Lösche Berichte, die älter als die gegebene Version sind purgeVersionDetails=Lösche Berichte, die älter als die gegebene Version sind
deleteAppDetails=Lösche diese App und alle zugehörigen Daten deleteAppDetails=Lösche diese App und alle zugehörigen Daten
delete=Lösche delete=Lösche
cancel=Abbrechen

View file

@ -178,3 +178,4 @@ purgeVersion=Purge reports from previous versions
purgeVersionDetails=Delete reports older than a certain version purgeVersionDetails=Delete reports older than a certain version
deleteAppDetails=Delete this app and all data associated with it deleteAppDetails=Delete this app and all data associated with it
delete=Delete delete=Delete
cancel=Cancel