improve first time setup ui
This commit is contained in:
parent
e38945e193
commit
3c65baaa38
5 changed files with 72 additions and 5 deletions
|
@ -34,7 +34,23 @@ public interface HasStyle extends com.vaadin.flow.component.HasStyle {
|
||||||
getStyle().set("color","inherit");
|
getStyle().set("color","inherit");
|
||||||
}
|
}
|
||||||
|
|
||||||
default void setPadding(int value, HasSize.Unit unit) {
|
default void setPadding(double value, HasSize.Unit unit) {
|
||||||
getStyle().set("padding", value + unit.getText());
|
getStyle().set("padding", value + unit.getText());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default void setPaddingLeft(double value, HasSize.Unit unit) {
|
||||||
|
getStyle().set("padding-left", value + unit.getText());
|
||||||
|
}
|
||||||
|
|
||||||
|
default void setPaddingTop(double value, HasSize.Unit unit) {
|
||||||
|
getStyle().set("padding-top", value + unit.getText());
|
||||||
|
}
|
||||||
|
|
||||||
|
default void setPaddingRight(double value, HasSize.Unit unit) {
|
||||||
|
getStyle().set("padding-right", value + unit.getText());
|
||||||
|
}
|
||||||
|
|
||||||
|
default void setPaddingBottom(double value, HasSize.Unit unit) {
|
||||||
|
getStyle().set("padding-bottom", value + unit.getText());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,13 +19,18 @@ package com.faendir.acra.ui.component;
|
||||||
import com.faendir.acra.i18n.Messages;
|
import com.faendir.acra.i18n.Messages;
|
||||||
import com.faendir.acra.model.User;
|
import com.faendir.acra.model.User;
|
||||||
import com.faendir.acra.service.UserService;
|
import com.faendir.acra.service.UserService;
|
||||||
|
import com.vaadin.flow.component.AbstractField;
|
||||||
|
import com.vaadin.flow.component.Component;
|
||||||
import com.vaadin.flow.component.Composite;
|
import com.vaadin.flow.component.Composite;
|
||||||
|
import com.vaadin.flow.component.HasValue;
|
||||||
import com.vaadin.flow.component.button.Button;
|
import com.vaadin.flow.component.button.Button;
|
||||||
import com.vaadin.flow.component.textfield.PasswordField;
|
import com.vaadin.flow.component.textfield.PasswordField;
|
||||||
import com.vaadin.flow.component.textfield.TextField;
|
import com.vaadin.flow.component.textfield.TextField;
|
||||||
import com.vaadin.flow.data.binder.Binder;
|
import com.vaadin.flow.data.binder.Binder;
|
||||||
import com.vaadin.flow.data.binder.ValidationResult;
|
import com.vaadin.flow.data.binder.ValidationResult;
|
||||||
import com.vaadin.flow.data.validator.EmailValidator;
|
import com.vaadin.flow.data.validator.EmailValidator;
|
||||||
|
import com.vaadin.flow.dom.Element;
|
||||||
|
import com.vaadin.flow.dom.ElementFactory;
|
||||||
import org.springframework.lang.NonNull;
|
import org.springframework.lang.NonNull;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
|
|
||||||
|
@ -44,6 +49,8 @@ public class UserEditor extends Composite<FlexLayout> {
|
||||||
this.user = newUser ? new User("", "", Arrays.asList(User.Role.ADMIN, User.Role.USER)) : u;
|
this.user = newUser ? new User("", "", Arrays.asList(User.Role.ADMIN, User.Role.USER)) : u;
|
||||||
Binder<User> binder = new Binder<>();
|
Binder<User> binder = new Binder<>();
|
||||||
Translatable.Value<TextField> username = Translatable.createTextField(user.getUsername(), Messages.USERNAME);
|
Translatable.Value<TextField> username = Translatable.createTextField(user.getUsername(), Messages.USERNAME);
|
||||||
|
exposeInput(username);
|
||||||
|
username.setWidthFull();
|
||||||
Binder.BindingBuilder<User, String> usernameBindingBuilder = binder.forField(username);
|
Binder.BindingBuilder<User, String> usernameBindingBuilder = binder.forField(username);
|
||||||
if (newUser) {
|
if (newUser) {
|
||||||
usernameBindingBuilder.asRequired(getTranslation(Messages.USERNAME_REQUIRED));
|
usernameBindingBuilder.asRequired(getTranslation(Messages.USERNAME_REQUIRED));
|
||||||
|
@ -52,6 +59,7 @@ public class UserEditor extends Composite<FlexLayout> {
|
||||||
.bind(User::getUsername, newUser ? User::setUsername : null);
|
.bind(User::getUsername, newUser ? User::setUsername : null);
|
||||||
getContent().add(username);
|
getContent().add(username);
|
||||||
Translatable.Value<TextField> mail = Translatable.createTextField(user.getMail(), Messages.EMAIL);
|
Translatable.Value<TextField> mail = Translatable.createTextField(user.getMail(), Messages.EMAIL);
|
||||||
|
mail.setWidthFull();
|
||||||
EmailValidator emailValidator = new EmailValidator(getTranslation(Messages.INVALID_MAIL));
|
EmailValidator emailValidator = new EmailValidator(getTranslation(Messages.INVALID_MAIL));
|
||||||
binder.forField(mail).withValidator((m, c) -> {
|
binder.forField(mail).withValidator((m, c) -> {
|
||||||
if (m.isEmpty()) {
|
if (m.isEmpty()) {
|
||||||
|
@ -61,9 +69,15 @@ public class UserEditor extends Composite<FlexLayout> {
|
||||||
}).bind(User::getMail, User::setMail);
|
}).bind(User::getMail, User::setMail);
|
||||||
getContent().add(mail);
|
getContent().add(mail);
|
||||||
Translatable.Value<PasswordField> newPassword = Translatable.createPasswordField(Messages.NEW_PASSWORD);
|
Translatable.Value<PasswordField> newPassword = Translatable.createPasswordField(Messages.NEW_PASSWORD);
|
||||||
|
exposeInput(newPassword);
|
||||||
|
newPassword.setWidthFull();
|
||||||
Translatable.Value<PasswordField> repeatPassword = Translatable.createPasswordField(Messages.REPEAT_PASSWORD);
|
Translatable.Value<PasswordField> repeatPassword = Translatable.createPasswordField(Messages.REPEAT_PASSWORD);
|
||||||
|
exposeInput(repeatPassword);
|
||||||
|
repeatPassword.setWidthFull();
|
||||||
if (!newUser) {
|
if (!newUser) {
|
||||||
Translatable.Value<PasswordField> oldPassword = Translatable.createPasswordField(Messages.OLD_PASSWORD);
|
Translatable.Value<PasswordField> oldPassword = Translatable.createPasswordField(Messages.OLD_PASSWORD);
|
||||||
|
exposeInput(oldPassword);
|
||||||
|
oldPassword.setWidthFull();
|
||||||
Binder.Binding<User, String> oldPasswordBinding = binder.forField(oldPassword).withValidator(p -> {
|
Binder.Binding<User, String> oldPasswordBinding = binder.forField(oldPassword).withValidator(p -> {
|
||||||
if (!newPassword.getValue().isEmpty() || !oldPassword.getValue().isEmpty()) {
|
if (!newPassword.getValue().isEmpty() || !oldPassword.getValue().isEmpty()) {
|
||||||
return userService.checkPassword(user, p);
|
return userService.checkPassword(user, p);
|
||||||
|
@ -76,12 +90,14 @@ public class UserEditor extends Composite<FlexLayout> {
|
||||||
repeatPassword.addValueChangeListener(e -> oldPasswordBinding.validate());
|
repeatPassword.addValueChangeListener(e -> oldPasswordBinding.validate());
|
||||||
}
|
}
|
||||||
Binder.BindingBuilder<User, String> newPasswordBindingBuilder = binder.forField(newPassword);
|
Binder.BindingBuilder<User, String> newPasswordBindingBuilder = binder.forField(newPassword);
|
||||||
|
Binder.BindingBuilder<User, String> repeatPasswordBindingBuilder = binder.forField(repeatPassword);
|
||||||
if (newUser) {
|
if (newUser) {
|
||||||
newPasswordBindingBuilder.asRequired(getTranslation(Messages.PASSWORD_REQUIRED));
|
newPasswordBindingBuilder.asRequired(getTranslation(Messages.PASSWORD_REQUIRED));
|
||||||
|
repeatPasswordBindingBuilder.asRequired(getTranslation(Messages.PASSWORD_REQUIRED));
|
||||||
}
|
}
|
||||||
newPasswordBindingBuilder.bind(user1 -> "", User::setPlainTextPassword);
|
newPasswordBindingBuilder.bind(user1 -> "", User::setPlainTextPassword);
|
||||||
getContent().add(newPassword);
|
getContent().add(newPassword);
|
||||||
Binder.Binding<User, String> repeatPasswordBinding = binder.forField(repeatPassword).withValidator(p -> p.equals(newPassword.getValue()), getTranslation(Messages.PASSWORDS_NOT_MATCHING)).bind(user1 -> "", (user1, s) -> doNothing());
|
Binder.Binding<User, String> repeatPasswordBinding = repeatPasswordBindingBuilder.withValidator(p -> p.equals(newPassword.getValue()), getTranslation(Messages.PASSWORDS_NOT_MATCHING)).bind(user1 -> "", (user1, s) -> doNothing());
|
||||||
newPassword.addValueChangeListener(e -> {
|
newPassword.addValueChangeListener(e -> {
|
||||||
if (!repeatPassword.getValue().isEmpty()) {
|
if (!repeatPassword.getValue().isEmpty()) {
|
||||||
repeatPasswordBinding.validate();
|
repeatPasswordBinding.validate();
|
||||||
|
@ -96,10 +112,24 @@ public class UserEditor extends Composite<FlexLayout> {
|
||||||
onSuccess.run();
|
onSuccess.run();
|
||||||
}
|
}
|
||||||
}, Messages.CONFIRM);
|
}, Messages.CONFIRM);
|
||||||
|
button.setWidthFull();
|
||||||
button.getContent().setEnabled(false);
|
button.getContent().setEnabled(false);
|
||||||
binder.addStatusChangeListener(e -> button.getContent().setEnabled(e.getBinder().hasChanges()));
|
binder.addStatusChangeListener(e -> button.getContent().setEnabled(e.getBinder().hasChanges()));
|
||||||
getContent().add(button);
|
getContent().add(button);
|
||||||
getContent().setFlexDirection(FlexLayout.FlexDirection.COLUMN);
|
getContent().setFlexDirection(FlexLayout.FlexDirection.COLUMN);
|
||||||
|
getContent().setMaxWidthFull();
|
||||||
|
getContent().setWidth("calc(var(--lumo-size-m) * 10)");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* password managers need an input outside the shadow dom, which we add here.
|
||||||
|
* @param field the field which should be visible to password managers
|
||||||
|
* @param <T> the type of the field
|
||||||
|
*/
|
||||||
|
private <T extends Component & HasValue<AbstractField.ComponentValueChangeEvent<T, String>, String> & com.vaadin.flow.component.HasValidation> void exposeInput(Translatable.Value<T> field) {
|
||||||
|
Element input = ElementFactory.createInput();
|
||||||
|
input.setAttribute("slot", "input");
|
||||||
|
field.getElement().appendChild(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doNothing() {
|
private void doNothing() {
|
||||||
|
|
|
@ -25,6 +25,7 @@ import com.faendir.acra.ui.base.Path;
|
||||||
import com.faendir.acra.ui.base.popup.Popup;
|
import com.faendir.acra.ui.base.popup.Popup;
|
||||||
import com.faendir.acra.ui.component.DropdownMenu;
|
import com.faendir.acra.ui.component.DropdownMenu;
|
||||||
import com.faendir.acra.ui.component.FlexLayout;
|
import com.faendir.acra.ui.component.FlexLayout;
|
||||||
|
import com.faendir.acra.ui.component.Label;
|
||||||
import com.faendir.acra.ui.component.Translatable;
|
import com.faendir.acra.ui.component.Translatable;
|
||||||
import com.faendir.acra.ui.component.UserEditor;
|
import com.faendir.acra.ui.component.UserEditor;
|
||||||
import com.faendir.acra.ui.view.user.AccountView;
|
import com.faendir.acra.ui.view.user.AccountView;
|
||||||
|
@ -151,7 +152,23 @@ public class MainView extends ParentLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showFirstTimeSetup() {
|
private void showFirstTimeSetup() {
|
||||||
setContent(new UserEditor(userService, null, () -> UI.getCurrent().getPage().reload()));
|
Translatable<Image> logo = Translatable.createImage("frontend/logo.png", Messages.ACRARIUM);
|
||||||
|
logo.setWidthFull();
|
||||||
|
logo.setPaddingTop(0.5, Unit.REM);
|
||||||
|
logo.setPaddingBottom(1, Unit.REM);
|
||||||
|
Translatable<Label> welcomeLabel = Translatable.createLabel(Messages.WELCOME);
|
||||||
|
welcomeLabel.getStyle().set("font-size", "var(--lumo-font-size-xxl");
|
||||||
|
FlexLayout header = new FlexLayout(welcomeLabel, logo, Translatable.createLabel(Messages.CREATE_ADMIN));
|
||||||
|
header.setFlexDirection(FlexDirection.COLUMN);
|
||||||
|
header.setAlignSelf(Alignment.CENTER, welcomeLabel);
|
||||||
|
header.setWidth(0, Unit.PIXEL);
|
||||||
|
FlexLayout wrapper = new FlexLayout(header);
|
||||||
|
wrapper.expand(header);
|
||||||
|
UserEditor userEditor = new UserEditor(userService, null, () -> UI.getCurrent().getPage().reload());
|
||||||
|
FlexLayout layout = new FlexLayout(wrapper, userEditor);
|
||||||
|
layout.setFlexDirection(FlexDirection.COLUMN);
|
||||||
|
layout.setSizeUndefined();
|
||||||
|
setContent(layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean login(@NonNull String username, @NonNull String password) {
|
private boolean login(@NonNull String username, @NonNull String password) {
|
||||||
|
|
|
@ -153,4 +153,6 @@ spikeMailSubject=Große Anzahl an Berichten für %s
|
||||||
spikeMailTemplate=<a href='%s'>%s</a> hat stark erhöhtes Berichtaufkommen in Version %s mit %d Berichten heute
|
spikeMailTemplate=<a href='%s'>%s</a> hat stark erhöhtes Berichtaufkommen in Version %s mit %d Berichten heute
|
||||||
usernameRequired=Sie müssen einen Nutzernamen wählen
|
usernameRequired=Sie müssen einen Nutzernamen wählen
|
||||||
usernameTaken=Dieser Nutzername ist bereits vergeben
|
usernameTaken=Dieser Nutzername ist bereits vergeben
|
||||||
passwordRequired=Ein Passwort muss gesetzt werden
|
passwordRequired=Ein Passwort muss gesetzt werden
|
||||||
|
welcome=Willkommen zu
|
||||||
|
createAdmin=Zuerst müssen Sie einen Adminstrator anlegen:
|
|
@ -153,4 +153,6 @@ account=Account
|
||||||
invalidMail=Invalid email
|
invalidMail=Invalid email
|
||||||
usernameRequired=A username is required
|
usernameRequired=A username is required
|
||||||
usernameTaken=That username is already taken
|
usernameTaken=That username is already taken
|
||||||
passwordRequired=A password is required
|
passwordRequired=A password is required
|
||||||
|
welcome=Welcome to
|
||||||
|
createAdmin=First, you have to create an administrator:
|
Loading…
Reference in a new issue