Improve state display

This commit is contained in:
crschnick 2023-06-29 22:58:03 +00:00
parent 38cdf08bf2
commit 2069d08db1
8 changed files with 96 additions and 18 deletions

View file

@ -1,14 +1,16 @@
package io.xpipe.app.comp.base;
import atlantafx.base.theme.Styles;
import io.xpipe.app.fxcomps.SimpleComp;
import io.xpipe.app.fxcomps.impl.FancyTooltipAugment;
import io.xpipe.app.fxcomps.util.PlatformThread;
import io.xpipe.app.fxcomps.util.SimpleChangeListener;
import javafx.beans.binding.Bindings;
import javafx.beans.value.ObservableValue;
import javafx.scene.layout.Pane;
import javafx.geometry.Pos;
import javafx.scene.layout.Region;
import org.kordamp.ikonli.javafx.FontIcon;
import org.kordamp.ikonli.javafx.StackedFontIcon;
public class SystemStateComp extends SimpleComp {
@ -19,8 +21,8 @@ public class SystemStateComp extends SimpleComp {
}
public static enum State {
STOPPED,
RUNNING,
FAILURE,
SUCCESS,
OTHER
}
@ -29,14 +31,45 @@ public class SystemStateComp extends SimpleComp {
@Override
protected Region createSimple() {
var icon = PlatformThread.sync(Bindings.createStringBinding(() -> {
return state.getValue() == State.STOPPED ? "mdmz-stop_circle" : state.getValue() == State.RUNNING ? "mdrmz-play_circle_outline" : "mdmz-remove_circle_outline";
}, state));
var icon = PlatformThread.sync(Bindings.createStringBinding(
() -> {
return state.getValue() == State.FAILURE
? "mdi2l-lightning-bolt"
: state.getValue() == State.SUCCESS ? "mdal-check" : "mdsmz-remove";
},
state));
var fi = new FontIcon();
fi.getStyleClass().add("inner-icon");
SimpleChangeListener.apply(icon, val -> fi.setIconLiteral(val));
new FancyTooltipAugment<>(PlatformThread.sync(name)).augment(fi);
var pane = new Pane(fi);
var border = new FontIcon("mdi2c-circle-outline");
border.getStyleClass().add("outer-icon");
border.setOpacity(0.5);
var success = Styles.toDataURI(".stacked-ikonli-font-icon > .outer-icon { -fx-icon-color: -color-success-emphasis; }");
var failure = Styles.toDataURI(".stacked-ikonli-font-icon > .outer-icon { -fx-icon-color: -color-danger-emphasis; }");
var other = Styles.toDataURI(".stacked-ikonli-font-icon > .outer-icon { -fx-icon-color: -color-accent-emphasis; }");
var pane = new StackedFontIcon();
pane.getChildren().addAll(fi, border);
pane.setAlignment(Pos.CENTER);
var dataClass1 = """
.stacked-ikonli-font-icon > .outer-icon {
-fx-icon-size: 22px;
}
.stacked-ikonli-font-icon > .inner-icon {
-fx-icon-size: 12px;
}
""";
pane.getStylesheets().add(Styles.toDataURI(dataClass1));
SimpleChangeListener.apply(PlatformThread.sync(state), val -> {
pane.getStylesheets().removeAll(success, failure, other);
pane.getStylesheets().add(val == State.SUCCESS ? success : val == State.FAILURE ? failure: other);
});
new FancyTooltipAugment<>(PlatformThread.sync(name)).augment(pane);
return pane;
}
}

View file

@ -98,9 +98,14 @@ public abstract class StoreEntryComp extends SimpleComp {
protected Label createInformation() {
var information = new Label();
information.setGraphicTextGap(7);
information.textProperty().bind(PlatformThread.sync(entry.getInformation()));
information.getStyleClass().add("information");
AppFont.header(information);
var state = entry.getEntry().getProvider().stateDisplay(entry);
information.setGraphic(state.createRegion());
return information;
}

View file

@ -1,12 +1,14 @@
package io.xpipe.app.ext;
import io.xpipe.app.comp.base.MarkdownComp;
import io.xpipe.app.comp.base.SystemStateComp;
import io.xpipe.app.comp.storage.store.StandardStoreEntryComp;
import io.xpipe.app.comp.storage.store.StoreEntrySectionComp;
import io.xpipe.app.comp.storage.store.StoreEntryWrapper;
import io.xpipe.app.comp.storage.store.StoreSection;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.fxcomps.Comp;
import io.xpipe.app.storage.DataStoreEntry;
import io.xpipe.core.dialog.Dialog;
import io.xpipe.core.store.*;
import io.xpipe.core.util.JacksonizedValue;
@ -40,6 +42,28 @@ public interface DataStoreProvider {
return new StoreEntrySectionComp(section);
}
default String failureInfo() {
return null;
}
default Comp<?> stateDisplay(StoreEntryWrapper w) {
var state = Bindings.createObjectBinding(
() -> {
return w.getState().getValue() == DataStoreEntry.State.COMPLETE_BUT_INVALID
? SystemStateComp.State.FAILURE
: w.getState().getValue() == DataStoreEntry.State.COMPLETE_AND_VALID
? SystemStateComp.State.SUCCESS
: SystemStateComp.State.OTHER;
},
w.getState());
var name = Bindings.createStringBinding(
() -> {
return w.getState().getValue() == DataStoreEntry.State.COMPLETE_BUT_INVALID ? "stop" : "start";
},
w.getState());
return new SystemStateComp(name, state);
}
default Comp<?> createInsightsComp(ObservableValue<DataStore> store) {
var content = Bindings.createStringBinding(
() -> {

View file

@ -4,6 +4,7 @@ import io.xpipe.core.store.DataStore;
import io.xpipe.core.util.DataStateProvider;
import java.nio.file.Path;
import java.util.Objects;
import java.util.UUID;
import java.util.function.Supplier;
@ -20,8 +21,10 @@ public class DataStateProviderImpl extends DataStateProvider {
return;
}
entry.get().getElementState().put(key, value);
entry.get().simpleRefresh();
var old = entry.get().getElementState().put(key, value);
if (!Objects.equals(old, value)) {
entry.get().simpleRefresh();
}
}
@Override

View file

@ -97,6 +97,13 @@ public class DataStoreEntry extends StorageElement {
State state,
Configuration configuration,
boolean expanded) {
// The validation must be stuck if that happens
var stateToUse = state;
if (state == State.VALIDATING) {
stateToUse = State.COMPLETE_BUT_INVALID;
}
var entry = new DataStoreEntry(
directory,
uuid,
@ -106,7 +113,7 @@ public class DataStoreEntry extends StorageElement {
information,
storeNode,
false,
state,
stateToUse,
configuration,
expanded);
return entry;
@ -216,12 +223,6 @@ public class DataStoreEntry extends StorageElement {
TODO: Implement singular change functions
*/
public void refresh(boolean deep) throws Exception {
// Assume that refresh can't be called while validating.
// Therefore the validation must be stuck if that happens
if (state == State.VALIDATING) {
state = State.COMPLETE_BUT_INVALID;
}
var oldStore = store;
DataStore newStore = DataStorageParser.storeFromNode(storeNode);
if (newStore == null

View file

@ -31,7 +31,14 @@ public sealed interface OsType permits OsType.Windows, OsType.Linux, OsType.MacO
}
default String getSystemIdFile(ShellControl pc) throws Exception {
return FileNames.join(getXPipeHomeDirectory(pc), "system_id");
var home = getXPipeHomeDirectory(pc);
// Sometimes the home variable is not set or empty
if (home == null || home.isBlank()) {
return null;
}
return FileNames.join(home, "system_id");
}
List<String> determineInterestingPaths(ShellControl pc) throws Exception;

View file

@ -25,6 +25,8 @@ public interface ShellDialect {
.collect(Collectors.joining(" "));
}
CommandControl queryVersion(ShellControl shellControl);
CommandControl prepareTempDirectory(ShellControl shellControl, String directory);
String initFileName(ShellControl sc) throws Exception;

View file

@ -30,6 +30,9 @@ public class XPipeSystemId {
public static UUID getSystemId(ShellControl proc) throws Exception {
var file = proc.getOsType().getSystemIdFile(proc);
if (file == null) {
return UUID.randomUUID();
}
if (!proc.getShellDialect().createFileExistsCommand(proc, file).executeAndCheck()) {
return writeRandom(proc, file);