From eaf8d075faac5d1f488e74c47ec6e2ecc578cd9f Mon Sep 17 00:00:00 2001 From: crschnick Date: Wed, 13 Nov 2024 15:00:49 +0000 Subject: [PATCH] Various fixes --- .../app/browser/BrowserSessionTabsComp.java | 24 ++++++++++++------- .../xpipe/app/core/window/ModifiedStage.java | 2 +- .../java/io/xpipe/app/ext/ShellSession.java | 2 +- .../xpipe/app/issue/TerminalErrorHandler.java | 2 +- .../xpipe/app/prefs/WorkspacesCategory.java | 3 ++- .../xpipe/app/terminal/TerminalDockModel.java | 1 - .../io/xpipe/app/update/GitHubUpdater.java | 6 +++-- .../io/xpipe/app/update/PortableUpdater.java | 3 ++- .../app/update/UpdateAvailableAlert.java | 2 +- .../io/xpipe/app/update/UpdateHandler.java | 7 ++++-- .../java/io/xpipe/app/util/FileOpener.java | 8 ++++++- .../java/io/xpipe/app/util/Hyperlinks.java | 12 ++++------ .../io/xpipe/app/util/LicensedFeature.java | 10 +++----- .../io/xpipe/app/util/OptionsBuilder.java | 2 +- .../xpipe/app/resources/style/dialog-comp.css | 2 +- .../io/xpipe/app/resources/style/prefs.css | 2 +- .../io/xpipe/app/resources/theme/mocha.css | 2 +- dist/changelogs/13.0.md | 21 ++++++++-------- 18 files changed, 62 insertions(+), 49 deletions(-) diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserSessionTabsComp.java b/app/src/main/java/io/xpipe/app/browser/BrowserSessionTabsComp.java index 97864dd3c..ea33c8ec1 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserSessionTabsComp.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserSessionTabsComp.java @@ -263,26 +263,32 @@ public class BrowserSessionTabsComp extends SimpleComp { var cm = ContextMenuHelper.create(); if (tabModel.isCloseable()) { - var unsplit = ContextMenuHelper.item(LabelGraphic.none(), AppI18n.get("unpinTab")); - unsplit.visibleProperty() + var unpin = ContextMenuHelper.item(LabelGraphic.none(), AppI18n.get("unpinTab")); + unpin.visibleProperty() .bind(PlatformThread.sync(Bindings.createBooleanBinding( () -> { return model.getGlobalPinnedTab().getValue() != null && model.getGlobalPinnedTab().getValue().equals(tabModel); }, model.getGlobalPinnedTab()))); - unsplit.setOnAction(event -> { + unpin.setOnAction(event -> { model.unpinTab(tabModel); event.consume(); }); - cm.getItems().add(unsplit); + cm.getItems().add(unpin); - var split = ContextMenuHelper.item(LabelGraphic.none(), AppI18n.get("pinTab")); - split.setOnAction(event -> { + var pin = ContextMenuHelper.item(LabelGraphic.none(), AppI18n.get("pinTab")); + pin.visibleProperty() + .bind(PlatformThread.sync(Bindings.createBooleanBinding( + () -> { + return model.getGlobalPinnedTab().getValue() == null; + }, + model.getGlobalPinnedTab()))); + pin.setOnAction(event -> { model.pinTab(tabModel); event.consume(); }); - cm.getItems().add(split); + cm.getItems().add(pin); } var select = ContextMenuHelper.item(LabelGraphic.none(), AppI18n.get("selectTab")); @@ -364,7 +370,9 @@ public class BrowserSessionTabsComp extends SimpleComp { private Tab createTab(TabPane tabs, BrowserSessionTab tabModel) { var tab = new Tab(); - tab.setContextMenu(createContextMenu(tabs, tab, tabModel)); + if (tabModel.isCloseable()) { + tab.setContextMenu(createContextMenu(tabs, tab, tabModel)); + } tab.setClosable(tabModel.isCloseable()); // Prevent closing while busy diff --git a/app/src/main/java/io/xpipe/app/core/window/ModifiedStage.java b/app/src/main/java/io/xpipe/app/core/window/ModifiedStage.java index 0224b1641..0c55e177b 100644 --- a/app/src/main/java/io/xpipe/app/core/window/ModifiedStage.java +++ b/app/src/main/java/io/xpipe/app/core/window/ModifiedStage.java @@ -88,7 +88,7 @@ public class ModifiedStage extends Stage { NativeWinWindowControl.DmwaWindowAttribute.DWMWA_USE_IMMERSIVE_DARK_MODE.get(), AppPrefs.get().theme.getValue().isDark()); boolean seamlessFrame; - if (AppPrefs.get().performanceMode().get() || !mergeFrame()) { + if (AppPrefs.get().performanceMode().get() || !mergeFrame() || AppMainWindow.getInstance() == null || stage != AppMainWindow.getInstance().getStage()) { seamlessFrame = false; } else { seamlessFrame = ctrl.setWindowBackdrop(NativeWinWindowControl.DwmSystemBackDropType.MICA_ALT); diff --git a/app/src/main/java/io/xpipe/app/ext/ShellSession.java b/app/src/main/java/io/xpipe/app/ext/ShellSession.java index 1ff3a7693..806c14ead 100644 --- a/app/src/main/java/io/xpipe/app/ext/ShellSession.java +++ b/app/src/main/java/io/xpipe/app/ext/ShellSession.java @@ -60,6 +60,6 @@ public class ShellSession extends Session { } public void stop() throws Exception { - shellControl.close(); + shellControl.shutdown(); } } diff --git a/app/src/main/java/io/xpipe/app/issue/TerminalErrorHandler.java b/app/src/main/java/io/xpipe/app/issue/TerminalErrorHandler.java index 7fb882e31..7aa953894 100644 --- a/app/src/main/java/io/xpipe/app/issue/TerminalErrorHandler.java +++ b/app/src/main/java/io/xpipe/app/issue/TerminalErrorHandler.java @@ -77,7 +77,7 @@ public class TerminalErrorHandler extends GuiErrorHandlerBase implements ErrorHa var rel = XPipeDistributionType.get() .getUpdateHandler() .refreshUpdateCheck( - false, !AppPrefs.get().automaticallyUpdate().get()); + false, false); if (rel != null && rel.isUpdate()) { var update = AppWindowHelper.showBlockingAlert(alert -> { alert.setAlertType(Alert.AlertType.INFORMATION); diff --git a/app/src/main/java/io/xpipe/app/prefs/WorkspacesCategory.java b/app/src/main/java/io/xpipe/app/prefs/WorkspacesCategory.java index c064ba3b6..f675d7a85 100644 --- a/app/src/main/java/io/xpipe/app/prefs/WorkspacesCategory.java +++ b/app/src/main/java/io/xpipe/app/prefs/WorkspacesCategory.java @@ -16,9 +16,10 @@ public class WorkspacesCategory extends AppPrefsCategory { @Override protected Comp create() { return new OptionsBuilder() - .addTitle(LicenseProvider.get().getFeature("workspaces").suffixObservable("manageWorkspaces")) + .addTitle("manageWorkspaces") .sub(new OptionsBuilder() .nameAndDescription("workspaceAdd") + .licenseRequirement("workspaces") .addComp(new ButtonComp(AppI18n.observable("addWorkspace"), WorkspaceCreationAlert::showAsync))) .disable(!LicenseProvider.get().getFeature("workspaces").isSupported()) .buildComp(); diff --git a/app/src/main/java/io/xpipe/app/terminal/TerminalDockModel.java b/app/src/main/java/io/xpipe/app/terminal/TerminalDockModel.java index ac744e303..6562b09e7 100644 --- a/app/src/main/java/io/xpipe/app/terminal/TerminalDockModel.java +++ b/app/src/main/java/io/xpipe/app/terminal/TerminalDockModel.java @@ -154,7 +154,6 @@ public class TerminalDockModel { } this.viewBounds = new Rect(x, y, w, h); - TrackEvent.withTrace("Terminal view resized").tag("rect", viewBounds).handle(); updatePositions(); } diff --git a/app/src/main/java/io/xpipe/app/update/GitHubUpdater.java b/app/src/main/java/io/xpipe/app/update/GitHubUpdater.java index e4966f352..3f1558fa9 100644 --- a/app/src/main/java/io/xpipe/app/update/GitHubUpdater.java +++ b/app/src/main/java/io/xpipe/app/update/GitHubUpdater.java @@ -41,7 +41,8 @@ public class GitHubUpdater extends UpdateHandler { lastUpdateCheckResult.getValue().getReleaseUrl(), downloadFile.get(), changelog, - lastUpdateCheckResult.getValue().getAssetType()); + lastUpdateCheckResult.getValue().getAssetType(), + lastUpdateCheckResult.getValue().isSecurityOnly()); preparedUpdate.setValue(rel); } @@ -93,7 +94,8 @@ public class GitHubUpdater extends UpdateHandler { ghAsset.get().getBrowserDownloadUrl(), assetType, Instant.now(), - isUpdate)); + isUpdate, + securityOnly)); return lastUpdateCheckResult.getValue(); } } diff --git a/app/src/main/java/io/xpipe/app/update/PortableUpdater.java b/app/src/main/java/io/xpipe/app/update/PortableUpdater.java index 60a853427..5837004d2 100644 --- a/app/src/main/java/io/xpipe/app/update/PortableUpdater.java +++ b/app/src/main/java/io/xpipe/app/update/PortableUpdater.java @@ -48,7 +48,8 @@ public class PortableUpdater extends UpdateHandler { null, null, Instant.now(), - isUpdate)); + isUpdate, + securityOnly)); return lastUpdateCheckResult.getValue(); } } diff --git a/app/src/main/java/io/xpipe/app/update/UpdateAvailableAlert.java b/app/src/main/java/io/xpipe/app/update/UpdateAvailableAlert.java index f0d6fd393..99e178e0e 100644 --- a/app/src/main/java/io/xpipe/app/update/UpdateAvailableAlert.java +++ b/app/src/main/java/io/xpipe/app/update/UpdateAvailableAlert.java @@ -23,7 +23,7 @@ public class UpdateAvailableAlert { } // Check whether we still have the latest version prepared - uh.refreshUpdateCheckSilent(false, !AppPrefs.get().automaticallyUpdate().get()); + uh.refreshUpdateCheckSilent(false, uh.getPreparedUpdate().getValue().isSecurityOnly()); if (uh.getPreparedUpdate().getValue() == null) { return; } diff --git a/app/src/main/java/io/xpipe/app/update/UpdateHandler.java b/app/src/main/java/io/xpipe/app/update/UpdateHandler.java index e079bfee0..da703f4a9 100644 --- a/app/src/main/java/io/xpipe/app/update/UpdateHandler.java +++ b/app/src/main/java/io/xpipe/app/update/UpdateHandler.java @@ -191,7 +191,8 @@ public abstract class UpdateHandler { lastUpdateCheckResult.getValue().getReleaseUrl(), null, changelog, - lastUpdateCheckResult.getValue().getAssetType()); + lastUpdateCheckResult.getValue().getAssetType(), + lastUpdateCheckResult.getValue().isSecurityOnly()); preparedUpdate.setValue(rel); } @@ -214,7 +215,7 @@ public abstract class UpdateHandler { var available = XPipeDistributionType.get() .getUpdateHandler() .refreshUpdateCheckSilent( - false, !AppPrefs.get().automaticallyUpdate().get()); + false, preparedUpdate.getValue().isSecurityOnly()); if (preparedUpdate.getValue() == null) { return; } @@ -267,6 +268,7 @@ public abstract class UpdateHandler { AppInstaller.InstallerAssetType assetType; Instant checkTime; boolean isUpdate; + boolean securityOnly; } @Value @@ -280,5 +282,6 @@ public abstract class UpdateHandler { Path file; String body; AppInstaller.InstallerAssetType assetType; + boolean securityOnly; } } 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 d68d2c3ae..71785e231 100644 --- a/app/src/main/java/io/xpipe/app/util/FileOpener.java +++ b/app/src/main/java/io/xpipe/app/util/FileOpener.java @@ -4,6 +4,8 @@ import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.core.process.CommandBuilder; import io.xpipe.core.process.OsType; +import io.xpipe.core.process.ShellDialect; +import io.xpipe.core.process.ShellDialects; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -56,7 +58,11 @@ public class FileOpener { public static void openInDefaultApplication(String localFile) { try (var pc = LocalShell.getShell().start()) { if (pc.getOsType().equals(OsType.WINDOWS)) { - pc.executeSimpleCommand("start \"\" \"" + localFile + "\""); + if (pc.getShellDialect() == ShellDialects.POWERSHELL) { + pc.command(CommandBuilder.of().add("Invoke-Item").addFile(localFile)).execute(); + } else { + pc.executeSimpleCommand("start \"\" \"" + localFile + "\""); + } } else if (pc.getOsType().equals(OsType.LINUX)) { pc.executeSimpleCommand("xdg-open \"" + localFile + "\""); } else { diff --git a/app/src/main/java/io/xpipe/app/util/Hyperlinks.java b/app/src/main/java/io/xpipe/app/util/Hyperlinks.java index d590511f2..0db1996d1 100644 --- a/app/src/main/java/io/xpipe/app/util/Hyperlinks.java +++ b/app/src/main/java/io/xpipe/app/util/Hyperlinks.java @@ -6,19 +6,17 @@ public class Hyperlinks { public static final String DOUBLE_PROMPT = "https://docs.xpipe.io/two-step-connections"; public static final String AGENT_SETUP = "https://docs.xpipe.io/ssh-agent-socket"; - public static final String GITHUB = "https://github.com/xpipe-io/xpipe"; - public static final String GITHUB_PTB = "https://github.com/xpipe-io/xpipe-ptb"; + public static final String GITHUB = "https://github.com/xpipe-io/xpipe?ref=xpipe.app"; + public static final String GITHUB_PTB = "https://github.com/xpipe-io/xpipe-ptb?ref=xpipe.app"; public static final String PRIVACY = "https://docs.xpipe.io/privacy-policy"; public static final String EULA = "https://docs.xpipe.io/end-user-license-agreement"; public static final String SECURITY = "https://docs.xpipe.io/security"; - public static final String TRANSLATE = "https://github.com/xpipe-io/xpipe/tree/master/lang"; + public static final String TRANSLATE = "https://github.com/xpipe-io/xpipe/tree/master/lang?ref=xpipe.app"; public static final String DISCORD = "https://discord.gg/8y89vS8cRb"; - public static final String GITHUB_WEBTOP = "https://github.com/xpipe-io/xpipe-webtop"; - public static final String SELFHST_ICONS = "https://github.com/selfhst/icons"; + public static final String GITHUB_WEBTOP = "https://github.com/xpipe-io/xpipe-webtop?ref=xpipe.app"; + public static final String SELFHST_ICONS = "https://github.com/selfhst/icons?ref=xpipe.app"; public static final String SLACK = "https://join.slack.com/t/XPipe/shared_invite/zt-1awjq0t5j-5i4UjNJfNe1VN4b_auu6Cg"; - public static final String PRODUCT_HUNT = - "https://www.producthunt.com/posts/xpipe?embed=true&utm_source=badge-featured&utm_medium=badge&utm_souce=badge-xpipe"; static final String[] browsers = { "xdg-open", "google-chrome", "firefox", "opera", "konqueror", "mozilla", "gnome-open", "open" diff --git a/app/src/main/java/io/xpipe/app/util/LicensedFeature.java b/app/src/main/java/io/xpipe/app/util/LicensedFeature.java index 71c0f73d8..8641934c9 100644 --- a/app/src/main/java/io/xpipe/app/util/LicensedFeature.java +++ b/app/src/main/java/io/xpipe/app/util/LicensedFeature.java @@ -2,6 +2,7 @@ package io.xpipe.app.util; import io.xpipe.app.core.AppI18n; +import javafx.beans.binding.Bindings; import javafx.beans.value.ObservableValue; import java.util.Optional; @@ -10,15 +11,10 @@ public interface LicensedFeature { Optional getDescriptionSuffix(); - public default ObservableValue suffixObservable(ObservableValue s) { - return s.map(s2 -> - getDescriptionSuffix().map(suffix -> s2 + " (" + suffix + "+)").orElse(s2)); - } + ObservableValue suffixObservable(ObservableValue s); public default ObservableValue suffixObservable(String key) { - return AppI18n.observable(key).map(s -> getDescriptionSuffix() - .map(suffix -> s + " (" + suffix + "+)") - .orElse(s)); + return suffixObservable(AppI18n.observable(key)); } public default String suffix(String s) { diff --git a/app/src/main/java/io/xpipe/app/util/OptionsBuilder.java b/app/src/main/java/io/xpipe/app/util/OptionsBuilder.java index 59d6974a6..b8a7e03e8 100644 --- a/app/src/main/java/io/xpipe/app/util/OptionsBuilder.java +++ b/app/src/main/java/io/xpipe/app/util/OptionsBuilder.java @@ -143,7 +143,7 @@ public class OptionsBuilder { null, null, null, - Comp.of(() -> new Label(title.getValue())).styleClass("title-header"))); + new LabelComp(title).styleClass("title-header"))); return this; } diff --git a/app/src/main/resources/io/xpipe/app/resources/style/dialog-comp.css b/app/src/main/resources/io/xpipe/app/resources/style/dialog-comp.css index 8701d665a..323ce4ef9 100644 --- a/app/src/main/resources/io/xpipe/app/resources/style/dialog-comp.css +++ b/app/src/main/resources/io/xpipe/app/resources/style/dialog-comp.css @@ -16,6 +16,6 @@ .dialog-comp .buttons { -fx-padding: 10; -fx-border-color: -color-border-default; - -fx-background-color: -color-bg-inset; + -fx-background-color: -color-bg-overlay; -fx-border-width: 1 0 0 0; } diff --git a/app/src/main/resources/io/xpipe/app/resources/style/prefs.css b/app/src/main/resources/io/xpipe/app/resources/style/prefs.css index 49660fb4a..ce1f03625 100644 --- a/app/src/main/resources/io/xpipe/app/resources/style/prefs.css +++ b/app/src/main/resources/io/xpipe/app/resources/style/prefs.css @@ -14,7 +14,7 @@ } .prefs-container > .title-header { - -fx-padding: 2em 0 -1em 0; + -fx-padding: 4em 0 -1em 0; -fx-font-weight: BOLD; -fx-font-size: 1.5em; } diff --git a/app/src/main/resources/io/xpipe/app/resources/theme/mocha.css b/app/src/main/resources/io/xpipe/app/resources/theme/mocha.css index 4587c84b1..11226241a 100644 --- a/app/src/main/resources/io/xpipe/app/resources/theme/mocha.css +++ b/app/src/main/resources/io/xpipe/app/resources/theme/mocha.css @@ -112,7 +112,7 @@ -fx-font-size: 14px; } -.root { -color-bg-default-transparent: #0d1117d2; } +.root { -color-bg-default-transparent: #10141ad2; } .root .table-view { -color-cell-bg-odd: derive(-color-bg-subtle, -35%); diff --git a/dist/changelogs/13.0.md b/dist/changelogs/13.0.md index 53d744a31..a9a6b9aa5 100644 --- a/dist/changelogs/13.0.md +++ b/dist/changelogs/13.0.md @@ -1,9 +1,8 @@ ## VMs -- There is now support for KVM/QEMU virtual machines that can be accessed via the libvirt CLI tools `virsh`. This includes support for other driver URLs as well aside from KVM and QEMU. -- You can now override a VM IP if you're using an advanced networking setup where the default IP detection is not suitable. +- There is now support for KVM/QEMU virtual machines that can be accessed via the libvirt CLI tools `virsh`. This includes support for other driver URLs as well aside from KVM and QEMU. This integration is available starting from the homelab plan +- You can now override a VM IP if you're using an advanced networking setup where the default IP detection is not suitable - Fix remote VM SSH connections not being able to use the keys and identities from the local system -- VM states are now properly updated and shown - There is now a new restart button for containers and VMs ## File browser @@ -13,18 +12,18 @@ - The previous system history tab is now always shown - You can now change the default download location for the move to downloads button -## Terminal tacking +## Shell sessions + +Many improvements have been implemented for reusability of shell sessions running in the background. Whenever you access a system or a parent system, XPipe will connect to it just as before but keep this session open in the background for some time, under the assumption that you will typically perform multiple actions shortly afterward. This will improve the speed of many actions and also results in less authentication prompts when you are using something like 2FA. + +## Terminals - Closing a terminal tab/window while the session is loading will now cancel the loading process in XPipe as well - A newly opened terminal will now regain focus after any password prompt was entered in xpipe -## Shell session caching - -There were made improvements for reusability of shell sessions running in the background. Whenever you access a system or a parent system, XPipe will connect to it just as before but keep this session open in the background for some time, under the assumption that users will typically perform multiple actions afterward. This will improve the speed of many actions and also results in less authentication prompts when you are using something like 2FA. - ## Security updates -There's now a new mechanism in place for checking for security updates separately from the normal update check. This is important going forward, to be able to act quickly when any security patch is published, so that all users have the possibility to get notified even if they don't follow announcements on the GitHub repo or on Discord. You can also disable this functionality if you want. +There's now a new mechanism in place for checking for security updates separately from the normal update check. This is important going forward, to be able to act quickly when any security patch is published, so that all users have the possibility to get notified even if they don't follow announcements on the GitHub repo or on Discord. You can also disable this functionality in the settings if you want. ## Other @@ -36,12 +35,12 @@ There's now a new mechanism in place for checking for security updates separatel ## Fixes +- Fix Proxmox detection not working when not logging in as root - Fix tunnels not closing properly when having to be closed forcefully - Fix vmware integration failing when files other than .vmx were in the VM directories - Fix Tabby not launching properly on Windows - Fix SSH and docker issues with home assistant systems -- Fix Proxmox detection not working when not logging in as root -- Fix system dark mode changes not being applied if they were changed while XPipe was not running - Fix git readme not showing connections in nested children categories - Fix style issues with the mocha theme - Fix color contrast for some themes +- Fix system dark mode changes not being applied if they were changed while XPipe was not running