mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-25 09:00:26 +00:00
Improve state display
This commit is contained in:
parent
38cdf08bf2
commit
2069d08db1
8 changed files with 96 additions and 18 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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(
|
||||
() -> {
|
||||
|
|
|
@ -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,9 +21,11 @@ public class DataStateProviderImpl extends DataStateProvider {
|
|||
return;
|
||||
}
|
||||
|
||||
entry.get().getElementState().put(key, value);
|
||||
var old = entry.get().getElementState().put(key, value);
|
||||
if (!Objects.equals(old, value)) {
|
||||
entry.get().simpleRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getState(DataStore store, String key, Class<T> c, Supplier<T> def) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue