This commit is contained in:
crschnick
2026-05-18 11:04:16 +00:00
parent 26b62dde59
commit bba6715bfe
82 changed files with 522 additions and 514 deletions

View File

@@ -62,9 +62,7 @@ public final class BrowserConnectionListComp extends SimpleRegionBuilder {
});
busyEntries.addListener((SetChangeListener<? super StoreSection>) change -> {
PlatformThread.runLaterIfNeeded(() -> {
struc.pseudoClassStateChanged(
BUSY,
change.getSet().contains(s));
struc.pseudoClassStateChanged(BUSY, change.getSet().contains(s));
});
});
});

View File

@@ -10,7 +10,6 @@ import io.xpipe.app.platform.DerivedObservableList;
import io.xpipe.app.platform.LabelGraphic;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.util.DocumentationLink;
import io.xpipe.app.util.ThreadHelper;
import javafx.beans.binding.Bindings;

View File

@@ -2,7 +2,6 @@ package io.xpipe.app.browser.file;
import io.xpipe.app.browser.BrowserFullSessionModel;
import io.xpipe.app.browser.action.impl.TransferFilesActionProvider;
import io.xpipe.app.comp.base.ModalOverlay;
import io.xpipe.app.core.AppCache;
import io.xpipe.app.core.AppLocalTemp;
import io.xpipe.app.core.AppSystemInfo;

View File

@@ -10,8 +10,8 @@ import io.xpipe.app.ext.FileKind;
import io.xpipe.app.platform.LabelGraphic;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.util.ThreadHelper;
import io.xpipe.core.OsType;
import javafx.beans.value.ObservableValue;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
@@ -49,7 +49,8 @@ public class EditFileMenuProvider implements BrowserMenuLeafProvider {
public KeyCombination getShortcut() {
return switch (OsType.ofLocal()) {
case OsType.Linux linux -> new KeyCodeCombination(KeyCode.ENTER, KeyCombination.SHORTCUT_DOWN);
case OsType.MacOs macOs -> new KeyCodeCombination(KeyCode.DOWN, KeyCombination.SHORTCUT_DOWN, KeyCombination.SHIFT_DOWN);
case OsType.MacOs macOs ->
new KeyCodeCombination(KeyCode.DOWN, KeyCombination.SHORTCUT_DOWN, KeyCombination.SHIFT_DOWN);
case OsType.Windows windows -> new KeyCodeCombination(KeyCode.ENTER, KeyCombination.SHORTCUT_DOWN);
};
}

View File

@@ -8,8 +8,8 @@ import io.xpipe.app.browser.menu.BrowserMenuCategory;
import io.xpipe.app.browser.menu.BrowserMenuLeafProvider;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.platform.LabelGraphic;
import io.xpipe.core.OsType;
import javafx.beans.value.ObservableValue;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
@@ -37,9 +37,9 @@ public class OpenFileDefaultMenuProvider implements BrowserMenuLeafProvider {
@Override
public KeyCombination getShortcut() {
return switch (OsType.ofLocal()) {
case OsType.Linux linux -> new KeyCodeCombination(KeyCode.ENTER);
case OsType.MacOs macOs -> new KeyCodeCombination(KeyCode.DOWN, KeyCombination.SHORTCUT_DOWN);
case OsType.Windows windows -> new KeyCodeCombination(KeyCode.ENTER);
case OsType.Linux ignored -> new KeyCodeCombination(KeyCode.ENTER);
case OsType.MacOs ignored -> new KeyCodeCombination(KeyCode.DOWN, KeyCombination.SHORTCUT_DOWN);
case OsType.Windows ignored -> new KeyCodeCombination(KeyCode.ENTER);
};
}

View File

@@ -12,9 +12,6 @@ import io.xpipe.app.platform.LabelGraphic;
import io.xpipe.core.OsType;
import javafx.beans.value.ObservableValue;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyCombination;
import java.util.List;

View File

@@ -8,8 +8,8 @@ import io.xpipe.app.browser.menu.BrowserMenuCategory;
import io.xpipe.app.browser.menu.BrowserMenuLeafProvider;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.platform.LabelGraphic;
import io.xpipe.core.OsType;
import javafx.beans.value.ObservableValue;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
@@ -32,9 +32,9 @@ public class OpenNativeFileDetailsMenuProvider implements BrowserMenuLeafProvide
@Override
public KeyCombination getShortcut() {
return switch (OsType.ofLocal()) {
case OsType.Linux linux -> new KeyCodeCombination(KeyCode.ENTER, KeyCombination.ALT_DOWN);
case OsType.MacOs macOs -> new KeyCodeCombination(KeyCode.I, KeyCombination.SHORTCUT_DOWN);
case OsType.Windows windows -> new KeyCodeCombination(KeyCode.ENTER, KeyCombination.ALT_DOWN);
case OsType.Linux ignored -> new KeyCodeCombination(KeyCode.ENTER, KeyCombination.ALT_DOWN);
case OsType.MacOs ignored -> new KeyCodeCombination(KeyCode.I, KeyCombination.SHORTCUT_DOWN);
case OsType.Windows ignored -> new KeyCodeCombination(KeyCode.ENTER, KeyCombination.ALT_DOWN);
};
}

View File

@@ -7,8 +7,8 @@ import io.xpipe.app.browser.menu.BrowserMenuLeafProvider;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.ext.FileKind;
import io.xpipe.app.platform.LabelGraphic;
import io.xpipe.core.OsType;
import javafx.beans.value.ObservableValue;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;

View File

@@ -15,8 +15,6 @@ import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseButton;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Rectangle;
import atlantafx.base.controls.CustomTextField;
import org.kordamp.ikonli.javafx.FontIcon;

View File

@@ -34,7 +34,11 @@ public class IntegratedTextAreaComp extends RegionStructureBuilder<AnchorPane, I
private final boolean fitHeight;
public IntegratedTextAreaComp(
Property<String> value, boolean lazy, String identifier, ObservableValue<String> fileType, boolean fitHeight) {
Property<String> value,
boolean lazy,
String identifier,
ObservableValue<String> fileType,
boolean fitHeight) {
this.value = value;
this.lazy = lazy;
this.identifier = identifier;
@@ -57,7 +61,8 @@ public class IntegratedTextAreaComp extends RegionStructureBuilder<AnchorPane, I
return script(value, type, fitHeight);
}
public static IntegratedTextAreaComp script(Property<ShellScript> value, ObservableValue<String> fileType, boolean fitHeight) {
public static IntegratedTextAreaComp script(
Property<ShellScript> value, ObservableValue<String> fileType, boolean fitHeight) {
var string = new SimpleStringProperty();
value.subscribe(shellScript -> {
string.set(shellScript != null ? shellScript.getValue() : null);

View File

@@ -6,8 +6,8 @@ import io.xpipe.app.comp.RegionBuilder;
import io.xpipe.app.core.AppLayoutModel;
import io.xpipe.app.hub.comp.StoreViewState;
import io.xpipe.app.platform.DerivedObservableList;
import io.xpipe.app.util.GlobalTimer;
import javafx.animation.AnimationTimer;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
@@ -162,11 +162,13 @@ public class ListBoxViewComp<T> extends RegionBuilder<ScrollPane> {
Platform.runLater(() -> {
dirty.set(true);
});
GlobalTimer.delay(() -> {
Platform.runLater(() -> {
dirty.set(true);
});
}, Duration.ofMillis(50));
GlobalTimer.delay(
() -> {
Platform.runLater(() -> {
dirty.set(true);
});
},
Duration.ofMillis(50));
});
shown.addListener((ListChangeListener<? super T>) (change) -> {
Platform.runLater(() -> {

View File

@@ -10,7 +10,6 @@ import io.xpipe.app.platform.PlatformThread;
import io.xpipe.core.InPlaceSecretValue;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleObjectProperty;

View File

@@ -76,7 +76,7 @@ public class SideMenuBarComp extends RegionBuilder<VBox> {
{
var b = new IconButtonComp("mdi2u-update", () -> {
ThreadHelper.runFailableAsync(() -> {
var r = UpdateAvailableDialog.showIfNeeded(false);
var r = UpdateAvailableDialog.showIfNeeded(false);
if (!r) {
AppPrefs.get().selectCategory("about");
UpdateHandler uh = AppDistributionType.get().getUpdateHandler();

View File

@@ -2,7 +2,6 @@ package io.xpipe.app.comp.base;
import io.xpipe.app.comp.RegionBuilder;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.issue.ErrorEventFactory;
import io.xpipe.app.util.ThreadHelper;
import io.xpipe.core.FailableSupplier;

View File

@@ -6,10 +6,7 @@ import io.xpipe.app.platform.PlatformThread;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleStringProperty;
import javafx.scene.control.TextField;
import javafx.scene.control.skin.TextFieldSkin;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Rectangle;
import java.util.Objects;

View File

@@ -8,14 +8,14 @@ import io.xpipe.app.platform.OptionsBuilder;
import io.xpipe.app.process.OsFileSystem;
import io.xpipe.app.util.ThreadHelper;
import io.xpipe.app.util.TlsCertificateFormat;
import javafx.beans.property.SimpleStringProperty;
import lombok.Getter;
import lombok.SneakyThrows;
import lombok.Value;
import org.apache.commons.io.FilenameUtils;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.nio.charset.StandardCharsets;
@@ -24,6 +24,8 @@ import java.nio.file.Path;
import java.security.KeyStore;
import java.security.cert.*;
import java.util.*;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
public class AppCertStore {
@@ -42,23 +44,23 @@ public class AppCertStore {
return trustManager.getAcceptedIssuers();
}
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
trustManager.checkClientTrusted(chain, authType);
}
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
try {
trustManager.checkServerTrusted(chain, authType);
} catch (CertificateException e) {
var cause = e.getCause();
var nonTrusted = cause != null && cause.getClass().getName().equals("sun.security.provider.certpath.SunCertPathBuilderException");
var nonTrusted = cause != null
&& cause.getClass()
.getName()
.equals("sun.security.provider.certpath.SunCertPathBuilderException");
if (nonTrusted) {
showTrustDialog(chain[chain.length - 1]);
ErrorEventFactory.preconfigure(ErrorEventFactory.fromThrowable(e)
.expected()
.omit());
ErrorEventFactory.preconfigure(
ErrorEventFactory.fromThrowable(e).expected().omit());
throw e;
} else {
throw ErrorEventFactory.expected(e);
@@ -69,10 +71,13 @@ public class AppCertStore {
@Getter
private final List<Entry> certificates;
private X509TrustManager trustManager;
private final SavingTrustManager savingTrustManager = new SavingTrustManager();
private AppCertStore(List<Entry> certificates) {this.certificates = certificates;}
private AppCertStore(List<Entry> certificates) {
this.certificates = certificates;
}
public static Path getDir() {
return AppProperties.get().getDataDir().resolve("cacerts");
@@ -137,8 +142,7 @@ public class AppCertStore {
String alias = list.nextElement();
// Check if this cert is labeled a trust anchor.
if (alias.contains(" [jdk")) {
X509Certificate cert = (X509Certificate) ks
.getCertificate(alias);
X509Certificate cert = (X509Certificate) ks.getCertificate(alias);
s.append(convertToPem(cert));
}
}
@@ -189,13 +193,18 @@ public class AppCertStore {
.prefWidth(650);
var modal = ModalOverlay.of("untrustedCertificateTitle", options);
modal.addButton(ModalButton.cancel());
modal.addButton(new ModalButton("trust", () -> {
ThreadHelper.runAsync(() -> {
addCertificate(name.getValue(), certificate);
});
}, true, true).augment(button -> {
button.disableProperty().bind(name.isNull());
}));
modal.addButton(new ModalButton(
"trust",
() -> {
ThreadHelper.runAsync(() -> {
addCertificate(name.getValue(), certificate);
});
},
true,
true)
.augment(button -> {
button.disableProperty().bind(name.isNull());
}));
modal.show();
}
@@ -235,7 +244,8 @@ public class AppCertStore {
INSTANCE = new AppCertStore(list);
try {
INSTANCE.refreshCertBundle(!AppProperties.get().isDevelopmentEnvironment() && AppProperties.get().isNewBuildSession());
INSTANCE.refreshCertBundle(!AppProperties.get().isDevelopmentEnvironment()
&& AppProperties.get().isNewBuildSession());
} catch (Exception e) {
ErrorEventFactory.fromThrowable(e).expected().handle();
}
@@ -248,7 +258,8 @@ public class AppCertStore {
private static X509Certificate parseCertificate(Path file) throws Exception {
var b = Files.readAllBytes(file);
return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(new ByteArrayInputStream(b));
return (X509Certificate)
CertificateFactory.getInstance("X.509").generateCertificate(new ByteArrayInputStream(b));
}
private static String convertToPem(X509Certificate cert) throws CertificateEncodingException {

View File

@@ -3,7 +3,6 @@ package io.xpipe.app.core;
import io.xpipe.app.Main;
import io.xpipe.app.core.mode.AppOperationMode;
import io.xpipe.app.issue.ErrorEventFactory;
import io.xpipe.app.issue.TrackEvent;
import io.xpipe.app.platform.PlatformState;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.util.ThreadHelper;

View File

@@ -28,7 +28,6 @@ import io.xpipe.app.prefs.WorkspaceManager;
import io.xpipe.app.process.LocalShell;
import io.xpipe.app.pwman.KeePassXcPasswordManager;
import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.core.AppCertStore;
import io.xpipe.app.storage.DataStorageSyncHandler;
import io.xpipe.app.terminal.TerminalDockHubManager;
import io.xpipe.app.terminal.TerminalLauncherManager;

View File

@@ -11,7 +11,6 @@ import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.update.AppDistributionType;
import io.xpipe.app.util.GlobalTimer;
import io.xpipe.app.util.NativeWinWindowControl;
import io.xpipe.app.util.ThreadHelper;
import io.xpipe.core.OsType;
import javafx.application.Platform;

View File

@@ -2,7 +2,6 @@ package io.xpipe.app.cred;
import io.xpipe.app.comp.base.*;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.AppSystemInfo;
import io.xpipe.app.ext.ProcessControlProvider;
import io.xpipe.app.ext.ShellStore;
import io.xpipe.app.ext.ValidationException;
@@ -21,7 +20,6 @@ import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.util.DocumentationLink;
import io.xpipe.app.util.ThreadHelper;
import io.xpipe.app.util.Validators;
import io.xpipe.core.FilePath;
import io.xpipe.core.InPlaceSecretValue;
import io.xpipe.core.KeyValue;
import io.xpipe.core.OsType;
@@ -154,7 +152,8 @@ public class KeyFileStrategy implements SshIdentityStrategy {
: (ShellStore) DataStorage.get().local().getStore();
var ex = fs.getOrStartSession().view().fileExists(pubFile);
if (ex) {
var contents = fs.getOrStartSession().view().readTextFile(pubFile).strip();
var contents =
fs.getOrStartSession().view().readTextFile(pubFile).strip();
Platform.runLater(() -> {
publicKey.set(contents);
});
@@ -272,7 +271,9 @@ public class KeyFileStrategy implements SshIdentityStrategy {
return List.of(
KeyValue.raw("IdentitiesOnly", "yes"),
KeyValue.raw("IdentityAgent", "none"),
KeyValue.escape("IdentityFile", file.toAbsoluteFilePath(sc).resolveTildeHome(sc.view().userHome())),
KeyValue.escape(
"IdentityFile",
file.toAbsoluteFilePath(sc).resolveTildeHome(sc.view().userHome())),
KeyValue.raw("PKCS11Provider", "none"));
}

View File

@@ -80,7 +80,8 @@ public class PasswordManagerAgentStrategy implements SshIdentityAgentStrategy {
.hide(pwmanErrorProp.isNull())
.nameAndDescription(useKeyName() ? "agentKeyName" : "publicKeyRequired")
.documentationLink(DocumentationLink.SSH_AGENT_PUBLIC_KEYS)
.addComp(new SshAgentKeyListComp(config.getFileSystem(), p, identifier, useKeyName(), false), identifier)
.addComp(
new SshAgentKeyListComp(config.getFileSystem(), p, identifier, useKeyName(), false), identifier)
.disable(pwmanErrorProp.isNotNull())
.nonNull()
.bind(

View File

@@ -147,8 +147,9 @@ public interface SecurityKeyImpl {
switch (sc.getOsType()) {
case OsType.MacOs ignored -> FilePath.of("/usr/lib/ssh-keychain.dylib");
default ->
throw ErrorEventFactory.expected(new UnsupportedOperationException(
"macOS keychain is not supported as a PKCS#11 provider on other operating systems"));
throw ErrorEventFactory.expected(
new UnsupportedOperationException(
"macOS keychain is not supported as a PKCS#11 provider on other operating systems"));
};
return file;
}

View File

@@ -4,9 +4,7 @@ import io.xpipe.app.core.AppInstallation;
import io.xpipe.app.ext.ProcessControlProvider;
import io.xpipe.app.ext.ShellStore;
import io.xpipe.app.ext.ValidationException;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.issue.ErrorEventFactory;
import io.xpipe.app.platform.BindingsHelper;
import io.xpipe.app.platform.OptionsBuilder;
import io.xpipe.app.platform.OptionsChoiceBuilder;
import io.xpipe.app.process.CommandBuilder;
@@ -19,7 +17,6 @@ import io.xpipe.app.util.Validators;
import io.xpipe.core.KeyValue;
import io.xpipe.core.OsType;
import javafx.beans.binding.Bindings;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
@@ -53,7 +50,9 @@ public class SecurityKeyStrategy implements SshIdentityKeyListStrategy {
}
ThreadHelper.runFailableAsync(() -> {
var fs = config.getFileSystem().getValue() != null ? config.getFileSystem().getValue().getStore() : (ShellStore) DataStorage.get().local().getStore().asNeeded();
var fs = config.getFileSystem().getValue() != null
? config.getFileSystem().getValue().getStore()
: (ShellStore) DataStorage.get().local().getStore().asNeeded();
filePath.set(impl.determineLibraryPath(fs.getOrStartSession()).toString());
});
});
@@ -67,7 +66,8 @@ public class SecurityKeyStrategy implements SshIdentityKeyListStrategy {
ThreadHelper.runFailableAsync(() -> {
var impl = securityKey.get();
if (impl != null) {
filePath.set(impl.determineLibraryPath(fs.getStore().getOrStartSession()).toString());
filePath.set(impl.determineLibraryPath(fs.getStore().getOrStartSession())
.toString());
} else {
filePath.set(null);
}

View File

@@ -39,8 +39,8 @@ public class SshAgentKeyListComp extends SimpleRegionBuilder {
ObservableValue<DataStoreEntryRef<ShellStore>> ref,
ObservableValue<? extends SshIdentityKeyListStrategy> sshIdentityStrategy,
StringProperty value,
boolean useKeyNames, boolean requireComplete
) {
boolean useKeyNames,
boolean requireComplete) {
this.ref = ref;
this.sshIdentityStrategy = sshIdentityStrategy;
this.value = value;
@@ -55,14 +55,16 @@ public class SshAgentKeyListComp extends SimpleRegionBuilder {
useKeyNames ? "<name>" : "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIBmhLUTJiP...== <key comment>"));
var button = new ButtonComp(null, new LabelGraphic.IconGraphic("mdi2m-magnify-scan"), null);
if (requireComplete) {
button.disable(Bindings.createBooleanBinding(() -> {
try {
sshIdentityStrategy.getValue().checkComplete();
return false;
} catch (Exception e) {
return true;
}
}, sshIdentityStrategy));
button.disable(Bindings.createBooleanBinding(
() -> {
try {
sshIdentityStrategy.getValue().checkComplete();
return false;
} catch (Exception e) {
return true;
}
},
sshIdentityStrategy));
}
button.apply(struc -> {
struc.setOnAction(event -> {

View File

@@ -3,8 +3,8 @@ package io.xpipe.app.ext;
import io.xpipe.app.comp.BaseRegionBuilder;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.hub.comp.StoreSection;
import io.xpipe.app.hub.comp.SystemStateComp;
import javafx.beans.binding.Bindings;
import javafx.beans.value.ObservableValue;
@@ -17,9 +17,13 @@ public interface CountGroupStoreProvider extends DataStoreProvider {
@Override
default BaseRegionBuilder<?, ?> stateDisplay(StoreSection section) {
return new SystemStateComp(Bindings.createObjectBinding(() -> {
return section.getShownChildren().getList().isEmpty() ? SystemStateComp.State.OTHER : SystemStateComp.State.SUCCESS;
}, section.getShownChildren().getList()));
return new SystemStateComp(Bindings.createObjectBinding(
() -> {
return section.getShownChildren().getList().isEmpty()
? SystemStateComp.State.OTHER
: SystemStateComp.State.SUCCESS;
},
section.getShownChildren().getList()));
}
@Override
@@ -28,20 +32,22 @@ public interface CountGroupStoreProvider extends DataStoreProvider {
() -> {
var all = section.getAllChildren().getList();
var allCount = all.stream()
.filter(s -> !excludeNonCountable() || s.getWrapper().getEntry().getProvider()
.includeInConnectionCount()).count();
.filter(s -> !excludeNonCountable()
|| s.getWrapper().getEntry().getProvider().includeInConnectionCount())
.count();
var shown = section.getShownChildren().getList();
var shownCount = shown.stream()
.filter(s -> !excludeNonCountable() || s.getWrapper().getEntry().getProvider()
.includeInConnectionCount()).count();
.filter(s -> !excludeNonCountable()
|| s.getWrapper().getEntry().getProvider().includeInConnectionCount())
.count();
if (allCount == 0) {
return AppI18n.get("no" + getCountTranslationKey() + "s");
}
var string = allCount == shownCount ? allCount : shownCount + "/" + allCount;
return allCount == 1
? AppI18n.get("has" + getCountTranslationKey(), string)
: AppI18n.get("has" + getCountTranslationKey() + "s", string);
? AppI18n.get("has" + getCountTranslationKey(), string)
: AppI18n.get("has" + getCountTranslationKey() + "s", string);
},
section.getShownChildren().getList(),
section.getAllChildren().getList(),

View File

@@ -88,5 +88,5 @@ public abstract class ProcessControlProvider {
public abstract void addAskpassEnvironment(
CommandBuilder b, String prefix, UUID requestId, UUID secretId, String... askpassName);
public abstract void refreshWsl() throws Exception;
public abstract void refreshWsl();
}

View File

@@ -34,7 +34,7 @@ public abstract class Session implements AutoCloseable {
}
if (checkInactive()) {
handleSessionDeath();
handleSessionDeath();
}
});
return false;

View File

@@ -9,7 +9,6 @@ import io.xpipe.core.FailableSupplier;
import lombok.Getter;
import java.time.Duration;
import java.time.Instant;
@Getter
public class ShellSession extends Session {
@@ -90,7 +89,9 @@ public class ShellSession extends Session {
@Override
public boolean checkInactive() {
var secs = AppPrefs.get() != null ? AppPrefs.get().backgroundSessionInactivityTimeout().getValue() : null;
var secs = AppPrefs.get() != null
? AppPrefs.get().backgroundSessionInactivityTimeout().getValue()
: null;
if (secs == null || secs <= 0) {
return false;
}

View File

@@ -31,7 +31,8 @@ public interface SingletonSessionStoreProvider extends DataStoreProvider {
default BaseRegionBuilder<?, ?> stateDisplay(StoreSection section) {
return new SystemStateComp(Bindings.createObjectBinding(
() -> {
SingletonSessionStore<?> s = section.getWrapper().getEntry().getStore().asNeeded();
SingletonSessionStore<?> s =
section.getWrapper().getEntry().getStore().asNeeded();
if (!supportsSession(s)) {
return SystemStateComp.State.SUCCESS;
}

View File

@@ -18,27 +18,29 @@ import java.util.Set;
public interface StartOnInitStore extends SelfReferentialStore, DataStore {
static void init() {
GlobalTimer.delay(() -> {
ThreadHelper.runFailableAsync(() -> {
var enabled = getEnabledStores();
for (DataStoreEntry e : DataStorage.get().getStoreEntries()) {
if (e.getStore() instanceof StartOnInitStore i
&& e.getValidity().isUsable()
&& enabled.contains(i.getSelfEntry().ref())
&& i.canAutomaticallyStart()) {
try {
i.startOnInit();
} catch (Throwable ex) {
ErrorEventFactory.fromThrowable(ex)
.description("Unable to automatically start connection "
+ DataStorage.get().getStoreEntryDisplayName(i.getSelfEntry()))
.expected()
.handle();
GlobalTimer.delay(
() -> {
ThreadHelper.runFailableAsync(() -> {
var enabled = getEnabledStores();
for (DataStoreEntry e : DataStorage.get().getStoreEntries()) {
if (e.getStore() instanceof StartOnInitStore i
&& e.getValidity().isUsable()
&& enabled.contains(i.getSelfEntry().ref())
&& i.canAutomaticallyStart()) {
try {
i.startOnInit();
} catch (Throwable ex) {
ErrorEventFactory.fromThrowable(ex)
.description("Unable to automatically start connection "
+ DataStorage.get().getStoreEntryDisplayName(i.getSelfEntry()))
.expected()
.handle();
}
}
}
}
}
});
}, Duration.ofSeconds(5));
});
},
Duration.ofSeconds(5));
}
static Set<DataStoreEntryRef<?>> getEnabledStores() {

View File

@@ -5,6 +5,7 @@ import io.xpipe.app.hub.action.HubLeafProvider;
import io.xpipe.app.hub.comp.StoreViewState;
import io.xpipe.app.storage.DataStoreEntryRef;
import io.xpipe.app.util.ThreadHelper;
import javafx.application.Platform;
public abstract class InitHubLeafProvider<T extends DataStore, O> implements HubLeafProvider<T> {

View File

@@ -97,7 +97,9 @@ public class StoreCategoryComp extends SimpleRegionBuilder {
})
.disable(Bindings.isEmpty(category.getChildren().getList()))
.style("expand-button")
.describe(d -> d.nameKey("expand").shortcut(new KeyCodeCombination(KeyCode.SPACE)).showTooltips(false));
.describe(d -> d.nameKey("expand")
.shortcut(new KeyCodeCombination(KeyCode.SPACE))
.showTooltips(false));
var focus = new SimpleBooleanProperty();
var hover = new SimpleBooleanProperty();

View File

@@ -87,51 +87,52 @@ public class StoreCategoryConfigComp extends SimpleRegionBuilder {
var syncDisable = !DataStorage.get().supportsSync()
|| ((sync.getValue() == null || !sync.getValue())
&& !wrapper.getCategory().canShare());
options.title("sync").sub(new OptionsBuilder().name(
specialCategorySync
? AppI18n.observable(
"categorySyncSpecial", wrapper.getName().getValue())
: AppI18n.observable("categorySync"))
.description("categorySyncDescription")
.addComp(createToggle(sync, parentConfig.getSync()), sync)
.disable(syncDisable)
)
options.title("sync")
.sub(new OptionsBuilder()
.name(
specialCategorySync
? AppI18n.observable(
"categorySyncSpecial",
wrapper.getName().getValue())
: AppI18n.observable("categorySync"))
.description("categorySyncDescription")
.addComp(createToggle(sync, parentConfig.getSync()), sync)
.disable(syncDisable))
.title("connectionHandling")
.sub(new OptionsBuilder().nameAndDescription("categoryDontAllowScripts")
.addComp(createToggle(scripts, parentConfig.getDontAllowScripts()), scripts)
.hide(!connectionsCategory)
.nameAndDescription("categoryConfirmAllModifications")
.addComp(createToggle(confirm, parentConfig.getConfirmAllModifications()), confirm)
.hide(!connectionsCategory)
)
.sub(new OptionsBuilder()
.nameAndDescription("categoryDontAllowScripts")
.addComp(createToggle(scripts, parentConfig.getDontAllowScripts()), scripts)
.hide(!connectionsCategory)
.nameAndDescription("categoryConfirmAllModifications")
.addComp(createToggle(confirm, parentConfig.getConfirmAllModifications()), confirm)
.hide(!connectionsCategory))
.title("connectionConfiguration")
.sub(new OptionsBuilder()
.nameAndDescription("categoryFreeze")
.addComp(createToggle(freeze, parentConfig.getFreezeConfigurations()), freeze)
.hide(!connectionsCategory)
.nameAndDescription("categoryDefaultIdentity")
.addComp(
new StoreChoiceComp<>(
null,
identityRef,
DataStore.class,
null,
StoreViewState.get().getAllIdentitiesCategory(),
DataStoreCreationCategory.IDENTITY),
identityRef)
.hide(!connectionsCategory)
.nameAndDescription("categoryDefaultGateway")
.addComp(
new StoreChoiceComp<>(
null,
gatewayRef,
DataStore.class,
null,
StoreViewState.get().getAllConnectionsCategory(),
DataStoreCreationCategory.HOST),
gatewayRef)
.hide(!connectionsCategory)
)
.nameAndDescription("categoryFreeze")
.addComp(createToggle(freeze, parentConfig.getFreezeConfigurations()), freeze)
.hide(!connectionsCategory)
.nameAndDescription("categoryDefaultIdentity")
.addComp(
new StoreChoiceComp<>(
null,
identityRef,
DataStore.class,
null,
StoreViewState.get().getAllIdentitiesCategory(),
DataStoreCreationCategory.IDENTITY),
identityRef)
.hide(!connectionsCategory)
.nameAndDescription("categoryDefaultGateway")
.addComp(
new StoreChoiceComp<>(
null,
gatewayRef,
DataStore.class,
null,
StoreViewState.get().getAllConnectionsCategory(),
DataStoreCreationCategory.HOST),
gatewayRef)
.hide(!connectionsCategory))
.bind(
() -> {
return new DataStoreCategoryConfig(

View File

@@ -10,7 +10,6 @@ import io.xpipe.app.ext.DataStoreCreationCategory;
import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.storage.DataStoreEntry;
import io.xpipe.app.storage.DataStoreEntryRef;
import io.xpipe.core.OsType;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
@@ -74,7 +73,8 @@ public class StoreChoiceComp<T extends DataStore> extends SimpleRegionBuilder {
ObjectProperty<DataStoreEntryRef<T>> selected,
Class<?> storeClass,
Predicate<DataStoreEntryRef<T>> applicableCheck,
StoreCategoryWrapper initialCategory, DataStoreCreationCategory creationCategory) {
StoreCategoryWrapper initialCategory,
DataStoreCreationCategory creationCategory) {
this(self, selected, storeClass, applicableCheck, initialCategory, true, creationCategory);
}

View File

@@ -1,6 +1,5 @@
package io.xpipe.app.hub.comp;
import atlantafx.base.layout.InputGroup;
import io.xpipe.app.comp.RegionBuilder;
import io.xpipe.app.comp.base.*;
import io.xpipe.app.core.AppFontSizes;
@@ -30,7 +29,6 @@ import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
import atlantafx.base.controls.Popover;
import atlantafx.base.theme.Styles;
import lombok.RequiredArgsConstructor;
import org.kordamp.ikonli.javafx.FontIcon;
@@ -142,29 +140,31 @@ public class StoreChoicePopover<T extends DataStore> {
initialExpanded);
var category = new StoreCategoryChoiceComp(
rootCategory != null ? rootCategory.getRoot() : null,
StoreViewState.get().getActiveCategory(),
selectedCategory,
explicitCategory == null,
ignored -> true);
var filter = FilterComp.ofStoreFilter(storeFilter)
.hgrow();
rootCategory != null ? rootCategory.getRoot() : null,
StoreViewState.get().getActiveCategory(),
selectedCategory,
explicitCategory == null,
ignored -> true);
var filter = FilterComp.ofStoreFilter(storeFilter).hgrow();
var addButton = creationCategory != null ?
new ButtonComp(null, new LabelGraphic.IconGraphic("mdi2p-plus"), () -> {
StoreCreationDialog.showCreation(DataStoreProviders.byId(creationCategory.getDefaultProvider()).orElseThrow(), creationCategory);
})
.describe(d -> d.nameKey("addConnection")) :
RegionBuilder.of(() -> {
var m = MenuHelper.createMenuButton();
m.setGraphic(new FontIcon("mdi2p-plus-box-outline"));
m.setMaxHeight(100);
m.setMinHeight(0);
StoreCreationMenu.addButtons(m.getItems(), false);
return m;
})
.describe(d -> d.nameKey("addConnection"))
.padding(new Insets(-5));
var addButton = creationCategory != null
? new ButtonComp(null, new LabelGraphic.IconGraphic("mdi2p-plus"), () -> {
StoreCreationDialog.showCreation(
DataStoreProviders.byId(creationCategory.getDefaultProvider())
.orElseThrow(),
creationCategory);
})
.describe(d -> d.nameKey("addConnection"))
: RegionBuilder.of(() -> {
var m = MenuHelper.createMenuButton();
m.setGraphic(new FontIcon("mdi2p-plus-box-outline"));
m.setMaxHeight(100);
m.setMinHeight(0);
StoreCreationMenu.addButtons(m.getItems(), false);
return m;
})
.describe(d -> d.nameKey("addConnection"))
.padding(new Insets(-5));
var top = new InputGroupComp(List.of(category, filter, addButton))
.setMainReference(category)

View File

@@ -55,14 +55,15 @@ public class StoreCreationDialog {
DataStorage.get().addStoreEntryIfNotPresent(newE);
} else {
var wasChanged = !e.getStore().equals(newE.getStore());
var madeValid = !e.getValidity().isUsable()
&& newE.getValidity().isUsable();
var madeValid =
!e.getValidity().isUsable() && newE.getValidity().isUsable();
// We might still have changed some auxiliary config value
// So, always force an update, regardless of wasChanged
DataStorage.get().updateEntry(e, newE);
if (wasChanged && madeValid
if (wasChanged
&& madeValid
&& validated
&& e.getProvider().shouldShowScan()
&& AppPrefs.get()

View File

@@ -10,11 +10,9 @@ import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.collections.ObservableList;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuButton;
import javafx.scene.control.MenuItem;
import javafx.scene.control.SeparatorMenuItem;
import lombok.NonNull;
import org.kordamp.ikonli.javafx.FontIcon;
import java.util.Arrays;
@@ -61,29 +59,23 @@ public class StoreCreationMenu {
items.add(new SeparatorMenuItem());
items
.add(categoryMenu(
"addIdentity",
"mdi2a-account-multiple-plus",
DataStoreCreationCategory.IDENTITY));
items.add(categoryMenu("addIdentity", "mdi2a-account-multiple-plus", DataStoreCreationCategory.IDENTITY));
items.add(new SeparatorMenuItem());
items
.add(categoryMenu("addService", "mdi2l-link-plus", DataStoreCreationCategory.SERVICE));
items.add(categoryMenu("addService", "mdi2l-link-plus", DataStoreCreationCategory.SERVICE));
items
.add(categoryMenu(
"addTunnel", "mdi2v-vector-polyline-plus", DataStoreCreationCategory.TUNNEL));
items.add(categoryMenu("addTunnel", "mdi2v-vector-polyline-plus", DataStoreCreationCategory.TUNNEL));
items.add(new SeparatorMenuItem());
items
.add(categoryMenu("addCommand", "mdi2c-code-greater-than", DataStoreCreationCategory.COMMAND));
items.add(categoryMenu("addCommand", "mdi2c-code-greater-than", DataStoreCreationCategory.COMMAND));
items
.add(categoryMenu(
"addScript", "mdi2s-script-text-outline", DataStoreCreationCategory.SCRIPT, DataStoreCreationCategory.SCRIPT_SOURCE));
items.add(categoryMenu(
"addScript",
"mdi2s-script-text-outline",
DataStoreCreationCategory.SCRIPT,
DataStoreCreationCategory.SCRIPT_SOURCE));
items.add(new SeparatorMenuItem());
@@ -101,22 +93,20 @@ public class StoreCreationMenu {
});
actionMenu.getItems().addFirst(item);
items
.add(categoryMenu(
"addOther",
"mdi2f-folder-plus-outline",
DataStoreCreationCategory.NETWORK,
DataStoreCreationCategory.CLUSTER,
DataStoreCreationCategory.FILE_SYSTEM,
DataStoreCreationCategory.SERIAL));
items.add(categoryMenu(
"addOther",
"mdi2f-folder-plus-outline",
DataStoreCreationCategory.NETWORK,
DataStoreCreationCategory.CLUSTER,
DataStoreCreationCategory.FILE_SYSTEM,
DataStoreCreationCategory.SERIAL));
items.add(new SeparatorMenuItem());
items.add(actionMenu);
}
private static Menu categoryMenu(
String name, String graphic, DataStoreCreationCategory... categories) {
private static Menu categoryMenu(String name, String graphic, DataStoreCreationCategory... categories) {
var providers = DataStoreProviders.getAll().stream()
.filter(dataStoreProvider ->
Arrays.asList(categories).contains(dataStoreProvider.getCreationCategory()))

View File

@@ -64,10 +64,11 @@ public class StoreCreationModel {
this.filter = filter;
this.name = new SimpleStringProperty(initialName != null && !initialName.isEmpty() ? initialName : null);
this.existingEntry = existingEntry;
this.existingDependencies = existingEntry != null ?
DataStorage.get().getDependencies(existingEntry).stream()
.<DataStore>map(ref -> ref.getStore())
.toList() : null;
this.existingDependencies = existingEntry != null
? DataStorage.get().getDependencies(existingEntry).stream()
.<DataStore>map(ref -> ref.getStore())
.toList()
: null;
this.staticDisplay = staticDisplay;
this.consumer = consumer;
this.uuid = existingEntry != null ? existingEntry.getUuid() : UUID.randomUUID();
@@ -102,16 +103,12 @@ public class StoreCreationModel {
}
var initial = DataStoreEntry.createNew(
uuid,
DataStorage.get().getSelectedCategory().getUuid(),
name.getValue(),
store.getValue());
uuid, DataStorage.get().getSelectedCategory().getUuid(), name.getValue(), store.getValue());
var entryRef = existingEntry != null
? existingEntry
: DataStorage.get().getDefaultDisplayParent(initial).orElse(initial);
var targetCategory = getTargetCategory(entryRef.getCategoryUuid());
return DataStoreEntry.createNew(
uuid, targetCategory.getUuid(), name.getValue(), store.getValue());
return DataStoreEntry.createNew(uuid, targetCategory.getUuid(), name.getValue(), store.getValue());
},
name,
store);

View File

@@ -677,8 +677,8 @@ public abstract class StoreEntryComp extends SimpleRegionBuilder {
.anyMatch(h -> h.getUuid().equals(DataStorage.LOCAL_IDENTITIES_CATEGORY_UUID));
if (isLocalIdentity) {
return DataStorage.get().getCategoryParentHierarchy(w.getCategory()).stream()
.noneMatch(
h -> h.getUuid().equals(DataStorage.SYNCED_IDENTITIES_CATEGORY_UUID));
.noneMatch(h ->
h.getUuid().equals(DataStorage.SYNCED_IDENTITIES_CATEGORY_UUID));
}
var isSyncedIdentity = DataStorage.get()
@@ -688,8 +688,8 @@ public abstract class StoreEntryComp extends SimpleRegionBuilder {
.anyMatch(h -> h.getUuid().equals(DataStorage.SYNCED_IDENTITIES_CATEGORY_UUID));
if (isSyncedIdentity) {
return DataStorage.get().getCategoryParentHierarchy(w.getCategory()).stream()
.noneMatch(
h -> h.getUuid().equals(DataStorage.LOCAL_IDENTITIES_CATEGORY_UUID));
.noneMatch(h ->
h.getUuid().equals(DataStorage.LOCAL_IDENTITIES_CATEGORY_UUID));
}
return true;

View File

@@ -7,7 +7,6 @@ import io.xpipe.app.comp.SimpleRegionBuilder;
import io.xpipe.app.comp.augment.ContextMenuAugment;
import io.xpipe.app.comp.base.*;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.AppImages;
import io.xpipe.app.core.window.AppDialog;
import io.xpipe.app.ext.DataStore;
import io.xpipe.app.hub.action.BatchHubProvider;
@@ -32,7 +31,6 @@ import javafx.scene.input.MouseButton;
import javafx.scene.layout.Region;
import atlantafx.base.theme.Styles;
import org.kordamp.ikonli.javafx.FontIcon;
import java.util.ArrayList;
import java.util.List;
@@ -41,7 +39,9 @@ public class StoreEntryListBatchBarComp extends SimpleRegionBuilder {
private final BooleanProperty expanded;
public StoreEntryListBatchBarComp(BooleanProperty expanded) {this.expanded = expanded;}
public StoreEntryListBatchBarComp(BooleanProperty expanded) {
this.expanded = expanded;
}
@Override
protected Region createSimple() {
@@ -79,7 +79,8 @@ public class StoreEntryListBatchBarComp extends SimpleRegionBuilder {
expanded.set(!expanded.get());
});
toggleExpand.describe(d -> d.nameKey("expand"));
toggleExpand.hide(Bindings.isEmpty(StoreViewState.get().getEffectiveBatchModeSelection().getList()));
toggleExpand.hide(Bindings.isEmpty(
StoreViewState.get().getEffectiveBatchModeSelection().getList()));
toggleExpand.apply(struc -> {
struc.getStyleClass().remove(Styles.FLAT);
struc.minWidthProperty().bind(struc.heightProperty());
@@ -108,9 +109,9 @@ public class StoreEntryListBatchBarComp extends SimpleRegionBuilder {
}
private ObservableList<BaseRegionBuilder<?, ?>> createActions() {
var actions = DerivedObservableList.<BaseRegionBuilder<?,?>>arrayList(true);
var actions = DerivedObservableList.<BaseRegionBuilder<?, ?>>arrayList(true);
StoreViewState.get().getBatchModeSelection().getList().addListener((ListChangeListener<
? super StoreEntryWrapper>)
? super StoreEntryWrapper>)
c -> {
actions.getList().clear();
for (var p : getCompatibleActionProviders()) {
@@ -176,9 +177,12 @@ public class StoreEntryListBatchBarComp extends SimpleRegionBuilder {
.getEffectiveBatchModeSelection()
.mapped(storeEntryWrapper -> storeEntryWrapper.getEntry().<T>ref());
var batchActions = s.getChildren(childrenRefs.getList());
var name = Bindings.createStringBinding(() -> {
return expanded.get() ? s.getName().getValue() : null;
}, expanded, s.getName());
var name = Bindings.createStringBinding(
() -> {
return expanded.get() ? s.getName().getValue() : null;
},
expanded,
s.getName());
var button = new ButtonComp(name, new SimpleObjectProperty<>(s.getIcon()), () -> {
if (batchActions.size() > 0) {
return;
@@ -210,122 +214,126 @@ public class StoreEntryListBatchBarComp extends SimpleRegionBuilder {
private BaseRegionBuilder<?, ?> buildMoveButton() {
var i18n = AppI18n.observable("move");
var name = Bindings.createStringBinding(() -> {
return expanded.get() ? i18n.getValue() : null;
}, expanded, i18n);
var button = new ButtonComp(name, new SimpleObjectProperty<>(new LabelGraphic.IconGraphic("mdi2f-folder-move-outline")), null);
var name = Bindings.createStringBinding(
() -> {
return expanded.get() ? i18n.getValue() : null;
},
expanded,
i18n);
var button = new ButtonComp(
name, new SimpleObjectProperty<>(new LabelGraphic.IconGraphic("mdi2f-folder-move-outline")), null);
button.describe(d -> d.name(i18n));
button.apply(new ContextMenuAugment<>(
mouseEvent -> mouseEvent.getButton() == MouseButton.PRIMARY, keyEvent -> false, () -> {
var selection = StoreViewState.get().getBatchModeSelection().getList();
if (selection.isEmpty()) {
return null;
}
var selection = StoreViewState.get().getBatchModeSelection().getList();
if (selection.isEmpty()) {
return null;
}
var refWrapper = selection.getFirst();
var refWrapper = selection.getFirst();
var menu = MenuHelper.createContextMenu();
StoreViewState.get()
.getSortedCategories(
refWrapper.getCategory().getValue().getRoot(), true)
.getList()
.stream()
.filter(w -> {
var isSource = DataStorage.get()
.getCategoryParentHierarchy(DataStorage.get()
.getStoreCategory(refWrapper.getEntry()))
.stream()
.anyMatch(h -> h.getUuid().equals(DataStorage.SCRIPT_SOURCES_CATEGORY_UUID));
if (isSource) {
return DataStorage.get().getCategoryParentHierarchy(w.getCategory()).stream()
.anyMatch(
h -> h.getUuid().equals(DataStorage.SCRIPT_SOURCES_CATEGORY_UUID));
}
var menu = MenuHelper.createContextMenu();
StoreViewState.get()
.getSortedCategories(
refWrapper.getCategory().getValue().getRoot(), true)
.getList()
.stream()
.filter(w -> {
var isSource = DataStorage.get()
.getCategoryParentHierarchy(
DataStorage.get().getStoreCategory(refWrapper.getEntry()))
.stream()
.anyMatch(h -> h.getUuid().equals(DataStorage.SCRIPT_SOURCES_CATEGORY_UUID));
if (isSource) {
return DataStorage.get().getCategoryParentHierarchy(w.getCategory()).stream()
.anyMatch(
h -> h.getUuid().equals(DataStorage.SCRIPT_SOURCES_CATEGORY_UUID));
}
var isScript = DataStorage.get()
.getCategoryParentHierarchy(DataStorage.get()
.getStoreCategory(refWrapper.getEntry()))
.stream()
.anyMatch(h -> h.getUuid().equals(DataStorage.ALL_SCRIPTS_CATEGORY_UUID));
if (isScript) {
return DataStorage.get().getCategoryParentHierarchy(w.getCategory()).stream()
.noneMatch(
h -> h.getUuid().equals(DataStorage.SCRIPT_SOURCES_CATEGORY_UUID));
}
var isScript = DataStorage.get()
.getCategoryParentHierarchy(
DataStorage.get().getStoreCategory(refWrapper.getEntry()))
.stream()
.anyMatch(h -> h.getUuid().equals(DataStorage.ALL_SCRIPTS_CATEGORY_UUID));
if (isScript) {
return DataStorage.get().getCategoryParentHierarchy(w.getCategory()).stream()
.noneMatch(
h -> h.getUuid().equals(DataStorage.SCRIPT_SOURCES_CATEGORY_UUID));
}
var isLocalIdentity = DataStorage.get()
.getCategoryParentHierarchy(DataStorage.get()
.getStoreCategory(refWrapper.getEntry()))
.stream()
.anyMatch(h -> h.getUuid().equals(DataStorage.LOCAL_IDENTITIES_CATEGORY_UUID));
if (isLocalIdentity) {
return DataStorage.get().getCategoryParentHierarchy(w.getCategory()).stream()
.noneMatch(
h -> h.getUuid().equals(DataStorage.SYNCED_IDENTITIES_CATEGORY_UUID));
}
var isLocalIdentity = DataStorage.get()
.getCategoryParentHierarchy(
DataStorage.get().getStoreCategory(refWrapper.getEntry()))
.stream()
.anyMatch(h -> h.getUuid().equals(DataStorage.LOCAL_IDENTITIES_CATEGORY_UUID));
if (isLocalIdentity) {
return DataStorage.get().getCategoryParentHierarchy(w.getCategory()).stream()
.noneMatch(h ->
h.getUuid().equals(DataStorage.SYNCED_IDENTITIES_CATEGORY_UUID));
}
var isSyncedIdentity = DataStorage.get()
.getCategoryParentHierarchy(DataStorage.get()
.getStoreCategory(refWrapper.getEntry()))
.stream()
.anyMatch(h -> h.getUuid().equals(DataStorage.SYNCED_IDENTITIES_CATEGORY_UUID));
if (isSyncedIdentity) {
return DataStorage.get().getCategoryParentHierarchy(w.getCategory()).stream()
.noneMatch(
h -> h.getUuid().equals(DataStorage.LOCAL_IDENTITIES_CATEGORY_UUID));
}
var isSyncedIdentity = DataStorage.get()
.getCategoryParentHierarchy(
DataStorage.get().getStoreCategory(refWrapper.getEntry()))
.stream()
.anyMatch(h -> h.getUuid().equals(DataStorage.SYNCED_IDENTITIES_CATEGORY_UUID));
if (isSyncedIdentity) {
return DataStorage.get().getCategoryParentHierarchy(w.getCategory()).stream()
.noneMatch(h ->
h.getUuid().equals(DataStorage.LOCAL_IDENTITIES_CATEGORY_UUID));
}
return true;
})
.forEach(targetCategory -> {
var m = new CustomMenuItem();
return true;
})
.forEach(targetCategory -> {
var m = new CustomMenuItem();
var li = new Label();
li.setGraphic(PrettyImageHelper.ofFixedSizeSquare(
targetCategory
.getIconFile()
.getValue(),
16)
.padding(new Insets(0, 0, 1, 0))
.build());
li.setText(targetCategory.getName().getValue());
li.setPadding(new Insets(0, 1, 1, targetCategory.getDepth() * 10));
m.setContent(li);
var li = new Label();
li.setGraphic(PrettyImageHelper.ofFixedSizeSquare(
targetCategory.getIconFile().getValue(), 16)
.padding(new Insets(0, 0, 1, 0))
.build());
li.setText(targetCategory.getName().getValue());
li.setPadding(new Insets(0, 1, 1, targetCategory.getDepth() * 10));
m.setContent(li);
m.setOnAction(event -> {
for (StoreEntryWrapper w : selection) {
w.moveTo(targetCategory.getCategory());
}
event.consume();
});
if (targetCategory.getParent() == null) {
m.setDisable(true);
}
m.setOnAction(event -> {
for (StoreEntryWrapper w : selection) {
w.moveTo(targetCategory.getCategory());
}
event.consume();
});
if (targetCategory.getParent() == null) {
m.setDisable(true);
}
menu.getItems().add(m);
});
return menu;
}));
menu.getItems().add(m);
});
return menu;
}));
return button;
}
private BaseRegionBuilder<?, ?> buildDeleteButton() {
var i18n = AppI18n.observable("delete");
var name = Bindings.createStringBinding(() -> {
return expanded.get() ? i18n.getValue() : null;
}, expanded, i18n);
var button = new ButtonComp(name, new SimpleObjectProperty<>(new LabelGraphic.IconGraphic("mdal-delete_outline")), () -> {
var confirm = AppDialog.confirm("confirmDeletion");
if (!confirm) {
return;
}
var name = Bindings.createStringBinding(
() -> {
return expanded.get() ? i18n.getValue() : null;
},
expanded,
i18n);
var button = new ButtonComp(
name, new SimpleObjectProperty<>(new LabelGraphic.IconGraphic("mdal-delete_outline")), () -> {
var confirm = AppDialog.confirm("confirmDeletion");
if (!confirm) {
return;
}
var selection = StoreViewState.get().getBatchModeSelection().getList();
for (StoreEntryWrapper w : selection) {
w.delete();
}
});
var selection = StoreViewState.get().getBatchModeSelection().getList();
for (StoreEntryWrapper w : selection) {
w.delete();
}
});
button.describe(d -> d.name(i18n));
return button;
}

View File

@@ -5,16 +5,13 @@ import io.xpipe.app.comp.SimpleRegionBuilder;
import io.xpipe.app.comp.augment.ContextMenuAugment;
import io.xpipe.app.comp.base.ListBoxViewComp;
import io.xpipe.app.comp.base.MultiContentComp;
import io.xpipe.app.comp.base.StackComp;
import io.xpipe.app.comp.base.VerticalComp;
import io.xpipe.app.core.AppCache;
import io.xpipe.app.core.AppImages;
import io.xpipe.app.core.AppLayoutModel;
import io.xpipe.app.platform.MenuHelper;
import io.xpipe.app.prefs.AppPrefs;
import javafx.beans.binding.Bindings;
import javafx.beans.property.ReadOnlyBooleanWrapper;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ObservableValue;
import javafx.css.PseudoClass;

View File

@@ -16,9 +16,7 @@ import javafx.geometry.Bounds;
import javafx.scene.Cursor;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Region;
import javafx.scene.shape.Rectangle;
import atlantafx.base.controls.CustomTextField;
import atlantafx.base.controls.Popover;

View File

@@ -5,7 +5,6 @@ import io.xpipe.app.comp.base.IntroComp;
import io.xpipe.app.comp.base.IntroListComp;
import io.xpipe.app.comp.base.PrettyImageHelper;
import io.xpipe.app.platform.LabelGraphic;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.util.DocumentationLink;
import io.xpipe.app.util.ScanDialog;

View File

@@ -32,8 +32,8 @@ public class StoreListChoiceComp<T extends DataStore> extends SimpleRegionBuilde
ListProperty<DataStoreEntryRef<T>> selectedList,
Class<T> storeClass,
Predicate<DataStoreEntryRef<T>> applicableCheck,
StoreCategoryWrapper initialCategory, DataStoreCreationCategory creationCategory
) {
StoreCategoryWrapper initialCategory,
DataStoreCreationCategory creationCategory) {
this.selectedList = selectedList;
this.storeClass = storeClass;
this.applicableCheck = applicableCheck;

View File

@@ -2,13 +2,11 @@ package io.xpipe.app.issue;
import io.xpipe.app.core.mode.AppOperationMode;
import io.xpipe.app.process.ProcessOutputException;
import io.xpipe.app.util.DocumentationLink;
import io.xpipe.core.OsType;
import java.nio.file.AccessDeniedException;
import java.nio.file.NoSuchFileException;
import java.util.*;
import javax.net.ssl.SSLHandshakeException;
public class ErrorEventFactory {

View File

@@ -1,6 +1,5 @@
package io.xpipe.app.issue;
import io.sentry.protocol.Feedback;
import io.xpipe.app.core.AppCertStore;
import io.xpipe.app.core.AppLogs;
import io.xpipe.app.core.AppProperties;
@@ -14,6 +13,7 @@ import io.xpipe.app.util.LicenseProvider;
import io.xpipe.app.util.LicenseRequiredException;
import io.sentry.*;
import io.sentry.protocol.Feedback;
import io.sentry.protocol.Geo;
import io.sentry.protocol.SentryId;
import io.sentry.protocol.User;
@@ -250,9 +250,12 @@ public class SentryErrorHandler implements ErrorHandler {
s.setTag("initial", AppProperties.get() != null ? AppProperties.get().isInitialLaunch() + "" : "false");
var httpProxy = HttpProxy.getActiveProxy();
var doProxy = httpProxy.isPresent() && !HttpProxy.disableTlsVerification() && AppCertStore.get().getCertificates().isEmpty();
var doProxy = httpProxy.isPresent()
&& !HttpProxy.disableTlsVerification()
&& AppCertStore.get().getCertificates().isEmpty();
if (doProxy) {
var sentryProxy = new SentryOptions.Proxy(httpProxy.get().getHost(),
var sentryProxy = new SentryOptions.Proxy(
httpProxy.get().getHost(),
"" + httpProxy.get().getPort(),
httpProxy.get().isSocks5() ? Proxy.Type.SOCKS : Proxy.Type.HTTP,
httpProxy.get().getUser(),

View File

@@ -1,7 +1,5 @@
package io.xpipe.app.platform;
import com.fasterxml.jackson.databind.JavaType;
import io.xpipe.app.browser.file.BrowserHistorySavedState;
import io.xpipe.app.comp.BaseRegionBuilder;
import io.xpipe.app.comp.RegionBuilder;
import io.xpipe.app.comp.base.*;
@@ -14,8 +12,8 @@ import io.xpipe.app.util.Checkable;
import io.xpipe.app.util.DocumentationLink;
import io.xpipe.app.util.LicenseProvider;
import io.xpipe.core.InPlaceSecretValue;
import io.xpipe.core.JacksonMapper;
import javafx.beans.property.*;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
@@ -184,7 +182,9 @@ public class OptionsBuilder {
public OptionsBuilder subExpandable(String key, OptionsBuilder builder, String trackKey) {
var javaType =
JacksonMapper.getDefault().getTypeFactory().constructCollectionLikeType(List.class, String.class);
var expanded = trackKey != null && AppCache.getNonNull("advancedExpanded", javaType, () -> List.of()).contains(trackKey);
var expanded = trackKey != null
&& AppCache.getNonNull("advancedExpanded", javaType, () -> List.of())
.contains(trackKey);
sub(builder, null);
var subComp = this.comp;

View File

@@ -19,9 +19,8 @@ import io.xpipe.app.update.AppDistributionType;
import io.xpipe.app.util.DesktopHelper;
import io.xpipe.app.util.HttpHelper;
import io.xpipe.app.util.HttpProxy;
import io.xpipe.app.util.ThreadHelper;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
@@ -46,26 +45,37 @@ public class HttpProxyCategory extends AppPrefsCategory {
protected BaseRegionBuilder<?, ?> create() {
var prefs = AppPrefs.get();
var testComp = new TestButtonComp(() -> {
var addr = new SimpleStringProperty(AppCache.getNonNull("httpProxyTest", String.class, () -> null));
var addrField = new TextFieldComp(addr).apply(textField -> textField.setPromptText("https://example.com"));
var modal = ModalOverlay.of("proxyTestAddressDialogTitle", new OptionsBuilder()
.nameAndDescription("proxyTestAddress").addComp(addrField, addr).buildComp().prefWidth(450));
modal.addButton(ModalButton.cancel());
modal.addButton(ModalButton.ok());
modal.showAndWait();
if (addr.get() == null) {
return false;
}
var addr = new SimpleStringProperty(AppCache.getNonNull("httpProxyTest", String.class, () -> null));
var addrField = new TextFieldComp(addr).apply(textField -> textField.setPromptText("https://example.com"));
var modal = ModalOverlay.of(
"proxyTestAddressDialogTitle",
new OptionsBuilder()
.nameAndDescription("proxyTestAddress")
.addComp(addrField, addr)
.buildComp()
.prefWidth(450));
modal.addButton(ModalButton.cancel());
modal.addButton(ModalButton.ok());
modal.showAndWait();
if (addr.get() == null) {
return false;
}
AppCache.update("httpProxyTest", addr.get());
var effectiveAddr = addr.get();
if (!effectiveAddr.startsWith("http")) {
effectiveAddr = "https://" + effectiveAddr;
}
if (!effectiveAddr.startsWith("http")) {
effectiveAddr = "https://" + effectiveAddr;
}
var res = HttpHelper.client().send(HttpRequest.newBuilder().GET().uri(URI.create(effectiveAddr)).build(), HttpResponse.BodyHandlers.ofString());
HttpHelper.checkOrThrow(res);
return true;
var res = HttpHelper.client()
.send(
HttpRequest.newBuilder()
.GET()
.uri(URI.create(effectiveAddr))
.build(),
HttpResponse.BodyHandlers.ofString());
HttpHelper.checkOrThrow(res);
return true;
});
return new OptionsBuilder()
.title("httpProxyConfiguration")
@@ -80,8 +90,7 @@ public class HttpProxyCategory extends AppPrefsCategory {
});
}))
.pref(prefs.disableHttpsTlsCheck)
.addToggle(prefs.disableHttpsTlsCheck)
)
.addToggle(prefs.disableHttpsTlsCheck))
.buildComp();
}

View File

@@ -147,7 +147,11 @@ public class McpCategory extends AppPrefsCategory {
.addComp(tabComp.maxWidth(getCompWidth()))
.pref(prefs.mcpAdditionalContext)
.addComp(new IntegratedTextAreaComp(
prefs.mcpAdditionalContext, false, "prompt", new SimpleStringProperty("txt"), true)
prefs.mcpAdditionalContext,
false,
"prompt",
new SimpleStringProperty("txt"),
true)
.applyStructure(structure -> {
structure
.getTextArea()

View File

@@ -5,7 +5,6 @@ import io.xpipe.app.comp.base.*;
import io.xpipe.app.core.App;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.platform.BindingsHelper;
import io.xpipe.app.pwman.PasswordManager;
import io.xpipe.app.util.GlobalTimer;
import io.xpipe.app.util.ThreadHelper;
@@ -38,7 +37,8 @@ public class PasswordManagerTestComp extends SimpleRegionBuilder {
this(new SimpleStringProperty(), handleEnter, false, false);
}
public PasswordManagerTestComp(Property<String> value, boolean handleEnter, boolean showName, boolean showSettings) {
public PasswordManagerTestComp(
Property<String> value, boolean handleEnter, boolean showName, boolean showSettings) {
this.value = value;
this.handleEnter = handleEnter;
this.showName = showName;
@@ -59,7 +59,8 @@ public class PasswordManagerTestComp extends SimpleRegionBuilder {
? (showName ? p.getDisplayName() + " - " : "") + p.getKeyPlaceholder()
: "?";
},
prefs.passwordManager, AppI18n.activeLanguage())))
prefs.passwordManager,
AppI18n.activeLanguage())))
.hgrow();
if (handleEnter) {
field.apply(struc -> struc.setOnKeyPressed(event -> {

View File

@@ -14,18 +14,11 @@ import io.xpipe.app.terminal.TerminalLaunch;
import io.xpipe.app.util.*;
import io.xpipe.core.FilePath;
import javafx.application.Platform;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.layout.Region;
import atlantafx.base.theme.Styles;
import org.kordamp.ikonli.javafx.FontIcon;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
public class SyncCategory extends AppPrefsCategory {
@@ -42,7 +35,7 @@ public class SyncCategory extends AppPrefsCategory {
public BaseRegionBuilder<?, ?> create() {
var prefs = AppPrefs.get();
var testButton = new TestButtonComp( () -> {
var testButton = new TestButtonComp(() -> {
var r = DataStorageSyncHandler.getInstance().validateConnection();
return r;
});

View File

@@ -45,9 +45,8 @@ public class SystemCategory extends AppPrefsCategory {
.filter(b -> b.isAvailable())
.toList(),
true)
.maxWidth(getCompWidth()))
)
.title("shells")
.maxWidth(getCompWidth())))
.title("shells")
.sub(new OptionsBuilder()
.pref(prefs.localShellDialect)
.addComp(
@@ -59,15 +58,14 @@ public class SystemCategory extends AppPrefsCategory {
prefs.localShellDialect)
.pref(prefs.backgroundSessionInactivityTimeout)
.addComp(
new IntFieldComp(prefs.backgroundSessionInactivityTimeout).apply(struc -> {
struc.setPromptText("3600");
}).maxWidth(100),
prefs.backgroundSessionInactivityTimeout)
)
.title("developer")
.sub(new OptionsBuilder()
.pref(prefs.developerMode)
.addToggle(prefs.developerMode));
new IntFieldComp(prefs.backgroundSessionInactivityTimeout)
.apply(struc -> {
struc.setPromptText("3600");
})
.maxWidth(100),
prefs.backgroundSessionInactivityTimeout))
.title("developer")
.sub(new OptionsBuilder().pref(prefs.developerMode).addToggle(prefs.developerMode));
return builder.buildComp();
}
}

View File

@@ -7,7 +7,6 @@ import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.AppProperties;
import io.xpipe.app.ext.PrefsChoiceValue;
import io.xpipe.app.ext.ProcessControlProvider;
import io.xpipe.app.ext.ScanProvider;
import io.xpipe.app.ext.ShellStore;
import io.xpipe.app.hub.comp.StoreChoiceComp;
import io.xpipe.app.hub.comp.StoreViewState;
@@ -22,7 +21,6 @@ import io.xpipe.core.OsType;
import javafx.beans.binding.Bindings;
import javafx.beans.property.ReadOnlyBooleanWrapper;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.geometry.Insets;

View File

@@ -177,8 +177,10 @@ public class KeeperPasswordManager implements PasswordManager {
command.killOnTimeout(CountDown.of().start(30_000));
command.sensitive();
var output = command.readStdoutAndStderr();
if (command.getExitCode() == CommandControl.EXIT_TIMEOUT_EXIT_CODE ||
(command.getExitCode() != 0 && !output[1].isEmpty() && !output[1].contains("get: Cannot find"))) {
if (command.getExitCode() == CommandControl.EXIT_TIMEOUT_EXIT_CODE
|| (command.getExitCode() != 0
&& !output[1].isEmpty()
&& !output[1].contains("get: Cannot find"))) {
throw ErrorEventFactory.expected(new IllegalStateException("Failed to request Keeper 2FA SMS"));
}
@@ -617,7 +619,9 @@ public class KeeperPasswordManager implements PasswordManager {
}
if (exitCode == CommandControl.EXIT_TIMEOUT_EXIT_CODE) {
ErrorEventFactory.fromMessage("Keeper request timed out").expected().handle();
ErrorEventFactory.fromMessage("Keeper request timed out")
.expected()
.handle();
return null;
}

View File

@@ -8,7 +8,6 @@ import io.xpipe.app.core.AppSystemInfo;
import io.xpipe.app.ext.ProcessControlProvider;
import io.xpipe.app.issue.ErrorEventFactory;
import io.xpipe.app.platform.OptionsBuilder;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.prefs.PasswordManagerTestComp;
import io.xpipe.app.process.CommandBuilder;
import io.xpipe.app.process.CommandSupport;

View File

@@ -1,6 +1,5 @@
package io.xpipe.app.pwman;
import com.fasterxml.jackson.annotation.JsonTypeName;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.AppProperties;
import io.xpipe.app.issue.ErrorEventFactory;
@@ -11,6 +10,7 @@ import io.xpipe.core.OsType;
import io.xpipe.core.SecretValue;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeName;
import lombok.*;
import lombok.experimental.FieldDefaults;

View File

@@ -4,9 +4,6 @@ import lombok.SneakyThrows;
import org.bouncycastle.crypto.generators.Argon2BytesGenerator;
import org.bouncycastle.crypto.params.Argon2Parameters;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.security.spec.KeySpec;
import java.util.Random;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;

View File

@@ -1,7 +1,6 @@
package io.xpipe.app.secret;
import io.xpipe.app.comp.base.IntegratedTextAreaComp;
import io.xpipe.app.comp.base.TextFieldComp;
import io.xpipe.app.ext.ProcessControlProvider;
import io.xpipe.app.ext.ValidationException;
import io.xpipe.app.issue.ErrorEventFactory;
@@ -12,9 +11,9 @@ import io.xpipe.app.util.Validators;
import io.xpipe.core.InPlaceSecretValue;
import javafx.beans.property.Property;
import javafx.beans.property.ReadOnlyObjectWrapper;
import com.fasterxml.jackson.annotation.JsonTypeName;
import javafx.beans.property.ReadOnlyObjectWrapper;
import lombok.Builder;
import lombok.Value;
import lombok.extern.jackson.Jacksonized;
@@ -32,9 +31,14 @@ public class SecretCustomCommandStrategy implements SecretRetrievalStrategy {
Property<SecretCustomCommandStrategy> p, SecretStrategyChoiceConfig config) {
var options = new OptionsBuilder();
var cmdProperty = options.map(p, SecretCustomCommandStrategy::getCommand);
return options
.nameAndDescription("customCommandValue")
.addComp(IntegratedTextAreaComp.script(cmdProperty, new ReadOnlyObjectWrapper<>(LocalShell.getDialect().getScriptFileEnding()), true), cmdProperty)
return options.nameAndDescription("customCommandValue")
.addComp(
IntegratedTextAreaComp.script(
cmdProperty,
new ReadOnlyObjectWrapper<>(
LocalShell.getDialect().getScriptFileEnding()),
true),
cmdProperty)
.nonNull()
.bind(
() -> {

View File

@@ -1,9 +1,5 @@
package io.xpipe.app.secret;
import io.xpipe.app.comp.base.ButtonComp;
import io.xpipe.app.comp.base.InputGroupComp;
import io.xpipe.app.comp.base.TextFieldComp;
import io.xpipe.app.core.App;
import io.xpipe.app.ext.ValidationException;
import io.xpipe.app.issue.ErrorEventFactory;
import io.xpipe.app.platform.OptionsBuilder;
@@ -11,18 +7,15 @@ import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.prefs.PasswordManagerTestComp;
import io.xpipe.app.util.Validators;
import javafx.beans.binding.Bindings;
import javafx.beans.property.Property;
import com.fasterxml.jackson.annotation.JsonTypeName;
import lombok.Builder;
import lombok.Value;
import lombok.extern.jackson.Jacksonized;
import org.kordamp.ikonli.javafx.FontIcon;
import java.nio.CharBuffer;
import java.time.Duration;
import java.util.List;
@JsonTypeName("passwordManager")
@Builder

View File

@@ -22,7 +22,6 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.crypto.SecretKey;
public abstract class DataStorage {

View File

@@ -1,11 +1,10 @@
package io.xpipe.app.storage;
import io.xpipe.app.secret.EncryptionKey;
import io.xpipe.app.secret.VaultKeySecretValue;
import lombok.Value;
import org.bouncycastle.util.Arrays;
import javax.crypto.SecretKey;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
@@ -13,6 +12,7 @@ import java.nio.file.Path;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.UUID;
import javax.crypto.SecretKey;
@Value
public class DataStorageVaultKey {

View File

@@ -1,10 +1,8 @@
package io.xpipe.app.storage;
import io.xpipe.app.ext.LocalStore;
import io.xpipe.app.secret.EncryptionKey;
import java.time.Instant;
import javax.crypto.SecretKey;
public class ImpersistentStorage extends DataStorage {

View File

@@ -7,7 +7,6 @@ import io.xpipe.app.ext.DataStorageExtensionProvider;
import io.xpipe.app.ext.LocalStore;
import io.xpipe.app.issue.ErrorEventFactory;
import io.xpipe.app.issue.TrackEvent;
import io.xpipe.app.secret.EncryptionKey;
import io.xpipe.app.util.DocumentationLink;
import io.xpipe.app.util.GlobalTimer;
import io.xpipe.app.util.ThreadHelper;
@@ -17,16 +16,13 @@ import lombok.Getter;
import org.apache.commons.io.FileUtils;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.SecureRandom;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.ReentrantLock;
import javax.crypto.SecretKey;
public class StandardStorage extends DataStorage {

View File

@@ -37,7 +37,7 @@ public abstract class ConfigFileTerminalPrompt implements TerminalPrompt {
p.getValue() != null
? p.getValue().getConfigFileExtension()
: null),
false)
false)
.prefHeight(400),
prop)
.bind(

View File

@@ -109,7 +109,8 @@ public class TerminalDockHubManager {
}
var modal = ModalOverlay.of("terminalDockDialogTitle", AppDialog.dialogTextKey("terminalDockDialogContent"));
modal.addButton(new ModalButton("openSettings", () -> AppPrefs.get().selectCategory("connectionHub"), true, false));
modal.addButton(
new ModalButton("openSettings", () -> AppPrefs.get().selectCategory("connectionHub"), true, false));
modal.addButton(new ModalButton("keepEnabled", null, true, true));
modal.show();
AppCache.update("terminalDockDialog", true);
@@ -135,7 +136,8 @@ public class TerminalDockHubManager {
});
private final AppLayoutModel.QueueEntry queueEntry = new AppLayoutModel.QueueEntry(
AppI18n.observable(
"toggleTerminalDock", new KeyCodeCombination(KeyCode.T, KeyCombination.SHORTCUT_DOWN).getDisplayText()),
"toggleTerminalDock",
new KeyCodeCombination(KeyCode.T, KeyCombination.SHORTCUT_DOWN).getDisplayText()),
new LabelGraphic.NodeGraphic(() -> {
var inner = new FontIcon();
inner.iconCodeProperty()

View File

@@ -28,8 +28,7 @@ public class TerminalDockView implements WindowDockListener {
}
public synchronized void removeTerminal(TerminalView.TerminalSession s) {
terminalInstances.removeIf(controllableTerminalSession ->
controllableTerminalSession.equals(s));
terminalInstances.removeIf(controllableTerminalSession -> controllableTerminalSession.equals(s));
}
public synchronized boolean isActive() {
@@ -128,7 +127,8 @@ public class TerminalDockView implements WindowDockListener {
var owner = TerminalView.get().getSessions().stream()
.filter(shellSession -> shellSession.getRequest().equals(request))
.map(shellSession -> shellSession.getTerminal())
.findFirst().orElse(null);
.findFirst()
.orElse(null);
if (owner == null) {
return false;
}

View File

@@ -316,7 +316,12 @@ public class TerminalLauncher {
fullLocalCommand,
LocalShell.getDialect());
return Optional.of(new TerminalLaunchConfiguration(
null, AppNames.ofCurrent().getName(), AppNames.ofCurrent().getName(), false, launchConfiguration.isDock(), List.of(pane)));
null,
AppNames.ofCurrent().getName(),
AppNames.ofCurrent().getName(),
false,
launchConfiguration.isDock(),
List.of(pane)));
} else {
var multiplexerCommand = multiplexer
.get()
@@ -336,7 +341,12 @@ public class TerminalLauncher {
fullLocalCommand,
LocalShell.getDialect());
return Optional.of(new TerminalLaunchConfiguration(
null, AppNames.ofCurrent().getName(), AppNames.ofCurrent().getName(), false, launchConfiguration.isDock(), List.of(pane)));
null,
AppNames.ofCurrent().getName(),
AppNames.ofCurrent().getName(),
false,
launchConfiguration.isDock(),
List.of(pane)));
}
}

View File

@@ -289,7 +289,8 @@ public class TerminalView {
if (!(o instanceof ControllableTerminalSession that)) {
return false;
}
return Objects.equals(terminalProcess.pid(), that.terminalProcess.pid()) && Objects.equals(controllable.getRawHandle(), that.controllable.getRawHandle());
return Objects.equals(terminalProcess.pid(), that.terminalProcess.pid())
&& Objects.equals(controllable.getRawHandle(), that.controllable.getRawHandle());
}
@Override

View File

@@ -131,16 +131,15 @@ public interface WezTerminalType extends ExternalTerminalType, TrackableTerminal
gui.add("--config", "enable_tab_bar=true");
}
var command = CommandBuilder.of()
.add(gui)
.add("start");
var command = CommandBuilder.of().add(gui).add("start");
if (configuration.isDock()) {
var bounds = NativeWinWindowControl.MAIN_WINDOW.getBounds();
command.add("--position").addQuoted(bounds.getX() + "," +(bounds.getY() + 20));
command.add("--position").addQuoted(bounds.getX() + "," + (bounds.getY() + 20));
}
command.add("--always-new-process").add(configuration.getPanes().getFirst().getDialectLaunchCommand());
command.add("--always-new-process")
.add(configuration.getPanes().getFirst().getDialectLaunchCommand());
ExternalApplicationHelper.startAsync(command);
activeSocket = waitForInstanceStart(50);
if (activeSocket.isEmpty()) {

View File

@@ -4,14 +4,12 @@ import io.xpipe.app.core.AppCache;
import io.xpipe.app.core.AppInstallation;
import io.xpipe.app.core.AppProperties;
import io.xpipe.app.core.AppSystemInfo;
import io.xpipe.app.core.window.AppMainWindow;
import io.xpipe.app.issue.ErrorEventFactory;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.process.CommandBuilder;
import io.xpipe.app.process.LocalShell;
import io.xpipe.app.process.ShellDialects;
import io.xpipe.app.util.NativeWinWindowControl;
import io.xpipe.app.util.RemoteDesktopDockView;
import io.xpipe.core.FilePath;
import io.xpipe.core.JacksonMapper;

View File

@@ -1,12 +1,12 @@
package io.xpipe.app.util;
import io.xpipe.app.core.AppCertStore;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.issue.ErrorAction;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.issue.ErrorEventFactory;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.core.AppCertStore;
import lombok.SneakyThrows;
import java.io.*;
@@ -25,9 +25,7 @@ public class HttpHelper {
@SneakyThrows
public static HttpClient client() {
var proxy = HttpProxy.getActiveProxy();
return client(
proxy.orElse(null),
!HttpProxy.disableTlsVerification());
return client(proxy.orElse(null), !HttpProxy.disableTlsVerification());
}
@SneakyThrows
@@ -57,7 +55,7 @@ public class HttpHelper {
var certStore = AppCertStore.get();
if (certStore != null) {
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, new TrustManager[]{certStore.getCustomTrustManager()}, null);
context.init(null, new TrustManager[] {certStore.getCustomTrustManager()}, null);
builder.sslContext(context);
}
}

View File

@@ -9,6 +9,7 @@ import io.xpipe.app.platform.LabelGraphic;
import io.xpipe.app.platform.PlatformThread;
import io.xpipe.app.storage.DataStoreEntry;
import io.xpipe.app.storage.DataStoreEntryRef;
import javafx.beans.binding.Bindings;
import java.util.List;
@@ -39,9 +40,13 @@ public class ScanDialog {
true,
true);
var list = comp.getBase().getSelected();
button.augment(r -> r.disableProperty().bind(PlatformThread.sync(Bindings.createBooleanBinding(() -> {
return comp.getBusy().get() || list.isEmpty();
}, comp.getBusy(), list))));
button.augment(r -> r.disableProperty()
.bind(PlatformThread.sync(Bindings.createBooleanBinding(
() -> {
return comp.getBusy().get() || list.isEmpty();
},
comp.getBusy(),
list))));
modal.addButton(button);
modal.show();
}

View File

@@ -39,6 +39,7 @@ public class ScanDialogBase {
private final boolean showButton;
private final ObservableList<ScanProvider.ScanOpportunity> available =
FXCollections.synchronizedObservableList(FXCollections.observableArrayList());
@Getter
private final ListProperty<ScanProvider.ScanOpportunity> selected =
new SimpleListProperty<>(FXCollections.synchronizedObservableList(FXCollections.observableArrayList()));

View File

@@ -13,6 +13,7 @@ import javafx.beans.property.*;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.layout.Region;
import lombok.Getter;
class ScanSingleDialogComp extends ModalOverlayContentComp {

View File

@@ -2,7 +2,6 @@ package io.xpipe.app.util;
import java.security.MessageDigest;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAKey;
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
@@ -11,7 +10,8 @@ import java.util.*;
public class TlsCertificateFormat {
private static final DateTimeFormatter DATE_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd").withZone(ZoneOffset.UTC);
private static final DateTimeFormatter DATE_FMT =
DateTimeFormatter.ofPattern("yyyy-MM-dd").withZone(ZoneOffset.UTC);
public static String format(X509Certificate cert) {
var sb = new StringBuilder();
@@ -106,23 +106,21 @@ public class TlsCertificateFormat {
int len = dn.length();
while (i < len) {
while (i < len && dn.charAt(i) == ' ')
i++;
while (i < len && dn.charAt(i) == ' ') i++;
if (i >= len) {
break;
}
int typeStart = i;
while (i < len && dn.charAt(i) != '=')
i++;
while (i < len && dn.charAt(i) != '=') i++;
if (i >= len) {
break;
}
String type = dn.substring(typeStart, i).trim().toUpperCase();
i++;
while (i < len && dn.charAt(i) == ' ')
do {
i++;
} while (i < len && dn.charAt(i) == ' ');
var value = new StringBuilder();
@@ -133,8 +131,7 @@ public class TlsCertificateFormat {
i++;
}
map.putIfAbsent(type, "#" + value);
while (i < len && dn.charAt(i) != ',' && dn.charAt(i) != ';')
i++;
while (i < len && dn.charAt(i) != ',' && dn.charAt(i) != ';') i++;
if (i < len) {
i++;
}

View File

@@ -1,17 +1,13 @@
package io.xpipe.ext.base.host;
import io.xpipe.app.comp.BaseRegionBuilder;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.ext.*;
import io.xpipe.app.hub.comp.*;
import io.xpipe.app.platform.OptionsBuilder;
import io.xpipe.app.storage.DataStoreCategory;
import io.xpipe.app.util.DocumentationLink;
import javafx.beans.binding.Bindings;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableValue;
import lombok.SneakyThrows;

View File

@@ -1,12 +1,9 @@
package io.xpipe.ext.base.script;
import io.xpipe.app.comp.base.ButtonComp;
import io.xpipe.app.comp.base.InputGroupComp;
import io.xpipe.app.comp.base.IntegratedTextAreaComp;
import io.xpipe.app.comp.base.TextFieldComp;
import io.xpipe.app.core.AppCache;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.window.AppDialog;
import io.xpipe.app.ext.DataStoreCreationCategory;
import io.xpipe.app.ext.DataStoreDependencies;
import io.xpipe.app.ext.ShellDialectChoiceComp;
@@ -14,7 +11,6 @@ import io.xpipe.app.ext.ValidationException;
import io.xpipe.app.hub.comp.StoreChoiceComp;
import io.xpipe.app.hub.comp.StoreViewState;
import io.xpipe.app.issue.ErrorEventFactory;
import io.xpipe.app.platform.LabelGraphic;
import io.xpipe.app.platform.OptionsBuilder;
import io.xpipe.app.process.ShellDialect;
import io.xpipe.app.process.ShellScript;
@@ -162,7 +158,10 @@ public interface ScriptTextSource {
.documentationLink(DocumentationLink.SCRIPTING_COMPATIBILITY)
.addComp(choice, dialect)
.nameAndDescription("scriptTextSourceUrl")
.addComp(new TextFieldComp(url).apply(textField -> textField.setPromptText("https://example.com/my-script.sh")), url)
.addComp(
new TextFieldComp(url)
.apply(textField -> textField.setPromptText("https://example.com/my-script.sh")),
url)
.nonNull()
.bind(
() -> Url.builder()

View File

@@ -1,19 +1,11 @@
package io.xpipe.ext.base.service;
import io.xpipe.app.comp.BaseRegionBuilder;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.ext.CountGroupStoreProvider;
import io.xpipe.app.ext.DataStore;
import io.xpipe.app.ext.DataStoreProvider;
import io.xpipe.app.ext.DataStoreUsageCategory;
import io.xpipe.app.hub.comp.*;
import io.xpipe.app.storage.DataStoreEntry;
import io.xpipe.app.util.DocumentationLink;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableValue;
public abstract class AbstractServiceGroupStoreProvider implements CountGroupStoreProvider {
@Override

View File

@@ -152,7 +152,8 @@ public abstract class AbstractServiceStoreProvider implements SingletonSessionSt
return SystemStateComp.State.OTHER;
}
AbstractServiceStore s = section.getWrapper().getEntry().getStore().asNeeded();
AbstractServiceStore s =
section.getWrapper().getEntry().getStore().asNeeded();
if (!s.requiresTunnel()) {
return SystemStateComp.State.SUCCESS;

View File

@@ -22,17 +22,18 @@ import java.util.List;
public class IncusContainerStoreProvider implements ShellStoreProvider {
public BaseRegionBuilder<?, ?> stateDisplay(StoreSection section) {
return new OsLogoComp(section.getWrapper(), BindingsHelper.map(section.getWrapper().getPersistentState(), o -> {
var state = (ContainerStoreState) o;
var cs = state.getContainerState();
if (cs != null && cs.toLowerCase().contains("stopped")) {
return SystemStateComp.State.FAILURE;
} else if (cs != null && cs.toLowerCase().contains("running")) {
return SystemStateComp.State.SUCCESS;
} else {
return SystemStateComp.State.OTHER;
}
}));
return new OsLogoComp(
section.getWrapper(), BindingsHelper.map(section.getWrapper().getPersistentState(), o -> {
var state = (ContainerStoreState) o;
var cs = state.getContainerState();
if (cs != null && cs.toLowerCase().contains("stopped")) {
return SystemStateComp.State.FAILURE;
} else if (cs != null && cs.toLowerCase().contains("running")) {
return SystemStateComp.State.SUCCESS;
} else {
return SystemStateComp.State.OTHER;
}
}));
}
@Override

View File

@@ -22,17 +22,18 @@ import java.util.List;
public class LxdContainerStoreProvider implements ShellStoreProvider {
public BaseRegionBuilder<?, ?> stateDisplay(StoreSection section) {
return new OsLogoComp(section.getWrapper(), BindingsHelper.map(section.getWrapper().getPersistentState(), o -> {
var state = (ContainerStoreState) o;
var cs = state.getContainerState();
if (cs != null && cs.toLowerCase().contains("stopped")) {
return SystemStateComp.State.FAILURE;
} else if (cs != null && cs.toLowerCase().contains("running")) {
return SystemStateComp.State.SUCCESS;
} else {
return SystemStateComp.State.OTHER;
}
}));
return new OsLogoComp(
section.getWrapper(), BindingsHelper.map(section.getWrapper().getPersistentState(), o -> {
var state = (ContainerStoreState) o;
var cs = state.getContainerState();
if (cs != null && cs.toLowerCase().contains("stopped")) {
return SystemStateComp.State.FAILURE;
} else if (cs != null && cs.toLowerCase().contains("running")) {
return SystemStateComp.State.SUCCESS;
} else {
return SystemStateComp.State.OTHER;
}
}));
}
@Override

View File

@@ -89,17 +89,18 @@ public class PodmanContainerStoreProvider implements ShellStoreProvider {
}
public BaseRegionBuilder<?, ?> stateDisplay(StoreSection section) {
return new OsLogoComp(section.getWrapper(), BindingsHelper.map(section.getWrapper().getPersistentState(), o -> {
var state = (ContainerStoreState) o;
var cs = state.getContainerState();
if (cs != null && cs.toLowerCase().contains("exited")) {
return SystemStateComp.State.FAILURE;
} else if (cs != null && cs.toLowerCase().contains("up")) {
return SystemStateComp.State.SUCCESS;
} else {
return SystemStateComp.State.OTHER;
}
}));
return new OsLogoComp(
section.getWrapper(), BindingsHelper.map(section.getWrapper().getPersistentState(), o -> {
var state = (ContainerStoreState) o;
var cs = state.getContainerState();
if (cs != null && cs.toLowerCase().contains("exited")) {
return SystemStateComp.State.FAILURE;
} else if (cs != null && cs.toLowerCase().contains("up")) {
return SystemStateComp.State.SUCCESS;
} else {
return SystemStateComp.State.OTHER;
}
}));
}
@Override