mirror of
https://github.com/xpipe-io/xpipe.git
synced 2026-06-04 21:58:02 -04:00
Cleanup
This commit is contained in:
@@ -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));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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(() -> {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 -> {
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ public abstract class Session implements AutoCloseable {
|
||||
}
|
||||
|
||||
if (checkInactive()) {
|
||||
handleSessionDeath();
|
||||
handleSessionDeath();
|
||||
}
|
||||
});
|
||||
return false;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()))
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 -> {
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(
|
||||
() -> {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ public abstract class ConfigFileTerminalPrompt implements TerminalPrompt {
|
||||
p.getValue() != null
|
||||
? p.getValue().getConfigFileExtension()
|
||||
: null),
|
||||
false)
|
||||
false)
|
||||
.prefHeight(400),
|
||||
prop)
|
||||
.bind(
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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()));
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user