Implement fix all button

This commit is contained in:
Armin Schrenk
2022-11-25 17:17:55 +01:00
parent 74e3c28441
commit 4dc1d59305
5 changed files with 95 additions and 42 deletions

View File

@@ -8,8 +8,12 @@ import org.cryptomator.ui.common.FxController;
import javax.inject.Inject;
import javafx.beans.binding.Binding;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.binding.BooleanExpression;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.fxml.FXML;
@@ -35,30 +39,42 @@ public class CheckDetailController implements FxController {
private final Binding<Number> countOfCritSeverity;
private final Binding<Boolean> warnOrCritsExist;
private final ResultListCellFactory resultListCellFactory;
private final ResultFixApplier resultFixApplier;
private final BooleanProperty fixAllInfoResultsExecuted;
private final BooleanBinding fixAllInfoResultsPossible;
public ListView<Result> resultsListView;
private Subscription resultSubscription;
@Inject
public CheckDetailController(ObjectProperty<Check> selectedTask, ResultListCellFactory resultListCellFactory) {
public CheckDetailController(ObjectProperty<Check> selectedTask, ResultListCellFactory resultListCellFactory, ResultFixApplier resultFixApplier) {
this.resultListCellFactory = resultListCellFactory;
this.resultFixApplier = resultFixApplier;
this.results = EasyBind.wrapList(FXCollections.observableArrayList());
this.check = selectedTask;
this.checkState = selectedTask.flatMap(Check::stateProperty);
this.checkName = selectedTask.map(Check::getName).orElse("");
this.checkRunning = BooleanExpression.booleanExpression(checkState.map(Check.CheckState.RUNNING::equals).orElse(false));
this.checkScheduled = BooleanExpression.booleanExpression(checkState.map(Check.CheckState.SCHEDULED::equals).orElse(false));
this.checkSkipped =BooleanExpression.booleanExpression(checkState.map(Check.CheckState.SKIPPED::equals).orElse(false));
this.checkSkipped = BooleanExpression.booleanExpression(checkState.map(Check.CheckState.SKIPPED::equals).orElse(false));
this.checkSucceeded = BooleanExpression.booleanExpression(checkState.map(Check.CheckState.SUCCEEDED::equals).orElse(false));
this.checkFailed = BooleanExpression.booleanExpression(checkState.map(Check.CheckState.ERROR::equals).orElse(false));
this.checkCancelled = BooleanExpression.booleanExpression(checkState.map(Check.CheckState.CANCELLED::equals).orElse(false));
this.checkFinished = checkSucceeded.or(checkFailed).or(checkCancelled);
this.countOfWarnSeverity = results.reduce(countSeverity(DiagnosticResult.Severity.WARN));
this.countOfCritSeverity = results.reduce(countSeverity(DiagnosticResult.Severity.CRITICAL));
this.warnOrCritsExist = EasyBind.combine(checkSucceeded, countOfWarnSeverity, countOfCritSeverity, (suceeded, warns, crits) -> suceeded && (warns.longValue() > 0 || crits.longValue() > 0) );
this.warnOrCritsExist = EasyBind.combine(checkSucceeded, countOfWarnSeverity, countOfCritSeverity, (suceeded, warns, crits) -> suceeded && (warns.longValue() > 0 || crits.longValue() > 0));
this.fixAllInfoResultsExecuted = new SimpleBooleanProperty(false);
this.fixAllInfoResultsPossible = Bindings.createBooleanBinding(() -> results.stream().anyMatch(this::isFixableInfoResult), results) //
.and(fixAllInfoResultsExecuted.not());
selectedTask.addListener(this::selectedTaskChanged);
}
private boolean isFixableInfoResult(Result r) {
return r.diagnosis().getSeverity() == DiagnosticResult.Severity.INFO && r.getState() == Result.FixState.FIXABLE;
}
private void selectedTaskChanged(ObservableValue<? extends Check> observable, Check oldValue, Check newValue) {
if (resultSubscription != null) {
resultSubscription.unsubscribe();
@@ -78,6 +94,13 @@ public class CheckDetailController implements FxController {
resultsListView.setCellFactory(resultListCellFactory);
}
@FXML
public void fixAllInfoResults() {
fixAllInfoResultsExecuted.setValue(true);
results.stream().filter(this::isFixableInfoResult).forEach(resultFixApplier::fix);
}
/* Getter/Setter */
public String getCheckName() {
@@ -175,4 +198,13 @@ public class CheckDetailController implements FxController {
public Check getCheck() {
return check.get();
}
public ObservableValue<Boolean> fixAllInfoResultsPossibleProperty() {
return fixAllInfoResultsPossible;
}
public boolean getFixAllInfoResultsPossible() {
return fixAllInfoResultsPossible.getValue();
}
}

View File

@@ -23,6 +23,8 @@ import java.util.concurrent.atomic.AtomicReference;
@HealthCheckScoped
class ResultFixApplier {
private static final Logger LOG = LoggerFactory.getLogger(ResultFixApplier.class);
private final Path vaultPath;
private final SecureRandom csprng;
private final Masterkey masterkey;
@@ -40,19 +42,26 @@ class ResultFixApplier {
public CompletionStage<Void> fix(Result result) {
Preconditions.checkArgument(result.getState() == Result.FixState.FIXABLE);
result.setState(Result.FixState.FIXING);
return CompletableFuture.runAsync(() -> fix(result.diagnosis()), sequentialExecutor)
return CompletableFuture.runAsync(() -> result.setState(Result.FixState.FIXING), Platform::runLater) //
.thenRunAsync(() -> fix(result.diagnosis()), sequentialExecutor) //
.whenCompleteAsync((unused, throwable) -> {
var fixed = throwable == null ? Result.FixState.FIXED : Result.FixState.FIX_FAILED;
result.setState(fixed);
final Result.FixState s;
if (throwable == null) {
LOG.debug("Fix for {} applied successful.", result.diagnosis().getClass().getName());
s = Result.FixState.FIXED;
} else {
LOG.error("Failed to apply fix for {}", result.diagnosis().getClass().getName(), throwable);
s = Result.FixState.FIX_FAILED;
}
result.setState(s);
}, Platform::runLater);
}
public void fix(DiagnosticResult diagnosis) {
private void fix(DiagnosticResult diagnosis) {
try (var masterkeyClone = masterkey.copy(); //
var cryptor = CryptorProvider.forScheme(vaultConfig.getCipherCombo()).provide(masterkeyClone, csprng)) {
diagnosis.getFix(vaultPath, vaultConfig, masterkeyClone, cryptor)
.orElseThrow(() -> new IllegalStateException("No fix for diagnosis "+diagnosis.getClass().getName() +" implemented."))
diagnosis.getFix(vaultPath, vaultConfig, masterkeyClone, cryptor) //
.orElseThrow(() -> new IllegalStateException("No fix for diagnosis " + diagnosis.getClass().getName() + " implemented.")) //
.apply();
} catch (Exception e) {
throw new FixFailedException(e);
@@ -60,6 +69,7 @@ class ResultFixApplier {
}
public static class FixFailedException extends CompletionException {
private FixFailedException(Throwable cause) {
super(cause);
}

View File

@@ -12,7 +12,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.binding.ObjectBinding;
@@ -49,8 +48,8 @@ public class ResultListCellController implements FxController {
private final BooleanBinding fixFailed;
private final BooleanBinding fixRunningOrDone;
private final List<Subscription> subscriptions;
private final Tooltip fixSuccess;
private final Tooltip fixFail;
private final Tooltip fixSuccessTip;
private final Tooltip fixFailTip;
private AutoAnimator fixRunningRotator;
@@ -73,10 +72,10 @@ public class ResultListCellController implements FxController {
this.fixFailed = Bindings.createBooleanBinding(this::isFixFailed, fixState);
this.fixRunningOrDone = fixing.or(fixed).or(fixFailed);
this.subscriptions = new ArrayList<>();
this.fixSuccess = new Tooltip(resourceBundle.getString("health.fix.successTip"));
this.fixFail = new Tooltip(resourceBundle.getString("health.fix.failTip"));
fixSuccess.setShowDelay(Duration.millis(100));
fixFail.setShowDelay(Duration.millis(100));
this.fixSuccessTip = new Tooltip(resourceBundle.getString("health.fix.successTip"));
this.fixFailTip = new Tooltip(resourceBundle.getString("health.fix.failTip"));
fixSuccessTip.setShowDelay(Duration.millis(100));
fixFailTip.setShowDelay(Duration.millis(100));
}
@FXML
@@ -93,22 +92,20 @@ public class ResultListCellController implements FxController {
.onCondition(fixing) //
.afterStop(() -> fixView.setRotate(0)) //
.build();
fixState.addListener(((observable, oldValue, newValue) -> {
if (newValue == Result.FixState.FIXED) {
Tooltip.install(fixView, fixSuccessTip);
} else if (newValue == Result.FixState.FIX_FAILED) {
Tooltip.install(fixView, fixFailTip);
}
}));
}
@FXML
public void fix() {
Result r = result.get();
if (r != null) {
fixApplier.fix(r).whenCompleteAsync(this::fixFinished, Platform::runLater);
}
}
private void fixFinished(Void unused, Throwable exception) {
if (exception != null) {
LOG.error("Failed to apply fix", exception);
Tooltip.install(fixView, fixFail);
} else {
Tooltip.install(fixView, fixSuccess);
fixApplier.fix(r);
}
}