fix showing solved bugs
This commit is contained in:
parent
aeaff00798
commit
589bb861b4
9 changed files with 103 additions and 199 deletions
|
@ -1,96 +0,0 @@
|
|||
package com.faendir.acra.dataprovider;
|
||||
|
||||
import com.faendir.acra.config.AcraConfiguration;
|
||||
import com.vaadin.data.provider.AbstractBackEndDataProvider;
|
||||
import com.vaadin.data.provider.Query;
|
||||
import com.vaadin.data.provider.QuerySortOrder;
|
||||
import com.vaadin.shared.data.sort.SortDirection;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.IntSupplier;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* @author Lukas
|
||||
* @since 13.12.2017
|
||||
*/
|
||||
public class BufferedDataProvider<T> extends AbstractBackEndDataProvider<T, Void> implements ObservableDataProvider<T, Void> {
|
||||
private final int pageSize;
|
||||
private final Function<Pageable, Slice<T>> getter;
|
||||
private final IntSupplier counter;
|
||||
private final List<SizeListener> sizeListeners;
|
||||
|
||||
public BufferedDataProvider(int pageSize, Function<Pageable, Slice<T>> getter, IntSupplier counter) {
|
||||
this.getter = getter;
|
||||
this.counter = counter;
|
||||
this.pageSize = pageSize;
|
||||
this.sizeListeners = new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Stream<T> fetchFromBackEnd(Query<T, Void> query) {
|
||||
Sort sort = Sort.by(query.getSortOrders().stream().map(OrderAdapter::new).collect(Collectors.toList()));
|
||||
Slice<T> slice = getter.apply(PageRequest.of(query.getOffset() / pageSize, pageSize, sort));
|
||||
if (!slice.hasContent()) return Stream.empty();
|
||||
List<T> content = slice.getContent();
|
||||
int ignore = query.getOffset() % pageSize;
|
||||
int size = content.size() - ignore;
|
||||
Stream<T> result = content.stream().skip(ignore);
|
||||
while (size < query.getLimit() && slice.hasNext()) {
|
||||
slice = getter.apply(slice.nextPageable());
|
||||
if (slice.hasContent()) {
|
||||
content = slice.getContent();
|
||||
size += content.size();
|
||||
result = Stream.concat(result, content.stream());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int sizeInBackEnd(Query<T, Void> query) {
|
||||
int result = counter.getAsInt();
|
||||
sizeListeners.forEach(listener -> listener.sizeChanged(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSizeListener(SizeListener listener) {
|
||||
sizeListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSizeListener(SizeListener listener) {
|
||||
sizeListeners.remove(listener);
|
||||
}
|
||||
|
||||
@Component
|
||||
public static class Factory {
|
||||
private final AcraConfiguration configuration;
|
||||
|
||||
@Autowired
|
||||
public Factory(AcraConfiguration configuration) {
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
public <P, T> BufferedDataProvider<T> create(P parameter, BiFunction<P, Pageable, Slice<T>> getter, Function<P, Integer> counter) {
|
||||
return new BufferedDataProvider<>(configuration.getPaginationSize(), pageable -> getter.apply(parameter, pageable), () -> counter.apply(parameter));
|
||||
}
|
||||
}
|
||||
|
||||
private static class OrderAdapter extends Sort.Order {
|
||||
OrderAdapter(QuerySortOrder adapt) {
|
||||
super(adapt.getDirection() == SortDirection.ASCENDING ? Sort.Direction.ASC : Sort.Direction.DESC, adapt.getSorted());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
package com.faendir.acra.dataprovider;
|
||||
|
||||
import com.vaadin.data.provider.DataProvider;
|
||||
|
||||
/**
|
||||
* @author Lukas
|
||||
* @since 06.01.2018
|
||||
*/
|
||||
public interface ObservableDataProvider<T,F> extends DataProvider<T,F> {
|
||||
void addSizeListener(SizeListener listener);
|
||||
|
||||
void removeSizeListener(SizeListener listener);
|
||||
|
||||
interface SizeListener {
|
||||
void sizeChanged(int size);
|
||||
}
|
||||
}
|
|
@ -13,16 +13,17 @@ import java.util.ArrayList;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* @author lukas
|
||||
* @since 30.05.18
|
||||
*/
|
||||
public class QueryDslDataProvider<T> extends AbstractBackEndDataProvider<T, Void> implements ObservableDataProvider<T, Void> {
|
||||
public class QueryDslDataProvider<T> extends AbstractBackEndDataProvider<T, Void> {
|
||||
private final List<SizeListener> sizeListeners;
|
||||
private final JPAQuery<T> fetchBase;
|
||||
private final JPAQuery<?> countBase;
|
||||
private final Supplier<JPAQuery<T>> fetchProvider;
|
||||
private final Supplier<JPAQuery<?>> countProvider;
|
||||
private final Map<String, Expression<? extends Comparable>> sortOptions;
|
||||
|
||||
public QueryDslDataProvider(JPAQuery<T> base) {
|
||||
|
@ -30,22 +31,20 @@ public class QueryDslDataProvider<T> extends AbstractBackEndDataProvider<T, Void
|
|||
}
|
||||
|
||||
public QueryDslDataProvider(JPAQuery<T> fetchBase, JPAQuery<?> countBase) {
|
||||
this.fetchBase = fetchBase;
|
||||
this.countBase = countBase;
|
||||
this(fetchBase::clone, countBase::clone);
|
||||
}
|
||||
|
||||
public QueryDslDataProvider(Supplier<JPAQuery<T>> fetchProvider, Supplier<JPAQuery<?>> countProvider){
|
||||
this.fetchProvider = fetchProvider;
|
||||
this.countProvider = countProvider;
|
||||
sizeListeners = new ArrayList<>();
|
||||
sortOptions = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSizeListener(SizeListener listener) {
|
||||
sizeListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSizeListener(SizeListener listener) {
|
||||
sizeListeners.remove(listener);
|
||||
}
|
||||
|
||||
public String addSortable(Expression<? extends Comparable> expression) {
|
||||
String id = String.valueOf(sortOptions.size());
|
||||
sortOptions.put(id, expression);
|
||||
|
@ -54,7 +53,7 @@ public class QueryDslDataProvider<T> extends AbstractBackEndDataProvider<T, Void
|
|||
|
||||
@Override
|
||||
protected Stream<T> fetchFromBackEnd(Query<T, Void> query) {
|
||||
JPAQuery<T> q = fetchBase.clone().offset(query.getOffset()).limit(query.getLimit());
|
||||
JPAQuery<T> q = fetchProvider.get().offset(query.getOffset()).limit(query.getLimit());
|
||||
for (QuerySortOrder order : query.getSortOrders()) {
|
||||
Expression<? extends Comparable> sort = sortOptions.get(order.getSorted());
|
||||
if (sort != null) {
|
||||
|
@ -66,8 +65,13 @@ public class QueryDslDataProvider<T> extends AbstractBackEndDataProvider<T, Void
|
|||
|
||||
@Override
|
||||
protected int sizeInBackEnd(Query<T, Void> query) {
|
||||
int result = Math.toIntExact(countBase.fetchCount());
|
||||
int result = Math.toIntExact(countProvider.get().fetchCount());
|
||||
sizeListeners.forEach(listener -> listener.sizeChanged(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface SizeListener {
|
||||
void sizeChanged(int size);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,33 +1,31 @@
|
|||
package com.faendir.acra.model.view;
|
||||
|
||||
import com.faendir.acra.model.QApp;
|
||||
import com.faendir.acra.model.QBug;
|
||||
import com.faendir.acra.model.QReport;
|
||||
import com.querydsl.jpa.impl.JPAQuery;
|
||||
import org.springframework.lang.NonNull;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
import static com.faendir.acra.model.QApp.app;
|
||||
import static com.faendir.acra.model.QBug.bug;
|
||||
import static com.faendir.acra.model.QReport.report;
|
||||
|
||||
/**
|
||||
* @author lukas
|
||||
* @since 30.05.18
|
||||
*/
|
||||
public abstract class Queries {
|
||||
private static final QApp APP = QApp.app;
|
||||
private static final QReport REPORT = QReport.report;
|
||||
private static final QBug BUG = QBug.bug;
|
||||
private static final JPAQuery<VBug> V_BUG = new JPAQuery<>().from(BUG)
|
||||
.join(REPORT)
|
||||
.on(REPORT.bug.eq(BUG))
|
||||
.select(new QVBug(BUG, REPORT.date.max(), REPORT.count()))
|
||||
.groupBy(BUG);
|
||||
private static final JPAQuery<VApp> V_APP = new JPAQuery<>().from(APP)
|
||||
.join(BUG)
|
||||
.on(BUG.app.eq(APP))
|
||||
.join(REPORT)
|
||||
.on(REPORT.bug.eq(BUG))
|
||||
.select(new QVApp(APP, REPORT.count()))
|
||||
.groupBy(APP);
|
||||
private static final JPAQuery<VBug> V_BUG = new JPAQuery<>().from(bug)
|
||||
.join(report)
|
||||
.on(report.bug.eq(bug))
|
||||
.select(new QVBug(bug, report.date.max(), report.count()))
|
||||
.groupBy(bug);
|
||||
private static final JPAQuery<VApp> V_APP = new JPAQuery<>().from(app)
|
||||
.join(bug)
|
||||
.on(bug.app.eq(app))
|
||||
.join(report)
|
||||
.on(report.bug.eq(bug))
|
||||
.select(new QVApp(app, bug.countDistinct(), report.count()))
|
||||
.groupBy(app);
|
||||
|
||||
public static JPAQuery<VBug> selectVBug(@NonNull EntityManager entityManager) {
|
||||
return V_BUG.clone(entityManager);
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.faendir.acra.model.view;
|
|||
|
||||
import com.faendir.acra.model.App;
|
||||
import com.querydsl.core.annotations.QueryProjection;
|
||||
import org.springframework.lang.NonNull;
|
||||
|
||||
/**
|
||||
* @author lukas
|
||||
|
@ -10,11 +11,13 @@ import com.querydsl.core.annotations.QueryProjection;
|
|||
public class VApp {
|
||||
private final App app;
|
||||
private final long reportCount;
|
||||
private final long bugCount;
|
||||
|
||||
@QueryProjection
|
||||
public VApp(App app, long reportCount) {
|
||||
public VApp(App app, long bugCount, long reportCount) {
|
||||
this.app = app;
|
||||
this.reportCount = reportCount;
|
||||
this.bugCount = bugCount;
|
||||
}
|
||||
|
||||
public App getApp() {
|
||||
|
@ -24,4 +27,17 @@ public class VApp {
|
|||
public long getReportCount() {
|
||||
return reportCount;
|
||||
}
|
||||
|
||||
public long getBugCount() {
|
||||
return bugCount;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return app.getId();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String getName() {
|
||||
return app.getName();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,12 +7,7 @@ import com.faendir.acra.model.Bug;
|
|||
import com.faendir.acra.model.Permission;
|
||||
import com.faendir.acra.model.ProguardMapping;
|
||||
import com.faendir.acra.model.QApp;
|
||||
import com.faendir.acra.model.QAttachment;
|
||||
import com.faendir.acra.model.QBug;
|
||||
import com.faendir.acra.model.QPermission;
|
||||
import com.faendir.acra.model.QProguardMapping;
|
||||
import com.faendir.acra.model.QReport;
|
||||
import com.faendir.acra.model.QUser;
|
||||
import com.faendir.acra.model.Report;
|
||||
import com.faendir.acra.model.User;
|
||||
import com.faendir.acra.model.view.Queries;
|
||||
|
@ -58,22 +53,25 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.faendir.acra.model.QApp.app;
|
||||
import static com.faendir.acra.model.QAttachment.attachment;
|
||||
import static com.faendir.acra.model.QBug.bug;
|
||||
import static com.faendir.acra.model.QPermission.permission;
|
||||
import static com.faendir.acra.model.QProguardMapping.proguardMapping;
|
||||
import static com.faendir.acra.model.QReport.report;
|
||||
import static com.faendir.acra.model.QUser.user;
|
||||
|
||||
/**
|
||||
* @author lukas
|
||||
* @since 16.05.18
|
||||
*/
|
||||
@Service
|
||||
public class DataService implements Serializable {
|
||||
private static final QUser USER = QUser.user;
|
||||
private static final QPermission PERMISSION = QPermission.permission;
|
||||
private static final QApp APP = QApp.app;
|
||||
private static final QReport REPORT = QReport.report;
|
||||
private static final QBug BUG = QBug.bug;
|
||||
private static final QProguardMapping MAPPING = QProguardMapping.proguardMapping;
|
||||
private static final QAttachment ATTACHMENT = QAttachment.attachment;
|
||||
@NonNull private final Log log = LogFactory.getLog(getClass());
|
||||
@NonNull private final UserService userService;
|
||||
@NonNull private final EntityManager entityManager;
|
||||
|
@ -89,32 +87,33 @@ public class DataService implements Serializable {
|
|||
boolean isAdmin = SecurityUtils.hasRole(User.Role.ADMIN);
|
||||
Function<JPQLQuery<?>, BooleanExpression> existenceFunction = isAdmin ? JPQLQuery::notExists : JPQLQuery::exists;
|
||||
BiFunction<EnumPath<Permission.Level>, Permission.Level, BooleanExpression> compareFunction = isAdmin ? EnumPath::lt : EnumPath::goe;
|
||||
BooleanExpression where = existenceFunction.apply(JPAExpressions.select(PERMISSION)
|
||||
.from(USER)
|
||||
.join(USER.permissions, PERMISSION)
|
||||
.where(USER.username.eq(SecurityUtils.getUsername()).and(PERMISSION.app.eq(APP)).and(compareFunction.apply(PERMISSION.level, Permission.Level.VIEW))));
|
||||
return new QueryDslDataProvider<>(Queries.selectVApp(entityManager).where(where), new JPAQuery<>(entityManager).from(APP).where(where));
|
||||
BooleanExpression where = existenceFunction.apply(JPAExpressions.select(permission)
|
||||
.from(user)
|
||||
.join(user.permissions, permission)
|
||||
.where(user.username.eq(SecurityUtils.getUsername()).and(permission.app.eq(app)).and(compareFunction.apply(permission.level, Permission.Level.VIEW))));
|
||||
return new QueryDslDataProvider<>(Queries.selectVApp(entityManager).where(where), new JPAQuery<>(entityManager).from(app).where(where));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public QueryDslDataProvider<VBug> getBugProvider(@NonNull App app, boolean onlyNonSolved) {
|
||||
BooleanExpression where = BUG.app.eq(app).and(onlyNonSolved ? BUG.solved.eq(false) : Expressions.TRUE);
|
||||
return new QueryDslDataProvider<>(Queries.selectVBug(entityManager).where(where), new JPAQuery<>(entityManager).from(BUG).where(where));
|
||||
public QueryDslDataProvider<VBug> getBugProvider(@NonNull App app, BooleanSupplier onlyNonSolvedProvider) {
|
||||
Supplier<BooleanExpression> whereSupplier = () -> onlyNonSolvedProvider.getAsBoolean() ? bug.app.eq(app).and(bug.solved.eq(false)) : bug.app.eq(app);
|
||||
return new QueryDslDataProvider<>(() -> Queries.selectVBug(entityManager).where(whereSupplier.get()),
|
||||
() -> new JPAQuery<>(entityManager).from(bug).where(whereSupplier.get()));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public QueryDslDataProvider<Report> getReportProvider(@NonNull Bug bug) {
|
||||
return new QueryDslDataProvider<>(new JPAQuery<>(entityManager).from(REPORT).where(REPORT.bug.eq(bug)).select(REPORT));
|
||||
return new QueryDslDataProvider<>(new JPAQuery<>(entityManager).from(report).where(report.bug.eq(bug)).select(report));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public QueryDslDataProvider<Report> getReportProvider(@NonNull App app) {
|
||||
return new QueryDslDataProvider<>(new JPAQuery<>(entityManager).from(REPORT).join(REPORT.bug).where(REPORT.bug.app.eq(app)).select(REPORT));
|
||||
return new QueryDslDataProvider<>(new JPAQuery<>(entityManager).from(report).join(report.bug).where(report.bug.app.eq(app)).select(report));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public QueryDslDataProvider<ProguardMapping> getMappingProvider(@NonNull App app) {
|
||||
return new QueryDslDataProvider<>(new JPAQuery<>(entityManager).from(MAPPING).where(MAPPING.app.eq(app)).select(MAPPING));
|
||||
return new QueryDslDataProvider<>(new JPAQuery<>(entityManager).from(proguardMapping).where(proguardMapping.app.eq(app)).select(proguardMapping));
|
||||
}
|
||||
|
||||
@Transactional
|
||||
|
@ -154,9 +153,9 @@ public class DataService implements Serializable {
|
|||
Bug bug = list.remove(0);
|
||||
bug.setTitle(title);
|
||||
StringPath stringPath = Expressions.stringPath("trace");
|
||||
bug.setStacktraces(new JPAQuery<>(entityManager).from(BUG).join(BUG.stacktraces, stringPath).where(BUG.in(bugs)).select(stringPath).fetch());
|
||||
bug.setStacktraces(new JPAQuery<>(entityManager).from(QBug.bug).join(QBug.bug.stacktraces, stringPath).where(QBug.bug.in(bugs)).select(stringPath).fetch());
|
||||
bug = store(bug);
|
||||
CloseableIterator<Report> iterator = new JPAQuery<>(entityManager).from(REPORT).where(REPORT.bug.in(list)).select(REPORT).iterate();
|
||||
CloseableIterator<Report> iterator = new JPAQuery<>(entityManager).from(report).where(report.bug.in(list)).select(report).iterate();
|
||||
while (iterator.hasNext()) {
|
||||
Report report = iterator.next();
|
||||
report.setBug(bug);
|
||||
|
@ -174,25 +173,28 @@ public class DataService implements Serializable {
|
|||
|
||||
@NonNull
|
||||
public Optional<ProguardMapping> findMapping(@NonNull App app, int versionCode) {
|
||||
return Optional.ofNullable(new JPAQuery<>(entityManager).from(MAPPING).where(MAPPING.app.eq(app).and(MAPPING.versionCode.eq(versionCode))).select(MAPPING).fetchOne());
|
||||
return Optional.ofNullable(new JPAQuery<>(entityManager).from(proguardMapping)
|
||||
.where(proguardMapping.app.eq(app).and(proguardMapping.versionCode.eq(versionCode)))
|
||||
.select(proguardMapping)
|
||||
.fetchOne());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Optional<Report> findReport(@NonNull String id) {
|
||||
return Optional.ofNullable(new JPAQuery<>(entityManager).from(REPORT)
|
||||
.join(REPORT.bug, BUG)
|
||||
return Optional.ofNullable(new JPAQuery<>(entityManager).from(report)
|
||||
.join(report.bug, bug)
|
||||
.fetchJoin()
|
||||
.join(BUG.app, APP)
|
||||
.join(bug.app, app)
|
||||
.fetchJoin()
|
||||
.where(REPORT.id.eq(id))
|
||||
.select(REPORT)
|
||||
.where(report.id.eq(id))
|
||||
.select(report)
|
||||
.fetchOne());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Optional<VBug> findBug(@NonNull String encodedId) {
|
||||
try {
|
||||
return Optional.ofNullable(Queries.selectVBug(entityManager).where(BUG.id.eq(Integer.parseInt(encodedId))).fetchOne());
|
||||
return Optional.ofNullable(Queries.selectVBug(entityManager).where(bug.id.eq(Integer.parseInt(encodedId))).fetchOne());
|
||||
} catch (NumberFormatException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
@ -201,7 +203,7 @@ public class DataService implements Serializable {
|
|||
@NonNull
|
||||
public Optional<App> findApp(@NonNull String encodedId) {
|
||||
try {
|
||||
return Optional.ofNullable(new JPAQuery<>(entityManager).from(APP).where(APP.id.eq(Integer.parseInt(encodedId))).select(APP).fetchOne());
|
||||
return Optional.ofNullable(new JPAQuery<>(entityManager).from(app).where(app.id.eq(Integer.parseInt(encodedId))).select(app).fetchOne());
|
||||
} catch (NumberFormatException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
@ -209,27 +211,27 @@ public class DataService implements Serializable {
|
|||
|
||||
@NonNull
|
||||
public List<App> findAllApps() {
|
||||
return new JPAQuery<>(entityManager).from(APP).select(APP).fetch();
|
||||
return new JPAQuery<>(entityManager).from(app).select(app).fetch();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public List<Attachment> findAttachments(@NonNull Report report) {
|
||||
return new JPAQuery<>(entityManager).from(ATTACHMENT).where(ATTACHMENT.report.eq(report)).select(ATTACHMENT).fetch();
|
||||
return new JPAQuery<>(entityManager).from(attachment).where(attachment.report.eq(report)).select(attachment).fetch();
|
||||
}
|
||||
|
||||
private void deleteOrphanBugs() {
|
||||
new JPADeleteClause(entityManager, BUG).where(JPAExpressions.selectFrom(REPORT).where(REPORT.bug.eq(BUG)).notExists()).execute();
|
||||
new JPADeleteClause(entityManager, bug).where(JPAExpressions.selectFrom(report).where(report.bug.eq(bug)).notExists()).execute();
|
||||
}
|
||||
|
||||
private Optional<Bug> findBug(@NonNull App app, @NonNull String stacktrace) {
|
||||
return Optional.ofNullable(new JPAQuery<>(entityManager).from(BUG).where(BUG.app.eq(app).and(BUG.stacktraces.any().eq(stacktrace))).select(BUG).fetchFirst());
|
||||
return Optional.ofNullable(new JPAQuery<>(entityManager).from(bug).where(bug.app.eq(app).and(bug.stacktraces.any().eq(stacktrace))).select(bug).fetchFirst());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void changeConfiguration(@NonNull App app, @NonNull App.Configuration configuration) {
|
||||
app.setConfiguration(configuration);
|
||||
app = store(app);
|
||||
CloseableIterator<Report> iterator = new JPAQuery<>(entityManager).from(REPORT).join(REPORT.bug, BUG).where(BUG.app.eq(app)).select(REPORT).iterate();
|
||||
CloseableIterator<Report> iterator = new JPAQuery<>(entityManager).from(report).join(report.bug, bug).where(bug.app.eq(app)).select(report).iterate();
|
||||
while (iterator.hasNext()) {
|
||||
Report report = iterator.next();
|
||||
String stacktrace = Utils.generifyStacktrace(report.getStacktrace(), app.getConfiguration());
|
||||
|
@ -250,19 +252,19 @@ public class DataService implements Serializable {
|
|||
public void deleteReportsOlderThanDays(@NonNull App app, @NonNull int days) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.add(Calendar.DAY_OF_MONTH, -days);
|
||||
new JPADeleteClause(entityManager, REPORT).where(REPORT.bug.app.eq(app).and(REPORT.date.before(calendar.getTime())));
|
||||
new JPADeleteClause(entityManager, report).where(report.bug.app.eq(app).and(report.date.before(calendar.getTime())));
|
||||
deleteOrphanBugs();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void deleteReportsBeforeVersion(@NonNull App app, int versionCode) {
|
||||
new JPADeleteClause(entityManager, REPORT).where(REPORT.bug.app.eq(app).and(REPORT.versionCode.lt(versionCode)));
|
||||
new JPADeleteClause(entityManager, report).where(report.bug.app.eq(app).and(report.versionCode.lt(versionCode)));
|
||||
deleteOrphanBugs();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void createNewReport(@NonNull String reporterUserName, @NonNull String content, @NonNull List<MultipartFile> attachments) {
|
||||
App app = new JPAQuery<>(entityManager).from(APP).where(APP.reporter.username.eq(reporterUserName)).select(APP).fetchOne();
|
||||
App app = new JPAQuery<>(entityManager).from(QApp.app).where(QApp.app.reporter.username.eq(reporterUserName)).select(QApp.app).fetchOne();
|
||||
if (app != null) {
|
||||
JSONObject jsonObject = new JSONObject(content);
|
||||
String stacktrace = Utils.generifyStacktrace(jsonObject.optString(ReportField.STACK_TRACE.name()), app.getConfiguration());
|
||||
|
@ -281,8 +283,8 @@ public class DataService implements Serializable {
|
|||
}
|
||||
|
||||
public <T> Map<T, Long> countReports(@NonNull Predicate where, Expression<?> groupBy, @NonNull Expression<T> select) {
|
||||
List<Tuple> result = ((JPAQuery<?>) new JPAQuery<>(entityManager)).from(REPORT).where(where).groupBy(groupBy).select(select, REPORT.id.count()).fetch();
|
||||
return result.stream().collect(Collectors.toMap(tuple -> tuple.get(select), tuple -> tuple.get(REPORT.id.count())));
|
||||
List<Tuple> result = ((JPAQuery<?>) new JPAQuery<>(entityManager)).from(report).where(where).groupBy(groupBy).select(select, report.id.count()).fetch();
|
||||
return result.stream().collect(Collectors.toMap(tuple -> tuple.get(select), tuple -> tuple.get(report.id.count())));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
@ -292,6 +294,6 @@ public class DataService implements Serializable {
|
|||
|
||||
@NonNull
|
||||
public <T> List<T> getFromReports(@NonNull Predicate where, @NonNull Expression<T> select, ComparableExpressionBase<?> order) {
|
||||
return ((JPAQuery<?>) new JPAQuery<>(entityManager)).from(REPORT).where(where).select(select).distinct().orderBy(order.asc()).fetch();
|
||||
return ((JPAQuery<?>) new JPAQuery<>(entityManager)).from(report).where(where).select(select).distinct().orderBy(order.asc()).fetch();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.faendir.acra.ui.view;
|
||||
|
||||
import com.faendir.acra.model.QApp;
|
||||
import com.faendir.acra.model.QBug;
|
||||
import com.faendir.acra.model.QReport;
|
||||
import com.faendir.acra.model.User;
|
||||
import com.faendir.acra.model.view.VApp;
|
||||
|
@ -46,9 +47,10 @@ public class Overview extends BaseView {
|
|||
grid.setResponsive(true);
|
||||
grid.setSizeToRows();
|
||||
grid.setSelectionMode(Grid.SelectionMode.NONE);
|
||||
grid.addColumn(app -> app.getApp().getName(), QApp.app.name, "Name");
|
||||
grid.addColumn(VApp::getName, QApp.app.name, "Name");
|
||||
grid.addColumn(VApp::getBugCount, QBug.bug.countDistinct(), "Bugs");
|
||||
grid.addColumn(VApp::getReportCount, QReport.report.count(), "Reports");
|
||||
grid.addOnClickNavigation(getNavigationManager(), AppView.class, e -> String.valueOf(e.getItem().getApp().getId()));
|
||||
grid.addOnClickNavigation(getNavigationManager(), AppView.class, e -> String.valueOf(e.getItem().getId()));
|
||||
VerticalLayout layout = new VerticalLayout();
|
||||
if (SecurityUtils.hasRole(User.Role.ADMIN)) {
|
||||
Button add = new Button("New App", e -> addApp());
|
||||
|
|
|
@ -63,11 +63,11 @@ public class BugTab implements AppTab {
|
|||
layout.addComponent(header);
|
||||
layout.setComponentAlignment(header, Alignment.MIDDLE_LEFT);
|
||||
CheckBox hideSolved = new CheckBox("Hide solved", true);
|
||||
MyGrid<VBug> bugs = new MyGrid<>(null, dataService.getBugProvider(app, true));
|
||||
MyGrid<VBug> bugs = new MyGrid<>(null, dataService.getBugProvider(app, hideSolved::getValue));
|
||||
bugs.setSelectionMode(Grid.SelectionMode.MULTI);
|
||||
hideSolved.addValueChangeListener(e -> layout.getUI().access(() -> {
|
||||
Set<VBug> selection = bugs.getSelectedItems();
|
||||
bugs.setDataProvider(dataService.getBugProvider(app, e.getValue()));
|
||||
bugs.getDataProvider().refreshAll();
|
||||
selection.forEach(bugs::select);
|
||||
}));
|
||||
Button merge = new Button("Merge bugs", e -> {
|
||||
|
|
|
@ -25,7 +25,7 @@ import java.util.function.Function;
|
|||
*/
|
||||
public class MyGrid<T> extends Composite {
|
||||
private final ExposingGrid<T> grid;
|
||||
private QueryDslDataProvider<T> dataProvider;
|
||||
private final QueryDslDataProvider<T> dataProvider;
|
||||
|
||||
public MyGrid(String caption, QueryDslDataProvider<T> dataProvider) {
|
||||
this.dataProvider = dataProvider;
|
||||
|
@ -106,11 +106,6 @@ public class MyGrid<T> extends Composite {
|
|||
return dataProvider;
|
||||
}
|
||||
|
||||
public void setDataProvider(QueryDslDataProvider<T> dataProvider) {
|
||||
this.dataProvider = dataProvider;
|
||||
grid.setDataProvider(dataProvider);
|
||||
}
|
||||
|
||||
public static class MiddleClickExtension<T> extends Grid.AbstractGridExtension<T> {
|
||||
private MiddleClickExtension(MyGrid<T> myGrid) {
|
||||
ExposingGrid<T> grid = myGrid.grid;
|
||||
|
|
Loading…
Reference in a new issue