refactor popups for consistency and code reduction

This commit is contained in:
F43nd1r 2017-12-19 05:12:13 +01:00
parent fb49597377
commit 897ee9cbb9
14 changed files with 312 additions and 191 deletions

View file

@ -9,6 +9,7 @@ import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import java.util.function.BooleanSupplier;
import java.util.stream.Stream;
public final class SecurityUtils {
@ -34,18 +35,19 @@ public final class SecurityUtils {
public static boolean hasPermission(@NonNull App app, @NonNull Permission.Level level) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
return authentication != null
&& getPermission(app, authentication.getAuthorities().stream().filter(Permission.class::isInstance).map(Permission.class::cast)).ordinal() >= level.ordinal();
&& getPermission(app, authentication.getAuthorities().stream().filter(Permission.class::isInstance).map(Permission.class::cast),
() -> hasRole(UserManager.ROLE_ADMIN)).ordinal() >= level.ordinal();
}
public static Permission.Level getPermission(@NonNull App app, @NonNull User user){
return getPermission(app, user.getPermissions().stream());
public static Permission.Level getPermission(@NonNull App app, @NonNull User user) {
return getPermission(app, user.getPermissions().stream(), () -> user.getRoles().contains(UserManager.ROLE_ADMIN));
}
@NonNull
private static Permission.Level getPermission(@NonNull App app, @NonNull Stream<Permission> permissionStream) {
private static Permission.Level getPermission(@NonNull App app, @NonNull Stream<Permission> permissionStream, BooleanSupplier isAdmin) {
return permissionStream.filter(permission -> permission.getApp().equals(app))
.findAny()
.map(Permission::getLevel)
.orElseGet(() -> hasRole(UserManager.ROLE_ADMIN) ? Permission.Level.ADMIN : Permission.Level.NONE);
.orElseGet(() -> isAdmin.getAsBoolean() ? Permission.Level.ADMIN : Permission.Level.NONE);
}
}

View file

@ -7,7 +7,6 @@ import org.springframework.data.domain.Slice;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.lang.NonNull;
import java.util.List;
import java.util.Optional;
/**
@ -15,7 +14,6 @@ import java.util.Optional;
* @since 11.12.2017
*/
public interface BugRepository extends JpaRepository<Bug, Integer> {
List<Bug> findAllByApp(@NonNull App app);
Slice<Bug> findAllByApp(@NonNull App app, @NonNull Pageable pageable);
Slice<Bug> findAllByAppAndSolvedFalse(@NonNull App app, @NonNull Pageable pageable);
int countAllByApp(@NonNull App app);

View file

@ -2,10 +2,11 @@ package com.faendir.acra.sql.data;
import com.faendir.acra.sql.model.App;
import com.faendir.acra.sql.model.ProguardMapping;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.lang.NonNull;
import java.util.List;
import java.util.Optional;
/**
@ -13,7 +14,9 @@ import java.util.Optional;
* @since 11.12.2017
*/
public interface ProguardMappingRepository extends JpaRepository<ProguardMapping, ProguardMapping.MetaData> {
List<ProguardMapping> findAllByApp(@NonNull App app);
Slice<ProguardMapping> findAllByApp(@NonNull App app, @NonNull Pageable pageable);
int countAllByApp(@NonNull App app);
default Optional<ProguardMapping> findById(@NonNull App app, int versionCode) {
return findById(new ProguardMapping.MetaData(app, versionCode));

View file

@ -47,7 +47,7 @@ public class ProguardMapping {
}
public static class MetaData implements Serializable {
private App app;
private int app;
private int versionCode;
@PersistenceConstructor
@ -55,18 +55,10 @@ public class ProguardMapping {
}
public MetaData(App app, int versionCode) {
this.app = app;
this.app = app.getId();
this.versionCode = versionCode;
}
public App getApp() {
return app;
}
public int getVersionCode() {
return versionCode;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;

View file

@ -17,7 +17,6 @@ import org.springframework.stereotype.Component;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
/**
@ -104,15 +103,6 @@ public class UserManager {
userRepository.save(user);
}
@NonNull
public List<User> getUsers() {
List<User> users = userRepository.findAll();
if (users.stream().noneMatch(user -> user.getUsername().equals(acraConfiguration.getUser().getName()))) {
users.add(getDefaultUser());
}
return users;
}
@NonNull
private User getDefaultUser() {
return new User(acraConfiguration.getUser().getName(), passwordEncoder.encode(acraConfiguration.getUser().getPassword()), Arrays.asList(ROLE_USER, ROLE_ADMIN));

View file

@ -1,11 +1,17 @@
package com.faendir.acra.sql.user;
import com.faendir.acra.sql.model.User;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.lang.NonNull;
/**
* @author Lukas
* @since 20.05.2017
*/
interface UserRepository extends JpaRepository<User, String> {
public interface UserRepository extends JpaRepository<User, String> {
Slice<User> findAllByRoles(@NonNull String role, @NonNull Pageable pageable);
int countAllByRoles(@NonNull String role);
}

View file

@ -10,6 +10,7 @@ import com.faendir.acra.sql.user.UserManager;
import com.faendir.acra.ui.view.base.ConfigurationLabel;
import com.faendir.acra.ui.view.base.MyGrid;
import com.faendir.acra.ui.view.base.NamedView;
import com.faendir.acra.ui.view.base.Popup;
import com.faendir.acra.util.BufferedDataProvider;
import com.faendir.acra.util.Style;
import com.vaadin.data.provider.ConfigurableFilterDataProvider;
@ -18,9 +19,7 @@ import com.vaadin.spring.annotation.SpringView;
import com.vaadin.ui.Button;
import com.vaadin.ui.Grid;
import com.vaadin.ui.TextField;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.util.Pair;
import org.springframework.lang.NonNull;
@ -66,21 +65,12 @@ public class Overview extends NamedView {
}
private void addApp() {
Window window = new Window("New App");
TextField name = new TextField("Name");
Button create = new Button("Create");
VerticalLayout layout = new VerticalLayout(name, create);
create.addClickListener(e -> {
new Popup().setTitle("New App").addComponent(name).addCreateButton(popup -> {
Pair<User, String> userPasswordPair = userManager.createReporterUser();
appRepository.save(new App(name.getValue(), userPasswordPair.getFirst()));
grid.getDataProvider().refreshAll();
layout.removeAllComponents();
layout.addComponent(new ConfigurationLabel(userPasswordPair.getFirst().getUsername(), userPasswordPair.getSecond()));
layout.addComponent(new Button("Close", e2 -> window.close()));
window.center();
});
window.setContent(layout);
window.center();
UI.getCurrent().addWindow(window);
popup.clear().addComponent(new ConfigurationLabel(userPasswordPair.getFirst().getUsername(), userPasswordPair.getSecond())).addCloseButton().show();
}).show();
}
}

View file

@ -0,0 +1,32 @@
package com.faendir.acra.ui.view.base;
import com.vaadin.ui.Upload;
import java.io.ByteArrayOutputStream;
/**
* @author Lukas
* @since 19.12.2017
*/
public class InMemoryUpload extends Upload {
private final ByteArrayOutputStream outputStream;
private boolean finished;
public InMemoryUpload(String caption) {
super();
outputStream = new ByteArrayOutputStream();
finished = false;
setCaption(caption);
setReceiver((filename, mimeType) -> outputStream);
addSucceededListener(event -> finished = true);
addFailedListener(event -> finished = false);
}
public boolean isUploaded() {
return finished;
}
public String getUploadedString() {
return outputStream.toString();
}
}

View file

@ -0,0 +1,114 @@
package com.faendir.acra.ui.view.base;
import com.faendir.acra.util.Style;
import com.vaadin.ui.Button;
import com.vaadin.ui.Component;
import com.vaadin.ui.FormLayout;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.UI;
import com.vaadin.ui.Window;
import org.springframework.data.util.Pair;
import org.springframework.lang.NonNull;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
/**
* @author Lukas
* @since 19.12.2017
*/
public class Popup extends Window {
private final List<Component> components;
private final Map<ValidatedField<?, ?>, Pair<Boolean, ValidatedField.Listener>> fields;
private final List<Button> buttons;
public Popup() {
components = new ArrayList<>();
fields = new HashMap<>();
buttons = new ArrayList<>();
}
@NonNull
public Popup setTitle(@NonNull String title) {
super.setCaption(title);
return this;
}
@NonNull
public Popup addCreateButton(@NonNull Consumer<Popup> onCreateAction) {
buttons.add(new Button("Create", event -> onCreateAction.accept(this)));
return this;
}
@NonNull
public Popup addCloseButton() {
buttons.add(new Button("Close", event -> close()));
return this;
}
@NonNull
public Popup addYesNoButtons(@NonNull Consumer<Popup> onYesAction) {
buttons.add(new Button("Yes", event -> onYesAction.accept(this)));
buttons.add(new Button("No", event -> close()));
return this;
}
@NonNull
public Popup addComponent(@NonNull Component component) {
components.add(component);
return this;
}
public Popup addValidatedField(@NonNull ValidatedField<?, ?> validatedField) {
return addValidatedField(validatedField, false);
}
public Popup addValidatedField(@NonNull ValidatedField<?, ?> validatedField, boolean isInitialValid) {
ValidatedField.Listener listener = value -> updateField(validatedField, value);
validatedField.addListener(listener);
fields.put(validatedField, Pair.of(isInitialValid, listener));
return addComponent(validatedField.getField());
}
private void updateField(@NonNull ValidatedField<?, ?> field, boolean value) {
fields.put(field, Pair.of(value, fields.get(field).getSecond()));
checkValid();
}
public Popup clear() {
components.clear();
fields.forEach((field, booleanListenerPair) -> field.removeListener(booleanListenerPair.getSecond()));
fields.clear();
buttons.clear();
return this;
}
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::addComponent);
buttons.forEach(button -> button.setWidth(100, Unit.PERCENTAGE));
}
components.forEach(component -> component.setWidth(100, Unit.PERCENTAGE));
FormLayout layout = new FormLayout();
components.forEach(layout::addComponent);
checkValid();
Style.apply(layout, Style.PADDING_LEFT, Style.PADDING_RIGHT);
setContent(layout);
center();
if (!isAttached()) {
UI.getCurrent().addWindow(this);
}
}
private void checkValid() {
boolean valid = fields.values().stream().map(Pair::getFirst).reduce(Boolean::logicalAnd).orElse(true);
buttons.forEach(button -> button.setEnabled(valid));
}
}

View file

@ -1,24 +1,44 @@
package com.faendir.acra.ui.view.base;
import com.vaadin.server.UserError;
import com.vaadin.ui.AbstractComponent;
import com.vaadin.ui.AbstractField;
import org.springframework.lang.NonNull;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* @author Lukas
* @since 22.06.2017
*/
public class ValidatedField<V, T extends AbstractField<V>> {
public class ValidatedField<V, T extends AbstractComponent> {
private final T field;
private final Supplier<V> valueSupplier;
private final Map<Function<V, Boolean>, String> validators;
private final List<Listener> listeners;
private boolean valid;
public ValidatedField(T field) {
private ValidatedField(T field, Supplier<V> valueSupplier, Consumer<Consumer<V>> listenerRegistration){
this.field = field;
validators = new HashMap<>();
field.addValueChangeListener(e -> validate(e.getValue()));
this.valueSupplier = valueSupplier;
this.validators = new HashMap<>();
this.listeners = new ArrayList<>();
this.valid = false;
listenerRegistration.accept(this::validate);
}
public static <V, T extends AbstractField<V>> ValidatedField<V, T> of(T field) {
return new ValidatedField<>(field, field::getValue, vConsumer -> field.addValueChangeListener(event -> vConsumer.accept(event.getValue())));
}
public static <V, T extends AbstractComponent> ValidatedField<V, T> of(T field, Supplier<V> valueSupplier, Consumer<Consumer<V>> listenerRegistration){
return new ValidatedField<>(field, valueSupplier, listenerRegistration);
}
public ValidatedField<V, T> addValidator(Function<V, Boolean> validator, String errorMessage) {
@ -31,11 +51,11 @@ public class ValidatedField<V, T extends AbstractField<V>> {
}
public boolean isValid() {
return validate(field.getValue());
return validate(valueSupplier.get());
}
private boolean validate(V value) {
return validators.entrySet().stream().allMatch(entry -> {
boolean valid = validators.entrySet().stream().allMatch(entry -> {
if (entry.getKey().apply(value)) {
field.setComponentError(null);
return true;
@ -44,9 +64,22 @@ public class ValidatedField<V, T extends AbstractField<V>> {
return false;
}
});
if(this.valid != valid){
this.valid = valid;
listeners.forEach(listener -> listener.onValidationChanged(valid));
}
return valid;
}
public V getValue() {
return field.getValue();
public void addListener(@NonNull Listener listener) {
listeners.add(listener);
}
public void removeListener(@NonNull Listener listener) {
listeners.remove(listener);
}
public interface Listener {
void onValidationChanged(boolean value);
}
}

View file

@ -35,7 +35,7 @@ import java.util.Set;
*/
@SpringComponent
@ViewScope
public class BugTab extends VerticalLayout implements MyTabSheet.Tab {
public class BugTab implements MyTabSheet.Tab {
public static final String CAPTION = "Bugs";
@NonNull private final BugRepository bugRepository;
@NonNull private final ReportRepository reportRepository;
@ -45,16 +45,21 @@ public class BugTab extends VerticalLayout implements MyTabSheet.Tab {
public BugTab(@NonNull BugRepository bugRepository, @NonNull ReportRepository reportRepository) {
this.bugRepository = bugRepository;
this.reportRepository = reportRepository;
setCaption(CAPTION);
}
@Override
public String getCaption() {
return CAPTION;
}
@Override
public Component createContent(@NonNull App app, @NonNull NavigationManager navigationManager) {
VerticalLayout layout = new VerticalLayout();
CheckBox hideSolved = new CheckBox("Hide solved", true);
addComponent(hideSolved);
setComponentAlignment(hideSolved, Alignment.MIDDLE_RIGHT);
layout.addComponent(hideSolved);
layout.setComponentAlignment(hideSolved, Alignment.MIDDLE_RIGHT);
MyGrid<Bug> bugs = new MyGrid<>(null, createDataProvider(app, true));
hideSolved.addValueChangeListener(e -> getUI().access(() -> {
hideSolved.addValueChangeListener(e -> layout.getUI().access(() -> {
Set<Bug> selection = bugs.getSelectedItems();
bugs.setDataProvider(createDataProvider(app, e.getValue()));
selection.forEach(bugs::select);
@ -72,10 +77,10 @@ public class BugTab extends VerticalLayout implements MyTabSheet.Tab {
reports = new ReportList(app, navigationManager, reportRepository::delete,
new BufferedDataProvider<>(selection.get(), reportRepository::findAllByBug, reportRepository::countAllByBug));
reports.setSizeFull();
replaceComponent(this.reportList, reports);
setExpandRatio(reports, 1);
layout.replaceComponent(this.reportList, reports);
layout.setExpandRatio(reports, 1);
} else if (this.reportList != null) {
removeComponent(this.reportList);
layout.removeComponent(this.reportList);
}
this.reportList = reports;
});
@ -83,11 +88,11 @@ public class BugTab extends VerticalLayout implements MyTabSheet.Tab {
bug.setSolved(e.getValue());
bugRepository.save(bug);
}), new ComponentRenderer(), "Solved");
addComponent(bugs);
setExpandRatio(bugs, 1);
setSizeFull();
Style.NO_PADDING.apply(this);
return this;
layout.addComponent(bugs);
layout.setExpandRatio(bugs, 1);
layout.setSizeFull();
Style.NO_PADDING.apply(layout);
return layout;
}
private BufferedDataProvider<Bug> createDataProvider(@NonNull App app, boolean hideSolved) {

View file

@ -6,24 +6,21 @@ import com.faendir.acra.sql.model.App;
import com.faendir.acra.sql.model.Permission;
import com.faendir.acra.sql.model.ProguardMapping;
import com.faendir.acra.ui.NavigationManager;
import com.faendir.acra.ui.view.base.InMemoryUpload;
import com.faendir.acra.ui.view.base.MyGrid;
import com.faendir.acra.ui.view.base.MyTabSheet;
import com.faendir.acra.ui.view.base.Popup;
import com.faendir.acra.ui.view.base.ValidatedField;
import com.faendir.acra.util.BufferedDataProvider;
import com.faendir.acra.util.Style;
import com.vaadin.server.UserError;
import com.vaadin.spring.annotation.SpringComponent;
import com.vaadin.spring.annotation.ViewScope;
import com.vaadin.ui.AbstractComponent;
import com.vaadin.ui.Button;
import com.vaadin.ui.Component;
import com.vaadin.ui.ProgressBar;
import com.vaadin.ui.TextField;
import com.vaadin.ui.UI;
import com.vaadin.ui.Upload;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;
import org.springframework.lang.NonNull;
import java.io.ByteArrayOutputStream;
import org.vaadin.risto.stepper.IntStepper;
/**
* @author Lukas
@ -31,70 +28,49 @@ import java.io.ByteArrayOutputStream;
*/
@SpringComponent
@ViewScope
public class DeObfuscationTab extends VerticalLayout implements MyTabSheet.Tab{
public class DeObfuscationTab implements MyTabSheet.Tab {
public static final String CAPTION = "De-Obfuscation";
@NonNull private final ProguardMappingRepository mappingRepository;
private boolean validNumber;
private boolean validFile;
public DeObfuscationTab(@NonNull ProguardMappingRepository mappingRepository) {
this.mappingRepository = mappingRepository;
setCaption(CAPTION);
}
@Override
public Component createContent(@NonNull App app, @NonNull NavigationManager navigationManager) {
MyGrid<ProguardMapping> grid = new MyGrid<>(null, mappingRepository.findAllByApp(app));
VerticalLayout layout = new VerticalLayout();
MyGrid<ProguardMapping> grid = new MyGrid<>(null, new BufferedDataProvider<>(app, mappingRepository::findAllByApp, mappingRepository::countAllByApp));
grid.addColumn(ProguardMapping::getVersionCode, "Version");
grid.setWidth(100, Unit.PERCENTAGE);
addComponent(grid);
setSizeFull();
Style.NO_PADDING.apply(this);
grid.setWidth(100, VerticalLayout.Unit.PERCENTAGE);
layout.addComponent(grid);
layout.setSizeFull();
Style.NO_PADDING.apply(layout);
if (SecurityUtils.hasPermission(app, Permission.Level.EDIT)) {
addComponent(new Button("Add File", e -> {
Window window = new Window("New Mapping Configuration");
Button confirm = new Button("Confirm");
confirm.setEnabled(false);
TextField version = new TextField("Version code", e1 -> {
try {
//noinspection ResultOfMethodCallIgnored
Integer.parseInt(e1.getValue());
validNumber = true;
confirm.setEnabled(validFile);
((AbstractComponent) e1.getComponent()).setComponentError(null);
} catch (NumberFormatException ex) {
validNumber = false;
confirm.setEnabled(false);
((AbstractComponent) e1.getComponent()).setComponentError(new UserError("Not a number"));
}
});
ByteArrayOutputStream out = new ByteArrayOutputStream();
Upload upload = new Upload("Mapping file:", (filename, mimeType) -> out);
layout.addComponent(new Button("Add File", e -> {
IntStepper version = new IntStepper("Version code");
version.setValue(1);
InMemoryUpload upload = new InMemoryUpload("Mapping file:");
ProgressBar progressBar = new ProgressBar();
progressBar.setSizeFull();
upload.addProgressListener((readBytes, contentLength) -> getUI().access(() -> progressBar.setValue((float) readBytes / contentLength)));
upload.addSucceededListener(e1 -> {
validFile = true;
confirm.setEnabled(validNumber);
});
upload.addFailedListener(e1 -> {
validFile = false;
confirm.setEnabled(false);
});
upload.setSizeFull();
confirm.addClickListener(e1 -> {
mappingRepository.save(new ProguardMapping(app, Integer.parseInt(version.getValue()), out.toString()));
grid.setItems(mappingRepository.findAllByApp(app));
window.close();
});
confirm.setSizeFull();
VerticalLayout layout = new VerticalLayout(version, upload, progressBar, confirm);
window.setContent(layout);
window.center();
UI.getCurrent().addWindow(window);
upload.addProgressListener((readBytes, contentLength) -> layout.getUI().access(() -> progressBar.setValue((float) readBytes / contentLength)));
new Popup().setTitle("New Mapping Configuration")
.addComponent(version)
.addValidatedField(ValidatedField.of(upload, () -> upload, consumer -> upload.addFinishedListener(event -> consumer.accept(upload)))
.addValidator(InMemoryUpload::isUploaded, "Upload failed"))
.addComponent(progressBar)
.addCreateButton(popup -> {
mappingRepository.save(new ProguardMapping(app, version.getValue(), upload.getUploadedString()));
grid.getDataProvider().refreshAll();
popup.close();
})
.show();
}));
}
setExpandRatio(grid, 1);
return this;
layout.setExpandRatio(grid, 1);
return layout;
}
@Override
public String getCaption() {
return CAPTION;
}
}

View file

@ -8,6 +8,8 @@ import com.faendir.acra.sql.user.UserManager;
import com.faendir.acra.ui.NavigationManager;
import com.faendir.acra.ui.view.base.ConfigurationLabel;
import com.faendir.acra.ui.view.base.MyTabSheet;
import com.faendir.acra.ui.view.base.Popup;
import com.vaadin.shared.ui.ContentMode;
import com.vaadin.spring.annotation.SpringComponent;
import com.vaadin.spring.annotation.ViewScope;
import com.vaadin.ui.Alignment;
@ -15,9 +17,7 @@ import com.vaadin.ui.Button;
import com.vaadin.ui.Component;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.util.Pair;
import org.springframework.lang.NonNull;
@ -32,7 +32,7 @@ import java.util.Date;
*/
@SpringComponent
@ViewScope
public class PropertiesTab extends VerticalLayout implements MyTabSheet.Tab {
public class PropertiesTab implements MyTabSheet.Tab {
public static final String CAPTION = "Properties";
@NonNull private final AppRepository appRepository;
private final ReportRepository reportRepository;
@ -43,44 +43,28 @@ public class PropertiesTab extends VerticalLayout implements MyTabSheet.Tab {
this.appRepository = appRepository;
this.reportRepository = reportRepository;
this.userManager = userManager;
setCaption(CAPTION);
}
@Override
public Component createContent(@NonNull App app, @NonNull NavigationManager navigationManager) {
addComponent(new Button("Create new ACRA Configuration", e -> {
Window window = new Window("Confirm");
VerticalLayout layout = new VerticalLayout();
layout.addComponent(new Label("Are you sure you want to create a new ACRA configuration? The existing configuration will be invalidated"));
Button yes = new Button("Yes", e1 -> {
layout.removeAllComponents();
Pair<User, String> userPasswordPair = userManager.createReporterUser();
app.setReporter(userPasswordPair.getFirst());
appRepository.save(app);
layout.addComponent(new ConfigurationLabel(userPasswordPair.getFirst().getUsername(), userPasswordPair.getSecond()));
layout.addComponent(new Button("Close", e2 -> window.close()));
window.center();
});
Button no = new Button("No", e1 -> window.close());
layout.addComponent(new HorizontalLayout(yes, no));
window.setContent(layout);
window.center();
UI.getCurrent().addWindow(window);
}));
addComponent(new Button("Delete App", e -> {
Window window = new Window("Confirm");
Label label = new Label("Are you sure you want to delete this app and all its reports and mappings?");
Button yes = new Button("Yes", e1 -> {
appRepository.delete(app);
window.close();
navigationManager.navigateBack();
});
Button no = new Button("No", e1 -> window.close());
VerticalLayout layout = new VerticalLayout(label, new HorizontalLayout(yes, no));
window.setContent(layout);
window.center();
UI.getCurrent().addWindow(window);
}));
VerticalLayout layout = new VerticalLayout();
layout.addComponent(new Button("Create new ACRA Configuration", e -> new Popup().setTitle("Confirm")
.addComponent(new Label("Are you sure you want to create a new ACRA configuration?<br>The existing configuration will be invalidated", ContentMode.HTML))
.addYesNoButtons(popup -> {
Pair<User, String> userPasswordPair = userManager.createReporterUser();
app.setReporter(userPasswordPair.getFirst());
appRepository.save(app);
popup.clear().addComponent(new ConfigurationLabel(userPasswordPair.getFirst().getUsername(), userPasswordPair.getSecond())).addCloseButton().show();
})
.show()));
layout.addComponent(new Button("Delete App", e -> new Popup().setTitle("Confirm")
.addComponent(new Label("Are you sure you want to delete this app and all its associated content?"))
.addYesNoButtons(popup -> {
appRepository.delete(app);
popup.close();
navigationManager.navigateBack();
})
.show()));
IntStepper age = new IntStepper();
age.setValue(30);
age.setMinValue(0);
@ -91,8 +75,13 @@ public class PropertiesTab extends VerticalLayout implements MyTabSheet.Tab {
reportRepository.deleteAllByBugAppAndDateBefore(app, keepAfter);
}), new Label("Reports older than "), age, new Label("Days"));
purgeAge.setDefaultComponentAlignment(Alignment.MIDDLE_CENTER);
addComponent(purgeAge);
setSizeUndefined();
return this;
layout.addComponent(purgeAge);
layout.setSizeUndefined();
return layout;
}
@Override
public String getCaption() {
return CAPTION;
}
}

View file

@ -6,28 +6,27 @@ import com.faendir.acra.sql.model.App;
import com.faendir.acra.sql.model.Permission;
import com.faendir.acra.sql.model.User;
import com.faendir.acra.sql.user.UserManager;
import com.faendir.acra.sql.user.UserRepository;
import com.faendir.acra.ui.view.annotation.RequiresRole;
import com.faendir.acra.ui.view.base.MyCheckBox;
import com.faendir.acra.ui.view.base.MyGrid;
import com.faendir.acra.ui.view.base.NamedView;
import com.faendir.acra.ui.view.base.Popup;
import com.faendir.acra.ui.view.base.ValidatedField;
import com.faendir.acra.util.BufferedDataProvider;
import com.faendir.acra.util.Style;
import com.vaadin.navigator.ViewChangeListener;
import com.vaadin.spring.annotation.SpringView;
import com.vaadin.ui.Button;
import com.vaadin.ui.ComboBox;
import com.vaadin.ui.FormLayout;
import com.vaadin.ui.Grid;
import com.vaadin.ui.PasswordField;
import com.vaadin.ui.TextField;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.NonNull;
import java.util.Arrays;
import java.util.Collections;
/**
* @author Lukas
@ -38,18 +37,19 @@ import java.util.Collections;
public class UserManagerView extends NamedView {
@NonNull private final UserManager userManager;
@NonNull private final AppRepository appRepository;
@NonNull private final MyGrid<User> userGrid;
@NonNull private final UserRepository userRepository;
private MyGrid<User> userGrid;
@Autowired
public UserManagerView(@NonNull UserManager userManager, @NonNull AppRepository appRepository) {
public UserManagerView(@NonNull UserManager userManager, @NonNull AppRepository appRepository, @NonNull UserRepository userRepository) {
this.userManager = userManager;
this.appRepository = appRepository;
this.userGrid = new MyGrid<>("Users", Collections.emptyList());
this.userRepository = userRepository;
}
@Override
public void enter(ViewChangeListener.ViewChangeEvent event) {
userGrid.setItems(userManager.getUsers());
userGrid = new MyGrid<>("Users", new BufferedDataProvider<>(UserManager.ROLE_USER, userRepository::findAllByRoles, userRepository::countAllByRoles));
userGrid.setSelectionMode(Grid.SelectionMode.NONE);
userGrid.addColumn(User::getUsername, "Username");
userGrid.addComponentColumn(user -> new MyCheckBox(user.getRoles().contains(UserManager.ROLE_ADMIN), !user.getUsername().equals(SecurityUtils.getUsername()),
@ -75,24 +75,15 @@ public class UserManagerView extends NamedView {
}
private void newUser() {
Window window = new Window("New User");
ValidatedField<String, TextField> name = new ValidatedField<>(new TextField("Username")).addValidator(s -> !s.isEmpty(), "Username cannot be empty")
.addValidator(s -> userManager.getUser(s) == null, "User already exists");
ValidatedField<String, PasswordField> password = new ValidatedField<>(new PasswordField("Password")).addValidator(s -> !s.isEmpty(), "Password cannot be empty");
ValidatedField<String, PasswordField> repeatPassword = new ValidatedField<>(new PasswordField("Repeat Password"))
.addValidator(s -> s.equals(password.getValue()), "Passwords do not match");
Button create = new Button("Create");
create.addClickListener(e -> {
if (name.isValid() && password.isValid() && repeatPassword.isValid()) {
userManager.createUser(name.getValue().toLowerCase(), password.getValue());
userGrid.setItems(userManager.getUsers());
window.close();
}
});
create.setWidth(100, Unit.PERCENTAGE);
FormLayout layout = new FormLayout(name.getField(), password.getField(), repeatPassword.getField(), create);
window.setContent(layout);
window.center();
UI.getCurrent().addWindow(window);
TextField name = new TextField("Username");
PasswordField password = new PasswordField("Password");
new Popup().setTitle("New User").addValidatedField(ValidatedField.of(name).addValidator(s -> !s.isEmpty(), "Username cannot be empty"))
.addValidatedField(ValidatedField.of(password).addValidator(s -> !s.isEmpty(), "Password cannot be empty"))
.addValidatedField(ValidatedField.of(new PasswordField("Repeat Password")).addValidator(s -> s.equals(password.getValue()), "Passwords do not match"))
.addCreateButton(popup->{
userManager.createUser(name.getValue().toLowerCase(), password.getValue());
userGrid.getDataProvider().refreshAll();
popup.close();
}).show();
}
}