From 1f2919278f6e26226096f86541a3ff4953ab98a0 Mon Sep 17 00:00:00 2001 From: crschnick Date: Tue, 1 Aug 2023 19:34:08 +0000 Subject: [PATCH] Refactor plus several fixes --- .../app/browser/BrowserBreadcrumbBar.java | 5 +- .../app/browser/BrowserFileListCompEntry.java | 2 +- .../app/browser/BrowserFileListModel.java | 2 +- .../app/browser/BrowserFileOverviewComp.java | 2 +- .../io/xpipe/app/browser/BrowserNavBar.java | 9 ++- .../xpipe/app/browser/OpenFileSystemComp.java | 2 +- .../app/browser/OpenFileSystemModel.java | 8 +++ .../comp/store/DsStoreProviderChoiceComp.java | 5 +- .../app/comp/store/GuiDsStoreCreator.java | 2 +- .../app/exchange/AskpassExchangeImpl.java | 53 +---------------- .../java/io/xpipe/app/issue/ErrorEvent.java | 5 +- .../app/prefs/ExternalApplicationType.java | 4 +- .../io/xpipe/app/storage/DataStorage.java | 14 +++-- .../java/io/xpipe/app/util/AskpassAlert.java | 7 ++- .../java/io/xpipe/app/util/FileOpener.java | 6 +- .../app/util/SecretRetrievalStrategy.java | 48 +++++++++++---- .../resources/img/connection_icon-dark.svg | 56 ++++++++++++++++++ .../app/resources/img/connection_icon.svg | 56 ++++++++++++++++++ .../app/resources/img/home_icon-dark.svg | 56 ++++++++++++++++++ .../io/xpipe/app/resources/img/home_icon.png | Bin 22980 -> 0 bytes .../io/xpipe/app/resources/img/home_icon.svg | 56 ++++++++++++++++++ .../xpipe/app/resources/img/machine_icon.png | Bin 13865 -> 0 bytes .../resources/web/github-markdown-dark.css | 7 ++- .../beacon/exchange/AskpassExchange.java | 6 +- .../io/xpipe/core/process/CommandBuilder.java | 5 ++ .../xpipe/core/process/ElevationResult.java | 9 +++ .../io/xpipe/core/process/ShellControl.java | 2 + .../io/xpipe/core/store/LaunchableStore.java | 4 ++ .../java/io/xpipe/core/util/UuidHelper.java | 5 ++ .../io/xpipe/core/util/XPipeInstallation.java | 4 +- dist/changelogs/1.5.0.md | 1 + .../xpipe/ext/base/action/LaunchAction.java | 3 +- .../ext/base/browser/FollowLinkAction.java | 2 +- .../ext/base/browser/OpenDirectoryAction.java | 2 +- 34 files changed, 351 insertions(+), 97 deletions(-) create mode 100644 app/src/main/resources/io/xpipe/app/resources/img/connection_icon-dark.svg create mode 100644 app/src/main/resources/io/xpipe/app/resources/img/connection_icon.svg create mode 100644 app/src/main/resources/io/xpipe/app/resources/img/home_icon-dark.svg delete mode 100644 app/src/main/resources/io/xpipe/app/resources/img/home_icon.png create mode 100644 app/src/main/resources/io/xpipe/app/resources/img/home_icon.svg delete mode 100644 app/src/main/resources/io/xpipe/app/resources/img/machine_icon.png create mode 100644 core/src/main/java/io/xpipe/core/process/ElevationResult.java diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserBreadcrumbBar.java b/app/src/main/java/io/xpipe/app/browser/BrowserBreadcrumbBar.java index 5b8b55a1..8afc08ec 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserBreadcrumbBar.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserBreadcrumbBar.java @@ -4,7 +4,6 @@ import atlantafx.base.controls.Breadcrumbs; import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.util.PlatformThread; import io.xpipe.app.fxcomps.util.SimpleChangeListener; -import io.xpipe.app.util.ThreadHelper; import io.xpipe.core.impl.FileNames; import javafx.scene.Node; import javafx.scene.control.Button; @@ -81,9 +80,7 @@ public class BrowserBreadcrumbBar extends SimpleComp { } breadcrumbs.selectedCrumbProperty().addListener((obs, old, val) -> { - ThreadHelper.runFailableAsync(() -> { - model.cdSync(val != null ? val.getValue() : null); - }); + model.cdAsync(val != null ? val.getValue() : null); }); return breadcrumbs; diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserFileListCompEntry.java b/app/src/main/java/io/xpipe/app/browser/BrowserFileListCompEntry.java index 5514c1cf..e14f1979 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserFileListCompEntry.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserFileListCompEntry.java @@ -200,7 +200,7 @@ public class BrowserFileListCompEntry { return; } - model.getFileSystemModel().cdSync(item.getRawFileEntry().getPath()); + model.getFileSystemModel().cdAsync(item.getRawFileEntry().getPath()); } }; DROP_TIMER.schedule(activeTask, 1000); diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserFileListModel.java b/app/src/main/java/io/xpipe/app/browser/BrowserFileListModel.java index c9af527b..a6a6e393 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserFileListModel.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserFileListModel.java @@ -128,7 +128,7 @@ public final class BrowserFileListModel { } if (entry.getRawFileEntry().resolved().getKind() == FileKind.DIRECTORY) { - fileSystemModel.cdSync(entry.getRawFileEntry().resolved().getPath()); + fileSystemModel.cdAsync(entry.getRawFileEntry().resolved().getPath()); } } } diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserFileOverviewComp.java b/app/src/main/java/io/xpipe/app/browser/BrowserFileOverviewComp.java index bb35dd13..f16e95bb 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserFileOverviewComp.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserFileOverviewComp.java @@ -31,7 +31,7 @@ public class BrowserFileOverviewComp extends SimpleComp { var icon = BrowserIcons.createIcon(entry); var l = new Button(entry.getPath(), icon.createRegion()); l.setOnAction(event -> { - model.cdSync(entry.getPath()); + model.cdAsync(entry.getPath()); event.consume(); }); l.setAlignment(Pos.CENTER_LEFT); diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserNavBar.java b/app/src/main/java/io/xpipe/app/browser/BrowserNavBar.java index 457d154f..a5df651d 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserNavBar.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserNavBar.java @@ -11,6 +11,7 @@ import io.xpipe.app.fxcomps.impl.PrettyImageComp; import io.xpipe.app.fxcomps.impl.StackComp; import io.xpipe.app.fxcomps.impl.TextFieldComp; import io.xpipe.app.fxcomps.util.SimpleChangeListener; +import io.xpipe.app.util.BusyProperty; import io.xpipe.app.util.ThreadHelper; import javafx.application.Platform; import javafx.beans.binding.Bindings; @@ -45,8 +46,10 @@ public class BrowserNavBar extends SimpleComp { }); path.addListener((observable, oldValue, newValue) -> { ThreadHelper.runFailableAsync(() -> { - var changed = model.cdSyncOrRetry(newValue, true); - changed.ifPresent(s -> Platform.runLater(() -> path.set(s))); + BusyProperty.execute(model.getBusy(), () -> { + var changed = model.cdSyncOrRetry(newValue, true); + changed.ifPresent(s -> Platform.runLater(() -> path.set(s))); + }); }); }); @@ -88,7 +91,7 @@ public class BrowserNavBar extends SimpleComp { () -> { var icon = model.getCurrentDirectory() != null ? FileIconManager.getFileIcon(model.getCurrentDirectory(), false) - : "home_icon.png"; + : "home_icon.svg"; return icon; }, model.getCurrentPath()); diff --git a/app/src/main/java/io/xpipe/app/browser/OpenFileSystemComp.java b/app/src/main/java/io/xpipe/app/browser/OpenFileSystemComp.java index e44efd79..69c50d1f 100644 --- a/app/src/main/java/io/xpipe/app/browser/OpenFileSystemComp.java +++ b/app/src/main/java/io/xpipe/app/browser/OpenFileSystemComp.java @@ -43,7 +43,7 @@ public class OpenFileSystemComp extends SimpleComp { private Region createContent() { var overview = new Button(null, new FontIcon("mdi2m-monitor")); - overview.setOnAction(e -> model.cdSync(null)); + overview.setOnAction(e -> model.cdAsync(null)); overview.disableProperty().bind(model.getInOverview()); overview.setAccessibleText("System overview"); diff --git a/app/src/main/java/io/xpipe/app/browser/OpenFileSystemModel.java b/app/src/main/java/io/xpipe/app/browser/OpenFileSystemModel.java index bd405197..1c381e6c 100644 --- a/app/src/main/java/io/xpipe/app/browser/OpenFileSystemModel.java +++ b/app/src/main/java/io/xpipe/app/browser/OpenFileSystemModel.java @@ -107,6 +107,14 @@ public final class OpenFileSystemModel { return new FileSystem.FileEntry(fileSystem, currentPath.get(), null, false, false, 0, null, FileKind.DIRECTORY); } + public void cdAsync(String path) { + ThreadHelper.runFailableAsync(() -> { + BusyProperty.execute(busy, () -> { + cdSync(path); + }); + }); + } + public void cdSync(String path) { cdSyncOrRetry(path, false).ifPresent(s -> cdSyncOrRetry(s, false)); } diff --git a/app/src/main/java/io/xpipe/app/comp/store/DsStoreProviderChoiceComp.java b/app/src/main/java/io/xpipe/app/comp/store/DsStoreProviderChoiceComp.java index 73a6095c..55a4b367 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/DsStoreProviderChoiceComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/DsStoreProviderChoiceComp.java @@ -26,10 +26,11 @@ public class DsStoreProviderChoiceComp extends Comp Predicate filter; Property provider; + boolean staticDisplay; private Region createDefaultNode() { return JfxHelper.createNamedEntry( - AppI18n.get("selectType"), AppI18n.get("selectTypeDescription"), "machine_icon.png"); + AppI18n.get("selectType"), AppI18n.get("selectTypeDescription"), "connection_icon.svg"); } private List getProviders() { @@ -50,7 +51,7 @@ public class DsStoreProviderChoiceComp extends Comp var comboBox = new CustomComboBoxBuilder<>(provider, this::createGraphic, createDefaultNode(), v -> true); comboBox.setAccessibleNames(dataStoreProvider -> dataStoreProvider.getDisplayName()); getProviders().stream() - .filter(p -> AppPrefs.get().developerShowHiddenProviders().get() || p.canManuallyCreate()) + .filter(p -> AppPrefs.get().developerShowHiddenProviders().get() || p.canManuallyCreate() || staticDisplay) .forEach(comboBox::add); ComboBox cb = comboBox.build(); cb.getStyleClass().add("data-source-type"); diff --git a/app/src/main/java/io/xpipe/app/comp/store/GuiDsStoreCreator.java b/app/src/main/java/io/xpipe/app/comp/store/GuiDsStoreCreator.java index 8dad7240..d7b43845 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/GuiDsStoreCreator.java +++ b/app/src/main/java/io/xpipe/app/comp/store/GuiDsStoreCreator.java @@ -240,7 +240,7 @@ public class GuiDsStoreCreator extends MultiStepComp.Step> { var layout = new BorderPane(); layout.getStyleClass().add("store-creator"); layout.setPadding(new Insets(20)); - var providerChoice = new DsStoreProviderChoiceComp(filter, provider); + var providerChoice = new DsStoreProviderChoiceComp(filter, provider, provider.getValue() != null); if (provider.getValue() != null) { providerChoice.apply(struc -> struc.get().setDisable(true)); } diff --git a/app/src/main/java/io/xpipe/app/exchange/AskpassExchangeImpl.java b/app/src/main/java/io/xpipe/app/exchange/AskpassExchangeImpl.java index d721f482..17332e41 100644 --- a/app/src/main/java/io/xpipe/app/exchange/AskpassExchangeImpl.java +++ b/app/src/main/java/io/xpipe/app/exchange/AskpassExchangeImpl.java @@ -1,69 +1,20 @@ package io.xpipe.app.exchange; -import io.xpipe.app.core.AppI18n; -import io.xpipe.app.core.AppWindowHelper; import io.xpipe.app.core.mode.OperationMode; -import io.xpipe.app.fxcomps.impl.SecretFieldComp; +import io.xpipe.app.util.AskpassAlert; import io.xpipe.beacon.BeaconHandler; import io.xpipe.beacon.exchange.AskpassExchange; -import io.xpipe.core.util.SecretValue; -import javafx.beans.property.SimpleObjectProperty; -import javafx.scene.control.Alert; -import javafx.scene.layout.StackPane; - -import java.util.HashMap; -import java.util.Map; public class AskpassExchangeImpl extends AskpassExchange implements MessageExchangeImpl { - private final Map requestToId = new HashMap<>(); - private final Map passwords = new HashMap<>(); - @Override public Response handleRequest(BeaconHandler handler, Request msg) { if (OperationMode.get().equals(OperationMode.BACKGROUND)) { OperationMode.switchTo(OperationMode.TRAY); } - // SecretValue set = AppCache.get(msg.getId(), SecretValue.class, () -> null); - // if (set != null) { - // return Response.builder().value(set).build(); - // } - - if (requestToId.containsKey(msg.getRequest())) { - var id = requestToId.remove(msg.getRequest()); - passwords.remove(id); - } - - if (passwords.containsKey(msg.getId())) { - return Response.builder() - .value(passwords.get(msg.getId()).getSecretValue()) - .build(); - } - - var prop = new SimpleObjectProperty(); - var r = AppWindowHelper.showBlockingAlert(alert -> { - alert.setTitle(AppI18n.get("askpassAlertTitle")); - alert.setHeaderText(msg.getPrompt()); - alert.setAlertType(Alert.AlertType.CONFIRMATION); - - var text = new SecretFieldComp(prop).createRegion(); - alert.getDialogPane().setContent(new StackPane(text)); - }) - .filter(b -> b.getButtonData().isDefaultButton() && prop.getValue() != null) - .map(t -> { - // AppCache.update(msg.getId(), prop.getValue()); - return prop.getValue(); - }) - .orElse(null); - - // If the result is null, assume that the operation was aborted by the user - if (r != null) { - passwords.put(msg.getId(), r); - requestToId.put(msg.getRequest(), msg.getId()); - } - + var r = AskpassAlert.query(msg.getPrompt(), msg.getRequest(), msg.getId()); return Response.builder().value(r != null ? r.getSecretValue() : null).build(); } } diff --git a/app/src/main/java/io/xpipe/app/issue/ErrorEvent.java b/app/src/main/java/io/xpipe/app/issue/ErrorEvent.java index fabf09e5..5a24b4f6 100644 --- a/app/src/main/java/io/xpipe/app/issue/ErrorEvent.java +++ b/app/src/main/java/io/xpipe/app/issue/ErrorEvent.java @@ -22,13 +22,16 @@ public class ErrorEvent { @Builder.Default private final boolean reportable = true; - private Throwable throwable; + private final Throwable throwable; @Singular private List attachments; private String userReport; + @Singular + private final List customActions; + public void attachUserReport(String text) { userReport = text; } diff --git a/app/src/main/java/io/xpipe/app/prefs/ExternalApplicationType.java b/app/src/main/java/io/xpipe/app/prefs/ExternalApplicationType.java index 49984261..dde68b4b 100644 --- a/app/src/main/java/io/xpipe/app/prefs/ExternalApplicationType.java +++ b/app/src/main/java/io/xpipe/app/prefs/ExternalApplicationType.java @@ -9,6 +9,7 @@ import io.xpipe.core.process.ShellDialects; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Comparator; import java.util.Optional; public abstract class ExternalApplicationType implements PrefsChoiceValue { @@ -55,13 +56,14 @@ public abstract class ExternalApplicationType implements PrefsChoiceValue { } // Check if returned paths are actually valid + // Also sort them by length to prevent finding a deeply buried app var valid = path.lines().filter(s -> { try { return Files.exists(Path.of(s)); } catch (Exception ex) { return false; } - }).toList(); + }).sorted(Comparator.comparingInt(value -> value.length())).toList(); // Prefer app in proper applications directory var app = valid.stream().filter(s -> s.startsWith("/Applications")).findFirst(); diff --git a/app/src/main/java/io/xpipe/app/storage/DataStorage.java b/app/src/main/java/io/xpipe/app/storage/DataStorage.java index c5e1980b..8a9a9d2e 100644 --- a/app/src/main/java/io/xpipe/app/storage/DataStorage.java +++ b/app/src/main/java/io/xpipe/app/storage/DataStorage.java @@ -101,14 +101,18 @@ public abstract class DataStorage { } public synchronized Optional getParent(DataStoreEntry entry, boolean display) { - if (!entry.getState().isUsable()) { + if (entry.getState() == DataStoreEntry.State.LOAD_FAILED) { return Optional.empty(); } - var provider = entry.getProvider(); - var parent = - display ? provider.getDisplayParent(entry.getStore()) : provider.getLogicalParent(entry.getStore()); - return parent != null ? getStoreEntryIfPresent(parent) : Optional.empty(); + try { + var provider = entry.getProvider(); + var parent = + display ? provider.getDisplayParent(entry.getStore()) : provider.getLogicalParent(entry.getStore()); + return parent != null ? getStoreEntryIfPresent(parent) : Optional.empty(); + } catch (Exception ex) { + return Optional.empty(); + } } public synchronized List getStoreChildren(DataStoreEntry entry, boolean display, boolean deep) { diff --git a/app/src/main/java/io/xpipe/app/util/AskpassAlert.java b/app/src/main/java/io/xpipe/app/util/AskpassAlert.java index 431c0900..0242de04 100644 --- a/app/src/main/java/io/xpipe/app/util/AskpassAlert.java +++ b/app/src/main/java/io/xpipe/app/util/AskpassAlert.java @@ -3,7 +3,6 @@ package io.xpipe.app.util; import io.xpipe.app.core.AppI18n; import io.xpipe.app.core.AppWindowHelper; import io.xpipe.app.fxcomps.impl.SecretFieldComp; -import io.xpipe.core.store.DataStore; import io.xpipe.core.util.SecretValue; import javafx.beans.property.SimpleObjectProperty; import javafx.scene.control.Alert; @@ -19,9 +18,9 @@ public class AskpassAlert { private static final Map requestToId = new HashMap<>(); private static final Map passwords = new HashMap<>(); - public static SecretValue query(String prompt, DataStore store) { + public static SecretValue query(String prompt, Object key) { var rid = UUID.randomUUID(); - var secretId = UUID.nameUUIDFromBytes(ByteBuffer.allocate(4).putInt(store.hashCode()).array()); + var secretId = UUID.nameUUIDFromBytes(ByteBuffer.allocate(4).putInt(key.hashCode()).array()); return query(prompt, rid, secretId); } @@ -39,6 +38,8 @@ public class AskpassAlert { var r = AppWindowHelper.showBlockingAlert(alert -> { alert.setTitle(AppI18n.get("askpassAlertTitle")); alert.setHeaderText(prompt); +// alert.getDialogPane().setHeader( +// AppWindowHelper.alertContentText(prompt)); alert.setAlertType(Alert.AlertType.CONFIRMATION); var text = new SecretFieldComp(prop).createRegion(); diff --git a/app/src/main/java/io/xpipe/app/util/FileOpener.java b/app/src/main/java/io/xpipe/app/util/FileOpener.java index 9a67e347..7589bd26 100644 --- a/app/src/main/java/io/xpipe/app/util/FileOpener.java +++ b/app/src/main/java/io/xpipe/app/util/FileOpener.java @@ -22,10 +22,11 @@ public class FileOpener { } var file = entry.getPath(); + var key = entry.getPath().hashCode() + entry.getFileSystem().hashCode(); FileBridge.get() .openIO( FileNames.getFileName(file), - file, + key, () -> { return entry.getFileSystem().openInput(file); }, @@ -40,10 +41,11 @@ public class FileOpener { } var file = entry.getPath(); + var key = entry.getPath().hashCode() + entry.getFileSystem().hashCode(); FileBridge.get() .openIO( FileNames.getFileName(file), - file, + key, () -> { return entry.getFileSystem().openInput(file); }, diff --git a/app/src/main/java/io/xpipe/app/util/SecretRetrievalStrategy.java b/app/src/main/java/io/xpipe/app/util/SecretRetrievalStrategy.java index ccac00ac..0b8fd762 100644 --- a/app/src/main/java/io/xpipe/app/util/SecretRetrievalStrategy.java +++ b/app/src/main/java/io/xpipe/app/util/SecretRetrievalStrategy.java @@ -17,18 +17,19 @@ import java.util.function.Supplier; @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") @JsonSubTypes({ - @JsonSubTypes.Type(value = SecretRetrievalStrategy.None.class), - @JsonSubTypes.Type(value = SecretRetrievalStrategy.Unsupported.class), - @JsonSubTypes.Type(value = SecretRetrievalStrategy.Reference.class), - @JsonSubTypes.Type(value = SecretRetrievalStrategy.InPlace.class), - @JsonSubTypes.Type(value = SecretRetrievalStrategy.Prompt.class), - @JsonSubTypes.Type(value = SecretRetrievalStrategy.CustomCommand.class), - @JsonSubTypes.Type(value = SecretRetrievalStrategy.PasswordManager.class) + @JsonSubTypes.Type(value = SecretRetrievalStrategy.None.class), + @JsonSubTypes.Type(value = SecretRetrievalStrategy.Reference.class), + @JsonSubTypes.Type(value = SecretRetrievalStrategy.InPlace.class), + @JsonSubTypes.Type(value = SecretRetrievalStrategy.Prompt.class), + @JsonSubTypes.Type(value = SecretRetrievalStrategy.CustomCommand.class), + @JsonSubTypes.Type(value = SecretRetrievalStrategy.PasswordManager.class) }) public interface SecretRetrievalStrategy { SecretValue retrieve(String displayName, DataStore store) throws Exception; + boolean supportsLocalAskpass(); + @JsonTypeName("none") public static class None implements SecretRetrievalStrategy { @@ -36,14 +37,10 @@ public interface SecretRetrievalStrategy { public SecretValue retrieve(String displayName, DataStore store) { return null; } - } - - @JsonTypeName("unsupported") - public static class Unsupported implements SecretRetrievalStrategy { @Override - public SecretValue retrieve(String displayName, DataStore store) { - throw new UnsupportedOperationException(); + public boolean supportsLocalAskpass() { + return true; } } @@ -61,6 +58,11 @@ public interface SecretRetrievalStrategy { public SecretValue retrieve(String displayName, DataStore store) { return supplier.get(); } + + @Override + public boolean supportsLocalAskpass() { + return false; + } } @JsonTypeName("inPlace") @@ -80,6 +82,11 @@ public interface SecretRetrievalStrategy { public SecretValue retrieve(String displayName, DataStore store) { return value; } + + @Override + public boolean supportsLocalAskpass() { + return false; + } } @JsonTypeName("prompt") @@ -89,6 +96,11 @@ public interface SecretRetrievalStrategy { public SecretValue retrieve(String displayName, DataStore store) { return AskpassAlert.query(displayName, store); } + + @Override + public boolean supportsLocalAskpass() { + return true; + } } @JsonTypeName("passwordManager") @@ -110,6 +122,11 @@ public interface SecretRetrievalStrategy { return SecretHelper.encrypt(cc.readStdoutOrThrow()); } } + + @Override + public boolean supportsLocalAskpass() { + return false; + } } @JsonTypeName("customCommand") @@ -126,5 +143,10 @@ public interface SecretRetrievalStrategy { return SecretHelper.encrypt(cc.readStdoutOrThrow()); } } + + @Override + public boolean supportsLocalAskpass() { + return false; + } } } diff --git a/app/src/main/resources/io/xpipe/app/resources/img/connection_icon-dark.svg b/app/src/main/resources/io/xpipe/app/resources/img/connection_icon-dark.svg new file mode 100644 index 00000000..2f5dcf64 --- /dev/null +++ b/app/src/main/resources/io/xpipe/app/resources/img/connection_icon-dark.svg @@ -0,0 +1,56 @@ + + + + + + + connection + + + + + connection + + + + diff --git a/app/src/main/resources/io/xpipe/app/resources/img/connection_icon.svg b/app/src/main/resources/io/xpipe/app/resources/img/connection_icon.svg new file mode 100644 index 00000000..43153f58 --- /dev/null +++ b/app/src/main/resources/io/xpipe/app/resources/img/connection_icon.svg @@ -0,0 +1,56 @@ + + + + + + + connection + + + + + connection + + + + diff --git a/app/src/main/resources/io/xpipe/app/resources/img/home_icon-dark.svg b/app/src/main/resources/io/xpipe/app/resources/img/home_icon-dark.svg new file mode 100644 index 00000000..5444866e --- /dev/null +++ b/app/src/main/resources/io/xpipe/app/resources/img/home_icon-dark.svg @@ -0,0 +1,56 @@ + + + + + + + home + + + + + home + + + + diff --git a/app/src/main/resources/io/xpipe/app/resources/img/home_icon.png b/app/src/main/resources/io/xpipe/app/resources/img/home_icon.png deleted file mode 100644 index c8f5fe9c849093029f429930018f3197d068b048..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22980 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 E04W4?*8l(j diff --git a/app/src/main/resources/io/xpipe/app/resources/img/home_icon.svg b/app/src/main/resources/io/xpipe/app/resources/img/home_icon.svg new file mode 100644 index 00000000..380a865f --- /dev/null +++ b/app/src/main/resources/io/xpipe/app/resources/img/home_icon.svg @@ -0,0 +1,56 @@ + + + + + + + home + + + + + home + + + + diff --git a/app/src/main/resources/io/xpipe/app/resources/img/machine_icon.png b/app/src/main/resources/io/xpipe/app/resources/img/machine_icon.png deleted file mode 100644 index e1a23719dd330b83270a3ed10258b20eca080e14..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13865 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 diff --git a/app/src/main/resources/io/xpipe/app/resources/web/github-markdown-dark.css b/app/src/main/resources/io/xpipe/app/resources/web/github-markdown-dark.css index 864d027b..de117201 100644 --- a/app/src/main/resources/io/xpipe/app/resources/web/github-markdown-dark.css +++ b/app/src/main/resources/io/xpipe/app/resources/web/github-markdown-dark.css @@ -1,11 +1,16 @@ +html { + font-family: Roboto; +} + .markdown-body { color-scheme: dark; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; margin: 0; + padding: 1em; color: #c9d1d9; font-family: -apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji"; - font-size: 16px; + font-size: 14px; line-height: 1.5; word-wrap: break-word; } diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/AskpassExchange.java b/beacon/src/main/java/io/xpipe/beacon/exchange/AskpassExchange.java index bb15c824..6d3b3b8c 100644 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/AskpassExchange.java +++ b/beacon/src/main/java/io/xpipe/beacon/exchange/AskpassExchange.java @@ -7,6 +7,8 @@ import lombok.NonNull; import lombok.Value; import lombok.extern.jackson.Jacksonized; +import java.util.UUID; + public class AskpassExchange implements MessageExchange { @Override @@ -19,10 +21,10 @@ public class AskpassExchange implements MessageExchange { @Value public static class Request implements RequestMessage { @NonNull - String id; + UUID id; @NonNull - String request; + UUID request; String prompt; } diff --git a/core/src/main/java/io/xpipe/core/process/CommandBuilder.java b/core/src/main/java/io/xpipe/core/process/CommandBuilder.java index 9569f2a6..aaee90a9 100644 --- a/core/src/main/java/io/xpipe/core/process/CommandBuilder.java +++ b/core/src/main/java/io/xpipe/core/process/CommandBuilder.java @@ -45,6 +45,11 @@ public class CommandBuilder { return this; } + public CommandBuilder remove(String s) { + elements.removeIf(element -> element instanceof Fixed fixed && s.equals(fixed.string)); + return this; + } + public CommandBuilder addQuoted(String s) { elements.add(new Fixed("\"" + s + "\"")); return this; diff --git a/core/src/main/java/io/xpipe/core/process/ElevationResult.java b/core/src/main/java/io/xpipe/core/process/ElevationResult.java new file mode 100644 index 00000000..71c148c6 --- /dev/null +++ b/core/src/main/java/io/xpipe/core/process/ElevationResult.java @@ -0,0 +1,9 @@ +package io.xpipe.core.process; + +import lombok.Value; + +@Value +public class ElevationResult { + String value; + boolean promptsUserInput; +} diff --git a/core/src/main/java/io/xpipe/core/process/ShellControl.java b/core/src/main/java/io/xpipe/core/process/ShellControl.java index 62f263b9..3e06be8c 100644 --- a/core/src/main/java/io/xpipe/core/process/ShellControl.java +++ b/core/src/main/java/io/xpipe/core/process/ShellControl.java @@ -88,6 +88,8 @@ public interface ShellControl extends ProcessControl { } } + ElevationResult elevateCommand(String input) throws Exception; + void restart() throws Exception; OsType getOsType(); diff --git a/core/src/main/java/io/xpipe/core/store/LaunchableStore.java b/core/src/main/java/io/xpipe/core/store/LaunchableStore.java index 3c0672f0..539ba969 100644 --- a/core/src/main/java/io/xpipe/core/store/LaunchableStore.java +++ b/core/src/main/java/io/xpipe/core/store/LaunchableStore.java @@ -2,5 +2,9 @@ package io.xpipe.core.store; public interface LaunchableStore extends DataStore { + default boolean canLaunch() { + return true; + } + String prepareLaunchCommand(String displayName) throws Exception; } diff --git a/core/src/main/java/io/xpipe/core/util/UuidHelper.java b/core/src/main/java/io/xpipe/core/util/UuidHelper.java index ff03f8c2..2457aa57 100644 --- a/core/src/main/java/io/xpipe/core/util/UuidHelper.java +++ b/core/src/main/java/io/xpipe/core/util/UuidHelper.java @@ -1,10 +1,15 @@ package io.xpipe.core.util; +import java.nio.charset.StandardCharsets; import java.util.Optional; import java.util.UUID; public class UuidHelper { + public static UUID generateFromObject(Object o) { + return UUID.nameUUIDFromBytes(o.toString().getBytes(StandardCharsets.UTF_8)); + } + public static Optional parse(String s) { try { return Optional.of(UUID.fromString(s)); diff --git a/core/src/main/java/io/xpipe/core/util/XPipeInstallation.java b/core/src/main/java/io/xpipe/core/util/XPipeInstallation.java index 5418b764..46922dce 100644 --- a/core/src/main/java/io/xpipe/core/util/XPipeInstallation.java +++ b/core/src/main/java/io/xpipe/core/util/XPipeInstallation.java @@ -178,7 +178,9 @@ public class XPipeInstallation { } public static String getLocalDefaultCliExecutable() { - Path path = ModuleHelper.isImage() ? getCurrentInstallationBasePath() : Path.of(getLocalDefaultInstallationBasePath(true)); + Path path = ModuleHelper.isImage() + ? getCurrentInstallationBasePath() + : Path.of(getLocalDefaultInstallationBasePath(true)); return path.resolve(getRelativeCliExecutablePath(OsType.getLocal())).toString(); } diff --git a/dist/changelogs/1.5.0.md b/dist/changelogs/1.5.0.md index dbcf2048..93cfb05d 100644 --- a/dist/changelogs/1.5.0.md +++ b/dist/changelogs/1.5.0.md @@ -63,6 +63,7 @@ This also comes with full support of the feature set for these environments - Implement a new internal API to better assemble complex commands - Rework os detection logic for passthrough environments like Cygwin and MSYS2 - Fix desktop directory not being determined correctly on Windows when it was moved from the default location +- Fix various checks in file browser not being applied properly and leading to wrong error messages - Rework threading in navigation bar in browser to improve responsiveness - Recheck if prepared update is still the latest one prior to installing it - Properly use shell script file extension for external editor when creating shell environments diff --git a/ext/base/src/main/java/io/xpipe/ext/base/action/LaunchAction.java b/ext/base/src/main/java/io/xpipe/ext/base/action/LaunchAction.java index 338e8ae9..329ab7ab 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/action/LaunchAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/action/LaunchAction.java @@ -57,13 +57,14 @@ public class LaunchAction implements ActionProvider { @Override public DefaultDataStoreCallSite getDefaultDataStoreCallSite() { return new DefaultDataStoreCallSite() { + @Override public boolean isApplicable(LaunchableStore o) { return DataStorage.get() .getStoreEntryIfPresent(o) .orElseThrow() .getState() - .isUsable(); + .isUsable() && o.canLaunch(); } @Override diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/FollowLinkAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/FollowLinkAction.java index 4719b2bf..593024bc 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/FollowLinkAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/FollowLinkAction.java @@ -20,7 +20,7 @@ public class FollowLinkAction implements LeafAction { @Override public void execute(OpenFileSystemModel model, List entries) { var target = FileNames.getParent(entries.get(0).getRawFileEntry().resolved().getPath()); - model.cdSync(target); + model.cdAsync(target); } @Override diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenDirectoryAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenDirectoryAction.java index 37c54d7b..398db85b 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenDirectoryAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/OpenDirectoryAction.java @@ -16,7 +16,7 @@ public class OpenDirectoryAction implements LeafAction { @Override public void execute(OpenFileSystemModel model, List entries) { - model.cdSync(entries.get(0).getRawFileEntry().getPath()); + model.cdAsync(entries.get(0).getRawFileEntry().getPath()); } @Override