ReportView improvements
This commit is contained in:
parent
232612a97f
commit
0649a6f402
9 changed files with 125 additions and 60 deletions
|
@ -18,14 +18,14 @@ plugins {
|
|||
id 'idea'
|
||||
id 'war'
|
||||
id 'org.springframework.boot' version '2.1.3.RELEASE'
|
||||
id 'com.devsoap.vaadin-flow' version '1.0.0.RC8'
|
||||
id 'com.devsoap.vaadin-flow' version '1.1'
|
||||
id 'io.spring.dependency-management' version '1.0.7.RELEASE'
|
||||
id 'cn.bestwu.propdeps' version '0.0.10'
|
||||
id 'net.researchgate.release' version '2.8.0'
|
||||
}
|
||||
|
||||
vaadin {
|
||||
version '13.0.0'
|
||||
version '13.0.4'
|
||||
submitStatistics false
|
||||
}
|
||||
|
||||
|
@ -96,7 +96,7 @@ dependencies {
|
|||
implementation 'org.codeartisans:org.json:20161124'
|
||||
implementation 'org.apache.commons:commons-text:1.6'
|
||||
implementation 'org.xbib:time:1.0.0'
|
||||
implementation 'ch.acra:acra-javacore:5.3.0-rc01'
|
||||
implementation 'ch.acra:acra-javacore:5.3.0'
|
||||
implementation 'com.faendir.proguard:retrace:1.3'
|
||||
implementation 'javax.xml.bind:jaxb-api:2.3.1'
|
||||
implementation 'com.github.ziplet:ziplet:2.3.0'
|
||||
|
@ -113,7 +113,7 @@ dependencies {
|
|||
compileJava.dependsOn(processResources)
|
||||
|
||||
war {
|
||||
archiveName = 'acra.war'
|
||||
archiveFileName = 'acra.war'
|
||||
version = version
|
||||
enabled = true
|
||||
}
|
||||
|
|
|
@ -42,7 +42,11 @@ public class AvatarService {
|
|||
|
||||
//@Cacheable(cacheNames = "avatars", key = "#report.installationId")
|
||||
public Component getAvatar(@NonNull Report report) {
|
||||
byte[] bytes = avatar.createAsPngBytes(report.getInstallationId().hashCode());
|
||||
return new Image(new StreamResource("", () -> new ByteArrayInputStream(bytes)), "");
|
||||
return new Image(getAvatar(report.getInstallationId()), "");
|
||||
}
|
||||
|
||||
public StreamResource getAvatar(@NonNull String installationId) {
|
||||
byte[] bytes = avatar.createAsPngBytes(installationId.hashCode());
|
||||
return new StreamResource("", () -> new ByteArrayInputStream(bytes));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,9 +21,9 @@ import com.faendir.acra.model.User;
|
|||
import com.faendir.acra.rest.RestReportInterface;
|
||||
import com.faendir.acra.ui.component.Label;
|
||||
import com.faendir.acra.ui.view.Overview;
|
||||
import com.vaadin.flow.component.UI;
|
||||
import com.vaadin.flow.i18n.LocaleChangeEvent;
|
||||
import com.vaadin.flow.i18n.LocaleChangeObserver;
|
||||
import com.vaadin.flow.router.RouteConfiguration;
|
||||
import org.springframework.lang.NonNull;
|
||||
|
||||
/**
|
||||
|
@ -40,6 +40,6 @@ public class ConfigurationLabel extends Label implements LocaleChangeObserver {
|
|||
|
||||
@Override
|
||||
public void localeChange(LocaleChangeEvent event) {
|
||||
getElement().setProperty("innerHTML", getTranslation(Messages.CONFIGURATION_LABEL, UI.getCurrent().getRouter().getUrl(Overview.class), RestReportInterface.REPORT_PATH, user.getUsername(), user.getPlainTextPassword()));
|
||||
getElement().setProperty("innerHTML", getTranslation(Messages.CONFIGURATION_LABEL, RouteConfiguration.forSessionScope().getUrl(Overview.class), RestReportInterface.REPORT_PATH, user.getUsername(), user.getPlainTextPassword()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import com.vaadin.flow.function.ValueProvider;
|
|||
import com.vaadin.flow.i18n.LocaleChangeEvent;
|
||||
import com.vaadin.flow.i18n.LocaleChangeObserver;
|
||||
import com.vaadin.flow.router.HasUrlParameter;
|
||||
import com.vaadin.flow.router.RouteConfiguration;
|
||||
import com.vaadin.flow.shared.Registration;
|
||||
import org.springframework.data.util.Pair;
|
||||
import org.springframework.lang.NonNull;
|
||||
|
@ -102,7 +103,7 @@ public class MyGrid<T> extends Composite<Grid<T>> implements LocaleChangeObserve
|
|||
}
|
||||
|
||||
public <C extends Component & HasUrlParameter<R>, R> void addOnClickNavigation(Class<C> target, Function<T, R> parameterTransformer) {
|
||||
getContent().addItemClickListener(e -> getUI().ifPresent(e.getButton() == 1 ? (ui -> ui.getPage().executeJavaScript("window.open(\"" + ui.getRouter().getUrl(target, parameterTransformer.apply(e.getItem())) + "\", \"blank\", \"\");")) : (ui -> ui.navigate(target, parameterTransformer.apply(e.getItem())))));
|
||||
getContent().addItemClickListener(e -> getUI().ifPresent(e.getButton() == 1 ? (ui -> ui.getPage().executeJavaScript("window.open(\"" + RouteConfiguration.forSessionScope().getUrl(target, parameterTransformer.apply(e.getItem())) + "\", \"blank\", \"\");")) : (ui -> ui.navigate(target, parameterTransformer.apply(e.getItem())))));
|
||||
}
|
||||
|
||||
public Registration addSelectionListener(SelectionListener<Grid<T>, T> listener) {
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* (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.faendir.acra.service.AvatarService;
|
||||
import com.vaadin.flow.component.html.Image;
|
||||
import org.springframework.lang.NonNull;
|
||||
|
||||
/**
|
||||
* @author lukas
|
||||
* @since 23.04.19
|
||||
*/
|
||||
public class InstallationView extends FlexLayout {
|
||||
private final Image image;
|
||||
private final Label label;
|
||||
private final AvatarService avatarService;
|
||||
|
||||
public InstallationView(@NonNull AvatarService avatarService) {
|
||||
this.avatarService = avatarService;
|
||||
image = new Image();
|
||||
label = new Label();
|
||||
add(image, label);
|
||||
label.setPaddingLeft(5, Unit.PIXEL);
|
||||
setAlignItems(Alignment.CENTER);
|
||||
}
|
||||
|
||||
public void setInstallationId(String installationId) {
|
||||
image.setSrc(avatarService.getAvatar(installationId));
|
||||
label.setText(installationId);
|
||||
}
|
||||
}
|
|
@ -20,7 +20,7 @@ package com.faendir.acra.ui.component;
|
|||
* @author lukas
|
||||
* @since 19.11.18
|
||||
*/
|
||||
public class Label extends com.vaadin.flow.component.html.Label {
|
||||
public class Label extends com.vaadin.flow.component.html.Label implements HasStyle {
|
||||
public Label() {
|
||||
}
|
||||
|
||||
|
|
|
@ -25,20 +25,17 @@ import com.faendir.acra.ui.base.HasSecureStringParameter;
|
|||
import com.faendir.acra.ui.base.Path;
|
||||
import com.faendir.acra.ui.component.Card;
|
||||
import com.faendir.acra.ui.component.CssGrid;
|
||||
import com.faendir.acra.ui.component.FlexLayout;
|
||||
import com.faendir.acra.ui.component.HasSize;
|
||||
import com.faendir.acra.ui.component.InstallationView;
|
||||
import com.faendir.acra.ui.component.Label;
|
||||
import com.faendir.acra.ui.component.Translatable;
|
||||
import com.faendir.acra.ui.view.MainView;
|
||||
import com.faendir.acra.ui.view.bug.tabs.ReportTab;
|
||||
import com.faendir.acra.util.Utils;
|
||||
import com.vaadin.flow.component.AttachEvent;
|
||||
import com.vaadin.flow.component.Component;
|
||||
import com.vaadin.flow.component.Composite;
|
||||
import com.vaadin.flow.component.Text;
|
||||
import com.vaadin.flow.component.html.Anchor;
|
||||
import com.vaadin.flow.component.html.Div;
|
||||
import com.vaadin.flow.component.orderedlayout.FlexComponent;
|
||||
import com.vaadin.flow.router.BeforeEvent;
|
||||
import com.vaadin.flow.router.Route;
|
||||
import com.vaadin.flow.server.InputStreamFactory;
|
||||
|
@ -47,11 +44,13 @@ import com.vaadin.flow.spring.annotation.SpringComponent;
|
|||
import com.vaadin.flow.spring.annotation.UIScope;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.xbib.time.pretty.PrettyTime;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
|
@ -64,14 +63,46 @@ import java.util.Optional;
|
|||
@Route(value = "report", layout = MainView.class)
|
||||
public class ReportView extends Composite<Div> implements HasSecureStringParameter, HasRoute {
|
||||
private final DataService dataService;
|
||||
private final AvatarService avatarService;
|
||||
private final Label version;
|
||||
private final Label date;
|
||||
private final InstallationView installation;
|
||||
private final Label email;
|
||||
private final Label comment;
|
||||
private final Translatable<Label> mappedStacktraceLabel;
|
||||
private final Translatable<Label> unmappedStacktraceLabel;
|
||||
private final Label stacktrace;
|
||||
private final Div attachments;
|
||||
private final Card details;
|
||||
private Report report;
|
||||
private PrettyTime prettyTime;
|
||||
|
||||
@Autowired
|
||||
public ReportView(@NonNull DataService dataService, @NonNull AvatarService avatarService) {
|
||||
this.dataService = dataService;
|
||||
this.avatarService = avatarService;
|
||||
prettyTime = new PrettyTime(Locale.US);
|
||||
getElement().getStyle().set("overflow", "auto");
|
||||
CssGrid summaryLayout = new CssGrid();
|
||||
summaryLayout.setTemplateColumns("auto auto");
|
||||
summaryLayout.setColumnGap(1, HasSize.Unit.EM);
|
||||
summaryLayout.setJustifyItems(CssGrid.JustifyMode.START);
|
||||
summaryLayout.setAlignItems(CssGrid.AlignMode.FIRST_BASELINE);
|
||||
Translatable<Label> installationLabel = Translatable.createLabel(Messages.USER).with(Label::secondary);
|
||||
version = new Label();
|
||||
date = new Label();
|
||||
installation = new InstallationView(avatarService);
|
||||
email = new Label();
|
||||
comment = new Label();
|
||||
mappedStacktraceLabel = Translatable.createLabel(Messages.DE_OBFUSCATED_STACKTRACE).with(Label::secondary);
|
||||
unmappedStacktraceLabel = Translatable.createLabel(Messages.NO_MAPPING_STACKTRACE).with(Label::secondary);
|
||||
stacktrace = new Label().honorWhitespaces();
|
||||
attachments = new Div();
|
||||
summaryLayout.add(Translatable.createLabel(Messages.VERSION).with(Label::secondary), version, Translatable.createLabel(Messages.DATE).with(Label::secondary), date, installationLabel, installation, Translatable.createLabel(Messages.EMAIL).with(Label::secondary), email, Translatable.createLabel(Messages.COMMENT).with(Label::secondary), comment, mappedStacktraceLabel, unmappedStacktraceLabel, stacktrace, Translatable.createLabel(Messages.ATTACHMENTS).with(Label::secondary));
|
||||
summaryLayout.alignItems(CssGrid.AlignMode.CENTER, installationLabel);
|
||||
Card summary = new Card(summaryLayout);
|
||||
summary.setHeader(Translatable.createText(Messages.SUMMARY));
|
||||
details = new Card();
|
||||
details.setHeader(Translatable.createText(Messages.DETAILS));
|
||||
getContent().add(summary, details);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -79,52 +110,34 @@ public class ReportView extends Composite<Div> implements HasSecureStringParamet
|
|||
Optional<Report> r = dataService.findReport(parameter);
|
||||
if (r.isPresent()) {
|
||||
report = r.get();
|
||||
version.setText(report.getStacktrace().getVersion().getName());
|
||||
date.setText(prettyTime.formatUnrounded(report.getDate().toLocalDateTime()));
|
||||
installation.setInstallationId(report.getInstallationId());
|
||||
email.setText(report.getUserEmail());
|
||||
comment.setText(report.getUserComment());
|
||||
Optional<String> mapping = Optional.ofNullable(report.getStacktrace().getVersion().getMappings());
|
||||
stacktrace.setText(mapping.map(m -> Utils.retrace(report.getStacktrace().getStacktrace(), m)).orElse(report.getStacktrace().getStacktrace()));
|
||||
mappedStacktraceLabel.getStyle().set("display", mapping.isPresent() ? null : "none");
|
||||
unmappedStacktraceLabel.getStyle().set("display", mapping.isPresent() ? "none" : null);
|
||||
attachments.removeAll();
|
||||
attachments.add(dataService.findAttachments(report).stream().map(attachment -> {
|
||||
Anchor anchor = new Anchor(new StreamResource(attachment.getFilename(), (InputStreamFactory) () -> {
|
||||
try {
|
||||
return attachment.getContent().getBinaryStream();
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e); //TODO
|
||||
}
|
||||
}), attachment.getFilename());
|
||||
anchor.getElement().setAttribute("download", true);
|
||||
return anchor;
|
||||
}).toArray(Component[]::new));
|
||||
details.removeAll();
|
||||
details.add(getLayoutForMap(report.getJsonObject().toMap()));
|
||||
} else {
|
||||
event.rerouteToError(IllegalArgumentException.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttach(AttachEvent attachEvent) {
|
||||
super.onAttach(attachEvent);
|
||||
getContent().removeAll();
|
||||
CssGrid summaryLayout = new CssGrid();
|
||||
summaryLayout.setTemplateColumns("auto auto");
|
||||
summaryLayout.setColumnGap(1, HasSize.Unit.EM);
|
||||
summaryLayout.setJustifyItems(CssGrid.JustifyMode.START);
|
||||
summaryLayout.setAlignItems(CssGrid.AlignMode.FIRST_BASELINE);
|
||||
summaryLayout.add(Translatable.createLabel(Messages.VERSION).with(Label::secondary), new Label(report.getStacktrace().getVersion().getName()));
|
||||
FlexLayout userLayout = new FlexLayout(avatarService.getAvatar(report), new Text(report.getInstallationId()));
|
||||
userLayout.setAlignItems(FlexComponent.Alignment.CENTER);
|
||||
Translatable<Label> userLabel = Translatable.createLabel(Messages.USER).with(Label::secondary);
|
||||
summaryLayout.alignItems(CssGrid.AlignMode.CENTER, userLabel);
|
||||
summaryLayout.add(userLabel, userLayout);
|
||||
summaryLayout.add(Translatable.createLabel(Messages.EMAIL).with(Label::secondary), new Label(report.getUserEmail()));
|
||||
summaryLayout.add(Translatable.createLabel(Messages.COMMENT).with(Label::secondary), new Label(report.getUserComment()));
|
||||
Optional<String> mapping = Optional.ofNullable(report.getStacktrace().getVersion().getMappings());
|
||||
Label stacktrace = new Label(mapping.map(m -> Utils.retrace(report.getStacktrace().getStacktrace(), m)).orElse(report.getStacktrace().getStacktrace()));
|
||||
stacktrace.honorWhitespaces();
|
||||
summaryLayout.add(Translatable.createLabel(mapping.isPresent() ? Messages.DE_OBFUSCATED_STACKTRACE : Messages.NO_MAPPING_STACKTRACE).with(Label::secondary), stacktrace);
|
||||
summaryLayout.add(Translatable.createLabel(Messages.ATTACHMENTS).with(Label::secondary), new Div(dataService.findAttachments(report).stream().map(attachment -> {
|
||||
Anchor anchor = new Anchor(new StreamResource(attachment.getFilename(), (InputStreamFactory) () -> {
|
||||
try {
|
||||
return attachment.getContent().getBinaryStream();
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e); //TODO
|
||||
}
|
||||
}), attachment.getFilename());
|
||||
anchor.getElement().setAttribute("download", true);
|
||||
return anchor;
|
||||
}).toArray(Component[]::new)));
|
||||
Card summaryCard = new Card(summaryLayout);
|
||||
summaryCard.setHeader(Translatable.createText(Messages.SUMMARY));
|
||||
getContent().add(summaryCard);
|
||||
|
||||
Card detailCard = new Card(getLayoutForMap(report.getJsonObject().toMap()));
|
||||
detailCard.setHeader(Translatable.createText(Messages.DETAILS));
|
||||
getContent().add(detailCard);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Div getLayoutForMap(@NonNull Map<String, ?> map) {
|
||||
CssGrid layout = new CssGrid();
|
||||
|
@ -159,7 +172,7 @@ public class ReportView extends Composite<Div> implements HasSecureStringParamet
|
|||
@NonNull
|
||||
@Override
|
||||
public Path.Element<?> getPathElement() {
|
||||
return new Path.ParametrizedTextElement<>(getClass(), report.getId(), Messages.ONE_ARG, report.getId());
|
||||
return new Path.ParametrizedTextElement<>(getClass(), report.getId(), Messages.REPORT_FROM, prettyTime.formatUnrounded(report.getDate().toLocalDateTime()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -157,4 +157,5 @@ passwordRequired=Ein Passwort muss gesetzt werden
|
|||
welcome=Willkommen zu
|
||||
createAdmin=Zuerst müssen Sie einen Adminstrator anlegen:
|
||||
notSolved=Nicht gelöst
|
||||
versionName=Versionsname
|
||||
versionName=Versionsname
|
||||
reportFrom=Bericht vom %s
|
|
@ -157,4 +157,5 @@ passwordRequired=A password is required
|
|||
welcome=Welcome to
|
||||
createAdmin=First, you have to create an administrator:
|
||||
notSolved=Not solved
|
||||
versionName=Version name
|
||||
versionName=Version name
|
||||
reportFrom=Report from %s
|
Loading…
Reference in a new issue