rework gui to be more wizard like:

* show first only checkbox list of checks and single run button
* then show list of check run status with results
This commit is contained in:
Armin Schrenk
2021-05-20 16:33:37 +02:00
parent 432be6dd80
commit 85ff7542f1
5 changed files with 66 additions and 36 deletions

View File

@@ -9,6 +9,7 @@ public enum FontAwesome5Icon {
BAN("\uF05E"), //
BUG("\uF188"), //
CHECK("\uF00C"), //
CLOCK("\uF017"), //
COG("\uF013"), //
COGS("\uF085"), //
COPY("\uF0C5"), //

View File

@@ -20,6 +20,9 @@ class CheckListCell extends ListCell<HealthCheckTask> {
item.stateProperty().addListener(this::stateChanged);
setGraphic(stateIcon);
stateIcon.setGlyph(glyphForState(item.getState()));
if (item.getState() == Worker.State.READY) {
stateIcon.setVisible(false);
}
setContentDisplay(ContentDisplay.LEFT);
} else {
setText(null);
@@ -29,12 +32,14 @@ class CheckListCell extends ListCell<HealthCheckTask> {
private void stateChanged(ObservableValue<? extends Worker.State> observable, Worker.State oldState, Worker.State newState) {
stateIcon.setGlyph(glyphForState(newState));
stateIcon.setVisible(true);
}
private FontAwesome5Icon glyphForState(Worker.State state) {
// TODO choose appropriate glyphs
return switch (state) {
case READY, SCHEDULED -> FontAwesome5Icon.ANCHOR;
case READY -> FontAwesome5Icon.COG; //just a placeholder
case SCHEDULED -> FontAwesome5Icon.CLOCK;
case RUNNING -> FontAwesome5Icon.SPINNER;
case FAILED -> FontAwesome5Icon.EXCLAMATION_TRIANGLE;
case CANCELLED -> FontAwesome5Icon.BAN;

View File

@@ -10,15 +10,22 @@ import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javafx.beans.binding.Binding;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Worker;
import javafx.fxml.FXML;
import javafx.scene.control.ListView;
import javafx.scene.control.cell.CheckBoxListCell;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
@@ -35,8 +42,10 @@ public class CheckListController implements FxController {
private final SimpleObjectProperty<Worker<?>> runningTask;
private final Binding<Boolean> running;
private final Binding<Boolean> finished;
private final Map<HealthCheckTask, BooleanProperty> listPickIndicators;
private final IntegerProperty numberOfPickedChecks;
private final BooleanBinding anyCheckSelected;
private final BooleanBinding readyToRun;
private final BooleanProperty showResultScreen;
/* FXML */
public ListView<HealthCheckTask> checksListView;
@@ -51,33 +60,35 @@ public class CheckListController implements FxController {
this.runningTask = new SimpleObjectProperty<>();
this.running = EasyBind.wrapNullable(runningTask).mapObservable(Worker::runningProperty).orElse(false);
this.finished = EasyBind.wrapNullable(runningTask).mapObservable(Worker::stateProperty).map(END_STATES::contains).orElse(false);
this.readyToRun = runningTask.isNull();
this.listPickIndicators = new HashMap<>();
this.numberOfPickedChecks = new SimpleIntegerProperty(0);
this.tasks.forEach(task -> {
var entrySelectedProp = new SimpleBooleanProperty(false);
entrySelectedProp.addListener((observable, oldValue, newValue) -> numberOfPickedChecks.set(numberOfPickedChecks.get() + (newValue ? 1 : -1)));
listPickIndicators.put(task, entrySelectedProp);
});
this.anyCheckSelected = selectedTask.isNotNull();
this.showResultScreen = new SimpleBooleanProperty(false);
}
@FXML
public void initialize() {
checksListView.setItems(tasks);
checksListView.setCellFactory(ignored -> new CheckListCell());
checksListView.setCellFactory(CheckBoxListCell.forListView(listPickIndicators::get));
selectedTask.bind(checksListView.getSelectionModel().selectedItemProperty());
}
@FXML
public synchronized void runSelectedChecks() {
startBatch(checksListView.getSelectionModel().getSelectedItems());
}
@FXML
public synchronized void runAllChecks() {
startBatch(checksListView.getItems());
}
private void startBatch(Iterable<HealthCheckTask> batch) {
public void runSelectedChecks() {
Preconditions.checkState(runningTask.get() == null);
var batch = checksListView.getItems().filtered(item -> listPickIndicators.get(item).get());
var batchService = new BatchService(batch);
batchService.setExecutor(executorService);
batchService.start();
runningTask.set(batchService);
checksListView.setCellFactory(view -> new CheckListCell());
showResultScreen.set(true);
checksListView.getSelectionModel().select(batch.getViewIndex(0));
}
@FXML
@@ -95,17 +106,8 @@ public class CheckListController implements FxController {
LOG.error("Failed to write health check report.", e);
}
}
/* Getter/Setter */
public boolean isReadyToRun() {
return readyToRun.get();
}
public BooleanBinding readyToRunProperty() {
return readyToRun;
}
public boolean isRunning() {
return running.getValue();
}
@@ -130,4 +132,21 @@ public class CheckListController implements FxController {
return anyCheckSelected;
}
public boolean getShowResultScreen() {
return showResultScreen.get();
}
public BooleanProperty showResultScreenProperty() {
return showResultScreen;
}
public int getNumberOfPickedChecks() {
return numberOfPickedChecks.get();
}
public IntegerProperty numberOfPickedChecksProperty() {
return numberOfPickedChecks;
}
}

View File

@@ -7,6 +7,7 @@
<?import javafx.scene.control.ListView?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import java.lang.Integer?>
<?import javafx.scene.layout.StackPane?>
<VBox xmlns:fx="http://javafx.com/fxml"
xmlns="http://javafx.com/javafx"
@@ -18,25 +19,28 @@
<padding>
<Insets topRightBottomLeft="12"/>
</padding>
<fx:define>
<Integer fx:id="ZERO" fx:value="0"/>
</fx:define>
<children>
<HBox spacing="12" VBox.vgrow="ALWAYS">
<VBox minWidth="80" spacing="6" >
<Label fx:id="listHeading" text="Health checks"/>
<!-- TODO:HEADER with select all checkbox -->
<ListView fx:id="checksListView" VBox.vgrow="ALWAYS"/>
</VBox>
<!-- Maybe use class Seperator ?-->
<VBox minWidth="300" alignment="CENTER" HBox.hgrow="ALWAYS" visible="${!controller.anyCheckSelected}" managed="${!controller.anyCheckSelected}" >
<Label text="TODO: Select a Check from the left list to get more info." wrapText="true" alignment="CENTER" />
</VBox>
<fx:include source="/fxml/health_check_details.fxml" visible="${controller.anyCheckSelected}" managed="${controller.anyCheckSelected}" HBox.hgrow="ALWAYS" />
<StackPane visible="${controller.showResultScreen}" managed="${controller.showResultScreen}" HBox.hgrow="ALWAYS" >
<VBox minWidth="300" alignment="CENTER" visible="${!controller.anyCheckSelected}" managed="${!controller.anyCheckSelected}" >
<Label text="%health.check.result.noSelectedCheck" wrapText="true" alignment="CENTER" />
</VBox>
<fx:include source="/fxml/health_check_details.fxml" visible="${controller.anyCheckSelected}" managed="${controller.anyCheckSelected}" />
</StackPane>
</HBox>
<ButtonBar buttonMinWidth="120" buttonOrder="+CX">
<buttons>
<!-- Buttons have a prefWidth to prevent uneven interface -->
<Button prefWidth="20" text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" onAction="#cancelCheck" visible="${controller.running}" managed="${controller.running}" />
<Button prefWidth="20" text="%health.check.runAllButton" ButtonBar.buttonData="NEXT_FORWARD" onAction="#runAllChecks" visible="${controller.readyToRun &amp;&amp; !controller.anyCheckSelected}" managed="${controller.readyToRun &amp;&amp; !controller.anyCheckSelected}" />
<Button prefWidth="20" text="%health.check.runSingleButton" ButtonBar.buttonData="NEXT_FORWARD" onAction="#runSelectedChecks" visible="${controller.readyToRun &amp;&amp; controller.anyCheckSelected}" managed="${controller.readyToRun &amp;&amp; controller.anyCheckSelected}" />
<Button text="TODO Export Results" ButtonBar.buttonData="NEXT_FORWARD" disable="${!controller.finished}" visible="${!controller.readyToRun}" managed="${!controller.readyToRun}" onAction="#exportResults"/>
<Button text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" onAction="#cancelCheck" disable="${!controller.running}" visible="${controller.showResultScreen}" managed="${controller.showResultScreen}" />
<Button text="%health.check.export" ButtonBar.buttonData="NEXT_FORWARD" defaultButton="true" disable="${!controller.finished}" visible="${controller.showResultScreen}" managed="${controller.showResultScreen}" onAction="#exportResults"/>
<Button text="%health.check.runBatchButton" ButtonBar.buttonData="NEXT_FORWARD" defaultButton="true" onAction="#runSelectedChecks" disable="${controller.numberOfPickedChecks == ZERO}" visible="${!controller.showResultScreen}" managed="${!controller.showResultScreen}"/>
</buttons>
</ButtonBar>
</children>

View File

@@ -148,8 +148,9 @@ migration.impossible.moreInfo=The vault can still be opened with an older versio
# Health Check
health.title=Vault Check
health.check.runSingleButton=Run selected Check
health.check.runAllButton=Run all Checks
health.check.runBatchButton=Run selected Checks
health.check.result.noSelectedCheck=For results select a finished check in the left list.
health.check.export=Export Report
# Preferences
preferences.title=Preferences