diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/SshLaunchExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/SshLaunchExchangeImpl.java index 3c0d19ee5..716da1155 100644 --- a/app/src/main/java/io/xpipe/app/beacon/impl/SshLaunchExchangeImpl.java +++ b/app/src/main/java/io/xpipe/app/beacon/impl/SshLaunchExchangeImpl.java @@ -12,7 +12,7 @@ public class SshLaunchExchangeImpl extends SshLaunchExchange { @Override public Object handle(HttpExchange exchange, Request msg) throws Exception { - var usedDialect = ShellDialects.ALL.stream() + var usedDialect = ShellDialects.getStartableDialects().stream() .filter(dialect -> dialect.getExecutableName().equalsIgnoreCase(msg.getArguments())) .findFirst(); if (msg.getArguments() != null @@ -21,6 +21,8 @@ public class SshLaunchExchangeImpl extends SshLaunchExchange { throw new BeaconClientException("Unexpected argument: " + msg.getArguments()); } + // There are sometimes multiple requests by a terminal client (e.g. Termius) + // This might fail sometimes, but it is expected var r = TerminalLauncherManager.waitForNextLaunch(); var c = ProcessControlProvider.get() .getEffectiveLocalDialect() diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserTransferModel.java b/app/src/main/java/io/xpipe/app/browser/BrowserTransferModel.java index d501b1392..5f7b52296 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserTransferModel.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserTransferModel.java @@ -166,7 +166,7 @@ public class BrowserTransferModel { var target = downloads.resolve(file.getFileName()); // Prevent DirectoryNotEmptyException if (Files.exists(target) && Files.isDirectory(target)) { - Files.delete(target); + FileUtils.deleteDirectory(target.toFile()); } Files.move(file, target, StandardCopyOption.REPLACE_EXISTING); } diff --git a/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListComp.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListComp.java index 4b0dfd75f..21a491558 100644 --- a/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListComp.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListComp.java @@ -634,6 +634,10 @@ public final class BrowserFileListComp extends SimpleComp { var it = getTableRow().getItem(); editing.setValue(null); ThreadHelper.runAsync(() -> { + if (it == null) { + return; + } + var r = fileList.rename(it, newValue); Platform.runLater(() -> { updateItem(getItem(), isEmpty()); diff --git a/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListModel.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListModel.java index 8495b91ba..e679a24f3 100644 --- a/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListModel.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListModel.java @@ -99,7 +99,8 @@ public final class BrowserFileListModel { } public BrowserEntry rename(BrowserEntry old, String newName) { - if (fileSystemModel == null + if (old == null || newName == null + || fileSystemModel == null || fileSystemModel.isClosed() || fileSystemModel.getCurrentPath().get() == null) { return old; diff --git a/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemComp.java b/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemComp.java index 7763a27b3..c982416fd 100644 --- a/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemComp.java +++ b/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemComp.java @@ -142,7 +142,7 @@ public class OpenFileSystemComp extends SimpleComp { } keyEvent.consume(); }); - InputHelper.onKeyCombination(root, new KeyCodeCombination(KeyCode.BACK_SPACE), true, keyEvent -> { + InputHelper.onKeyCombination(root, new KeyCodeCombination(KeyCode.BACK_SPACE), false, keyEvent -> { var p = model.getCurrentParentDirectory(); if (p != null) { model.cdAsync(p.getPath()); diff --git a/app/src/main/java/io/xpipe/app/core/mode/GuiMode.java b/app/src/main/java/io/xpipe/app/core/mode/GuiMode.java index aad069cbb..ad26c5d96 100644 --- a/app/src/main/java/io/xpipe/app/core/mode/GuiMode.java +++ b/app/src/main/java/io/xpipe/app/core/mode/GuiMode.java @@ -10,6 +10,7 @@ import io.xpipe.app.fxcomps.util.PlatformThread; import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.issue.TrackEvent; import io.xpipe.app.update.UpdateChangelogAlert; +import io.xpipe.app.util.NativeBridge; import io.xpipe.app.util.ThreadHelper; import javafx.stage.Stage; @@ -37,6 +38,7 @@ public class GuiMode extends PlatformMode { AppGreetings.showIfNeeded(); AppPtbCheck.check(); + NativeBridge.init(); TrackEvent.info("Waiting for window setup completion ..."); PlatformThread.runLaterIfNeededBlocking(() -> { diff --git a/app/src/main/java/io/xpipe/app/core/window/NativeMacOsWindowControl.java b/app/src/main/java/io/xpipe/app/core/window/NativeMacOsWindowControl.java index 0375fcd3b..a65c1ba95 100644 --- a/app/src/main/java/io/xpipe/app/core/window/NativeMacOsWindowControl.java +++ b/app/src/main/java/io/xpipe/app/core/window/NativeMacOsWindowControl.java @@ -46,7 +46,7 @@ public class NativeMacOsWindowControl { try { lib.get().setAppearance(new NativeLong(nsWindow), seamlessFrame, darkMode); if (seamlessFrame) { - ThreadHelper.sleep(250); + ThreadHelper.sleep(150); } } catch (Throwable e) { ErrorEvent.fromThrowable(e).handle(); diff --git a/app/src/main/java/io/xpipe/app/terminal/ExternalTerminalType.java b/app/src/main/java/io/xpipe/app/terminal/ExternalTerminalType.java index eab218332..98b1737c4 100644 --- a/app/src/main/java/io/xpipe/app/terminal/ExternalTerminalType.java +++ b/app/src/main/java/io/xpipe/app/terminal/ExternalTerminalType.java @@ -1,5 +1,6 @@ package io.xpipe.app.terminal; +import io.xpipe.app.beacon.AppBeaconServer; import io.xpipe.app.comp.base.MarkdownComp; import io.xpipe.app.core.AppCache; import io.xpipe.app.core.AppI18n; @@ -13,6 +14,7 @@ import io.xpipe.core.process.*; import io.xpipe.core.store.FilePath; import io.xpipe.core.util.FailableFunction; +import io.xpipe.core.util.XPipeInstallation; import javafx.scene.control.Alert; import javafx.scene.control.ButtonBar; import javafx.scene.control.ButtonType; @@ -238,6 +240,14 @@ public interface ExternalTerminalType extends PrefsChoiceValue { @Override protected void execute(Path file, LaunchConfiguration configuration) throws Exception { try (var sc = LocalShell.getShell()) { + // Since mobaxterm uses its own cygwin environment, we have to provide the beacon auth secret to the tmp there as well + // Otherwise it can't connect + var slashTemp = Path.of(System.getenv("APPDATA"), "MobaXterm", "slash", "tmp"); + if (Files.exists(slashTemp)) { + var authFileName = XPipeInstallation.getLocalBeaconAuthFile().getFileName().toString(); + Files.writeString(Path.of(slashTemp.toString(), authFileName),AppBeaconServer.get().getLocalAuthSecret()); + } + var fixedFile = configuration .getScriptFile() .toString() diff --git a/app/src/main/java/io/xpipe/app/util/DesktopShortcuts.java b/app/src/main/java/io/xpipe/app/util/DesktopShortcuts.java index bde39a45f..ce06f5865 100644 --- a/app/src/main/java/io/xpipe/app/util/DesktopShortcuts.java +++ b/app/src/main/java/io/xpipe/app/util/DesktopShortcuts.java @@ -23,7 +23,7 @@ public class DesktopShortcuts { $S.Arguments = '%s' $S.Save() """, - executable, shortcutPath, icon, args); + executable, shortcutPath, icon, args).replaceAll("\n", ";"); LocalShell.getLocalPowershell().executeSimpleCommand(content); return shortcutPath; } diff --git a/app/src/main/java/io/xpipe/app/util/NativeBridge.java b/app/src/main/java/io/xpipe/app/util/NativeBridge.java index a04e3f935..1add6e4cb 100644 --- a/app/src/main/java/io/xpipe/app/util/NativeBridge.java +++ b/app/src/main/java/io/xpipe/app/util/NativeBridge.java @@ -1,6 +1,7 @@ package io.xpipe.app.util; import io.xpipe.app.issue.ErrorEvent; +import io.xpipe.core.process.OsType; import io.xpipe.core.util.XPipeInstallation; import com.sun.jna.Library; @@ -15,6 +16,13 @@ public class NativeBridge { private static MacOsLibrary macOsLibrary; private static boolean loadingFailed; + public static void init() { + // Preload + if (OsType.getLocal() == OsType.MACOS) { + getMacOsLibrary(); + } + } + public static Optional getMacOsLibrary() { if (macOsLibrary == null && !loadingFailed) { try { diff --git a/core/src/main/java/io/xpipe/core/process/OsType.java b/core/src/main/java/io/xpipe/core/process/OsType.java index 5f43bc118..259144a42 100644 --- a/core/src/main/java/io/xpipe/core/process/OsType.java +++ b/core/src/main/java/io/xpipe/core/process/OsType.java @@ -28,7 +28,7 @@ public interface OsType { List determineInterestingPaths(ShellControl pc) throws Exception; - String getHomeDirectory(ShellControl pc) throws Exception; + String getUserHomeDirectory(ShellControl pc) throws Exception; String getFileSystemSeparator(); @@ -55,7 +55,7 @@ public interface OsType { @Override public List determineInterestingPaths(ShellControl pc) throws Exception { - var home = getHomeDirectory(pc); + var home = getUserHomeDirectory(pc); return List.of( home, FileNames.join(home, "Documents"), @@ -64,7 +64,7 @@ public interface OsType { } @Override - public String getHomeDirectory(ShellControl pc) throws Exception { + public String getUserHomeDirectory(ShellControl pc) throws Exception { return pc.executeSimpleStringCommand( pc.getShellDialect().getPrintEnvironmentVariableCommand("USERPROFILE")); } @@ -95,10 +95,10 @@ public interface OsType { @Override public List determineInterestingPaths(ShellControl pc) throws Exception { - var home = getHomeDirectory(pc); + var home = getUserHomeDirectory(pc); return List.of( home, - "/home", + FileNames.getParent(home), FileNames.join(home, "Downloads"), FileNames.join(home, "Documents"), "/etc", @@ -107,7 +107,7 @@ public interface OsType { } @Override - public String getHomeDirectory(ShellControl pc) throws Exception { + public String getUserHomeDirectory(ShellControl pc) throws Exception { return pc.executeSimpleStringCommand(pc.getShellDialect().getPrintEnvironmentVariableCommand("HOME")); } @@ -149,7 +149,7 @@ public interface OsType { @Override public List determineInterestingPaths(ShellControl pc) throws Exception { - var home = getHomeDirectory(pc); + var home = getUserHomeDirectory(pc); return List.of( home, FileNames.join(home, "Downloads"), @@ -162,7 +162,7 @@ public interface OsType { } @Override - public String getHomeDirectory(ShellControl pc) throws Exception { + public String getUserHomeDirectory(ShellControl pc) throws Exception { return pc.executeSimpleStringCommand(pc.getShellDialect().getPrintEnvironmentVariableCommand("HOME")); } diff --git a/core/src/main/java/module-info.java b/core/src/main/java/module-info.java index 692574970..1ccf7cf3f 100644 --- a/core/src/main/java/module-info.java +++ b/core/src/main/java/module-info.java @@ -17,7 +17,6 @@ open module io.xpipe.core { requires com.fasterxml.jackson.databind; requires java.net.http; requires static lombok; - requires java.sql; uses com.fasterxml.jackson.databind.Module; uses ProcessControlProvider; diff --git a/dist/changelogs/11.0.md b/dist/changelogs/11.0.md index a4a80cc93..2519be6c5 100644 --- a/dist/changelogs/11.0.md +++ b/dist/changelogs/11.0.md @@ -18,7 +18,7 @@ These work via a local SSH bridge that is managed by XPipe. ## Teleport support -There is now support to add your teleport connections that are available via tsh. You can do that by searching for available connections on any system which has tsh installed. +There is now support to add your teleport connections that are available via tsh. You can do that by searching for available connections on any system which has tsh installed. This is a separate integration from SSH, SSH config entries for teleport proxies do not work and are automatically filtered out. It solely works through the tsh tool. This feature is available in the Professional edition and is freely available to anyone for two weeks after this release using the Pro Preview. @@ -53,9 +53,12 @@ I received plenty of user feedback and had time to observe the inner workings of - Fix download move operation failing when moving a directory that already existed in the downloads folder - Fix some scrollbars unnecessarily showing - Fix file browser list jumping around on first show +- Fix missing libxtst6 dependency on some debian-based systems +- Fix file browser root session not applying same color of original connection ## Other +- Categories can now be assigned colors - There is now support to view and change users/groups in the file browser - External git vault data files are now also encrypted by default - Rework state information display for proxmox VMs diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/MultiExecuteSelectionAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/MultiExecuteSelectionAction.java index 6a1132293..d688cdff8 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/MultiExecuteSelectionAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/MultiExecuteSelectionAction.java @@ -5,14 +5,17 @@ import io.xpipe.app.browser.action.LeafAction; import io.xpipe.app.browser.file.BrowserEntry; import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.app.core.AppI18n; +import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.util.TerminalLauncher; import io.xpipe.core.process.CommandBuilder; +import io.xpipe.core.process.ProcessOutputException; import io.xpipe.core.process.ShellControl; import javafx.beans.value.ObservableValue; import java.util.List; +import java.util.concurrent.atomic.AtomicReference; public abstract class MultiExecuteSelectionAction implements BranchAction { @@ -63,10 +66,21 @@ public abstract class MultiExecuteSelectionAction implements BranchAction { model.withShell( pc -> { var cmd = createCommand(pc, model, entries); - pc.command(cmd) + AtomicReference out = new AtomicReference<>(); + AtomicReference err = new AtomicReference<>(); + long exitCode; + try (var command = pc.command(cmd) .withWorkingDirectory( - model.getCurrentDirectory().getPath()) - .execute(); + model.getCurrentDirectory().getPath()).start()) { + var r = command.readStdoutAndStderr(); + out.set(r[0]); + err.set(r[1]); + exitCode = command.getExitCode(); + } + // Only throw actual error output + if (exitCode != 0) { + throw ErrorEvent.expected(ProcessOutputException.of(exitCode, out.get(), err.get())); + } }, false); } diff --git a/ext/base/src/main/resources/io/xpipe/ext/base/resources/scripts/diff.sh b/ext/base/src/main/resources/io/xpipe/ext/base/resources/scripts/diff.sh index 57a3f23bb..4f760fba3 100644 --- a/ext/base/src/main/resources/io/xpipe/ext/base/resources/scripts/diff.sh +++ b/ext/base/src/main/resources/io/xpipe/ext/base/resources/scripts/diff.sh @@ -1 +1 @@ -diff "$1" "$2" +diff "$1" "$2" && echo "File contents are identical" diff --git a/lang/app/strings/translations_en.properties b/lang/app/strings/translations_en.properties index ae24c4eb5..cdaceece5 100644 --- a/lang/app/strings/translations_en.properties +++ b/lang/app/strings/translations_en.properties @@ -488,7 +488,7 @@ closeOtherTabs=Close other tabs closeAllTabs=Close all tabs closeLeftTabs=Close tabs to the left closeRightTabs=Close tabs to the right -addSerial=Serial ... +addSerial=Serial (Experimental) ... connect=Connect workspaces=Workspaces manageWorkspaces=Manage workspaces