From 8358eec1590b2007a4ad7c6df76635ae4dc6de77 Mon Sep 17 00:00:00 2001 From: crschnick Date: Mon, 18 Nov 2024 16:00:44 +0000 Subject: [PATCH] Fixes --- .../app/browser/BrowserFullSessionModel.java | 23 ++++++- .../file/BrowserFileSystemTabComp.java | 30 +++++++-- .../file/BrowserFileSystemTabModel.java | 3 +- .../xpipe/app/comp/store/StoreEntryComp.java | 2 + .../app/comp/store/StoreEntryWrapper.java | 2 +- .../java/io/xpipe/app/core/AppProperties.java | 4 ++ .../app/core/check/AppUserDirectoryCheck.java | 5 +- .../io/xpipe/app/core/mode/OperationMode.java | 1 - .../java/io/xpipe/app/prefs/AppPrefs.java | 62 +++++++----------- .../xpipe/app/prefs/FileBrowserCategory.java | 5 +- .../xpipe/app/util/HumanReadableFormat.java | 9 ++- .../xpipe/core/store/NetworkTunnelStore.java | 4 +- dist/changelogs/13.1.md | 47 ++++++++++++++ dist/changelogs/13.1_incremental.md | 5 ++ .../ext/base/browser/DownloadAction.java | 64 +++++++++++++++++++ .../service/CustomServiceStoreProvider.java | 2 +- ext/base/src/main/java/module-info.java | 1 + lang/app/strings/translations_da.properties | 2 + lang/app/strings/translations_de.properties | 2 + lang/app/strings/translations_en.properties | 4 +- lang/app/strings/translations_es.properties | 2 + lang/app/strings/translations_fr.properties | 2 + lang/app/strings/translations_it.properties | 2 + lang/app/strings/translations_ja.properties | 2 + lang/app/strings/translations_nl.properties | 2 + lang/app/strings/translations_pt.properties | 2 + lang/app/strings/translations_ru.properties | 2 + lang/app/strings/translations_tr.properties | 2 + lang/app/strings/translations_zh.properties | 2 + lang/base/strings/translations_da.properties | 1 + lang/base/strings/translations_de.properties | 1 + lang/base/strings/translations_en.properties | 1 + lang/base/strings/translations_es.properties | 1 + lang/base/strings/translations_fr.properties | 1 + lang/base/strings/translations_it.properties | 1 + lang/base/strings/translations_ja.properties | 1 + lang/base/strings/translations_nl.properties | 1 + lang/base/strings/translations_pt.properties | 1 + lang/base/strings/translations_ru.properties | 1 + lang/base/strings/translations_tr.properties | 1 + lang/base/strings/translations_zh.properties | 1 + version | 2 +- 42 files changed, 249 insertions(+), 60 deletions(-) create mode 100644 dist/changelogs/13.1.md create mode 100644 dist/changelogs/13.1_incremental.md create mode 100644 ext/base/src/main/java/io/xpipe/ext/base/browser/DownloadAction.java diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserFullSessionModel.java b/app/src/main/java/io/xpipe/app/browser/BrowserFullSessionModel.java index 5df06abad..a053d2b31 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserFullSessionModel.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserFullSessionModel.java @@ -5,6 +5,7 @@ import io.xpipe.app.browser.file.BrowserHistorySavedState; import io.xpipe.app.browser.file.BrowserHistorySavedStateImpl; import io.xpipe.app.browser.file.BrowserHistoryTabModel; import io.xpipe.app.browser.file.BrowserTransferModel; +import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStoreEntryRef; import io.xpipe.app.util.BooleanScope; @@ -34,6 +35,13 @@ public class BrowserFullSessionModel extends BrowserAbstractSessionModel { + DEFAULT.openSync(tab,null); + DEFAULT.pinTab(tab); + }); + } } private final BrowserTransferModel localTransfersStage = new BrowserTransferModel(this); @@ -41,6 +49,7 @@ public class BrowserFullSessionModel extends BrowserAbstractSessionModel globalPinnedTab = new SimpleObjectProperty<>(); private final ObservableMap splits = FXCollections.observableHashMap(); private final ObservableValue effectiveRightTab = createEffectiveRightTab(); + private final SequencedSet previousTabs = new LinkedHashSet<>(); private ObservableValue createEffectiveRightTab() { return Bindings.createObjectBinding( @@ -80,6 +89,13 @@ public class BrowserFullSessionModel extends BrowserAbstractSessionModel !c.getList().contains(browserSessionTab)); }); + + selectedEntry.addListener((observable, oldValue, newValue) -> { + if (newValue != null) { + previousTabs.remove(newValue); + previousTabs.add(newValue); + } + }); } public Set getAllTabs() { @@ -118,9 +134,10 @@ public class BrowserFullSessionModel extends BrowserAbstractSessionModel browserSessionTab != tab).toList(); + var prev = previousOthers.getLast(); + if (prev != null) { + getSelectedEntry().setValue(prev); } } diff --git a/app/src/main/java/io/xpipe/app/browser/file/BrowserFileSystemTabComp.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileSystemTabComp.java index d603faa4e..427efbddb 100644 --- a/app/src/main/java/io/xpipe/app/browser/file/BrowserFileSystemTabComp.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileSystemTabComp.java @@ -1,17 +1,17 @@ package io.xpipe.app.browser.file; +import io.xpipe.app.browser.BrowserFullSessionModel; import io.xpipe.app.browser.action.BrowserAction; import io.xpipe.app.comp.Comp; import io.xpipe.app.comp.SimpleComp; import io.xpipe.app.comp.SimpleCompStructure; import io.xpipe.app.comp.augment.ContextMenuAugment; -import io.xpipe.app.comp.base.ModalOverlayComp; -import io.xpipe.app.comp.base.MultiContentComp; -import io.xpipe.app.comp.base.TooltipAugment; -import io.xpipe.app.comp.base.VerticalComp; +import io.xpipe.app.comp.base.*; import io.xpipe.app.core.AppFont; import io.xpipe.app.util.InputHelper; +import io.xpipe.app.util.PlatformThread; +import javafx.beans.binding.Bindings; import javafx.geometry.Pos; import javafx.scene.control.Button; import javafx.scene.control.MenuButton; @@ -96,6 +96,28 @@ public class BrowserFileSystemTabComp extends SimpleComp { refreshBtn, terminalBtn, menuButton); + + if (model.getBrowserModel() instanceof BrowserFullSessionModel fullSessionModel) { + var pinButton = new Button(); + pinButton.graphicProperty().bind(PlatformThread.sync(Bindings.createObjectBinding(() -> { + if (fullSessionModel.getGlobalPinnedTab().getValue() != model) { + return new FontIcon("mdi2p-pin"); + } + + return new FontIcon("mdi2p-pin-off"); + }, fullSessionModel.getGlobalPinnedTab()))); + pinButton.setOnAction(e -> { + if (fullSessionModel.getGlobalPinnedTab().getValue() != model) { + fullSessionModel.pinTab(model); + } else { + fullSessionModel.unpinTab(model); + } + e.consume(); + }); + topBar.getChildren().add(7, pinButton); + squaredSize(navBar.get(), pinButton, true); + } + squaredSize(navBar.get(), overview, true); squaredSize(navBar.get(), backBtn, true); squaredSize(navBar.get(), forthBtn, true); diff --git a/app/src/main/java/io/xpipe/app/browser/file/BrowserFileSystemTabModel.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileSystemTabModel.java index 864f3a8de..75aa2d88b 100644 --- a/app/src/main/java/io/xpipe/app/browser/file/BrowserFileSystemTabModel.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileSystemTabModel.java @@ -113,7 +113,8 @@ public final class BrowserFileSystemTabModel extends BrowserStoreSessionTab { return !getWrapper().getDeletable().get() + && AppPrefs.get().developerMode().getValue() && !AppPrefs.get() .developerDisableGuiRestrictions() .get(); }, getWrapper().getDeletable(), + AppPrefs.get().developerMode(), AppPrefs.get().developerDisableGuiRestrictions())); del.setOnAction(event -> getWrapper().delete()); contextMenu.getItems().add(del); diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryWrapper.java b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryWrapper.java index 6e2fae963..edd24f9c1 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryWrapper.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryWrapper.java @@ -157,7 +157,7 @@ public class StoreEntryWrapper { busy.setValue(entry.getBusyCounter().get() != 0); deletable.setValue(entry.getConfiguration().isDeletable() - || AppPrefs.get().developerDisableGuiRestrictions().getValue()); + || (AppPrefs.get().developerMode().getValue() && AppPrefs.get().developerDisableGuiRestrictions().getValue())); sessionActive.setValue(entry.getStore() instanceof SingletonSessionStore ss && entry.getStore() instanceof ShellStore && ss.isSessionRunning()); diff --git a/app/src/main/java/io/xpipe/app/core/AppProperties.java b/app/src/main/java/io/xpipe/app/core/AppProperties.java index bb1e94d17..df0185083 100644 --- a/app/src/main/java/io/xpipe/app/core/AppProperties.java +++ b/app/src/main/java/io/xpipe/app/core/AppProperties.java @@ -1,5 +1,6 @@ package io.xpipe.app.core; +import io.xpipe.app.core.check.AppUserDirectoryCheck; import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.issue.TrackEvent; import io.xpipe.app.prefs.AppPrefs; @@ -121,6 +122,9 @@ public class AppProperties { autoAcceptEula = Optional.ofNullable(System.getProperty("io.xpipe.app.acceptEula")) .map(Boolean::parseBoolean) .orElse(false); + + // We require the user dir from here + AppUserDirectoryCheck.check(dataDir); AppCache.setBasePath(dataDir.resolve("cache")); UUID id = AppCache.getNonNull("uuid", UUID.class, null); if (id == null) { diff --git a/app/src/main/java/io/xpipe/app/core/check/AppUserDirectoryCheck.java b/app/src/main/java/io/xpipe/app/core/check/AppUserDirectoryCheck.java index 238e80f4b..45ea7e44d 100644 --- a/app/src/main/java/io/xpipe/app/core/check/AppUserDirectoryCheck.java +++ b/app/src/main/java/io/xpipe/app/core/check/AppUserDirectoryCheck.java @@ -7,12 +7,11 @@ import org.apache.commons.io.FileUtils; import java.io.IOException; import java.nio.file.Files; +import java.nio.file.Path; public class AppUserDirectoryCheck { - public static void check() { - var dataDirectory = AppProperties.get().getDataDir(); - + public static void check(Path dataDirectory) { try { FileUtils.forceMkdir(dataDirectory.toFile()); var testDirectory = dataDirectory.resolve("permissions_check"); diff --git a/app/src/main/java/io/xpipe/app/core/mode/OperationMode.java b/app/src/main/java/io/xpipe/app/core/mode/OperationMode.java index 60743e6a4..7d9dc6eb7 100644 --- a/app/src/main/java/io/xpipe/app/core/mode/OperationMode.java +++ b/app/src/main/java/io/xpipe/app/core/mode/OperationMode.java @@ -115,7 +115,6 @@ public abstract class OperationMode { TrackEvent.info("Initial setup"); AppProperties.init(); - AppUserDirectoryCheck.check(); AppTempCheck.check(); AppLogs.init(); AppDebugModeCheck.printIfNeeded(); diff --git a/app/src/main/java/io/xpipe/app/prefs/AppPrefs.java b/app/src/main/java/io/xpipe/app/prefs/AppPrefs.java index c2653ea71..3b489c4cc 100644 --- a/app/src/main/java/io/xpipe/app/prefs/AppPrefs.java +++ b/app/src/main/java/io/xpipe/app/prefs/AppPrefs.java @@ -43,6 +43,13 @@ public class AppPrefs { @Getter private final BooleanProperty requiresRestart = new SimpleBooleanProperty(false); + final BooleanProperty pinLocalMachineOnStartup = + map(Mapping.builder() + .property(new SimpleBooleanProperty(false)) + .key("pinLocalMachineOnStartup") + .valueClass(Boolean.class) + .requiresRestart(true) + .build()); final BooleanProperty dontAllowTerminalRestart = mapVaultShared(new SimpleBooleanProperty(false), "dontAllowTerminalRestart", Boolean.class, false); final BooleanProperty enableHttpApi = @@ -133,12 +140,8 @@ public class AppPrefs { mapLocal(new SimpleBooleanProperty(false), "developerMode", Boolean.class, true); final BooleanProperty developerDisableUpdateVersionCheck = mapLocal(new SimpleBooleanProperty(false), "developerDisableUpdateVersionCheck", Boolean.class, false); - private final ObservableBooleanValue developerDisableUpdateVersionCheckEffective = - bindDeveloperTrue(developerDisableUpdateVersionCheck); final BooleanProperty developerDisableGuiRestrictions = mapLocal(new SimpleBooleanProperty(false), "developerDisableGuiRestrictions", Boolean.class, false); - private final ObservableBooleanValue developerDisableGuiRestrictionsEffective = - bindDeveloperTrue(developerDisableGuiRestrictions); final BooleanProperty developerForceSshTty = mapLocal(new SimpleBooleanProperty(false), "developerForceSshTty", Boolean.class, false); @@ -195,6 +198,10 @@ public class AppPrefs { return dontAllowTerminalRestart; } + public ObservableBooleanValue pinLocalMachineOnStartup() { + return pinLocalMachineOnStartup; + } + private final IntegerProperty editorReloadTimeout = mapLocal(new SimpleIntegerProperty(1000), "editorReloadTimeout", Integer.class, false); private final BooleanProperty confirmDeletions = @@ -276,24 +283,6 @@ public class AppPrefs { return developerMode().getValue() && !ModuleHelper.isImage(); } - private ObservableBooleanValue bindDeveloperTrue(ObservableBooleanValue o) { - return Bindings.createBooleanBinding( - () -> { - return developerMode().getValue() && o.get(); - }, - o, - developerMode()); - } - - private ObservableBooleanValue bindDeveloperFalse(ObservableBooleanValue o) { - return Bindings.createBooleanBinding( - () -> { - return !developerMode().getValue() && o.get(); - }, - o, - developerMode()); - } - public ObservableValue externalPasswordManager() { return passwordManager; } @@ -488,33 +477,35 @@ public class AppPrefs { } public ObservableBooleanValue developerDisableUpdateVersionCheck() { - return developerDisableUpdateVersionCheckEffective; + return developerDisableUpdateVersionCheck; } public ObservableBooleanValue developerDisableGuiRestrictions() { - return developerDisableGuiRestrictionsEffective; + return developerDisableGuiRestrictions; } public ObservableBooleanValue developerForceSshTty() { - return bindDeveloperTrue(developerForceSshTty); + return developerForceSshTty; } @SuppressWarnings("unchecked") private T map(Mapping m) { mapping.add(m); + m.property.addListener((observable, oldValue, newValue) -> { + var running = OperationMode.get() == OperationMode.GUI; + if (running && m.requiresRestart) { + AppPrefs.get().requiresRestart.set(true); + } + }); return (T) m.getProperty(); } - @SuppressWarnings("unchecked") private T mapLocal(Property o, String name, Class clazz, boolean requiresRestart) { - mapping.add(new Mapping(name, o, clazz, false, requiresRestart)); - return (T) o; + return map(new Mapping(name, o, clazz, false, requiresRestart)); } - @SuppressWarnings("unchecked") - private T mapVaultShared(T o, String name, Class clazz, boolean requiresRestart) { - mapping.add(new Mapping(name, (Property) o, (Class) clazz, true, requiresRestart)); - return o; + private T mapVaultShared(Property o, String name, Class clazz, boolean requiresRestart) { + return map(new Mapping(name, o, clazz, true, requiresRestart)); } public void setFromExternal(ObservableValue prop, T newValue) { @@ -668,13 +659,6 @@ public class AppPrefs { this.vaultSpecific = vaultSpecific; this.requiresRestart = requiresRestart; this.licenseFeatureId = null; - - this.property.addListener((observable, oldValue, newValue) -> { - var running = OperationMode.get() == OperationMode.GUI; - if (running && requiresRestart) { - AppPrefs.get().requiresRestart.set(true); - } - }); } } diff --git a/app/src/main/java/io/xpipe/app/prefs/FileBrowserCategory.java b/app/src/main/java/io/xpipe/app/prefs/FileBrowserCategory.java index b0a916e3f..9b89c8103 100644 --- a/app/src/main/java/io/xpipe/app/prefs/FileBrowserCategory.java +++ b/app/src/main/java/io/xpipe/app/prefs/FileBrowserCategory.java @@ -21,7 +21,10 @@ public class FileBrowserCategory extends AppPrefsCategory { .pref(prefs.confirmAllDeletions) .addToggle(prefs.confirmAllDeletions) .pref(prefs.downloadsDirectory) - .addString(prefs.downloadsDirectory)) + .addString(prefs.downloadsDirectory) + .pref(prefs.pinLocalMachineOnStartup) + .addToggle(prefs.pinLocalMachineOnStartup) + ) .buildComp(); } } diff --git a/app/src/main/java/io/xpipe/app/util/HumanReadableFormat.java b/app/src/main/java/io/xpipe/app/util/HumanReadableFormat.java index c2be39371..85cdbd41c 100644 --- a/app/src/main/java/io/xpipe/app/util/HumanReadableFormat.java +++ b/app/src/main/java/io/xpipe/app/util/HumanReadableFormat.java @@ -48,8 +48,13 @@ public final class HumanReadableFormat { bytes /= b; ci.next(); } - var f = ci.getIndex() >= 2 ? "%.3f" : "%.0f"; - return String.format(f + " %cB", bytes / (double) b, ci.current()); + + var f = ci.getIndex() >= 2 ? "%.3f" : "%.1f"; + var r = String.format(f + " %cB", bytes / (double) b, ci.current()); + if (r.endsWith(".0")) { + r = r.substring(0, r.length() - 2); + } + return r; } public static String date(LocalDateTime x) { diff --git a/core/src/main/java/io/xpipe/core/store/NetworkTunnelStore.java b/core/src/main/java/io/xpipe/core/store/NetworkTunnelStore.java index 7307143dd..34997f312 100644 --- a/core/src/main/java/io/xpipe/core/store/NetworkTunnelStore.java +++ b/core/src/main/java/io/xpipe/core/store/NetworkTunnelStore.java @@ -42,7 +42,7 @@ public interface NetworkTunnelStore extends DataStore { } } - default boolean isLocallyTunneable() { + default boolean isLocallyTunnelable() { NetworkTunnelStore current = this; while (true) { if (current.getNetworkParent() == null) { @@ -58,7 +58,7 @@ public interface NetworkTunnelStore extends DataStore { } default NetworkTunnelSession sessionChain(int local, int remotePort, String address) throws Exception { - if (!isLocallyTunneable()) { + if (!isLocallyTunnelable()) { throw new IllegalStateException( "Unable to create tunnel chain as one intermediate system does not support tunneling"); } diff --git a/dist/changelogs/13.1.md b/dist/changelogs/13.1.md new file mode 100644 index 000000000..2547c6004 --- /dev/null +++ b/dist/changelogs/13.1.md @@ -0,0 +1,47 @@ +## 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. This integration is available starting from the homelab plan and can be used for free for two weeks after this release using the new release preview +- 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 +- There is now a new restart button for containers and VMs + +## File browser + +- There is now a new option in the context menu of a tab to pin it, allowing for having a split view with two different file systems +- There is now the option to dock terminals in the file browser (this is only available on Windows for now). You can disable this in Settings -> File browser -> Terminal docking if you don't like it +- The previous system history tab is now always shown +- You can now change the default download location for the move to downloads button + +## 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 + +## 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 in the settings if you want. + +## Other + +- The application style has been reworked +- The settings menu now shows a restart button when a setting has been changed that requires a restart to apply +- There is now an intro to scripts to provide some more information before using scripts +- Add ability to enable agent forwarding when using the SSH-Agent for identities +- The .rpm releases are now signed + +## 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 git readme not showing connections in nested children categories +- Fix Windows Terminal Preview and Canary not being recognized +- 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 diff --git a/dist/changelogs/13.1_incremental.md b/dist/changelogs/13.1_incremental.md new file mode 100644 index 000000000..602317c1e --- /dev/null +++ b/dist/changelogs/13.1_incremental.md @@ -0,0 +1,5 @@ +- Add pin tab button to the file browser menu bar to make tab splitting more prominent +- Add file browser setting to automatically start up with local machine tab pinned +- Add download context menu action in file browser as an alternative to dragging files to the download box +- Fix startup check for user directory permissions not working +- Fix various small bugs diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/DownloadAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/DownloadAction.java new file mode 100644 index 000000000..89273a9ec --- /dev/null +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/DownloadAction.java @@ -0,0 +1,64 @@ +package io.xpipe.ext.base.browser; + +import io.xpipe.app.browser.BrowserFullSessionModel; +import io.xpipe.app.browser.action.BrowserLeafAction; +import io.xpipe.app.browser.file.BrowserEntry; +import io.xpipe.app.browser.file.BrowserFileSystemTabModel; +import io.xpipe.app.core.AppI18n; +import io.xpipe.app.prefs.AppPrefs; +import io.xpipe.core.store.FileKind; +import javafx.beans.value.ObservableValue; +import javafx.scene.Node; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyCodeCombination; +import javafx.scene.input.KeyCombination; +import org.kordamp.ikonli.javafx.FontIcon; + +import java.util.Collections; +import java.util.List; + +public class DownloadAction implements BrowserLeafAction { + + @Override + public void execute(BrowserFileSystemTabModel model, List entries) { + var transfer = model.getBrowserModel(); + if (!(transfer instanceof BrowserFullSessionModel fullSessionModel)) { + return; + } + + fullSessionModel.getLocalTransfersStage().drop(model, entries); + } + + public String getId() { + return "download"; + } + + @Override + public Node getIcon(BrowserFileSystemTabModel model, List entries) { + return new FontIcon("mdi2d-download"); + } + + @Override + public Category getCategory() { + return Category.MUTATION; + } + + @Override + public KeyCombination getShortcut() { + return new KeyCodeCombination(KeyCode.D, KeyCombination.SHORTCUT_DOWN); + } + + @Override + public ObservableValue getName(BrowserFileSystemTabModel model, List entries) { + return AppI18n.observable("download"); + } + + @Override + public boolean isApplicable(BrowserFileSystemTabModel model, List entries) { + var transfer = model.getBrowserModel(); + if (!(transfer instanceof BrowserFullSessionModel)) { + return false; + } + return true; + } +} diff --git a/ext/base/src/main/java/io/xpipe/ext/base/service/CustomServiceStoreProvider.java b/ext/base/src/main/java/io/xpipe/ext/base/service/CustomServiceStoreProvider.java index 18cc84e77..f1270b008 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/service/CustomServiceStoreProvider.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/service/CustomServiceStoreProvider.java @@ -39,7 +39,7 @@ public class CustomServiceStoreProvider extends AbstractServiceStoreProvider { StoreChoiceComp.other( host, NetworkTunnelStore.class, - n -> n.getStore().isLocallyTunneable(), + n -> n.getStore().isLocallyTunnelable(), StoreViewState.get().getAllConnectionsCategory()), host) .nonNull() diff --git a/ext/base/src/main/java/module-info.java b/ext/base/src/main/java/module-info.java index 3fe581316..b569f4e81 100644 --- a/ext/base/src/main/java/module-info.java +++ b/ext/base/src/main/java/module-info.java @@ -36,6 +36,7 @@ open module io.xpipe.ext.base { requires atlantafx.base; provides BrowserAction with + DownloadAction, RunScriptAction, FollowLinkAction, BackAction, diff --git a/lang/app/strings/translations_da.properties b/lang/app/strings/translations_da.properties index 8f4851053..064f625db 100644 --- a/lang/app/strings/translations_da.properties +++ b/lang/app/strings/translations_da.properties @@ -554,3 +554,5 @@ enableTerminalDocking=Aktiver terminal-docking enableTerminalDockingDescription=Med terminal-docking kan du docke terminalvinduer til XPipe-applikationsvinduet for at simulere en nogenlunde integreret terminal. Terminalvinduerne styres derefter af XPipe, så de altid passer ind i docken. downloadsDirectory=Brugerdefineret download-mappe downloadsDirectoryDescription=Den brugerdefinerede mappe, som downloadede filer skal placeres i, når man klikker på knappen Flyt til downloads. Som standard vil XPipe bruge din brugers download-bibliotek. +pinLocalMachineOnStartup=Fastgør fane for lokal maskine ved opstart +pinLocalMachineOnStartupDescription=Åbn automatisk en fane på den lokale maskine og fastgør den. Det er nyttigt, hvis du ofte bruger en delt filbrowser med den lokale maskine og fjernfilsystemet åbent. diff --git a/lang/app/strings/translations_de.properties b/lang/app/strings/translations_de.properties index ab502d1e5..495b8bf90 100644 --- a/lang/app/strings/translations_de.properties +++ b/lang/app/strings/translations_de.properties @@ -548,3 +548,5 @@ enableTerminalDocking=St Finn We transmission enableTerminalDockingDescription=Mit Terminal Docking kannst du Terminalfenster an das XPipe-Anwendungsfenster andocken, um ein integriertes Terminal zu simulieren. Κ Finn continues theARotional'93 Veranstə Off extampİ Weṣς downloadsDirectory=Benutzerdefiniertes Download-Verzeichnis downloadsDirectoryDescription=Das benutzerdefinierte Verzeichnis, in das heruntergeladene Dateien verschoben werden sollen, wenn du auf die Schaltfläche In Downloads verschieben klickst. Standardmäßig verwendet XPipe dein Benutzer-Download-Verzeichnis. +pinLocalMachineOnStartup=Registerkarte "Lokaler Rechner" beim Starten anheften +pinLocalMachineOnStartupDescription=Öffne automatisch eine Registerkarte für den lokalen Rechner und pinne sie an. Dies ist nützlich, wenn du häufig einen geteilten Dateibrowser verwendest, bei dem der lokale Rechner und das entfernte Dateisystem geöffnet sind. diff --git a/lang/app/strings/translations_en.properties b/lang/app/strings/translations_en.properties index d39b6a830..8812a20ba 100644 --- a/lang/app/strings/translations_en.properties +++ b/lang/app/strings/translations_en.properties @@ -553,4 +553,6 @@ pinned=Pinned enableTerminalDocking=Enable terminal docking enableTerminalDockingDescription=With terminal docking you can dock terminal windows to the XPipe application window to simulate a somewhat integrated terminal. The terminal windows are then managed by XPipe to always fit into the dock. downloadsDirectory=Custom downloads directory -downloadsDirectoryDescription=The custom directory to put downloaded files into when clicking on the move to downloads button. By default, XPipe will use your user downloads directory. \ No newline at end of file +downloadsDirectoryDescription=The custom directory to put downloaded files into when clicking on the move to downloads button. By default, XPipe will use your user downloads directory. +pinLocalMachineOnStartup=Pin local machine tab on startup +pinLocalMachineOnStartupDescription=Automatically open a local machine tab and pin it. This is useful if you are frequently using a split file browser with the local machine and remote file system open. \ No newline at end of file diff --git a/lang/app/strings/translations_es.properties b/lang/app/strings/translations_es.properties index 437a171b5..7a4aa3ce3 100644 --- a/lang/app/strings/translations_es.properties +++ b/lang/app/strings/translations_es.properties @@ -535,3 +535,5 @@ enableTerminalDocking=Activar el acoplamiento de terminales enableTerminalDockingDescription=Con el acoplamiento de terminales puedes acoplar ventanas de terminal a la ventana de la aplicación XPipe para simular un terminal algo integrado. Las ventanas de terminal son gestionadas por XPipe para que siempre quepan en el acoplamiento. downloadsDirectory=Directorio de descargas personalizado downloadsDirectoryDescription=El directorio personalizado en el que colocar los archivos descargados al pulsar el botón mover a descargas. Por defecto, XPipe utilizará tu directorio de descargas de usuario. +pinLocalMachineOnStartup=Fijar la pestaña de máquina local al iniciar +pinLocalMachineOnStartupDescription=Abre automáticamente una pestaña de la máquina local y fíjala. Esto es útil si utilizas con frecuencia un explorador de archivos dividido con la máquina local y el sistema de archivos remoto abiertos. diff --git a/lang/app/strings/translations_fr.properties b/lang/app/strings/translations_fr.properties index 513fce93f..eb01ea470 100644 --- a/lang/app/strings/translations_fr.properties +++ b/lang/app/strings/translations_fr.properties @@ -535,3 +535,5 @@ enableTerminalDocking=Activer l'ancrage du terminal enableTerminalDockingDescription=Avec l'ancrage de terminal, tu peux ancrer des fenêtres de terminal à la fenêtre de l'application XPipe pour simuler un terminal quelque peu intégré. Les fenêtres du terminal sont alors gérées par XPipe pour toujours tenir dans la station d'accueil. downloadsDirectory=Répertoire de téléchargements personnalisé downloadsDirectoryDescription=Le répertoire personnalisé dans lequel placer les fichiers téléchargés lorsqu'on clique sur le bouton déplacer vers les téléchargements. Par défaut, XPipe utilisera le répertoire des téléchargements de l'utilisateur. +pinLocalMachineOnStartup=Onglet de la machine locale au démarrage +pinLocalMachineOnStartupDescription=Ouvrir automatiquement un onglet de machine locale et l'épingler. C'est utile si tu utilises fréquemment un navigateur de fichiers fractionné avec la machine locale et le système de fichiers distant ouverts. diff --git a/lang/app/strings/translations_it.properties b/lang/app/strings/translations_it.properties index 514171556..6e5e92754 100644 --- a/lang/app/strings/translations_it.properties +++ b/lang/app/strings/translations_it.properties @@ -535,3 +535,5 @@ enableTerminalDocking=Abilita l'aggancio del terminale enableTerminalDockingDescription=Con il docking del terminale puoi agganciare le finestre del terminale alla finestra dell'applicazione XPipe per simulare un terminale integrato. Le finestre del terminale vengono gestite da XPipe in modo da essere sempre inserite nel dock. downloadsDirectory=Directory di download personalizzata downloadsDirectoryDescription=La directory personalizzata in cui inserire i file scaricati quando si fa clic sul pulsante sposta nei download. Per impostazione predefinita, XPipe utilizzerà la directory dei download dell'utente. +pinLocalMachineOnStartup=Blocca la scheda della macchina locale all'avvio +pinLocalMachineOnStartupDescription=Apre automaticamente una scheda del computer locale e la blocca. Questa funzione è utile se utilizzi spesso un browser di file suddiviso con il computer locale e il file system remoto aperti. diff --git a/lang/app/strings/translations_ja.properties b/lang/app/strings/translations_ja.properties index a91962da2..646e10eac 100644 --- a/lang/app/strings/translations_ja.properties +++ b/lang/app/strings/translations_ja.properties @@ -535,3 +535,5 @@ enableTerminalDocking=端末のドッキングを有効にする enableTerminalDockingDescription=ターミナルドッキングを使えば、XPipeのアプリケーションウィンドウにターミナルウィンドウをドッキングさせることができる。ターミナルウィンドウはXPipeによって管理され、常にドックに収まる。 downloadsDirectory=カスタムダウンロードディレクトリ downloadsDirectoryDescription=ダウンロードに移動ボタンをクリックしたときに、ダウンロードしたファイルを置くカスタムディレクトリ。デフォルトでは、XPipeはユーザーダウンロードディレクトリを使用する。 +pinLocalMachineOnStartup=起動時にローカルマシンのタブをピン留めする +pinLocalMachineOnStartupDescription=ローカルマシンのタブを自動的に開き、ピン留めする。これは、ローカルマシンとリモートファイルシステムを開いた状態で、分割ファイルブラウザを頻繁に使用する場合に便利である。 diff --git a/lang/app/strings/translations_nl.properties b/lang/app/strings/translations_nl.properties index b07ec0d63..76635876c 100644 --- a/lang/app/strings/translations_nl.properties +++ b/lang/app/strings/translations_nl.properties @@ -535,3 +535,5 @@ enableTerminalDocking=Terminal docking inschakelen enableTerminalDockingDescription=Met terminal docking kun je terminalvensters in het XPipe toepassingsvenster plaatsen om een enigszins geïntegreerde terminal te simuleren. De terminalvensters worden dan door XPipe beheerd zodat ze altijd in het dock passen. downloadsDirectory=Aangepaste downloadmap downloadsDirectoryDescription=De aangepaste map om gedownloade bestanden in te plaatsen als je op de knop Verplaats naar downloads klikt. Standaard gebruikt XPipe je gebruikersdownloadmap. +pinLocalMachineOnStartup=Tabblad lokale machine vastpinnen bij het opstarten +pinLocalMachineOnStartupDescription=Automatisch een lokale machine tab openen en vastpinnen. Dit is handig als je vaak een gesplitste bestandsbrowser gebruikt met de lokale machine en het externe bestandssysteem open. diff --git a/lang/app/strings/translations_pt.properties b/lang/app/strings/translations_pt.properties index 90ba7ec7b..e456a3cf8 100644 --- a/lang/app/strings/translations_pt.properties +++ b/lang/app/strings/translations_pt.properties @@ -535,3 +535,5 @@ enableTerminalDocking=Ativar a ancoragem do terminal enableTerminalDockingDescription=Com o terminal docking podes acoplar janelas de terminal à janela da aplicação XPipe para simular um terminal integrado. As janelas de terminal são então geridas pelo XPipe para caberem sempre na doca. downloadsDirectory=Diretório de transferências personalizado downloadsDirectoryDescription=O diretório personalizado para colocar os arquivos baixados ao clicar no botão mover para downloads. Por defeito, o XPipe utiliza o diretório de downloads do utilizador. +pinLocalMachineOnStartup=Fixa o separador da máquina local no arranque +pinLocalMachineOnStartupDescription=Abre automaticamente um separador da máquina local e fixa-o. Isto é útil se estiveres a utilizar frequentemente um navegador de ficheiros dividido com a máquina local e o sistema de ficheiros remoto abertos. diff --git a/lang/app/strings/translations_ru.properties b/lang/app/strings/translations_ru.properties index 7a8bc5aeb..3049395b8 100644 --- a/lang/app/strings/translations_ru.properties +++ b/lang/app/strings/translations_ru.properties @@ -535,3 +535,5 @@ enableTerminalDocking=Включить стыковку терминалов enableTerminalDockingDescription=С помощью терминальной докировки ты можешь пристыковать окна терминалов к окну приложения XPipe, чтобы имитировать некий интегрированный терминал. Окна терминала управляются XPipe, чтобы всегда помещаться в док. downloadsDirectory=Пользовательский каталог загрузок downloadsDirectoryDescription=Пользовательская директория, в которую будут помещаться скачанные файлы при нажатии на кнопку перемещения в загрузки. По умолчанию XPipe будет использовать твой пользовательский каталог загрузок. +pinLocalMachineOnStartup=Закрепить вкладку локальной машины при запуске +pinLocalMachineOnStartupDescription=Автоматически открывай вкладку локальной машины и закрепляй ее. Это полезно, если ты часто используешь разделенный файловый браузер с открытыми локальной машиной и удаленной файловой системой. diff --git a/lang/app/strings/translations_tr.properties b/lang/app/strings/translations_tr.properties index b8d777c5a..135cf87b2 100644 --- a/lang/app/strings/translations_tr.properties +++ b/lang/app/strings/translations_tr.properties @@ -536,3 +536,5 @@ enableTerminalDocking=Terminal yerleştirmeyi etkinleştir enableTerminalDockingDescription=Terminal kenetleme ile terminal pencerelerini XPipe uygulama penceresine kenetleyerek bir nevi entegre terminal simülasyonu yapabilirsiniz. Terminal pencereleri daha sonra XPipe tarafından her zaman yuvaya sığacak şekilde yönetilir. downloadsDirectory=Özel indirme dizini downloadsDirectoryDescription=İndirilen dosyaları indirilenlere taşı düğmesine tıklandığında yerleştirilecek özel dizin. Varsayılan olarak, XPipe kullanıcı indirme dizininizi kullanacaktır. +pinLocalMachineOnStartup=Başlangıçta yerel makine sekmesini sabitleme +pinLocalMachineOnStartupDescription=Otomatik olarak bir yerel makine sekmesi açın ve sabitleyin. Bu, yerel makine ve uzak dosya sistemi açıkken sık sık bölünmüş bir dosya tarayıcısı kullanıyorsanız kullanışlıdır. diff --git a/lang/app/strings/translations_zh.properties b/lang/app/strings/translations_zh.properties index 93fa797d3..a851914d7 100644 --- a/lang/app/strings/translations_zh.properties +++ b/lang/app/strings/translations_zh.properties @@ -535,3 +535,5 @@ enableTerminalDocking=启用终端对接 enableTerminalDockingDescription=使用终端停靠功能,您可以将终端窗口停靠在 XPipe 应用程序窗口上,以模拟集成终端。XPipe会对终端窗口进行管理,使其始终适合停靠。 downloadsDirectory=自定义下载目录 downloadsDirectoryDescription=单击 "移动到下载 "按钮时将下载文件放入的自定义目录。默认情况下,XPipe 将使用您的用户下载目录。 +pinLocalMachineOnStartup=启动时 Pin 本地计算机选项卡 +pinLocalMachineOnStartupDescription=自动打开本地计算机标签并将其固定。如果你经常在打开本地机器和远程文件系统的情况下使用分割文件浏览器,这将非常有用。 diff --git a/lang/base/strings/translations_da.properties b/lang/base/strings/translations_da.properties index 3350129b5..1e7570319 100644 --- a/lang/base/strings/translations_da.properties +++ b/lang/base/strings/translations_da.properties @@ -187,3 +187,4 @@ untarDirectory=Untar to $DIR$ unzipDirectory=Pak ud til $DIR$ unzipHere=Pak ud her requiresRestart=Kræver en genstart for at kunne anvendes. +download=Download diff --git a/lang/base/strings/translations_de.properties b/lang/base/strings/translations_de.properties index f6139f1d7..71c193252 100644 --- a/lang/base/strings/translations_de.properties +++ b/lang/base/strings/translations_de.properties @@ -178,3 +178,4 @@ untarDirectory=Untar zu $DIR$ unzipDirectory=Entpacken nach $DIR$ unzipHere=Hier entpacken requiresRestart=Erfordert einen Neustart zur Anwendung. +download=Herunterladen diff --git a/lang/base/strings/translations_en.properties b/lang/base/strings/translations_en.properties index 934247690..67ea7479a 100644 --- a/lang/base/strings/translations_en.properties +++ b/lang/base/strings/translations_en.properties @@ -177,4 +177,5 @@ untarDirectory=Untar to $DIR$ unzipDirectory=Unzip to $DIR$ unzipHere=Unzip here requiresRestart=Requires a restart to apply. +download=Download diff --git a/lang/base/strings/translations_es.properties b/lang/base/strings/translations_es.properties index f14a60d88..67bcb6dbb 100644 --- a/lang/base/strings/translations_es.properties +++ b/lang/base/strings/translations_es.properties @@ -176,3 +176,4 @@ untarDirectory=Untar a $DIR$ unzipDirectory=Descomprimir a $DIR$ unzipHere=Descomprimir aquí requiresRestart=Requiere un reinicio para aplicarse. +download=Descargar diff --git a/lang/base/strings/translations_fr.properties b/lang/base/strings/translations_fr.properties index 57d1eee38..9edd4703d 100644 --- a/lang/base/strings/translations_fr.properties +++ b/lang/base/strings/translations_fr.properties @@ -176,3 +176,4 @@ untarDirectory=Untar to $DIR$ unzipDirectory=Décompresser pour $DIR$ unzipHere=Décompresse ici requiresRestart=Nécessite un redémarrage pour s'appliquer. +download=Télécharger diff --git a/lang/base/strings/translations_it.properties b/lang/base/strings/translations_it.properties index 473cf3e28..baedc0ad7 100644 --- a/lang/base/strings/translations_it.properties +++ b/lang/base/strings/translations_it.properties @@ -176,3 +176,4 @@ untarDirectory=Untar a $DIR$ unzipDirectory=Decomprimere in $DIR$ unzipHere=Decomprimi qui requiresRestart=Richiede un riavvio per essere applicato. +download=Scarica diff --git a/lang/base/strings/translations_ja.properties b/lang/base/strings/translations_ja.properties index d7a0be9a5..90663980c 100644 --- a/lang/base/strings/translations_ja.properties +++ b/lang/base/strings/translations_ja.properties @@ -176,3 +176,4 @@ untarDirectory=未対応$DIR$ unzipDirectory=解凍先$DIR$ unzipHere=ここで解凍する requiresRestart=適用には再起動が必要である。 +download=ダウンロード diff --git a/lang/base/strings/translations_nl.properties b/lang/base/strings/translations_nl.properties index c131bc643..aa18bcbb6 100644 --- a/lang/base/strings/translations_nl.properties +++ b/lang/base/strings/translations_nl.properties @@ -176,3 +176,4 @@ untarDirectory=Naar $DIR$ unzipDirectory=Uitpakken naar $DIR$ unzipHere=Hier uitpakken requiresRestart=Vereist een herstart om toe te passen. +download=Downloaden diff --git a/lang/base/strings/translations_pt.properties b/lang/base/strings/translations_pt.properties index 69f3e4918..c7bc9f2da 100644 --- a/lang/base/strings/translations_pt.properties +++ b/lang/base/strings/translations_pt.properties @@ -176,3 +176,4 @@ untarDirectory=Untar para $DIR$ unzipDirectory=Descompacta para $DIR$ unzipHere=Descompacta aqui requiresRestart=Requer um reinício para ser aplicado. +download=Descarrega diff --git a/lang/base/strings/translations_ru.properties b/lang/base/strings/translations_ru.properties index a6b217c6f..3c354757e 100644 --- a/lang/base/strings/translations_ru.properties +++ b/lang/base/strings/translations_ru.properties @@ -176,3 +176,4 @@ untarDirectory=Унтар к $DIR$ unzipDirectory=Разархивировать в $DIR$ unzipHere=Распакуйте здесь requiresRestart=Требует перезапуска для применения. +download=Скачать diff --git a/lang/base/strings/translations_tr.properties b/lang/base/strings/translations_tr.properties index 1fbb46403..e39e2a39b 100644 --- a/lang/base/strings/translations_tr.properties +++ b/lang/base/strings/translations_tr.properties @@ -176,3 +176,4 @@ untarDirectory=Untar'a $DIR$ unzipDirectory=Açmak için $DIR$ unzipHere=Buradan açın requiresRestart=Uygulamak için yeniden başlatma gerekir. +download=İndir diff --git a/lang/base/strings/translations_zh.properties b/lang/base/strings/translations_zh.properties index 28909226a..a0a1bf01c 100644 --- a/lang/base/strings/translations_zh.properties +++ b/lang/base/strings/translations_zh.properties @@ -176,3 +176,4 @@ untarDirectory=到$DIR$ unzipDirectory=解压缩为$DIR$ unzipHere=在此解压缩 requiresRestart=需要重新启动才能应用。 +download=下载 diff --git a/version b/version index 5cb7d8566..cdb4ac409 100644 --- a/version +++ b/version @@ -1 +1 @@ -13.0.1 +13.1