diff --git a/app/build.gradle b/app/build.gradle index b45cd5cea..bbb76d271 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -23,8 +23,8 @@ dependencies { api project(':beacon') compileOnly 'org.hamcrest:hamcrest:3.0' - compileOnly 'org.junit.jupiter:junit-jupiter-api:5.11.0' - compileOnly 'org.junit.jupiter:junit-jupiter-params:5.11.0' + compileOnly 'org.junit.jupiter:junit-jupiter-api:5.11.3' + compileOnly 'org.junit.jupiter:junit-jupiter-params:5.11.3' api 'com.vladsch.flexmark:flexmark:0.64.8' api 'com.vladsch.flexmark:flexmark-util:0.64.8' @@ -58,8 +58,8 @@ dependencies { api 'org.apache.commons:commons-lang3:3.17.0' api 'io.sentry:sentry:7.14.0' api 'commons-io:commons-io:2.16.1' - api group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: "2.17.2" - api group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: "2.17.2" + api group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: "2.18.1" + api group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: "2.18.1" api group: 'org.kordamp.ikonli', name: 'ikonli-material2-pack', version: "12.2.0" api group: 'org.kordamp.ikonli', name: 'ikonli-materialdesign2-pack', version: "12.2.0" api group: 'org.kordamp.ikonli', name: 'ikonli-javafx', version: "12.2.0" diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/ConnectionBrowseExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/ConnectionBrowseExchangeImpl.java index 1fb2f1d2a..35dfe1600 100644 --- a/app/src/main/java/io/xpipe/app/beacon/impl/ConnectionBrowseExchangeImpl.java +++ b/app/src/main/java/io/xpipe/app/beacon/impl/ConnectionBrowseExchangeImpl.java @@ -20,7 +20,7 @@ public class ConnectionBrowseExchangeImpl extends ConnectionBrowseExchange { throw new BeaconClientException("Not a file system connection"); } BrowserSessionModel.DEFAULT.openFileSystemSync( - e.ref(), msg.getDirectory() != null ? ignored -> msg.getDirectory() : null, null); + e.ref(), msg.getDirectory() != null ? ignored -> msg.getDirectory() : null, null, true); AppLayoutModel.get().selectBrowser(); return Response.builder().build(); } diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/ConnectionRefreshExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/ConnectionRefreshExchangeImpl.java index 3c97868e9..5fa336528 100644 --- a/app/src/main/java/io/xpipe/app/beacon/impl/ConnectionRefreshExchangeImpl.java +++ b/app/src/main/java/io/xpipe/app/beacon/impl/ConnectionRefreshExchangeImpl.java @@ -15,9 +15,9 @@ public class ConnectionRefreshExchangeImpl extends ConnectionRefreshExchange { .getStoreEntryIfPresent(msg.getConnection()) .orElseThrow(() -> new BeaconClientException("Unknown connection: " + msg.getConnection())); if (e.getStore() instanceof FixedHierarchyStore) { - DataStorage.get().refreshChildren(e, null, true); + DataStorage.get().refreshChildren(e, true); } else { - e.validateOrThrowAndClose(null); + e.validateOrThrow(); } return Response.builder().build(); } diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/ConnectionTerminalExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/ConnectionTerminalExchangeImpl.java index 0717de7f4..0e2fa42c9 100644 --- a/app/src/main/java/io/xpipe/app/beacon/impl/ConnectionTerminalExchangeImpl.java +++ b/app/src/main/java/io/xpipe/app/beacon/impl/ConnectionTerminalExchangeImpl.java @@ -1,10 +1,10 @@ package io.xpipe.app.beacon.impl; +import io.xpipe.app.ext.ShellStore; import io.xpipe.app.storage.DataStorage; import io.xpipe.app.util.TerminalLauncher; import io.xpipe.beacon.BeaconClientException; import io.xpipe.beacon.api.ConnectionTerminalExchange; -import io.xpipe.core.store.ShellStore; import com.sun.net.httpserver.HttpExchange; @@ -18,9 +18,8 @@ public class ConnectionTerminalExchangeImpl extends ConnectionTerminalExchange { if (!(e.getStore() instanceof ShellStore shellStore)) { throw new BeaconClientException("Not a shell connection"); } - try (var sc = shellStore.control().start()) { - TerminalLauncher.open(e, e.getName(), msg.getDirectory(), sc); - } + var sc = shellStore.getOrStartSession(); + TerminalLauncher.open(e, e.getName(), msg.getDirectory(), sc); return Response.builder().build(); } } diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/ShellStartExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/ShellStartExchangeImpl.java index 21cefe252..e9456fd45 100644 --- a/app/src/main/java/io/xpipe/app/beacon/impl/ShellStartExchangeImpl.java +++ b/app/src/main/java/io/xpipe/app/beacon/impl/ShellStartExchangeImpl.java @@ -2,10 +2,10 @@ package io.xpipe.app.beacon.impl; import io.xpipe.app.beacon.AppBeaconServer; import io.xpipe.app.beacon.BeaconShellSession; +import io.xpipe.app.ext.ShellStore; import io.xpipe.app.storage.DataStorage; import io.xpipe.beacon.BeaconClientException; import io.xpipe.beacon.api.ShellStartExchange; -import io.xpipe.core.store.ShellStore; import com.sun.net.httpserver.HttpExchange; import lombok.SneakyThrows; @@ -25,7 +25,9 @@ public class ShellStartExchangeImpl extends ShellStartExchange { var existing = AppBeaconServer.get().getCache().getShellSessions().stream() .filter(beaconShellSession -> beaconShellSession.getEntry().equals(e)) .findFirst(); - var control = (existing.isPresent() ? existing.get().getControl() : s.control()); + var control = (existing.isPresent() + ? existing.get().getControl() + : s.standaloneControl().start()); control.setNonInteractive(); control.start(); diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserHomeModel.java b/app/src/main/java/io/xpipe/app/browser/BrowserHomeModel.java new file mode 100644 index 000000000..676b7db51 --- /dev/null +++ b/app/src/main/java/io/xpipe/app/browser/BrowserHomeModel.java @@ -0,0 +1,49 @@ +package io.xpipe.app.browser; + +import io.xpipe.app.browser.session.BrowserAbstractSessionModel; +import io.xpipe.app.browser.session.BrowserSessionModel; +import io.xpipe.app.browser.session.BrowserSessionTab; +import io.xpipe.app.core.AppI18n; +import io.xpipe.app.fxcomps.Comp; +import io.xpipe.app.storage.DataColor; +import io.xpipe.core.store.*; + +import javafx.beans.property.*; + +public final class BrowserHomeModel extends BrowserSessionTab { + + public BrowserHomeModel(BrowserAbstractSessionModel browserModel) { + super(browserModel, AppI18n.get("overview"), null); + } + + @Override + public Comp comp() { + return new BrowserWelcomeComp((BrowserSessionModel) browserModel); + } + + @Override + public boolean canImmediatelyClose() { + return true; + } + + @Override + public void init() throws Exception {} + + @Override + public void close() {} + + @Override + public String getIcon() { + return null; + } + + @Override + public DataColor getColor() { + return null; + } + + @Override + public boolean isCloseable() { + return false; + } +} diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserSavedStateImpl.java b/app/src/main/java/io/xpipe/app/browser/BrowserSavedStateImpl.java index cbbd14545..ecbd14ce3 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserSavedStateImpl.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserSavedStateImpl.java @@ -39,7 +39,7 @@ public class BrowserSavedStateImpl implements BrowserSavedState { } private static BrowserSavedStateImpl load() { - return AppCache.get("browser-state", BrowserSavedStateImpl.class, () -> { + return AppCache.getNonNull("browser-state", BrowserSavedStateImpl.class, () -> { return new BrowserSavedStateImpl(FXCollections.observableArrayList()); }); } diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserTransferComp.java b/app/src/main/java/io/xpipe/app/browser/BrowserTransferComp.java index 5c3334684..dc722c250 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserTransferComp.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserTransferComp.java @@ -43,8 +43,11 @@ public class BrowserTransferComp extends SimpleComp { .apply(struc -> struc.get().setGraphic(new FontIcon("mdi2d-download-outline"))) .apply(struc -> struc.get().setWrapText(true)) .visible(model.getEmpty()); - var backgroundStack = - new StackComp(List.of(background)).grow(true, true).styleClass("download-background"); + var backgroundStack = new StackComp(List.of(background)) + .grow(true, true) + .styleClass("color-box") + .styleClass("gray") + .styleClass("download-background"); var binding = new DerivedObservableList<>(model.getItems(), true) .mapped(item -> item.getBrowserEntry()) diff --git a/app/src/main/java/io/xpipe/app/browser/action/LeafAction.java b/app/src/main/java/io/xpipe/app/browser/action/LeafAction.java index 5c1ad7815..3faa151f6 100644 --- a/app/src/main/java/io/xpipe/app/browser/action/LeafAction.java +++ b/app/src/main/java/io/xpipe/app/browser/action/LeafAction.java @@ -75,9 +75,8 @@ public interface LeafAction extends BrowserAction { var name = getName(model, selected); var mi = new MenuItem(); mi.textProperty().bind(BindingsHelper.map(name, s -> { - if (getProFeatureId() != null - && !LicenseProvider.get().getFeature(getProFeatureId()).isSupported()) { - return s + " (Pro)"; + if (getProFeatureId() != null) { + return LicenseProvider.get().getFeature(getProFeatureId()).suffix(s); } return s; })); 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 68b0e70fe..83aa20f08 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 @@ -130,7 +130,7 @@ public final class BrowserFileListComp extends SimpleComp { table.setAccessibleText("Directory contents"); table.setPlaceholder(new Region()); table.getStyleClass().add(Styles.STRIPED); - table.getColumns().setAll(filenameCol, sizeCol, modeCol, ownerCol, mtimeCol); + table.getColumns().setAll(filenameCol, mtimeCol, modeCol, ownerCol, sizeCol); table.getSortOrder().add(filenameCol); table.setFocusTraversable(true); table.setSortPolicy(param -> { @@ -313,8 +313,10 @@ public final class BrowserFileListComp extends SimpleComp { .filter(browserAction -> browserAction.getShortcut().match(event)) .findAny(); action.ifPresent(browserAction -> { + // Prevent concurrent modification by creating copy on platform thread + var selectionCopy = new ArrayList<>(selected); ThreadHelper.runFailableAsync(() -> { - browserAction.execute(fileList.getFileSystemModel(), selected); + browserAction.execute(fileList.getFileSystemModel(), selectionCopy); }); event.consume(); }); diff --git a/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemModel.java b/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemModel.java index 1accf26f4..8ee1fbc38 100644 --- a/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemModel.java +++ b/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemModel.java @@ -9,9 +9,10 @@ import io.xpipe.app.browser.file.BrowserFileTransferMode; import io.xpipe.app.browser.file.BrowserFileTransferOperation; import io.xpipe.app.browser.file.FileSystemHelper; import io.xpipe.app.browser.session.BrowserAbstractSessionModel; -import io.xpipe.app.browser.session.BrowserSessionTab; +import io.xpipe.app.browser.session.BrowserStoreSessionTab; import io.xpipe.app.comp.base.ModalOverlayComp; import io.xpipe.app.ext.ProcessControlProvider; +import io.xpipe.app.ext.ShellStore; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.storage.DataStorage; @@ -41,7 +42,7 @@ import java.util.Optional; import java.util.stream.Stream; @Getter -public final class OpenFileSystemModel extends BrowserSessionTab { +public final class OpenFileSystemModel extends BrowserStoreSessionTab { private final Property filter = new SimpleStringProperty(); private final BrowserFileListModel fileList; diff --git a/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemSavedState.java b/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemSavedState.java index fa3efa929..97759ae0a 100644 --- a/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemSavedState.java +++ b/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemSavedState.java @@ -57,9 +57,10 @@ public class OpenFileSystemSavedState { } static OpenFileSystemSavedState loadForStore(OpenFileSystemModel model) { - var state = AppCache.get("fs-state-" + model.getEntry().get().getUuid(), OpenFileSystemSavedState.class, () -> { - return new OpenFileSystemSavedState(); - }); + var state = AppCache.getNonNull( + "fs-state-" + model.getEntry().get().getUuid(), OpenFileSystemSavedState.class, () -> { + return new OpenFileSystemSavedState(); + }); state.setModel(model); return state; } diff --git a/app/src/main/java/io/xpipe/app/browser/session/BrowserAbstractSessionModel.java b/app/src/main/java/io/xpipe/app/browser/session/BrowserAbstractSessionModel.java index 0a28540ab..3414c19fd 100644 --- a/app/src/main/java/io/xpipe/app/browser/session/BrowserAbstractSessionModel.java +++ b/app/src/main/java/io/xpipe/app/browser/session/BrowserAbstractSessionModel.java @@ -13,13 +13,13 @@ import javafx.collections.ObservableList; import lombok.Getter; @Getter -public class BrowserAbstractSessionModel> { +public class BrowserAbstractSessionModel { protected final ObservableList sessionEntries = FXCollections.observableArrayList(); protected final Property selectedEntry = new SimpleObjectProperty<>(); protected final BooleanProperty busy = new SimpleBooleanProperty(); - public void closeAsync(BrowserSessionTab e) { + public void closeAsync(BrowserSessionTab e) { ThreadHelper.runAsync(() -> { closeSync(e); }); @@ -37,7 +37,7 @@ public class BrowserAbstractSessionModel> { } } - public void closeSync(BrowserSessionTab e) { + public void closeSync(BrowserSessionTab e) { e.close(); synchronized (BrowserAbstractSessionModel.this) { this.sessionEntries.remove(e); diff --git a/app/src/main/java/io/xpipe/app/browser/session/BrowserChooserComp.java b/app/src/main/java/io/xpipe/app/browser/session/BrowserChooserComp.java index 74d7f2135..000b9f223 100644 --- a/app/src/main/java/io/xpipe/app/browser/session/BrowserChooserComp.java +++ b/app/src/main/java/io/xpipe/app/browser/session/BrowserChooserComp.java @@ -6,10 +6,11 @@ import io.xpipe.app.browser.file.BrowserEntry; import io.xpipe.app.browser.fs.OpenFileSystemComp; import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.app.comp.base.DialogComp; -import io.xpipe.app.comp.base.SideSplitPaneComp; +import io.xpipe.app.comp.base.LeftSplitPaneComp; import io.xpipe.app.comp.store.StoreEntryWrapper; import io.xpipe.app.core.AppFont; import io.xpipe.app.core.AppLayoutModel; +import io.xpipe.app.ext.ShellStore; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.impl.StackComp; import io.xpipe.app.fxcomps.impl.VerticalComp; @@ -19,7 +20,6 @@ import io.xpipe.app.storage.DataStoreEntryRef; import io.xpipe.app.util.FileReference; import io.xpipe.app.util.ThreadHelper; import io.xpipe.core.store.FileSystemStore; -import io.xpipe.core.store.ShellStore; import javafx.beans.property.BooleanProperty; import javafx.collections.ListChangeListener; @@ -148,7 +148,7 @@ public class BrowserChooserComp extends DialogComp { }); var vertical = new VerticalComp(List.of(bookmarkTopBar, bookmarksContainer)).styleClass("left"); - var splitPane = new SideSplitPaneComp(vertical, stack) + var splitPane = new LeftSplitPaneComp(vertical, stack) .withInitialWidth(AppLayoutModel.get().getSavedState().getBrowserConnectionsWidth()) .withOnDividerChange(AppLayoutModel.get().getSavedState()::setBrowserConnectionsWidth) .styleClass("background") diff --git a/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionComp.java b/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionComp.java index 2a1a07084..06b3606ea 100644 --- a/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionComp.java +++ b/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionComp.java @@ -4,23 +4,25 @@ import io.xpipe.app.browser.BrowserBookmarkComp; import io.xpipe.app.browser.BrowserBookmarkHeaderComp; import io.xpipe.app.browser.BrowserTransferComp; import io.xpipe.app.comp.base.LoadingOverlayComp; -import io.xpipe.app.comp.base.SideSplitPaneComp; +import io.xpipe.app.comp.base.LeftSplitPaneComp; import io.xpipe.app.comp.store.StoreEntryWrapper; import io.xpipe.app.core.AppLayoutModel; +import io.xpipe.app.ext.ShellStore; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.impl.AnchorComp; +import io.xpipe.app.fxcomps.impl.LabelComp; import io.xpipe.app.fxcomps.impl.StackComp; import io.xpipe.app.fxcomps.impl.VerticalComp; import io.xpipe.app.fxcomps.util.BindingsHelper; import io.xpipe.app.fxcomps.util.PlatformThread; import io.xpipe.app.util.ThreadHelper; -import io.xpipe.core.store.ShellStore; import javafx.application.Platform; import javafx.beans.binding.Bindings; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleDoubleProperty; +import javafx.geometry.Insets; import javafx.scene.layout.AnchorPane; import javafx.scene.layout.Region; import javafx.scene.shape.Rectangle; @@ -67,7 +69,11 @@ public class BrowserSessionComp extends SimpleComp { var bookmarkTopBar = new BrowserBookmarkHeaderComp(); var bookmarksList = new BrowserBookmarkComp( - BindingsHelper.map(model.getSelectedEntry(), v -> v.getEntry().get()), + BindingsHelper.map( + model.getSelectedEntry(), + v -> v instanceof BrowserStoreSessionTab st + ? st.getEntry().get() + : null), applicable, action, bookmarkTopBar.getCategory(), @@ -99,8 +105,10 @@ public class BrowserSessionComp extends SimpleComp { var vertical = new VerticalComp(List.of(bookmarkTopBar, bookmarksContainer, localDownloadStage)).styleClass("left"); - var split = new SimpleDoubleProperty(); - var tabs = new BrowserSessionTabsComp(model, split).apply(struc -> { + var leftSplit = new SimpleDoubleProperty(); + var rightSplit = new SimpleDoubleProperty(); + var tabs = new BrowserSessionTabsComp(model, leftSplit, rightSplit); + tabs.apply(struc -> { struc.get().setViewOrder(1); struc.get().setPickOnBounds(false); AnchorPane.setTopAnchor(struc.get(), 0.0); @@ -108,20 +116,54 @@ public class BrowserSessionComp extends SimpleComp { AnchorPane.setLeftAnchor(struc.get(), 0.0); AnchorPane.setRightAnchor(struc.get(), 0.0); }); + + vertical.apply(struc -> { + struc.get() + .paddingProperty() + .bind(Bindings.createObjectBinding( + () -> new Insets(tabs.getHeaderHeight().get(), 0, 0, 0), tabs.getHeaderHeight())); + }); var loadingIndicator = LoadingOverlayComp.noProgress(Comp.empty(), model.getBusy()) .apply(struc -> { AnchorPane.setTopAnchor(struc.get(), 0.0); AnchorPane.setRightAnchor(struc.get(), 0.0); }) .styleClass("tab-loading-indicator"); - var loadingStack = new AnchorComp(List.of(tabs, loadingIndicator)); - var splitPane = new SideSplitPaneComp(vertical, loadingStack) + + var pinnedStack = new StackComp(List.of(new LabelComp("a"))); + pinnedStack.apply(struc -> { + model.getEffectiveRightTab().subscribe( (newValue) -> { + PlatformThread.runLaterIfNeeded(() -> { + if (newValue != null) { + var r = newValue.comp().createRegion(); + struc.get().getChildren().add(r); + } else { + struc.get().getChildren().clear(); + } + }); + }); + + rightSplit.addListener((observable, oldValue, newValue) -> { + struc.get().setMinWidth(newValue.doubleValue()); + struc.get().setMaxWidth(newValue.doubleValue()); + struc.get().setPrefWidth(newValue.doubleValue()); + }); + + AnchorPane.setBottomAnchor(struc.get(), 0.0); + AnchorPane.setRightAnchor(struc.get(), 0.0); + tabs.getHeaderHeight().subscribe(number -> { + AnchorPane.setTopAnchor(struc.get(), number.doubleValue()); + }); + }); + + var loadingStack = new AnchorComp(List.of(tabs, pinnedStack, loadingIndicator)); + var splitPane = new LeftSplitPaneComp(vertical, loadingStack) .withInitialWidth(AppLayoutModel.get().getSavedState().getBrowserConnectionsWidth()) .withOnDividerChange(d -> { AppLayoutModel.get().getSavedState().setBrowserConnectionsWidth(d); - split.set(d); - }) - .apply(struc -> { + leftSplit.set(d); + }); + splitPane.apply(struc -> { struc.getLeft().setMinWidth(200); struc.getLeft().setMaxWidth(500); struc.get().setPickOnBounds(false); @@ -140,9 +182,7 @@ public class BrowserSessionComp extends SimpleComp { } }); }); - - var r = splitPane.createRegion(); - r.getStyleClass().add("browser"); - return r; + splitPane.styleClass("browser"); + return splitPane.createRegion(); } } diff --git a/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionModel.java b/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionModel.java index 3fdc6fa43..2c6b18676 100644 --- a/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionModel.java +++ b/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionModel.java @@ -1,9 +1,11 @@ package io.xpipe.app.browser.session; +import io.xpipe.app.browser.BrowserHomeModel; import io.xpipe.app.browser.BrowserSavedState; import io.xpipe.app.browser.BrowserSavedStateImpl; import io.xpipe.app.browser.BrowserTransferModel; import io.xpipe.app.browser.fs.OpenFileSystemModel; +import io.xpipe.app.fxcomps.util.BindingsHelper; import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStoreEntryRef; import io.xpipe.app.util.BooleanScope; @@ -11,22 +13,94 @@ import io.xpipe.app.util.ThreadHelper; import io.xpipe.core.store.FileNames; import io.xpipe.core.store.FileSystemStore; import io.xpipe.core.util.FailableFunction; - +import javafx.beans.binding.Bindings; import javafx.beans.property.BooleanProperty; import javafx.beans.property.Property; import javafx.beans.property.SimpleBooleanProperty; - +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.value.ObservableValue; +import javafx.collections.FXCollections; +import javafx.collections.ListChangeListener; +import javafx.collections.ObservableMap; import lombok.Getter; import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; @Getter -public class BrowserSessionModel extends BrowserAbstractSessionModel> { +public class BrowserSessionModel extends BrowserAbstractSessionModel { public static final BrowserSessionModel DEFAULT = new BrowserSessionModel(); + static { + DEFAULT.getSessionEntries().add(new BrowserHomeModel(DEFAULT)); + } + private final BrowserTransferModel localTransfersStage = new BrowserTransferModel(this); private final Property draggingFiles = new SimpleBooleanProperty(); + private final Property globalPinnedTab = new SimpleObjectProperty<>(); + private final ObservableValue effectiveRightTab = createEffectiveRightTab(); + private final ObservableMap splits = FXCollections.observableHashMap(); + + private ObservableValue createEffectiveRightTab() { + return Bindings.createObjectBinding(() -> { + var current = selectedEntry.getValue(); + if (!current.isCloseable()) { + return null; + } + + var split = splits.get(current); + if (split != null) { + return split; + } + + var global = globalPinnedTab.getValue(); + if (global == null) { + return null; + } + + if (global == selectedEntry.getValue()) { + return null; + } + + return global; + }, globalPinnedTab, selectedEntry); + } + + public BrowserSessionModel() { + sessionEntries.addListener((ListChangeListener) c -> { + var v = globalPinnedTab.getValue(); + if (v != null && !c.getList().contains(v)) { + globalPinnedTab.setValue(null); + } + + splits.keySet().removeIf(browserSessionTab -> !c.getList().contains(browserSessionTab)); + }); + } + + public void splitTab(BrowserSessionTab tab, BrowserSessionTab split) { + splits.put(tab, split); + } + + public void pinTab(BrowserSessionTab tab) { + if (tab.equals(globalPinnedTab.getValue())) { + return; + } + + globalPinnedTab.setValue(tab); + + var nextIndex = getSessionEntries().indexOf(tab) + 1; + if (nextIndex < getSessionEntries().size()) { + getSelectedEntry().setValue(getSessionEntries().get(nextIndex)); + } + } + + public void unpinTab(BrowserSessionTab tab) { + ThreadHelper.runFailableAsync(() -> { + globalPinnedTab.setValue(null); + }); + } public void restoreState(BrowserSavedState state) { ThreadHelper.runAsync(() -> { @@ -74,14 +148,15 @@ public class BrowserSessionModel extends BrowserAbstractSessionModel { - openFileSystemSync(store, path, externalBusy); + openFileSystemSync(store, path, externalBusy, true); }); } public OpenFileSystemModel openFileSystemSync( DataStoreEntryRef store, FailableFunction path, - BooleanProperty externalBusy) + BooleanProperty externalBusy, + boolean select) throws Exception { OpenFileSystemModel model; try (var b = new BooleanScope(externalBusy != null ? externalBusy : new SimpleBooleanProperty()).start()) { @@ -91,8 +166,10 @@ public class BrowserSessionModel extends BrowserAbstractSessionModel { +public abstract class BrowserSessionTab { - protected final DataStoreEntryRef entry; protected final BooleanProperty busy = new SimpleBooleanProperty(); protected final BrowserAbstractSessionModel browserModel; protected final String name; protected final String tooltip; + protected final Property splitTab = new SimpleObjectProperty<>(); - public BrowserSessionTab(BrowserAbstractSessionModel browserModel, DataStoreEntryRef entry) { + public BrowserSessionTab(BrowserAbstractSessionModel browserModel, String name, String tooltip) { this.browserModel = browserModel; - this.entry = entry; - this.name = DataStorage.get().getStoreEntryDisplayName(entry.get()); - this.tooltip = DataStorage.get().getStorePath(entry.getEntry()).toString(); + this.name = name; + this.tooltip = tooltip; } public abstract Comp comp(); @@ -33,4 +34,12 @@ public abstract class BrowserSessionTab { public abstract void init() throws Exception; public abstract void close(); + + public abstract String getIcon(); + + public abstract DataColor getColor(); + + public boolean isCloseable() { + return true; + } } diff --git a/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionTabsComp.java b/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionTabsComp.java index e4cb2ef1a..1f3dd77b0 100644 --- a/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionTabsComp.java +++ b/app/src/main/java/io/xpipe/app/browser/session/BrowserSessionTabsComp.java @@ -1,7 +1,5 @@ package io.xpipe.app.browser.session; -import io.xpipe.app.browser.BrowserWelcomeComp; -import io.xpipe.app.comp.base.MultiContentComp; import io.xpipe.app.core.AppI18n; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.SimpleComp; @@ -10,28 +8,33 @@ import io.xpipe.app.fxcomps.impl.TooltipAugment; import io.xpipe.app.fxcomps.util.LabelGraphic; import io.xpipe.app.fxcomps.util.PlatformThread; import io.xpipe.app.prefs.AppPrefs; -import io.xpipe.app.storage.DataStorage; import io.xpipe.app.util.BooleanScope; import io.xpipe.app.util.ContextMenuHelper; import javafx.application.Platform; import javafx.beans.binding.Bindings; +import javafx.beans.property.DoubleProperty; import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleDoubleProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.value.ObservableDoubleValue; import javafx.beans.value.ObservableValue; import javafx.collections.ListChangeListener; +import javafx.css.PseudoClass; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.control.*; +import javafx.scene.control.skin.TabPaneSkin; import javafx.scene.input.*; import javafx.scene.layout.Region; import javafx.scene.layout.StackPane; import atlantafx.base.controls.RingProgressIndicator; import atlantafx.base.theme.Styles; +import lombok.Getter; import java.util.*; +import java.util.concurrent.atomic.AtomicReference; import static atlantafx.base.theme.Styles.DENSE; import static atlantafx.base.theme.Styles.toggleStyleClass; @@ -41,26 +44,30 @@ public class BrowserSessionTabsComp extends SimpleComp { private final BrowserSessionModel model; private final ObservableDoubleValue leftPadding; + private final DoubleProperty rightPadding; - public BrowserSessionTabsComp(BrowserSessionModel model, ObservableDoubleValue leftPadding) { + @Getter + private final DoubleProperty headerHeight; + + public BrowserSessionTabsComp(BrowserSessionModel model, ObservableDoubleValue leftPadding, DoubleProperty rightPadding) { this.model = model; this.leftPadding = leftPadding; + this.rightPadding = rightPadding; + this.headerHeight = new SimpleDoubleProperty(); } public Region createSimple() { - var map = new LinkedHashMap, ObservableValue>(); - map.put(Comp.hspacer().styleClass("top-spacer"), new SimpleBooleanProperty(true)); - map.put(Comp.of(() -> createTabPane()), Bindings.isNotEmpty(model.getSessionEntries())); - map.put( - new BrowserWelcomeComp(model).apply(struc -> StackPane.setAlignment(struc.get(), Pos.CENTER_LEFT)), - Bindings.createBooleanBinding( - () -> { - return model.getSessionEntries().size() == 0; - }, - model.getSessionEntries())); - var multi = new MultiContentComp(map); - multi.apply(struc -> ((StackPane) struc.get()).setAlignment(Pos.TOP_CENTER)); - return multi.createRegion(); + var tabs = createTabPane(); + var topBackground = Comp.hspacer().styleClass("top-spacer").createRegion(); + leftPadding.subscribe(number -> { + StackPane.setMargin(topBackground, new Insets(0, 0, 0, -number.doubleValue())); + }); + var stack = new StackPane(topBackground, tabs); + stack.setAlignment(Pos.TOP_CENTER); + topBackground.prefHeightProperty().bind(headerHeight); + topBackground.maxHeightProperty().bind(topBackground.prefHeightProperty()); + topBackground.prefWidthProperty().bind(tabs.widthProperty()); + return stack; } private TabPane createTabPane() { @@ -69,6 +76,7 @@ public class BrowserSessionTabsComp extends SimpleComp { tabs.setTabMinWidth(Region.USE_PREF_SIZE); tabs.setTabMaxWidth(400); tabs.setTabClosingPolicy(ALL_TABS); + tabs.setSkin(new TabPaneSkin(tabs)); Styles.toggleStyleClass(tabs, TabPane.STYLE_CLASS_FLOATING); toggleStyleClass(tabs, DENSE); @@ -80,22 +88,31 @@ public class BrowserSessionTabsComp extends SimpleComp { tabs.lookupAll(".tab-header-area").forEach(node -> { node.setClip(null); node.setPickOnBounds(false); + + var r = (Region) node; + r.prefHeightProperty().bind(r.maxHeightProperty()); + r.setMinHeight(Region.USE_PREF_SIZE); }); tabs.lookupAll(".headers-region").forEach(node -> { node.setClip(null); node.setPickOnBounds(false); + + var r = (Region) node; + r.prefHeightProperty().bind(r.maxHeightProperty()); + r.setMinHeight(Region.USE_PREF_SIZE); }); Region headerArea = (Region) tabs.lookup(".tab-header-area"); headerArea .paddingProperty() .bind(Bindings.createObjectBinding( - () -> new Insets(0, 0, 0, -leftPadding.get() + 2), leftPadding)); + () -> new Insets(2, 0, 4, -leftPadding.get() + 2), leftPadding)); + headerHeight.bind(headerArea.heightProperty()); }); } }); - var map = new HashMap, Tab>(); + var map = new HashMap(); // Restore state model.getSessionEntries().forEach(v -> { @@ -156,7 +173,7 @@ public class BrowserSessionTabsComp extends SimpleComp { }); }); - model.getSessionEntries().addListener((ListChangeListener>) c -> { + model.getSessionEntries().addListener((ListChangeListener) c -> { while (c.next()) { for (var r : c.getRemoved()) { PlatformThread.runLaterIfNeeded(() -> { @@ -245,9 +262,28 @@ public class BrowserSessionTabsComp extends SimpleComp { return tabs; } - private ContextMenu createContextMenu(TabPane tabs, Tab tab) { + private ContextMenu createContextMenu(TabPane tabs, Tab tab, BrowserSessionTab tabModel) { var cm = ContextMenuHelper.create(); + if (tabModel.isCloseable()) { + var unsplit = ContextMenuHelper.item(LabelGraphic.none(), AppI18n.get("unpinTab")); + unsplit.visibleProperty().bind(PlatformThread.sync(Bindings.createBooleanBinding(() -> { + return model.getGlobalPinnedTab().getValue() != null && model.getGlobalPinnedTab().getValue().equals(tabModel); + }, model.getGlobalPinnedTab()))); + unsplit.setOnAction(event -> { + model.unpinTab(tabModel); + event.consume(); + }); + cm.getItems().add(unsplit); + + var split = ContextMenuHelper.item(LabelGraphic.none(), AppI18n.get("pinTab")); + split.setOnAction(event -> { + model.pinTab(tabModel); + event.consume(); + }); + cm.getItems().add(split); + } + var select = ContextMenuHelper.item(LabelGraphic.none(), AppI18n.get("selectTab")); select.acceleratorProperty() .bind(Bindings.createObjectBinding( @@ -272,7 +308,9 @@ public class BrowserSessionTabsComp extends SimpleComp { var close = ContextMenuHelper.item(LabelGraphic.none(), AppI18n.get("closeTab")); close.setAccelerator(new KeyCodeCombination(KeyCode.W, KeyCombination.SHORTCUT_DOWN)); close.setOnAction(event -> { - tabs.getTabs().remove(tab); + if (tab.isClosable()) { + tabs.getTabs().remove(tab); + } event.consume(); }); cm.getItems().add(close); @@ -280,7 +318,9 @@ public class BrowserSessionTabsComp extends SimpleComp { var closeOthers = ContextMenuHelper.item(LabelGraphic.none(), AppI18n.get("closeOtherTabs")); closeOthers.setOnAction(event -> { tabs.getTabs() - .removeAll(tabs.getTabs().stream().filter(t -> t != tab).toList()); + .removeAll(tabs.getTabs().stream() + .filter(t -> t != tab && t.isClosable()) + .toList()); event.consume(); }); cm.getItems().add(closeOthers); @@ -290,7 +330,7 @@ public class BrowserSessionTabsComp extends SimpleComp { var index = tabs.getTabs().indexOf(tab); tabs.getTabs() .removeAll(tabs.getTabs().stream() - .filter(t -> tabs.getTabs().indexOf(t) < index) + .filter(t -> tabs.getTabs().indexOf(t) < index && t.isClosable()) .toList()); event.consume(); }); @@ -301,7 +341,7 @@ public class BrowserSessionTabsComp extends SimpleComp { var index = tabs.getTabs().indexOf(tab); tabs.getTabs() .removeAll(tabs.getTabs().stream() - .filter(t -> tabs.getTabs().indexOf(t) > index) + .filter(t -> tabs.getTabs().indexOf(t) > index && t.isClosable()) .toList()); event.consume(); }); @@ -311,7 +351,9 @@ public class BrowserSessionTabsComp extends SimpleComp { closeAll.setAccelerator( new KeyCodeCombination(KeyCode.W, KeyCombination.SHORTCUT_DOWN, KeyCombination.SHIFT_DOWN)); closeAll.setOnAction(event -> { - tabs.getTabs().clear(); + tabs.getTabs() + .removeAll( + tabs.getTabs().stream().filter(t -> t.isClosable()).toList()); event.consume(); }); cm.getItems().add(closeAll); @@ -319,36 +361,92 @@ public class BrowserSessionTabsComp extends SimpleComp { return cm; } - private Tab createTab(TabPane tabs, BrowserSessionTab model) { + private Tab createTab(TabPane tabs, BrowserSessionTab tabModel) { var tab = new Tab(); - tab.setContextMenu(createContextMenu(tabs, tab)); + tab.setContextMenu(createContextMenu(tabs, tab, tabModel)); - var ring = new RingProgressIndicator(0, false); - ring.setMinSize(16, 16); - ring.setPrefSize(16, 16); - ring.setMaxSize(16, 16); - ring.progressProperty() - .bind(Bindings.createDoubleBinding( - () -> model.getBusy().get() - && !AppPrefs.get().performanceMode().get() - ? -1d - : 0, - PlatformThread.sync(model.getBusy()), - AppPrefs.get().performanceMode())); + tab.setClosable(tabModel.isCloseable()); - var image = model.getEntry().get().getEffectiveIconFile(); - var logo = PrettyImageHelper.ofFixedSizeSquare(image, 16).createRegion(); + if (tabModel.getIcon() != null) { + var ring = new RingProgressIndicator(0, false); + ring.setMinSize(16, 16); + ring.setPrefSize(16, 16); + ring.setMaxSize(16, 16); + ring.progressProperty() + .bind(Bindings.createDoubleBinding( + () -> tabModel.getBusy().get() + && !AppPrefs.get().performanceMode().get() + ? -1d + : 0, + PlatformThread.sync(tabModel.getBusy()), + AppPrefs.get().performanceMode())); - tab.graphicProperty() - .bind(Bindings.createObjectBinding( - () -> { - return model.getBusy().get() ? ring : logo; - }, - PlatformThread.sync(model.getBusy()))); - tab.setText(model.getName()); + var image = tabModel.getIcon(); + var logo = PrettyImageHelper.ofFixedSizeSquare(image, 16).createRegion(); - Comp comp = model.comp(); - tab.setContent(comp.createRegion()); + tab.graphicProperty() + .bind(Bindings.createObjectBinding( + () -> { + return tabModel.getBusy().get() ? ring : logo; + }, + PlatformThread.sync(tabModel.getBusy()))); + } + + if (tabModel.getBrowserModel() instanceof BrowserSessionModel sessionModel) { + var global = PlatformThread.sync(sessionModel.getGlobalPinnedTab()); + tab.textProperty().bind(Bindings.createStringBinding(() -> { + return tabModel.getName() + (global.getValue() == tabModel ? " (" + AppI18n.get("pinned") + ")" : ""); + }, global, AppPrefs.get().language())); + } else { + tab.setText(tabModel.getName()); + } + + Comp comp = tabModel.comp(); + var compRegion = comp.createRegion(); + var empty = new StackPane(); + empty.widthProperty().addListener((observable, oldValue, newValue) -> { + if (tabModel.isCloseable() && tabs.getSelectionModel().getSelectedItem() == tab) { + rightPadding.setValue(newValue.doubleValue()); + } + }); + var split = new SplitPane(compRegion); + if (tabModel.isCloseable()) { + split.getItems().add(empty); + } + model.getEffectiveRightTab().subscribe(browserSessionTab -> { + PlatformThread.runLaterIfNeeded(() -> { + if (browserSessionTab != null && split.getItems().size() > 1) { + split.getItems().set(1, empty); + } else if (browserSessionTab != null && split.getItems().size() == 1) { + split.getItems().add(empty); + } else if (browserSessionTab == null && split.getItems().size() > 1) { + split.getItems().remove(1); + } + }); + }); + tab.setContent(split); + +// var lastSplitRegion = new AtomicReference(); +// model.getGlobalPinnedTab().subscribe( (newValue) -> { +// PlatformThread.runLaterIfNeeded(() -> { +// if (newValue != null) { +// var r = newValue.comp().createRegion(); +// split.getItems().add(r); +// lastSplitRegion.set(r); +// } else if (split.getItems().size() > 1) { +// split.getItems().removeLast(); +// } +// }); +// }); +// model.getSelectedEntry().addListener((observable, oldValue, newValue) -> { +// PlatformThread.runLaterIfNeeded(() -> { +// if (newValue != null && newValue.equals(model.getGlobalPinnedTab().getValue()) && split.getItems().size() > 1) { +// split.getItems().remove(lastSplitRegion.get()); +// } else if (split.getItems().size() > 1 && !split.getItems().contains(lastSplitRegion.get())) { +// split.getItems().add(lastSplitRegion.get()); +// } +// }); +// }); var id = UUID.randomUUID().toString(); tab.setId(id); @@ -360,18 +458,20 @@ public class BrowserSessionTabsComp extends SimpleComp { var w = l.maxWidthProperty(); l.minWidthProperty().bind(w); l.prefWidthProperty().bind(w); + if (!tabModel.isCloseable()) { + l.pseudoClassStateChanged(PseudoClass.getPseudoClass("static"), true); + } var close = (StackPane) tabs.lookup("#" + id + " .tab-close-button"); close.setPrefWidth(30); StackPane c = (StackPane) tabs.lookup("#" + id + " .tab-container"); c.getStyleClass().add("color-box"); - var color = - DataStorage.get().getEffectiveColor(model.getEntry().get()); + var color = tabModel.getColor(); if (color != null) { c.getStyleClass().add(color.getId()); } - new TooltipAugment<>(new SimpleStringProperty(model.getTooltip()), null).augment(c); + new TooltipAugment<>(new SimpleStringProperty(tabModel.getTooltip()), null).augment(c); c.addEventHandler( DragEvent.DRAG_ENTERED, mouseEvent -> Platform.runLater( diff --git a/app/src/main/java/io/xpipe/app/browser/session/BrowserStoreSessionTab.java b/app/src/main/java/io/xpipe/app/browser/session/BrowserStoreSessionTab.java new file mode 100644 index 000000000..47efd378b --- /dev/null +++ b/app/src/main/java/io/xpipe/app/browser/session/BrowserStoreSessionTab.java @@ -0,0 +1,41 @@ +package io.xpipe.app.browser.session; + +import io.xpipe.app.fxcomps.Comp; +import io.xpipe.app.storage.DataColor; +import io.xpipe.app.storage.DataStorage; +import io.xpipe.app.storage.DataStoreEntryRef; +import io.xpipe.core.store.DataStore; + +import lombok.Getter; + +@Getter +public abstract class BrowserStoreSessionTab extends BrowserSessionTab { + + protected final DataStoreEntryRef entry; + + public BrowserStoreSessionTab(BrowserAbstractSessionModel browserModel, DataStoreEntryRef entry) { + super( + browserModel, + DataStorage.get().getStoreEntryDisplayName(entry.get()), + DataStorage.get().getStorePath(entry.getEntry()).toString()); + this.entry = entry; + } + + public abstract Comp comp(); + + public abstract boolean canImmediatelyClose(); + + public abstract void init() throws Exception; + + public abstract void close(); + + @Override + public String getIcon() { + return entry.get().getEffectiveIconFile(); + } + + @Override + public DataColor getColor() { + return DataStorage.get().getEffectiveColor(entry.get()); + } +} diff --git a/app/src/main/java/io/xpipe/app/comp/base/IntegratedTextAreaComp.java b/app/src/main/java/io/xpipe/app/comp/base/IntegratedTextAreaComp.java index 5105b1a9e..81cd96022 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/IntegratedTextAreaComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/IntegratedTextAreaComp.java @@ -68,7 +68,14 @@ public class IntegratedTextAreaComp extends Comp value.setValue(Files.readString(paths.getFirst()))); + paths -> { + var first = paths.getFirst(); + if (Files.size(first) > 1_000_000) { + return; + } + + value.setValue(Files.readString(first)); + }); var struc = fileDrop.createStructure(); return new Structure(struc.get(), struc.getCompStructure().getTextArea()); } diff --git a/app/src/main/java/io/xpipe/app/comp/base/SideSplitPaneComp.java b/app/src/main/java/io/xpipe/app/comp/base/LeftSplitPaneComp.java similarity index 89% rename from app/src/main/java/io/xpipe/app/comp/base/SideSplitPaneComp.java rename to app/src/main/java/io/xpipe/app/comp/base/LeftSplitPaneComp.java index be27910da..3e3515d19 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/SideSplitPaneComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/LeftSplitPaneComp.java @@ -11,14 +11,14 @@ import lombok.Value; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; -public class SideSplitPaneComp extends Comp { +public class LeftSplitPaneComp extends Comp { private final Comp left; private final Comp center; private Double initialWidth; private Consumer onDividerChange; - public SideSplitPaneComp(Comp left, Comp center) { + public LeftSplitPaneComp(Comp left, Comp center) { this.left = left; this.center = center; } @@ -58,12 +58,12 @@ public class SideSplitPaneComp extends Comp { return new Structure(sidebar, c, r, r.getDividers().getFirst()); } - public SideSplitPaneComp withInitialWidth(double val) { + public LeftSplitPaneComp withInitialWidth(double val) { this.initialWidth = val; return this; } - public SideSplitPaneComp withOnDividerChange(Consumer onDividerChange) { + public LeftSplitPaneComp withOnDividerChange(Consumer onDividerChange) { this.onDividerChange = onDividerChange; return this; } diff --git a/app/src/main/java/io/xpipe/app/comp/base/SideMenuBarComp.java b/app/src/main/java/io/xpipe/app/comp/base/SideMenuBarComp.java index 963fafcf9..2ef83b746 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/SideMenuBarComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/SideMenuBarComp.java @@ -1,6 +1,5 @@ package io.xpipe.app.comp.base; -import io.xpipe.app.core.AppCache; import io.xpipe.app.core.AppFont; import io.xpipe.app.core.AppLayoutModel; import io.xpipe.app.fxcomps.Comp; @@ -9,17 +8,13 @@ import io.xpipe.app.fxcomps.SimpleCompStructure; import io.xpipe.app.fxcomps.impl.IconButtonComp; import io.xpipe.app.fxcomps.impl.StackComp; import io.xpipe.app.fxcomps.impl.TooltipAugment; -import io.xpipe.app.fxcomps.util.LabelGraphic; import io.xpipe.app.fxcomps.util.PlatformThread; import io.xpipe.app.update.UpdateAvailableAlert; import io.xpipe.app.update.XPipeDistributionType; -import io.xpipe.app.util.Hyperlinks; import javafx.application.Platform; import javafx.beans.binding.Bindings; import javafx.beans.property.Property; -import javafx.beans.property.SimpleBooleanProperty; -import javafx.beans.property.SimpleStringProperty; import javafx.css.PseudoClass; import javafx.geometry.Insets; import javafx.geometry.Pos; @@ -27,9 +22,6 @@ import javafx.scene.control.Button; import javafx.scene.layout.*; import javafx.scene.paint.Color; -import java.time.Instant; -import java.time.ZoneId; -import java.time.ZonedDateTime; import java.util.List; public class SideMenuBarComp extends Comp> { @@ -50,14 +42,14 @@ public class SideMenuBarComp extends Comp> { var selectedBorder = Bindings.createObjectBinding( () -> { var c = Platform.getPreferences().getAccentColor().desaturate(); - return new Background(new BackgroundFill(c, new CornerRadii(8), new Insets(10, 1, 10, 2))); + return new Background(new BackgroundFill(c, new CornerRadii(8), new Insets(12, 1, 12, 2))); }, Platform.getPreferences().accentColorProperty()); var hoverBorder = Bindings.createObjectBinding( () -> { var c = Platform.getPreferences().getAccentColor().darker().desaturate(); - return new Background(new BackgroundFill(c, new CornerRadii(8), new Insets(10, 1, 10, 2))); + return new Background(new BackgroundFill(c, new CornerRadii(8), new Insets(12, 1, 12, 2))); }, Platform.getPreferences().accentColorProperty()); @@ -141,29 +133,6 @@ public class SideMenuBarComp extends Comp> { vbox.getChildren().add(b.createRegion()); } - { - var zone = ZoneId.of(ZoneId.SHORT_IDS.get("PST")); - var now = Instant.now(); - var phStart = ZonedDateTime.of(2024, 10, 22, 0, 1, 0, 0, zone).toInstant(); - var phEnd = ZonedDateTime.of(2024, 10, 23, 0, 1, 0, 0, zone).toInstant(); - var clicked = AppCache.get("phClicked", Boolean.class, () -> false); - var phShow = now.isAfter(phStart) && now.isBefore(phEnd) && !clicked; - if (phShow) { - var hide = new SimpleBooleanProperty(false); - var b = new IconButtonComp(new LabelGraphic.ImageGraphic("app:producthunt-color.png", 24), () -> { - AppCache.update("phClicked", true); - Hyperlinks.open(Hyperlinks.PRODUCT_HUNT); - hide.set(true); - }) - .tooltip(new SimpleStringProperty("Product Hunt")); - b.apply(struc -> { - AppFont.setSize(struc.get(), 1); - }); - b.hide(hide); - vbox.getChildren().add(b.createRegion()); - } - } - var filler = new Button(); filler.setDisable(true); filler.setMaxHeight(3000); diff --git a/app/src/main/java/io/xpipe/app/comp/store/DenseStoreEntryComp.java b/app/src/main/java/io/xpipe/app/comp/store/DenseStoreEntryComp.java index 38b2160b8..7dc6b7165 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/DenseStoreEntryComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/DenseStoreEntryComp.java @@ -95,7 +95,16 @@ public class DenseStoreEntryComp extends StoreEntryComp { nameCC.setMinWidth(100); nameCC.setHgrow(Priority.ALWAYS); grid.getColumnConstraints().addAll(nameCC); + + var active = new StoreActiveComp(getWrapper()).createRegion(); var nameBox = new HBox(name, notes); + getWrapper().getSessionActive().subscribe(aBoolean -> { + if (!aBoolean) { + nameBox.getChildren().remove(active); + } else { + nameBox.getChildren().add(1, active); + } + }); nameBox.setSpacing(6); nameBox.setAlignment(Pos.CENTER_LEFT); grid.addRow(0, nameBox); diff --git a/app/src/main/java/io/xpipe/app/comp/store/StandardStoreEntryComp.java b/app/src/main/java/io/xpipe/app/comp/store/StandardStoreEntryComp.java index 4d2914f23..6b67d4d40 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StandardStoreEntryComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StandardStoreEntryComp.java @@ -41,11 +41,19 @@ public class StandardStoreEntryComp extends StoreEntryComp { grid.add(storeIcon, 0, 0, 1, 2); grid.getColumnConstraints().add(new ColumnConstraints(56)); - var nameAndNotes = new HBox(name, notes); - nameAndNotes.setSpacing(6); - nameAndNotes.setAlignment(Pos.CENTER_LEFT); - grid.add(nameAndNotes, 1, 0); - GridPane.setVgrow(nameAndNotes, Priority.ALWAYS); + var active = new StoreActiveComp(getWrapper()).createRegion(); + var nameBox = new HBox(name, notes); + nameBox.setSpacing(6); + nameBox.setAlignment(Pos.CENTER_LEFT); + grid.add(nameBox, 1, 0); + GridPane.setVgrow(nameBox, Priority.ALWAYS); + getWrapper().getSessionActive().subscribe(aBoolean -> { + if (!aBoolean) { + nameBox.getChildren().remove(active); + } else { + nameBox.getChildren().add(1, active); + } + }); var summaryBox = new HBox(createSummary()); summaryBox.setAlignment(Pos.TOP_LEFT); diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreActiveComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreActiveComp.java new file mode 100644 index 000000000..89d5afed2 --- /dev/null +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreActiveComp.java @@ -0,0 +1,38 @@ +package io.xpipe.app.comp.store; + +import io.xpipe.app.fxcomps.SimpleComp; +import io.xpipe.app.fxcomps.impl.TooltipAugment; + +import javafx.geometry.Pos; +import javafx.scene.input.MouseButton; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.scene.shape.Circle; + +public class StoreActiveComp extends SimpleComp { + + private final StoreEntryWrapper wrapper; + + public StoreActiveComp(StoreEntryWrapper wrapper) { + this.wrapper = wrapper; + } + + @Override + protected Region createSimple() { + var c = new Circle(6); + c.getStyleClass().add("dot"); + c.addEventFilter(MouseEvent.MOUSE_PRESSED, event -> { + if (event.getButton() == MouseButton.PRIMARY) { + wrapper.stopSession(); + event.consume(); + } + }); + var pane = new StackPane(c); + pane.setAlignment(Pos.CENTER); + pane.visibleProperty().bind(wrapper.getSessionActive()); + pane.getStyleClass().add("store-active-comp"); + new TooltipAugment<>("sessionActive", null).augment(pane); + return pane; + } +} diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreCreationComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreCreationComp.java index e0dd41b68..e8201c452 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreCreationComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreCreationComp.java @@ -20,7 +20,7 @@ import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStoreEntry; import io.xpipe.app.util.*; import io.xpipe.core.store.DataStore; -import io.xpipe.core.store.ValidationContext; +import io.xpipe.core.store.ValidatableStore; import io.xpipe.core.util.ValidationException; import javafx.application.Platform; @@ -157,6 +157,17 @@ public class StoreCreationComp extends DialogComp { }, name, store); + + skippable.bind(Bindings.createBooleanBinding( + () -> { + if (name.get() != null && store.get().isComplete() && store.get() instanceof ValidatableStore) { + return true; + } else { + return false; + } + }, + store, + name)); } public static void showEdit(DataStoreEntry e) { @@ -165,11 +176,8 @@ public class StoreCreationComp extends DialogComp { e.getProvider(), e.getStore(), v -> true, - (newE, context, validated) -> { + (newE, validated) -> { ThreadHelper.runAsync(() -> { - if (context != null) { - context.close(); - } if (!DataStorage.get().getStoreEntries().contains(e)) { DataStorage.get().addStoreEntryIfNotPresent(newE); } else { @@ -191,21 +199,22 @@ public class StoreCreationComp extends DialogComp { } public static void showCreation(DataStore base, DataStoreCreationCategory category) { + var prov = base != null ? DataStoreProviders.byStore(base) : null; show( null, - base != null ? DataStoreProviders.byStore(base) : null, + prov, base, - dataStoreProvider -> category.equals(dataStoreProvider.getCreationCategory()), - (e, context, validated) -> { + dataStoreProvider -> (category != null && category.equals(dataStoreProvider.getCreationCategory())) + || dataStoreProvider.equals(prov), + (e, validated) -> { try { DataStorage.get().addStoreEntryIfNotPresent(e); - if (context != null - && validated + if (validated && e.getProvider().shouldShowScan() && AppPrefs.get() .openConnectionSearchWindowOnConnectionCreation() .get()) { - ScanAlert.showAsync(e, context); + ScanAlert.showAsync(e); } } catch (Exception ex) { ErrorEvent.fromThrowable(ex).handle(); @@ -217,7 +226,7 @@ public class StoreCreationComp extends DialogComp { public interface CreationConsumer { - void consume(DataStoreEntry entry, ValidationContext validationContext, boolean validated); + void consume(DataStoreEntry entry, boolean validated); } private static void show( @@ -254,9 +263,9 @@ public class StoreCreationComp extends DialogComp { @Override protected List> customButtons() { return List.of( - new ButtonComp(AppI18n.observable("skip"), null, () -> { + new ButtonComp(AppI18n.observable("skipValidation"), null, () -> { if (showInvalidConfirmAlert()) { - commit(null, false); + commit(false); } else { finish(); } @@ -299,7 +308,7 @@ public class StoreCreationComp extends DialogComp { // We didn't change anything if (existingEntry != null && existingEntry.getStore().equals(store.getValue())) { - commit(null, false); + commit(false); return; } @@ -329,18 +338,14 @@ public class StoreCreationComp extends DialogComp { try (var ignored = new BooleanScope(busy).start()) { DataStorage.get().addStoreEntryInProgress(entry.getValue()); - var context = entry.getValue().validateAndKeepOpenOrThrowAndClose(null); - commit(context, true); + entry.getValue().validateOrThrow(); + commit(true); } catch (Throwable ex) { if (ex instanceof ValidationException) { ErrorEvent.expected(ex); - skippable.set(false); } else if (ex instanceof StackOverflowError) { // Cycles in connection graphs can fail hard but are expected ErrorEvent.expected(ex); - skippable.set(false); - } else { - skippable.set(true); } var newMessage = ExceptionConverter.convertMessage(ex); @@ -415,14 +420,14 @@ public class StoreCreationComp extends DialogComp { .createRegion(); } - private void commit(ValidationContext validationContext, boolean validated) { + private void commit(boolean validated) { if (finished.get()) { return; } finished.setValue(true); if (entry.getValue() != null) { - consumer.consume(entry.getValue(), validationContext, validated); + consumer.consume(entry.getValue(), validated); } PlatformThread.runLaterIfNeeded(() -> { @@ -433,7 +438,7 @@ public class StoreCreationComp extends DialogComp { private Region createLayout() { var layout = new BorderPane(); layout.getStyleClass().add("store-creator"); - var providerChoice = new StoreProviderChoiceComp(filter, provider, staticDisplay); + var providerChoice = new StoreProviderChoiceComp(filter, provider); var showProviders = (!staticDisplay && (providerChoice.getProviders().size() > 1 || providerChoice.getProviders().getFirst().showProviderChoice())) diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreCreationMenu.java b/app/src/main/java/io/xpipe/app/comp/store/StoreCreationMenu.java index df546265f..c3a932d78 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreCreationMenu.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreCreationMenu.java @@ -22,7 +22,7 @@ public class StoreCreationMenu { automatically.setGraphic(new FontIcon("mdi2e-eye-plus-outline")); automatically.textProperty().bind(AppI18n.observable("addAutomatically")); automatically.setOnAction(event -> { - ScanAlert.showAsync(null, null); + ScanAlert.showAsync(null); event.consume(); }); menu.getItems().add(automatically); @@ -32,13 +32,11 @@ public class StoreCreationMenu { menu.getItems().add(category("addDesktop", "mdi2c-camera-plus", DataStoreCreationCategory.DESKTOP, null)); - menu.getItems() - .add(category( - "addShell", "mdi2t-text-box-multiple", DataStoreCreationCategory.SHELL, "shellEnvironment")); - menu.getItems() .add(category("addScript", "mdi2s-script-text-outline", DataStoreCreationCategory.SCRIPT, "script")); + menu.getItems().add(category("addCommand", "mdi2c-code-greater-than", DataStoreCreationCategory.COMMAND, null)); + menu.getItems() .add(category( "addTunnel", "mdi2v-vector-polyline-plus", DataStoreCreationCategory.TUNNEL, "customService")); diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryComp.java index 7f74eeafe..ecdf73d14 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryComp.java @@ -439,7 +439,8 @@ public abstract class StoreEntryComp extends SimpleComp { && !LicenseProvider.get().getFeature(p.getProFeatureId()).isSupported(); if (proRequired) { item.setDisable(true); - item.textProperty().bind(Bindings.createStringBinding(() -> name.getValue() + " (Pro)", name)); + item.textProperty() + .bind(LicenseProvider.get().getFeature(p.getProFeatureId()).suffixObservable(name.getValue())); } else { item.textProperty().bind(name); } diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryListComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryListComp.java index 71474e3f7..ea9e69f1b 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryListComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryListComp.java @@ -2,11 +2,13 @@ package io.xpipe.app.comp.store; import io.xpipe.app.comp.base.ListBoxViewComp; import io.xpipe.app.comp.base.MultiContentComp; +import io.xpipe.app.core.AppCache; import io.xpipe.app.core.AppLayoutModel; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.SimpleComp; import javafx.beans.binding.Bindings; +import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.value.ObservableValue; import javafx.scene.layout.Region; @@ -34,18 +36,23 @@ public class StoreEntryListComp extends SimpleComp { StoreViewState.get().getActiveCategory().addListener((observable, oldValue, newValue) -> { struc.get().setVvalue(0); }); - }); - content.apply(struc -> { + // Reset scroll AppLayoutModel.get().getSelected().addListener((observable, oldValue, newValue) -> { struc.get().setVvalue(0); }); + + // Reset scroll + StoreViewState.get().getFilterString().addListener((observable, oldValue, newValue) -> { + struc.get().setVvalue(0); + }); }); return content.styleClass("store-list-comp"); } @Override protected Region createSimple() { + var scriptsIntroShowing = new SimpleBooleanProperty(!AppCache.getBoolean("scriptsIntroCompleted", false)); var initialCount = 1; var showIntro = Bindings.createBooleanBinding( () -> { @@ -63,6 +70,46 @@ public class StoreEntryListComp extends SimpleComp { }, StoreViewState.get().getAllEntries().getList(), StoreViewState.get().getActiveCategory()); + var showScriptsIntro = Bindings.createBooleanBinding( + () -> { + if (StoreViewState.get() + .getActiveCategory() + .getValue() + .getRoot() + .equals(StoreViewState.get().getAllScriptsCategory())) { + return scriptsIntroShowing.get(); + } + + return false; + }, + scriptsIntroShowing, + StoreViewState.get().getActiveCategory()); + var showList = Bindings.createBooleanBinding( + () -> { + if (StoreViewState.get() + .getActiveCategory() + .getValue() + .getRoot() + .equals(StoreViewState.get().getAllScriptsCategory())) { + return !scriptsIntroShowing.get(); + } + + if (StoreViewState.get() + .getCurrentTopLevelSection() + .getShownChildren() + .getList() + .isEmpty()) { + return false; + } + + return true; + }, + StoreViewState.get().getActiveCategory(), + scriptsIntroShowing, + StoreViewState.get() + .getCurrentTopLevelSection() + .getShownChildren() + .getList()); var map = new LinkedHashMap, ObservableValue>(); map.put( new StoreNotFoundComp(), @@ -73,13 +120,9 @@ public class StoreEntryListComp extends SimpleComp { .getCurrentTopLevelSection() .getShownChildren() .getList()))); - map.put( - createList(), - Bindings.not(Bindings.isEmpty(StoreViewState.get() - .getCurrentTopLevelSection() - .getShownChildren() - .getList()))); + map.put(createList(), showList); map.put(new StoreIntroComp(), showIntro); + map.put(new StoreScriptsIntroComp(scriptsIntroShowing), showScriptsIntro); return new MultiContentComp(map).createRegion(); } diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryListOverviewComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryListOverviewComp.java index 92a3640b5..a4483e82d 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryListOverviewComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryListOverviewComp.java @@ -83,13 +83,7 @@ public class StoreEntryListOverviewComp extends SimpleComp { return inRootCategory && showProvider; }, StoreViewState.get().getActiveCategory()); - var shownList = all.filtered( - storeEntryWrapper -> { - return storeEntryWrapper.matchesFilter( - StoreViewState.get().getFilterString().getValue()); - }, - StoreViewState.get().getFilterString()); - var count = new CountComp<>(shownList.getList(), all.getList()); + var count = new CountComp<>(all.getList(), all.getList()); var c = count.createRegion(); var topBar = new HBox( 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 4e43f2087..f3f7a89a0 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 @@ -9,6 +9,7 @@ import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStoreCategory; import io.xpipe.app.storage.DataStoreEntry; import io.xpipe.app.util.ThreadHelper; +import io.xpipe.core.store.SingletonSessionStore; import javafx.beans.property.*; import javafx.collections.FXCollections; @@ -44,6 +45,7 @@ public class StoreEntryWrapper { private final Property notes; private final Property customIcon = new SimpleObjectProperty<>(); private final Property iconFile = new SimpleObjectProperty<>(); + private final BooleanProperty sessionActive = new SimpleBooleanProperty(); public StoreEntryWrapper(DataStoreEntry entry) { this.entry = entry; @@ -118,7 +120,15 @@ public class StoreEntryWrapper { }); } - public void update() { + public void stopSession() { + ThreadHelper.runFailableAsync(() -> { + if (entry.getStore() instanceof SingletonSessionStore singletonSessionStore) { + singletonSessionStore.stopSessionIfNeeded(); + } + }); + } + + public synchronized void update() { // We are probably in shutdown then if (StoreViewState.get() == null) { return; @@ -147,6 +157,7 @@ public class StoreEntryWrapper { busy.setValue(entry.getBusyCounter().get() != 0); deletable.setValue(entry.getConfiguration().isDeletable() || AppPrefs.get().developerDisableGuiRestrictions().getValue()); + sessionActive.setValue(entry.getStore() instanceof SingletonSessionStore ss && ss.isSessionRunning()); category.setValue(StoreViewState.get() .getCategoryWrapper(DataStorage.get() @@ -220,7 +231,7 @@ public class StoreEntryWrapper { } public void refreshChildren() { - var hasChildren = DataStorage.get().refreshChildren(entry, null); + var hasChildren = DataStorage.get().refreshChildren(entry); PlatformThread.runLaterIfNeeded(() -> { expanded.set(hasChildren); }); diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreIntroComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreIntroComp.java index c427fca82..6ae9626f3 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreIntroComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreIntroComp.java @@ -39,7 +39,7 @@ public class StoreIntroComp extends SimpleComp { var scanButton = new Button(null, new FontIcon("mdi2m-magnify")); scanButton.textProperty().bind(AppI18n.observable("detectConnections")); - scanButton.setOnAction(event -> ScanAlert.showAsync(DataStorage.get().local(), null)); + scanButton.setOnAction(event -> ScanAlert.showAsync(DataStorage.get().local())); scanButton.setDefaultButton(true); var scanPane = new StackPane(scanButton); scanPane.setAlignment(Pos.CENTER); diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreLayoutComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreLayoutComp.java index 85a43b6f0..c2efd99a3 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreLayoutComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreLayoutComp.java @@ -1,6 +1,6 @@ package io.xpipe.app.comp.store; -import io.xpipe.app.comp.base.SideSplitPaneComp; +import io.xpipe.app.comp.base.LeftSplitPaneComp; import io.xpipe.app.core.AppActionLinkDetector; import io.xpipe.app.core.AppLayoutModel; import io.xpipe.app.fxcomps.SimpleComp; @@ -15,7 +15,7 @@ public class StoreLayoutComp extends SimpleComp { @Override protected Region createSimple() { - var struc = new SideSplitPaneComp(new StoreSidebarComp(), new StoreEntryListComp()) + var struc = new LeftSplitPaneComp(new StoreSidebarComp(), new StoreEntryListComp()) .withInitialWidth(AppLayoutModel.get().getSavedState().getSidebarWidth()) .withOnDividerChange(aDouble -> { AppLayoutModel.get().getSavedState().setSidebarWidth(aDouble); diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreProviderChoiceComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreProviderChoiceComp.java index 1833e589c..f72e2f184 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreProviderChoiceComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreProviderChoiceComp.java @@ -27,7 +27,6 @@ public class StoreProviderChoiceComp extends Comp filter; Property provider; - boolean staticDisplay; public List getProviders() { return DataStoreProviders.getAll().stream() @@ -65,9 +64,7 @@ public class StoreProviderChoiceComp extends Comp p.getCreationCategory() != null || staticDisplay) - .toList(); + var l = getProviders(); l.forEach(dataStoreProvider -> cb.getItems().add(dataStoreProvider)); if (provider.getValue() == null) { provider.setValue(l.getFirst()); diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreScriptsIntroComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreScriptsIntroComp.java new file mode 100644 index 000000000..a5d0541ed --- /dev/null +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreScriptsIntroComp.java @@ -0,0 +1,126 @@ +package io.xpipe.app.comp.store; + +import io.xpipe.app.core.AppCache; +import io.xpipe.app.core.AppFont; +import io.xpipe.app.core.AppI18n; +import io.xpipe.app.fxcomps.SimpleComp; +import io.xpipe.core.process.OsType; + +import javafx.beans.property.BooleanProperty; +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; + +import atlantafx.base.theme.Styles; +import org.kordamp.ikonli.javafx.FontIcon; + +public class StoreScriptsIntroComp extends SimpleComp { + + private final BooleanProperty show; + + public StoreScriptsIntroComp(BooleanProperty show) { + this.show = show; + } + + private Region createIntro() { + var title = new Label(); + title.textProperty().bind(AppI18n.observable("scriptsIntroTitle")); + if (OsType.getLocal() != OsType.MACOS) { + title.getStyleClass().add(Styles.TEXT_BOLD); + } + AppFont.setSize(title, 7); + + var introDesc = new Label(); + introDesc.textProperty().bind(AppI18n.observable("scriptsIntroText")); + introDesc.setWrapText(true); + introDesc.setMaxWidth(470); + + var img = new FontIcon("mdi2s-script-text"); + img.setIconSize(80); + var text = new VBox(title, introDesc); + text.setSpacing(5); + text.setAlignment(Pos.CENTER_LEFT); + var hbox = new HBox(img, text); + hbox.setSpacing(55); + hbox.setAlignment(Pos.CENTER); + + var v = new VBox(hbox); + v.setMinWidth(Region.USE_PREF_SIZE); + v.setMaxWidth(Region.USE_PREF_SIZE); + v.setMinHeight(Region.USE_PREF_SIZE); + v.setMaxHeight(Region.USE_PREF_SIZE); + + v.setSpacing(10); + v.getStyleClass().add("intro"); + return v; + } + + private Region createBottom() { + var title = new Label(); + title.textProperty().bind(AppI18n.observable("scriptsIntroBottomTitle")); + if (OsType.getLocal() != OsType.MACOS) { + title.getStyleClass().add(Styles.TEXT_BOLD); + } + AppFont.setSize(title, 7); + + var importDesc = new Label(); + importDesc.textProperty().bind(AppI18n.observable("scriptsIntroBottomText")); + importDesc.setWrapText(true); + importDesc.setMaxWidth(470); + + var importButton = new Button(null, new FontIcon("mdi2p-play-circle")); + importButton.setDefaultButton(true); + importButton.textProperty().bind(AppI18n.observable("scriptsIntroStart")); + importButton.setOnAction(event -> { + AppCache.update("scriptsIntroCompleted", true); + show.set(false); + }); + var importPane = new StackPane(importButton); + importPane.setAlignment(Pos.CENTER); + + var fi = new FontIcon("mdi2t-tooltip-edit"); + fi.setIconSize(80); + var img = new StackPane(fi); + img.setPrefWidth(100); + img.setPrefHeight(150); + var text = new VBox(title, importDesc); + text.setSpacing(5); + text.setAlignment(Pos.CENTER_LEFT); + var hbox = new HBox(img, text); + hbox.setSpacing(35); + hbox.setAlignment(Pos.CENTER); + + var v = new VBox(hbox, importPane); + v.setMinWidth(Region.USE_PREF_SIZE); + v.setMaxWidth(Region.USE_PREF_SIZE); + v.setMinHeight(Region.USE_PREF_SIZE); + v.setMaxHeight(Region.USE_PREF_SIZE); + + v.setSpacing(20); + v.getStyleClass().add("intro"); + return v; + } + + @Override + public Region createSimple() { + var intro = createIntro(); + var introImport = createBottom(); + var v = new VBox(intro, introImport); + v.setSpacing(80); + v.setMinWidth(Region.USE_PREF_SIZE); + v.setMaxWidth(Region.USE_PREF_SIZE); + v.setMinHeight(Region.USE_PREF_SIZE); + v.setMaxHeight(Region.USE_PREF_SIZE); + + var sp = new StackPane(v); + sp.setPadding(new Insets(40, 0, 0, 0)); + sp.setAlignment(Pos.CENTER); + sp.setPickOnBounds(false); + return sp; + } +} diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreSidebarComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreSidebarComp.java index 78787f909..c82656ab4 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreSidebarComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreSidebarComp.java @@ -31,6 +31,7 @@ public class StoreSidebarComp extends SimpleComp { .styleClass("gray") .styleClass("bar") .styleClass("filler-bar") + .minHeight(10) .vgrow())); sideBar.apply(struc -> struc.get().setFillWidth(true)); sideBar.styleClass("sidebar"); diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreViewState.java b/app/src/main/java/io/xpipe/app/comp/store/StoreViewState.java index 3bf5c1aab..7dfb94dda 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreViewState.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreViewState.java @@ -126,7 +126,7 @@ public class StoreViewState { activeCategory.addListener((observable, oldValue, newValue) -> { DataStorage.get().setSelectedCategory(newValue.getCategory()); }); - var selected = AppCache.get("selectedCategory", UUID.class, () -> DataStorage.DEFAULT_CATEGORY_UUID); + var selected = AppCache.getNonNull("selectedCategory", UUID.class, () -> DataStorage.DEFAULT_CATEGORY_UUID); activeCategory.setValue(categories.getList().stream() .filter(storeCategoryWrapper -> storeCategoryWrapper.getCategory().getUuid().equals(selected)) diff --git a/app/src/main/java/io/xpipe/app/core/AppCache.java b/app/src/main/java/io/xpipe/app/core/AppCache.java index 6872a05c6..2eefcf098 100644 --- a/app/src/main/java/io/xpipe/app/core/AppCache.java +++ b/app/src/main/java/io/xpipe/app/core/AppCache.java @@ -4,23 +4,20 @@ import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.util.JsonConfigHelper; import io.xpipe.core.util.JacksonMapper; +import lombok.Getter; +import lombok.Setter; import org.apache.commons.io.FileUtils; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.util.Optional; import java.util.function.Supplier; public class AppCache { - public static Optional getIfPresent(String key, Class type) { - return Optional.ofNullable(get(key, type, () -> null)); - } - - private static Path getBasePath() { - return AppProperties.get().getDataDir().resolve("cache"); - } + @Getter + @Setter + private static Path basePath; private static Path getPath(String key) { var name = key + ".cache"; @@ -47,7 +44,33 @@ public class AppCache { } @SuppressWarnings("unchecked") - public static T get(String key, Class type, Supplier notPresent) { + public static T getNonNull(String key, Class type, Supplier notPresent) { + var path = getPath(key); + if (Files.exists(path)) { + try { + var tree = JsonConfigHelper.readRaw(path); + if (tree.isMissingNode() || tree.isNull()) { + FileUtils.deleteQuietly(path.toFile()); + return notPresent.get(); + } + + var r = (T) JacksonMapper.getDefault().treeToValue(tree, type); + if (r == null || !type.isAssignableFrom(r.getClass())) { + FileUtils.deleteQuietly(path.toFile()); + return notPresent.get(); + } else { + return r; + } + } catch (Exception ex) { + ErrorEvent.fromThrowable(ex).omit().handle(); + FileUtils.deleteQuietly(path.toFile()); + } + } + return notPresent != null ? notPresent.get() : null; + } + + @SuppressWarnings("unchecked") + public static T getNullable(String key, Class type, Supplier notPresent) { var path = getPath(key); if (Files.exists(path)) { try { @@ -65,6 +88,25 @@ public class AppCache { return notPresent != null ? notPresent.get() : null; } + public static boolean getBoolean(String key, boolean notPresent) { + var path = getPath(key); + if (Files.exists(path)) { + try { + var tree = JsonConfigHelper.readRaw(path); + if (!tree.isBoolean()) { + FileUtils.deleteQuietly(path.toFile()); + return notPresent; + } + + return tree.asBoolean(); + } catch (Exception ex) { + ErrorEvent.fromThrowable(ex).omit().handle(); + FileUtils.deleteQuietly(path.toFile()); + } + } + return notPresent; + } + public static void update(String key, T val) { var path = getPath(key); @@ -79,12 +121,4 @@ public class AppCache { .handle(); } } - - public T getValue(String key, Class type, Supplier notPresent) { - return get(key, type, notPresent); - } - - public void updateValue(String key, T val) { - update(key, val); - } } diff --git a/app/src/main/java/io/xpipe/app/core/AppExtensionManager.java b/app/src/main/java/io/xpipe/app/core/AppExtensionManager.java index 337c27e44..0af537d49 100644 --- a/app/src/main/java/io/xpipe/app/core/AppExtensionManager.java +++ b/app/src/main/java/io/xpipe/app/core/AppExtensionManager.java @@ -140,7 +140,7 @@ public class AppExtensionManager { } private void loadAllExtensions() { - for (var ext : List.of("jdbc", "proc", "uacc")) { + for (var ext : List.of("proc", "uacc")) { var extension = findAndParseExtension(ext, baseLayer) .orElseThrow(() -> ExtensionException.corrupt("Missing module " + ext)); loadedExtensions.add(extension); diff --git a/app/src/main/java/io/xpipe/app/core/AppGreetings.java b/app/src/main/java/io/xpipe/app/core/AppGreetings.java index 4d061087d..bf0a25209 100644 --- a/app/src/main/java/io/xpipe/app/core/AppGreetings.java +++ b/app/src/main/java/io/xpipe/app/core/AppGreetings.java @@ -52,7 +52,7 @@ public class AppGreetings { } public static void showIfNeeded() { - boolean set = AppCache.get("legalAccepted", Boolean.class, () -> false); + boolean set = AppCache.getBoolean("legalAccepted", false); if (set || AppProperties.get().isDevelopmentEnvironment()) { return; } diff --git a/app/src/main/java/io/xpipe/app/core/AppLayoutModel.java b/app/src/main/java/io/xpipe/app/core/AppLayoutModel.java index 1a2420874..2afca9050 100644 --- a/app/src/main/java/io/xpipe/app/core/AppLayoutModel.java +++ b/app/src/main/java/io/xpipe/app/core/AppLayoutModel.java @@ -48,7 +48,7 @@ public class AppLayoutModel { } public static void init() { - var state = AppCache.get("layoutState", SavedState.class, () -> new SavedState(260, 300)); + var state = AppCache.getNonNull("layoutState", SavedState.class, () -> new SavedState(260, 300)); INSTANCE = new AppLayoutModel(state); } 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 0a18c8d45..db923b6ec 100644 --- a/app/src/main/java/io/xpipe/app/core/AppProperties.java +++ b/app/src/main/java/io/xpipe/app/core/AppProperties.java @@ -44,6 +44,8 @@ public class AppProperties { boolean locatorVersionCheck; boolean isTest; boolean autoAcceptEula; + UUID uuid; + boolean initialLaunch; public AppProperties() { var appDir = Path.of(System.getProperty("user.dir")).resolve("app"); @@ -113,6 +115,15 @@ public class AppProperties { autoAcceptEula = Optional.ofNullable(System.getProperty("io.xpipe.app.acceptEula")) .map(Boolean::parseBoolean) .orElse(false); + AppCache.setBasePath(dataDir.resolve("cache")); + UUID id = AppCache.getNonNull("uuid", UUID.class, null); + if (id == null) { + uuid = UUID.randomUUID(); + AppCache.update("uuid", uuid); + } else { + uuid = id; + } + initialLaunch = AppCache.getNonNull("lastBuild", String.class, () -> null) == null; } private static boolean isJUnitTest() { diff --git a/app/src/main/java/io/xpipe/app/core/AppState.java b/app/src/main/java/io/xpipe/app/core/AppState.java deleted file mode 100644 index 9c830f8ac..000000000 --- a/app/src/main/java/io/xpipe/app/core/AppState.java +++ /dev/null @@ -1,48 +0,0 @@ -package io.xpipe.app.core; - -import lombok.Setter; -import lombok.Value; -import lombok.experimental.NonFinal; - -import java.util.UUID; - -@Value -public class AppState { - - private static AppState INSTANCE; - - UUID userId; - boolean initialLaunch; - - @NonFinal - @Setter - String userName; - - @NonFinal - @Setter - String userEmail; - - public AppState() { - UUID id = AppCache.get("userId", UUID.class, null); - if (id == null) { - initialLaunch = AppCache.getIfPresent("lastBuild", String.class).isEmpty(); - userId = UUID.randomUUID(); - AppCache.update("userId", userId); - } else { - userId = id; - initialLaunch = false; - } - } - - public static void init() { - if (INSTANCE != null) { - return; - } - - INSTANCE = new AppState(); - } - - public static AppState get() { - return INSTANCE; - } -} diff --git a/app/src/main/java/io/xpipe/app/core/AppStyle.java b/app/src/main/java/io/xpipe/app/core/AppStyle.java index 44486a20e..96c78ba25 100644 --- a/app/src/main/java/io/xpipe/app/core/AppStyle.java +++ b/app/src/main/java/io/xpipe/app/core/AppStyle.java @@ -18,6 +18,7 @@ import java.util.*; public class AppStyle { private static final Map STYLESHEET_CONTENTS = new LinkedHashMap<>(); + private static final Map THEME_SPECIFIC_STYLESHEET_CONTENTS = new LinkedHashMap<>(); private static final List scenes = new ArrayList<>(); private static String FONT_CONTENTS = ""; @@ -33,6 +34,9 @@ public class AppStyle { AppPrefs.get().useSystemFont().addListener((c, o, n) -> { changeFontUsage(n); }); + AppPrefs.get().theme.addListener((c, o, n) -> { + changeTheme(n); + }); } } @@ -73,6 +77,19 @@ public class AppStyle { }); }); } + + AppResources.with(AppResources.XPIPE_MODULE, "theme", path -> { + if (!Files.exists(path)) { + return; + } + + for (AppTheme.Theme theme : AppTheme.Theme.ALL) { + var file = path.resolve(theme.getId() + ".css"); + var bytes = Files.readAllBytes(file); + var s = "data:text/css;base64," + Base64.getEncoder().encodeToString(bytes); + THEME_SPECIFIC_STYLESHEET_CONTENTS.put(theme, s); + } + }); } private static void changeFontUsage(boolean use) { @@ -87,8 +104,16 @@ public class AppStyle { } } + private static void changeTheme(AppTheme.Theme theme) { + scenes.forEach(scene -> { + scene.getStylesheets().removeAll(THEME_SPECIFIC_STYLESHEET_CONTENTS.values()); + scene.getStylesheets().add(THEME_SPECIFIC_STYLESHEET_CONTENTS.get(theme)); + }); + } + public static void reloadStylesheets(Scene scene) { STYLESHEET_CONTENTS.clear(); + THEME_SPECIFIC_STYLESHEET_CONTENTS.clear(); FONT_CONTENTS = ""; init(); @@ -107,7 +132,7 @@ public class AppStyle { if (AppPrefs.get() != null) { var t = AppPrefs.get().theme.get(); if (t != null) { - scene.getStylesheets().addAll(t.getAdditionalStylesheets()); + scene.getStylesheets().add(THEME_SPECIFIC_STYLESHEET_CONTENTS.get(t)); } } TrackEvent.debug("Added stylesheets for scene"); diff --git a/app/src/main/java/io/xpipe/app/core/AppTheme.java b/app/src/main/java/io/xpipe/app/core/AppTheme.java index 186690bbc..5687952ee 100644 --- a/app/src/main/java/io/xpipe/app/core/AppTheme.java +++ b/app/src/main/java/io/xpipe/app/core/AppTheme.java @@ -97,7 +97,10 @@ public class AppTheme { } try { - if (AppPrefs.get().theme.getValue() == null) { + var lastSystemDark = AppCache.getBoolean("lastTheme", false); + var nowDark = Platform.getPreferences().getColorScheme() == ColorScheme.DARK; + AppCache.update("lastTheme", nowDark); + if (AppPrefs.get().theme.getValue() == null || lastSystemDark != nowDark) { setDefault(); } @@ -237,7 +240,7 @@ public class AppTheme { public static final Theme CUPERTINO_LIGHT = new Theme("cupertinoLight", "cupertino", new CupertinoLight()); public static final Theme CUPERTINO_DARK = new Theme("cupertinoDark", "cupertino", new CupertinoDark()); public static final Theme DRACULA = new Theme("dracula", "dracula", new Dracula()); - public static final Theme MOCHA = new DerivedTheme("mocha", "primer", "Mocha", new PrimerDark()); + public static final Theme MOCHA = new DerivedTheme("mocha", "mocha", "Mocha", new PrimerDark()); // Adjust this to create your own theme public static final Theme CUSTOM = new DerivedTheme("custom", "primer", "Custom", new PrimerDark()); diff --git a/app/src/main/java/io/xpipe/app/core/check/AppAvCheck.java b/app/src/main/java/io/xpipe/app/core/check/AppAvCheck.java index d75c301cb..2aa1c5a72 100644 --- a/app/src/main/java/io/xpipe/app/core/check/AppAvCheck.java +++ b/app/src/main/java/io/xpipe/app/core/check/AppAvCheck.java @@ -3,7 +3,6 @@ package io.xpipe.app.core.check; import io.xpipe.app.comp.base.MarkdownComp; import io.xpipe.app.core.AppI18n; import io.xpipe.app.core.AppProperties; -import io.xpipe.app.core.AppState; import io.xpipe.app.core.AppStyle; import io.xpipe.app.core.mode.OperationMode; import io.xpipe.app.core.window.AppWindowHelper; @@ -35,7 +34,7 @@ public class AppAvCheck { public static void check() throws Throwable { // Only show this on first launch on windows - if (OsType.getLocal() != OsType.WINDOWS || !AppState.get().isInitialLaunch()) { + if (OsType.getLocal() != OsType.WINDOWS || !AppProperties.get().isInitialLaunch()) { return; } diff --git a/app/src/main/java/io/xpipe/app/core/check/AppJavaOptionsCheck.java b/app/src/main/java/io/xpipe/app/core/check/AppJavaOptionsCheck.java index e1715a608..5dd5357dd 100644 --- a/app/src/main/java/io/xpipe/app/core/check/AppJavaOptionsCheck.java +++ b/app/src/main/java/io/xpipe/app/core/check/AppJavaOptionsCheck.java @@ -6,7 +6,7 @@ import io.xpipe.app.issue.ErrorEvent; public class AppJavaOptionsCheck { public static void check() { - if (AppCache.get("javaOptionsWarningShown", Boolean.class, () -> false)) { + if (AppCache.getBoolean("javaOptionsWarningShown", false)) { return; } 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 cabdad67e..6e41e6463 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 @@ -105,12 +105,17 @@ public abstract class OperationMode { return; } + // Handle any startup uncaught errors + if (OperationMode.isInStartup() && thread.threadId() == 1) { + ex.printStackTrace(); + OperationMode.halt(1); + } + ErrorEvent.fromThrowable(ex).unhandled(true).build().handle(); }); TrackEvent.info("Initial setup"); AppProperties.init(); - AppState.init(); XPipeSession.init(AppProperties.get().getBuildUuid()); AppUserDirectoryCheck.check(); AppTempCheck.check(); diff --git a/app/src/main/java/io/xpipe/app/core/mode/PlatformMode.java b/app/src/main/java/io/xpipe/app/core/mode/PlatformMode.java index 3499dd5e6..b3d578ae3 100644 --- a/app/src/main/java/io/xpipe/app/core/mode/PlatformMode.java +++ b/app/src/main/java/io/xpipe/app/core/mode/PlatformMode.java @@ -56,7 +56,7 @@ public abstract class PlatformMode extends OperationMode { // If we downloaded an update, and decided to no longer automatically update, don't remind us! // You can still update manually in the about tab - if (AppPrefs.get().automaticallyUpdate().get()) { + if (AppPrefs.get().automaticallyUpdate().get() || AppPrefs.get().checkForSecurityUpdates().get()) { UpdateAvailableAlert.showIfNeeded(); } diff --git a/app/src/main/java/io/xpipe/app/core/window/AppMainWindow.java b/app/src/main/java/io/xpipe/app/core/window/AppMainWindow.java index c7eab9f37..f841d44c9 100644 --- a/app/src/main/java/io/xpipe/app/core/window/AppMainWindow.java +++ b/app/src/main/java/io/xpipe/app/core/window/AppMainWindow.java @@ -231,7 +231,7 @@ public class AppMainWindow { return null; } - WindowState state = AppCache.get("windowState", WindowState.class, () -> null); + WindowState state = AppCache.getNonNull("windowState", WindowState.class, () -> null); if (state == null) { return null; } diff --git a/app/src/main/java/io/xpipe/app/ext/LocalStore.java b/app/src/main/java/io/xpipe/app/ext/LocalStore.java index ab23d77a1..dd4d4d98d 100644 --- a/app/src/main/java/io/xpipe/app/ext/LocalStore.java +++ b/app/src/main/java/io/xpipe/app/ext/LocalStore.java @@ -4,7 +4,6 @@ import io.xpipe.core.process.ShellControl; import io.xpipe.core.process.ShellStoreState; import io.xpipe.core.store.DataStore; import io.xpipe.core.store.NetworkTunnelStore; -import io.xpipe.core.store.ShellStore; import io.xpipe.core.store.StatefulDataStore; import io.xpipe.core.util.JacksonizedValue; @@ -19,18 +18,22 @@ public class LocalStore extends JacksonizedValue return ShellStoreState.class; } - @Override - public ShellControl parentControl() { - var pc = ProcessControlProvider.get().createLocalProcessControl(true); - pc.withSourceStore(this); - pc.withShellStateInit(this); - pc.withShellStateFail(this); - return pc; + public ShellControl control(ShellControl parent) { + return parent; } @Override - public ShellControl control(ShellControl parent) { - return parent; + public ShellControlFunction shellFunction() { + return new ShellControlFunction() { + @Override + public ShellControl control() throws Exception { + var pc = ProcessControlProvider.get().createLocalProcessControl(true); + pc.withSourceStore(LocalStore.this); + pc.withShellStateInit(LocalStore.this); + pc.withShellStateFail(LocalStore.this); + return pc; + } + }; } @Override diff --git a/app/src/main/java/io/xpipe/app/ext/PrefsHandler.java b/app/src/main/java/io/xpipe/app/ext/PrefsHandler.java index 961f3ed24..e75fd2b81 100644 --- a/app/src/main/java/io/xpipe/app/ext/PrefsHandler.java +++ b/app/src/main/java/io/xpipe/app/ext/PrefsHandler.java @@ -6,5 +6,5 @@ import javafx.beans.property.Property; public interface PrefsHandler { - void addSetting(String id, Class c, Property property, Comp comp); + void addSetting(String id, Class c, Property property, Comp comp, boolean requiresRestart); } diff --git a/app/src/main/java/io/xpipe/app/ext/ScanProvider.java b/app/src/main/java/io/xpipe/app/ext/ScanProvider.java index e7bae26a9..23c569577 100644 --- a/app/src/main/java/io/xpipe/app/ext/ScanProvider.java +++ b/app/src/main/java/io/xpipe/app/ext/ScanProvider.java @@ -2,7 +2,6 @@ package io.xpipe.app.ext; import io.xpipe.app.storage.DataStoreEntry; import io.xpipe.core.process.ShellControl; -import io.xpipe.core.util.FailableRunnable; import io.xpipe.core.util.ModuleLayerLoader; import lombok.AllArgsConstructor; @@ -21,31 +20,34 @@ public abstract class ScanProvider { return ALL; } - public ScanOperation create(DataStoreEntry entry, ShellControl sc) throws Exception { + public ScanOpportunity create(DataStoreEntry entry, ShellControl sc) throws Exception { return null; } + public abstract void scan(DataStoreEntry entry, ShellControl sc) throws Throwable; + @Value @AllArgsConstructor - public static class ScanOperation { + public class ScanOpportunity { String nameKey; boolean disabled; boolean defaultSelected; - FailableRunnable scanner; String licenseFeatureId; - public ScanOperation( - String nameKey, boolean disabled, boolean defaultSelected, FailableRunnable scanner) { + public ScanOpportunity(String nameKey, boolean disabled, boolean defaultSelected) { this.nameKey = nameKey; this.disabled = disabled; this.defaultSelected = defaultSelected; - this.scanner = scanner; this.licenseFeatureId = null; } public String getLicensedFeatureId() { return licenseFeatureId; } + + public ScanProvider getProvider() { + return ScanProvider.this; + } } public static class Loader implements ModuleLayerLoader { diff --git a/app/src/main/java/io/xpipe/app/ext/ShellControlFunction.java b/app/src/main/java/io/xpipe/app/ext/ShellControlFunction.java new file mode 100644 index 000000000..08dd5978f --- /dev/null +++ b/app/src/main/java/io/xpipe/app/ext/ShellControlFunction.java @@ -0,0 +1,8 @@ +package io.xpipe.app.ext; + +import io.xpipe.core.process.ShellControl; + +public interface ShellControlFunction { + + ShellControl control() throws Exception; +} diff --git a/app/src/main/java/io/xpipe/app/ext/ShellControlParentStoreFunction.java b/app/src/main/java/io/xpipe/app/ext/ShellControlParentStoreFunction.java new file mode 100644 index 000000000..e62b7d460 --- /dev/null +++ b/app/src/main/java/io/xpipe/app/ext/ShellControlParentStoreFunction.java @@ -0,0 +1,14 @@ +package io.xpipe.app.ext; + +import io.xpipe.core.process.ShellControl; + +public interface ShellControlParentStoreFunction extends ShellControlFunction { + + default ShellControl control() throws Exception { + return control(getParentStore().standaloneControl()); + } + + ShellControl control(ShellControl parent) throws Exception; + + ShellStore getParentStore(); +} diff --git a/app/src/main/java/io/xpipe/app/ext/ShellSession.java b/app/src/main/java/io/xpipe/app/ext/ShellSession.java new file mode 100644 index 000000000..1ff3a7693 --- /dev/null +++ b/app/src/main/java/io/xpipe/app/ext/ShellSession.java @@ -0,0 +1,65 @@ +package io.xpipe.app.ext; + +import io.xpipe.core.process.ShellControl; +import io.xpipe.core.store.Session; +import io.xpipe.core.store.SessionListener; +import io.xpipe.core.util.FailableSupplier; + +import lombok.Getter; + +@Getter +public class ShellSession extends Session { + + private final FailableSupplier supplier; + private final ShellControl shellControl; + + public ShellSession(SessionListener listener, FailableSupplier supplier) throws Exception { + super(listener); + this.supplier = supplier; + this.shellControl = createControl(); + } + + public void start() throws Exception { + if (shellControl.isRunning()) { + return; + } else { + stop(); + } + + try { + shellControl.start(); + } catch (Exception ex) { + stop(); + throw ex; + } + } + + private ShellControl createControl() throws Exception { + var pc = supplier.get(); + pc.onStartupFail(shellControl -> { + listener.onStateChange(false); + }); + pc.onInit(shellControl -> { + listener.onStateChange(true); + }); + pc.onKill(() -> { + listener.onStateChange(false); + }); + // Listen for parent exit as onExit is called before exit is completed + // In case it is stuck, we would not get the right status otherwise + pc.getParentControl().ifPresent(p -> { + p.onExit(shellControl -> { + listener.onStateChange(false); + }); + }); + return pc; + } + + public boolean isRunning() { + return shellControl.isRunning(); + } + + public void stop() throws Exception { + shellControl.close(); + } +} diff --git a/app/src/main/java/io/xpipe/app/ext/ShellStore.java b/app/src/main/java/io/xpipe/app/ext/ShellStore.java new file mode 100644 index 000000000..a8b763ca2 --- /dev/null +++ b/app/src/main/java/io/xpipe/app/ext/ShellStore.java @@ -0,0 +1,74 @@ +package io.xpipe.app.ext; + +import io.xpipe.app.issue.ErrorEvent; +import io.xpipe.core.process.ShellControl; +import io.xpipe.core.store.*; + +public interface ShellStore extends DataStore, FileSystemStore, ValidatableStore, SingletonSessionStore { + + default ShellControl getOrStartSession() throws Exception { + var session = getSession(); + if (session != null) { + session.getShellControl().refreshRunningState(); + if (!session.isRunning()) { + stopSessionIfNeeded(); + } else { + try { + session.getShellControl().command(" echo xpipetest").execute(); + return session.getShellControl(); + } catch (Exception e) { + ErrorEvent.fromThrowable(e).expected().omit().handle(); + stopSessionIfNeeded(); + } + } + } + + startSessionIfNeeded(); + return new StubShellControl(getSession().getShellControl()); + } + + @Override + default ShellSession newSession() throws Exception { + var func = shellFunction(); + var c = func.control(); + if (!isInStorage()) { + c.withoutLicenseCheck(); + } + return new ShellSession(this, () -> c); + } + + @Override + default Class getSessionClass() { + return ShellSession.class; + } + + @Override + default FileSystem createFileSystem() throws Exception { + var func = shellFunction(); + return new ConnectionFileSystem(func.control()); + } + + ShellControlFunction shellFunction(); + + @Override + default void validate() throws Exception { + try (var sc = tempControl().start()) {} + } + + default ShellControl standaloneControl() throws Exception { + return shellFunction().control(); + } + + default ShellControl tempControl() throws Exception { + if (isSessionRunning()) { + return getOrStartSession(); + } + + var func = shellFunction(); + if (!(func instanceof ShellControlParentStoreFunction p)) { + return func.control(); + } + + return p.control(p.getParentStore().getOrStartSession()); + } +} diff --git a/app/src/main/java/io/xpipe/app/ext/StubShellControl.java b/app/src/main/java/io/xpipe/app/ext/StubShellControl.java new file mode 100644 index 000000000..65bf18a2a --- /dev/null +++ b/app/src/main/java/io/xpipe/app/ext/StubShellControl.java @@ -0,0 +1,13 @@ +package io.xpipe.app.ext; + +import io.xpipe.core.process.ShellControl; + +public class StubShellControl extends WrapperShellControl { + + public StubShellControl(ShellControl parent) { + super(parent); + } + + @Override + public void close() throws Exception {} +} diff --git a/app/src/main/java/io/xpipe/app/ext/WrapperShellControl.java b/app/src/main/java/io/xpipe/app/ext/WrapperShellControl.java new file mode 100644 index 000000000..5d56d5601 --- /dev/null +++ b/app/src/main/java/io/xpipe/app/ext/WrapperShellControl.java @@ -0,0 +1,338 @@ +package io.xpipe.app.ext; + +import io.xpipe.core.process.*; +import io.xpipe.core.store.DataStore; +import io.xpipe.core.store.FilePath; +import io.xpipe.core.util.FailableConsumer; + +import lombok.Getter; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.Charset; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Consumer; +import java.util.function.Function; + +public class WrapperShellControl implements ShellControl { + + @Getter + protected final ShellControl parent; + + public WrapperShellControl(ShellControl parent) { + this.parent = parent; + } + + @Override + public Optional getParentControl() { + return parent.getParentControl(); + } + + @Override + public ShellTtyState getTtyState() { + return parent.getTtyState(); + } + + @Override + public void setNonInteractive() { + parent.setNonInteractive(); + } + + @Override + public boolean isInteractive() { + return parent.isInteractive(); + } + + @Override + public ElevationHandler getElevationHandler() { + return parent.getElevationHandler(); + } + + @Override + public void setElevationHandler(ElevationHandler ref) { + parent.setElevationHandler(ref); + } + + @Override + public List getExitUuids() { + return parent.getExitUuids(); + } + + @Override + public void setWorkingDirectory(WorkingDirectoryFunction workingDirectory) { + parent.setWorkingDirectory(workingDirectory); + } + + @Override + public Optional getSourceStore() { + return parent.getSourceStore(); + } + + @Override + public ShellControl withSourceStore(DataStore store) { + return parent.withSourceStore(store); + } + + @Override + public List getInitCommands() { + return parent.getInitCommands(); + } + + @Override + public ParentSystemAccess getParentSystemAccess() { + return parent.getParentSystemAccess(); + } + + @Override + public void setParentSystemAccess(ParentSystemAccess access) { + parent.setParentSystemAccess(access); + } + + @Override + public ParentSystemAccess getLocalSystemAccess() { + return parent.getLocalSystemAccess(); + } + + @Override + public boolean isLocal() { + return parent.isLocal(); + } + + @Override + public ShellControl getMachineRootSession() { + return parent.getMachineRootSession(); + } + + @Override + public ShellControl withoutLicenseCheck() { + return parent.withoutLicenseCheck(); + } + + @Override + public String getOsName() { + return parent.getOsName(); + } + + @Override + public boolean isLicenseCheck() { + return parent.isLicenseCheck(); + } + + @Override + public ReentrantLock getLock() { + return parent.getLock(); + } + + @Override + public ShellDialect getOriginalShellDialect() { + return parent.getOriginalShellDialect(); + } + + @Override + public void setOriginalShellDialect(ShellDialect dialect) { + parent.setOriginalShellDialect(dialect); + } + + @Override + public ShellControl onInit(FailableConsumer pc) { + return parent.onInit(pc); + } + + @Override + public ShellControl onExit(Consumer pc) { + return parent.onExit(pc); + } + + @Override + public ShellControl onKill(Runnable pc) { + return parent.onKill(pc); + } + + @Override + public ShellControl onStartupFail(Consumer t) { + return parent.onStartupFail(t); + } + + @Override + public UUID getUuid() { + return parent.getUuid(); + } + + @Override + public ShellControl withExceptionConverter(ExceptionConverter converter) { + return parent.withExceptionConverter(converter); + } + + @Override + public void resetData() { + parent.resetData(); + } + + @Override + public String prepareTerminalOpen(TerminalInitScriptConfig config, WorkingDirectoryFunction workingDirectory) + throws Exception { + return parent.prepareTerminalOpen(config, workingDirectory); + } + + @Override + public void refreshRunningState() { + parent.refreshRunningState(); + } + + @Override + public void closeStdin() throws IOException { + parent.closeStdin(); + } + + @Override + public boolean isStdinClosed() { + return parent.isStdinClosed(); + } + + @Override + public boolean isRunning() { + return parent.isRunning(); + } + + @Override + public ShellDialect getShellDialect() { + return parent.getShellDialect(); + } + + @Override + public void writeLine(String line) throws IOException { + parent.writeLine(line); + } + + @Override + public void writeLine(String line, boolean log) throws IOException { + parent.writeLine(line, log); + } + + @Override + public void write(byte[] b) throws IOException { + parent.write(b); + } + + @Override + public void close() throws Exception { + parent.close(); + } + + @Override + public void shutdown() throws Exception { + parent.shutdown(); + } + + @Override + public void kill() { + parent.kill(); + } + + @Override + public ShellControl start() throws Exception { + return parent.start(); + } + + @Override + public InputStream getStdout() { + return parent.getStdout(); + } + + @Override + public OutputStream getStdin() { + return parent.getStdin(); + } + + @Override + public InputStream getStderr() { + return parent.getStderr(); + } + + @Override + public Charset getCharset() { + return parent.getCharset(); + } + + @Override + public ShellControl withErrorFormatter(Function formatter) { + return parent.withErrorFormatter(formatter); + } + + @Override + public String prepareIntermediateTerminalOpen( + TerminalInitFunction content, TerminalInitScriptConfig config, WorkingDirectoryFunction workingDirectory) + throws Exception { + return parent.prepareIntermediateTerminalOpen(content, config, workingDirectory); + } + + @Override + public FilePath getSystemTemporaryDirectory() { + return parent.getSystemTemporaryDirectory(); + } + + @Override + public ShellControl withSecurityPolicy(ShellSecurityPolicy policy) { + return parent.withSecurityPolicy(policy); + } + + @Override + public ShellSecurityPolicy getEffectiveSecurityPolicy() { + return parent.getEffectiveSecurityPolicy(); + } + + @Override + public String buildElevatedCommand(CommandConfiguration input, String prefix, UUID requestId, CountDown countDown) + throws Exception { + return parent.buildElevatedCommand(input, prefix, requestId, countDown); + } + + @Override + public void restart() throws Exception { + parent.restart(); + } + + @Override + public OsType.Any getOsType() { + return parent.getOsType(); + } + + @Override + public ShellControl elevated(ElevationFunction elevationFunction) { + return parent.elevated(elevationFunction); + } + + @Override + public ShellControl withInitSnippet(ShellInitCommand snippet) { + return parent.withInitSnippet(snippet); + } + + @Override + public ShellControl subShell(ShellOpenFunction command, ShellOpenFunction terminalCommand) { + return parent.subShell(command, terminalCommand); + } + + @Override + public ShellControl singularSubShell(ShellOpenFunction command) { + return parent.singularSubShell(command); + } + + @Override + public void cd(String directory) throws Exception { + parent.cd(directory); + } + + @Override + public CommandControl command(CommandBuilder builder) { + return parent.command(builder); + } + + @Override + public void exitAndWait() throws IOException { + parent.exitAndWait(); + } +} diff --git a/app/src/main/java/io/xpipe/app/fxcomps/Comp.java b/app/src/main/java/io/xpipe/app/fxcomps/Comp.java index 090a52d68..9cd68e6f1 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/Comp.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/Comp.java @@ -97,8 +97,8 @@ public abstract class Comp> { return apply(struc -> struc.get().setMinWidth(width)); } - public Comp minHeight(double width) { - return apply(struc -> struc.get().setMinHeight(width)); + public Comp minHeight(double height) { + return apply(struc -> struc.get().setMinHeight(height)); } public Comp maxWidth(int width) { diff --git a/app/src/main/java/io/xpipe/app/fxcomps/impl/DataStoreChoiceComp.java b/app/src/main/java/io/xpipe/app/fxcomps/impl/DataStoreChoiceComp.java index 320d0a529..2fe9885f4 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/impl/DataStoreChoiceComp.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/impl/DataStoreChoiceComp.java @@ -5,6 +5,7 @@ import io.xpipe.app.comp.store.*; import io.xpipe.app.core.AppFont; import io.xpipe.app.core.AppI18n; import io.xpipe.app.ext.LocalStore; +import io.xpipe.app.ext.ShellStore; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.storage.DataStorage; @@ -12,7 +13,6 @@ import io.xpipe.app.storage.DataStoreEntry; import io.xpipe.app.storage.DataStoreEntryRef; import io.xpipe.app.util.DataStoreCategoryChoiceComp; import io.xpipe.core.store.DataStore; -import io.xpipe.core.store.ShellStore; import javafx.beans.binding.Bindings; import javafx.beans.property.Property; diff --git a/app/src/main/java/io/xpipe/app/issue/GuiErrorHandlerBase.java b/app/src/main/java/io/xpipe/app/issue/GuiErrorHandlerBase.java index 5e050606b..52a8b03de 100644 --- a/app/src/main/java/io/xpipe/app/issue/GuiErrorHandlerBase.java +++ b/app/src/main/java/io/xpipe/app/issue/GuiErrorHandlerBase.java @@ -11,7 +11,6 @@ public class GuiErrorHandlerBase { try { PlatformState.initPlatformOrThrow(); AppProperties.init(); - AppState.init(); AppExtensionManager.init(false); AppI18n.init(); AppStyle.init(); diff --git a/app/src/main/java/io/xpipe/app/issue/SentryErrorHandler.java b/app/src/main/java/io/xpipe/app/issue/SentryErrorHandler.java index 2fc9785ad..638235d2f 100644 --- a/app/src/main/java/io/xpipe/app/issue/SentryErrorHandler.java +++ b/app/src/main/java/io/xpipe/app/issue/SentryErrorHandler.java @@ -2,7 +2,6 @@ package io.xpipe.app.issue; import io.xpipe.app.core.AppLogs; import io.xpipe.app.core.AppProperties; -import io.xpipe.app.core.AppState; import io.xpipe.app.core.mode.OperationMode; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.update.XPipeDistributionType; @@ -145,6 +144,11 @@ public class SentryErrorHandler implements ErrorHandler { AppPrefs.get() != null ? AppPrefs.get().automaticallyUpdate().getValue().toString() : "unknown"); + s.setTag( + "securityUpdatesEnabled", + AppPrefs.get() != null + ? AppPrefs.get().checkForSecurityUpdates().getValue().toString() + : "unknown"); s.setTag("initError", String.valueOf(OperationMode.isInStartup())); s.setTag( "developerMode", @@ -177,11 +181,7 @@ public class SentryErrorHandler implements ErrorHandler { } var user = new User(); - user.setId(AppState.get().getUserId().toString()); - if (ee.isShouldSendDiagnostics()) { - user.setEmail(AppState.get().getUserEmail()); - user.setUsername(AppState.get().getUserName()); - } + user.setId(AppProperties.get().getUuid().toString()); s.setUser(user); } @@ -189,7 +189,6 @@ public class SentryErrorHandler implements ErrorHandler { // Assume that this object is wrapped by a synchronous error handler if (!init) { AppProperties.init(); - AppState.init(); if (AppProperties.get().getSentryUrl() != null) { Sentry.init(options -> { options.setDsn(AppProperties.get().getSentryUrl()); 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 991f64549..a71888492 100644 --- a/app/src/main/java/io/xpipe/app/issue/TerminalErrorHandler.java +++ b/app/src/main/java/io/xpipe/app/issue/TerminalErrorHandler.java @@ -3,6 +3,7 @@ package io.xpipe.app.issue; import io.xpipe.app.core.*; import io.xpipe.app.core.mode.OperationMode; import io.xpipe.app.core.window.AppWindowHelper; +import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.update.XPipeDistributionType; import io.xpipe.app.util.Hyperlinks; import io.xpipe.app.util.ThreadHelper; @@ -40,7 +41,6 @@ public class TerminalErrorHandler extends GuiErrorHandlerBase implements ErrorHa private void handleGui(ErrorEvent event) { try { AppProperties.init(); - AppState.init(); AppExtensionManager.init(false); AppI18n.init(); AppStyle.init(); @@ -74,7 +74,7 @@ public class TerminalErrorHandler extends GuiErrorHandlerBase implements ErrorHa } try { - var rel = XPipeDistributionType.get().getUpdateHandler().refreshUpdateCheck(); + var rel = XPipeDistributionType.get().getUpdateHandler().refreshUpdateCheck(false, !AppPrefs.get().automaticallyUpdate().get()); 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/AppPrefs.java b/app/src/main/java/io/xpipe/app/prefs/AppPrefs.java index 02d6cc2d2..78565fd2a 100644 --- a/app/src/main/java/io/xpipe/app/prefs/AppPrefs.java +++ b/app/src/main/java/io/xpipe/app/prefs/AppPrefs.java @@ -1,6 +1,7 @@ package io.xpipe.app.prefs; import io.xpipe.app.core.*; +import io.xpipe.app.core.mode.OperationMode; import io.xpipe.app.ext.PrefsHandler; import io.xpipe.app.ext.PrefsProvider; import io.xpipe.app.fxcomps.Comp; @@ -22,8 +23,11 @@ import javafx.beans.value.ObservableDoubleValue; import javafx.beans.value.ObservableStringValue; import javafx.beans.value.ObservableValue; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Getter; import lombok.Value; +import lombok.experimental.NonFinal; import org.apache.commons.io.FileUtils; import java.nio.file.Path; @@ -36,100 +40,104 @@ public class AppPrefs { AppProperties.get() != null ? AppProperties.get().getDataDir().resolve("storage") : null; private static final String DEVELOPER_MODE_PROP = "io.xpipe.app.developerMode"; private static AppPrefs INSTANCE; - private final List> mapping = new ArrayList<>(); + private final List mapping = new ArrayList<>(); + + @Getter + private final BooleanProperty requiresRestart = new SimpleBooleanProperty(false); final BooleanProperty dontAllowTerminalRestart = - mapVaultSpecific(new SimpleBooleanProperty(false), "dontAllowTerminalRestart", Boolean.class); + mapVaultShared(new SimpleBooleanProperty(false), "dontAllowTerminalRestart", Boolean.class, false); final BooleanProperty enableHttpApi = - mapVaultSpecific(new SimpleBooleanProperty(false), "enableHttpApi", Boolean.class); + mapVaultShared(new SimpleBooleanProperty(false), "enableHttpApi", Boolean.class, false); final BooleanProperty dontAutomaticallyStartVmSshServer = - mapVaultSpecific(new SimpleBooleanProperty(false), "dontAutomaticallyStartVmSshServer", Boolean.class); + mapVaultShared(new SimpleBooleanProperty(false), "dontAutomaticallyStartVmSshServer", Boolean.class, false); final BooleanProperty dontAcceptNewHostKeys = - mapVaultSpecific(new SimpleBooleanProperty(false), "dontAcceptNewHostKeys", Boolean.class); - public final BooleanProperty performanceMode = map(new SimpleBooleanProperty(), "performanceMode", Boolean.class); + mapVaultShared(new SimpleBooleanProperty(false), "dontAcceptNewHostKeys", Boolean.class, false); + public final BooleanProperty performanceMode = mapLocal(new SimpleBooleanProperty(), "performanceMode", Boolean.class, false); public final BooleanProperty useBundledTools = - map(new SimpleBooleanProperty(false), "useBundledTools", Boolean.class); + mapLocal(new SimpleBooleanProperty(false), "useBundledTools", Boolean.class, true); public final ObjectProperty theme = - map(new SimpleObjectProperty<>(), "theme", AppTheme.Theme.class); - final BooleanProperty useSystemFont = map(new SimpleBooleanProperty(true), "useSystemFont", Boolean.class); - final Property uiScale = map(new SimpleObjectProperty<>(null), "uiScale", Integer.class); + mapLocal(new SimpleObjectProperty<>(), "theme", AppTheme.Theme.class, false); + final BooleanProperty useSystemFont = mapLocal(new SimpleBooleanProperty(true), "useSystemFont", Boolean.class, false); + final Property uiScale = mapLocal(new SimpleObjectProperty<>(null), "uiScale", Integer.class, true); final BooleanProperty saveWindowLocation = - map(new SimpleBooleanProperty(true), "saveWindowLocation", Boolean.class); + mapLocal(new SimpleBooleanProperty(true), "saveWindowLocation", Boolean.class, false); final ObjectProperty terminalType = - map(new SimpleObjectProperty<>(), "terminalType", ExternalTerminalType.class); + mapLocal(new SimpleObjectProperty<>(), "terminalType", ExternalTerminalType.class, false); final ObjectProperty rdpClientType = - map(new SimpleObjectProperty<>(), "rdpClientType", ExternalRdpClientType.class); - final DoubleProperty windowOpacity = map(new SimpleDoubleProperty(1.0), "windowOpacity", Double.class); + mapLocal(new SimpleObjectProperty<>(), "rdpClientType", ExternalRdpClientType.class, false); + final DoubleProperty windowOpacity = mapLocal(new SimpleDoubleProperty(1.0), "windowOpacity", Double.class, false); final StringProperty customRdpClientCommand = - map(new SimpleStringProperty(null), "customRdpClientCommand", String.class); + mapLocal(new SimpleStringProperty(null), "customRdpClientCommand", String.class, false); final StringProperty customTerminalCommand = - map(new SimpleStringProperty(null), "customTerminalCommand", String.class); + mapLocal(new SimpleStringProperty(null), "customTerminalCommand", String.class, false); final BooleanProperty clearTerminalOnInit = - map(new SimpleBooleanProperty(true), "clearTerminalOnInit", Boolean.class); + mapLocal(new SimpleBooleanProperty(true), "clearTerminalOnInit", Boolean.class, false); public final BooleanProperty disableCertutilUse = - map(new SimpleBooleanProperty(false), "disableCertutilUse", Boolean.class); + mapLocal(new SimpleBooleanProperty(false), "disableCertutilUse", Boolean.class, false); public final BooleanProperty useLocalFallbackShell = - map(new SimpleBooleanProperty(false), "useLocalFallbackShell", Boolean.class); - public final BooleanProperty disableTerminalRemotePasswordPreparation = mapVaultSpecific( - new SimpleBooleanProperty(false), "disableTerminalRemotePasswordPreparation", Boolean.class); + mapLocal(new SimpleBooleanProperty(false), "useLocalFallbackShell", Boolean.class, true); + public final BooleanProperty disableTerminalRemotePasswordPreparation = mapVaultShared( + new SimpleBooleanProperty(false), "disableTerminalRemotePasswordPreparation", Boolean.class, false); public final Property alwaysConfirmElevation = - mapVaultSpecific(new SimpleObjectProperty<>(false), "alwaysConfirmElevation", Boolean.class); + mapVaultShared(new SimpleObjectProperty<>(false), "alwaysConfirmElevation", Boolean.class, false); public final BooleanProperty dontCachePasswords = - mapVaultSpecific(new SimpleBooleanProperty(false), "dontCachePasswords", Boolean.class); + mapVaultShared(new SimpleBooleanProperty(false), "dontCachePasswords", Boolean.class, false); public final BooleanProperty denyTempScriptCreation = - mapVaultSpecific(new SimpleBooleanProperty(false), "denyTempScriptCreation", Boolean.class); + mapVaultShared(new SimpleBooleanProperty(false), "denyTempScriptCreation", Boolean.class, false); final Property passwordManager = - mapVaultSpecific(new SimpleObjectProperty<>(), "passwordManager", ExternalPasswordManager.class); + mapVaultShared(new SimpleObjectProperty<>(), "passwordManager", ExternalPasswordManager.class, false); final StringProperty passwordManagerCommand = - map(new SimpleStringProperty(""), "passwordManagerCommand", String.class); + mapLocal(new SimpleStringProperty(""), "passwordManagerCommand", String.class, false); final ObjectProperty startupBehaviour = - map(new SimpleObjectProperty<>(StartupBehaviour.GUI), "startupBehaviour", StartupBehaviour.class); + mapLocal(new SimpleObjectProperty<>(StartupBehaviour.GUI), "startupBehaviour", StartupBehaviour.class, true); public final BooleanProperty enableGitStorage = - map(new SimpleBooleanProperty(false), "enableGitStorage", Boolean.class); - final StringProperty storageGitRemote = map(new SimpleStringProperty(""), "storageGitRemote", String.class); + mapLocal(new SimpleBooleanProperty(false), "enableGitStorage", Boolean.class, true); + final StringProperty storageGitRemote = mapLocal(new SimpleStringProperty(""), "storageGitRemote", String.class, true); final ObjectProperty closeBehaviour = - map(new SimpleObjectProperty<>(CloseBehaviour.QUIT), "closeBehaviour", CloseBehaviour.class); + mapLocal(new SimpleObjectProperty<>(CloseBehaviour.QUIT), "closeBehaviour", CloseBehaviour.class, false); final ObjectProperty externalEditor = - map(new SimpleObjectProperty<>(), "externalEditor", ExternalEditorType.class); - final StringProperty customEditorCommand = map(new SimpleStringProperty(""), "customEditorCommand", String.class); - final BooleanProperty preferEditorTabs = map(new SimpleBooleanProperty(true), "preferEditorTabs", Boolean.class); + mapLocal(new SimpleObjectProperty<>(), "externalEditor", ExternalEditorType.class, false); + final StringProperty customEditorCommand = mapLocal(new SimpleStringProperty(""), "customEditorCommand", String.class, false); final BooleanProperty automaticallyCheckForUpdates = - map(new SimpleBooleanProperty(true), "automaticallyCheckForUpdates", Boolean.class); + mapLocal(new SimpleBooleanProperty(true), "automaticallyCheckForUpdates", Boolean.class, false); final BooleanProperty encryptAllVaultData = - mapVaultSpecific(new SimpleBooleanProperty(false), "encryptAllVaultData", Boolean.class); - final BooleanProperty enableTerminalLogging = - map(new SimpleBooleanProperty(false), "enableTerminalLogging", Boolean.class); + mapVaultShared(new SimpleBooleanProperty(false), "encryptAllVaultData", Boolean.class, true); + final BooleanProperty enableTerminalLogging = map(Mapping.builder() + .property(new SimpleBooleanProperty(false)).key("enableTerminalLogging").valueClass(Boolean.class).licenseFeatureId("logging").build()); final BooleanProperty enforceWindowModality = - map(new SimpleBooleanProperty(false), "enforceWindowModality", Boolean.class); + mapLocal(new SimpleBooleanProperty(false), "enforceWindowModality", Boolean.class, false); + final BooleanProperty checkForSecurityUpdates = + mapLocal(new SimpleBooleanProperty(true), "checkForSecurityUpdates", Boolean.class, false); final BooleanProperty condenseConnectionDisplay = - map(new SimpleBooleanProperty(false), "condenseConnectionDisplay", Boolean.class); + mapLocal(new SimpleBooleanProperty(false), "condenseConnectionDisplay", Boolean.class, false); final BooleanProperty showChildCategoriesInParentCategory = - map(new SimpleBooleanProperty(true), "showChildrenConnectionsInParentCategory", Boolean.class); + mapLocal(new SimpleBooleanProperty(true), "showChildrenConnectionsInParentCategory", Boolean.class, false); final BooleanProperty lockVaultOnHibernation = - map(new SimpleBooleanProperty(false), "lockVaultOnHibernation", Boolean.class); + mapLocal(new SimpleBooleanProperty(false), "lockVaultOnHibernation", Boolean.class, false); final BooleanProperty openConnectionSearchWindowOnConnectionCreation = - map(new SimpleBooleanProperty(true), "openConnectionSearchWindowOnConnectionCreation", Boolean.class); + mapLocal(new SimpleBooleanProperty(true), "openConnectionSearchWindowOnConnectionCreation", Boolean.class, false); final ObjectProperty storageDirectory = - map(new SimpleObjectProperty<>(DEFAULT_STORAGE_DIR), "storageDirectory", Path.class); + mapLocal(new SimpleObjectProperty<>(DEFAULT_STORAGE_DIR), "storageDirectory", Path.class, true); final BooleanProperty confirmAllDeletions = - map(new SimpleBooleanProperty(false), "confirmAllDeletions", Boolean.class); - final BooleanProperty developerMode = map(new SimpleBooleanProperty(false), "developerMode", Boolean.class); + mapLocal(new SimpleBooleanProperty(false), "confirmAllDeletions", Boolean.class, false); + final BooleanProperty developerMode = mapLocal(new SimpleBooleanProperty(false), "developerMode", Boolean.class, true); final BooleanProperty developerDisableUpdateVersionCheck = - map(new SimpleBooleanProperty(false), "developerDisableUpdateVersionCheck", Boolean.class); + mapLocal(new SimpleBooleanProperty(false), "developerDisableUpdateVersionCheck", Boolean.class, false); private final ObservableBooleanValue developerDisableUpdateVersionCheckEffective = bindDeveloperTrue(developerDisableUpdateVersionCheck); final BooleanProperty developerDisableGuiRestrictions = - map(new SimpleBooleanProperty(false), "developerDisableGuiRestrictions", Boolean.class); + mapLocal(new SimpleBooleanProperty(false), "developerDisableGuiRestrictions", Boolean.class, false); private final ObservableBooleanValue developerDisableGuiRestrictionsEffective = bindDeveloperTrue(developerDisableGuiRestrictions); final BooleanProperty developerForceSshTty = - map(new SimpleBooleanProperty(false), "developerForceSshTty", Boolean.class); + mapLocal(new SimpleBooleanProperty(false), "developerForceSshTty", Boolean.class, false); final ObjectProperty language = - map(new SimpleObjectProperty<>(SupportedLocale.getEnglish()), "language", SupportedLocale.class); + mapLocal(new SimpleObjectProperty<>(SupportedLocale.getEnglish()), "language", SupportedLocale.class, false); final BooleanProperty requireDoubleClickForConnections = - map(new SimpleBooleanProperty(false), "requireDoubleClickForConnections", Boolean.class); + mapLocal(new SimpleBooleanProperty(false), "requireDoubleClickForConnections", Boolean.class, false); public ObservableBooleanValue requireDoubleClickForConnections() { return requireDoubleClickForConnections; @@ -140,12 +148,16 @@ public class AppPrefs { @Getter private final StringProperty lockCrypt = - mapVaultSpecific(new SimpleStringProperty(), "workspaceLock", String.class); + mapVaultShared(new SimpleStringProperty(), "workspaceLock", String.class, true); final StringProperty apiKey = - mapVaultSpecific(new SimpleStringProperty(UUID.randomUUID().toString()), "apiKey", String.class); + mapVaultShared(new SimpleStringProperty(UUID.randomUUID().toString()), "apiKey", String.class ,true); final BooleanProperty disableApiAuthentication = - map(new SimpleBooleanProperty(false), "disableApiAuthentication", Boolean.class); + mapLocal(new SimpleBooleanProperty(false), "disableApiAuthentication", Boolean.class, false); + + public ObservableBooleanValue checkForSecurityUpdates() { + return checkForSecurityUpdates; + } public ObservableBooleanValue enableTerminalLogging() { return enableTerminalLogging; @@ -168,16 +180,16 @@ public class AppPrefs { } private final IntegerProperty editorReloadTimeout = - map(new SimpleIntegerProperty(1000), "editorReloadTimeout", Integer.class); + mapLocal(new SimpleIntegerProperty(1000), "editorReloadTimeout", Integer.class, false); private final BooleanProperty confirmDeletions = - map(new SimpleBooleanProperty(true), "confirmDeletions", Boolean.class); + mapLocal(new SimpleBooleanProperty(true), "confirmDeletions", Boolean.class, false); @Getter private final List categories; private final AppPrefsStorageHandler globalStorageHandler = new AppPrefsStorageHandler( AppProperties.get().getDataDir().resolve("settings").resolve("preferences.json")); - private final Map, Comp> customEntries = new LinkedHashMap<>(); + private final Map> customEntries = new LinkedHashMap<>(); @Getter private final Property selectedCategory; @@ -207,7 +219,7 @@ public class AppPrefs { new DeveloperCategory()) .filter(appPrefsCategory -> appPrefsCategory.show()) .toList(); - var selected = AppCache.get("selectedPrefsCategory", Integer.class, () -> 0); + var selected = AppCache.getNonNull("selectedPrefsCategory", Integer.class, () -> 0); if (selected == null) { selected = 0; } @@ -473,14 +485,20 @@ public class AppPrefs { } @SuppressWarnings("unchecked") - private T map(T o, String name, Class clazz) { - mapping.add(new Mapping<>(name, (Property) o, (Class) clazz)); - return o; + private T map(Mapping m) { + mapping.add(m); + return (T) m.getProperty(); } @SuppressWarnings("unchecked") - private T mapVaultSpecific(T o, String name, Class clazz) { - mapping.add(new Mapping<>(name, (Property) o, (Class) clazz, true)); + private T mapLocal(Property o, String name, Class clazz, boolean requiresRestart) { + mapping.add(new Mapping(name, o, clazz, false, requiresRestart)); + return (T) o; + } + + @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; } @@ -498,7 +516,7 @@ public class AppPrefs { if (rdpClientType.get() == null) { rdpClientType.setValue(ExternalRdpClientType.determineDefault()); } - if (AppState.get().isInitialLaunch()) { + if (AppProperties.get().isInitialLaunch()) { performanceMode.setValue(XPipeDistributionType.get() == XPipeDistributionType.WEBTOP); } } @@ -512,7 +530,7 @@ public class AppPrefs { } private void loadLocal() { - for (Mapping value : mapping) { + for (Mapping value : mapping) { if (value.isVaultSpecific()) { continue; } @@ -546,7 +564,7 @@ public class AppPrefs { } private void loadSharedRemote() { - for (Mapping value : mapping) { + for (Mapping value : mapping) { if (!value.isVaultSpecific()) { continue; } @@ -562,15 +580,19 @@ public class AppPrefs { } } - private T loadValue(AppPrefsStorageHandler handler, Mapping value) { + @SuppressWarnings("unchecked") + private T loadValue(AppPrefsStorageHandler handler, Mapping value) { + T def = (T) value.getProperty().getValue(); + Property property = (Property) value.getProperty(); + Class clazz = (Class) value.getValueClass(); var val = handler.loadObject( - value.getKey(), value.getValueClass(), value.getProperty().getValue()); - value.getProperty().setValue(val); + value.getKey(), clazz, def); + property.setValue(val); return val; } public void save() { - for (Mapping m : mapping) { + for (Mapping m : mapping) { AppPrefsStorageHandler handler = m.isVaultSpecific() ? vaultStorageHandler : globalStorageHandler; // It might be possible that we save while the vault handler is not initialized yet / has no file or // directory @@ -608,26 +630,36 @@ public class AppPrefs { return ExternalApplicationHelper.replaceFileArgument(passwordManagerCommand.get(), "KEY", key); } + public Mapping getMapping(Object property) { + return mapping.stream().filter(m -> m.property == property).findFirst().orElseThrow(); + } + @Value - public static class Mapping { + @Builder + @AllArgsConstructor + public static class Mapping { String key; - Property property; - Class valueClass; + Property property; + Class valueClass; boolean vaultSpecific; + boolean requiresRestart; + String licenseFeatureId; - public Mapping(String key, Property property, Class valueClass) { - this.key = key; - this.property = property; - this.valueClass = valueClass; - this.vaultSpecific = false; - } - - public Mapping(String key, Property property, Class valueClass, boolean vaultSpecific) { + public Mapping(String key, Property property, Class valueClass, boolean vaultSpecific, boolean requiresRestart) { this.key = key; this.property = property; this.valueClass = valueClass; 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); + } + }); } } @@ -635,8 +667,8 @@ public class AppPrefs { private class PrefsHandlerImpl implements PrefsHandler { @Override - public void addSetting(String id, Class c, Property property, Comp comp) { - var m = new Mapping<>(id, property, c); + public void addSetting(String id, Class c, Property property, Comp comp, boolean requiresRestart) { + var m = new Mapping(id, property, c, false, requiresRestart); customEntries.put(m, comp); mapping.add(m); } diff --git a/app/src/main/java/io/xpipe/app/prefs/AppPrefsComp.java b/app/src/main/java/io/xpipe/app/prefs/AppPrefsComp.java index 26332908a..caf4bd9a4 100644 --- a/app/src/main/java/io/xpipe/app/prefs/AppPrefsComp.java +++ b/app/src/main/java/io/xpipe/app/prefs/AppPrefsComp.java @@ -46,6 +46,7 @@ public class AppPrefsComp extends SimpleComp { sidebar.setMaxWidth(280); var split = new HBox(sidebar, pfxLimit); + HBox.setMargin(sidebar, new Insets(6)); HBox.setHgrow(pfxLimit, Priority.ALWAYS); split.setFillHeight(true); split.getStyleClass().add("prefs"); diff --git a/app/src/main/java/io/xpipe/app/prefs/AppPrefsSidebarComp.java b/app/src/main/java/io/xpipe/app/prefs/AppPrefsSidebarComp.java index 7528d8cb1..cf0821e0d 100644 --- a/app/src/main/java/io/xpipe/app/prefs/AppPrefsSidebarComp.java +++ b/app/src/main/java/io/xpipe/app/prefs/AppPrefsSidebarComp.java @@ -1,17 +1,24 @@ package io.xpipe.app.prefs; +import atlantafx.base.theme.Styles; import io.xpipe.app.comp.base.ButtonComp; import io.xpipe.app.core.AppI18n; +import io.xpipe.app.core.mode.OperationMode; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.impl.VerticalComp; import io.xpipe.app.fxcomps.util.PlatformThread; import javafx.css.PseudoClass; +import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.control.Button; import javafx.scene.layout.Region; import javafx.scene.text.TextAlignment; +import org.kordamp.ikonli.javafx.FontIcon; + +import java.util.ArrayList; +import java.util.stream.Collectors; public class AppPrefsSidebarComp extends SimpleComp { @@ -33,7 +40,17 @@ public class AppPrefsSidebarComp extends SimpleComp { }) .grow(true, false); }) - .toList(); + .collect(Collectors.toCollection(ArrayList::new)); + + var restartButton = new ButtonComp(AppI18n.observable("restart"), new FontIcon("mdi2r-restart"), () -> { + OperationMode.restart(); + }); + restartButton.grow(true, false); + restartButton.visible(AppPrefs.get().getRequiresRestart()); + restartButton.padding(new Insets(6, 10, 6, 6)); + buttons.add(Comp.vspacer()); + buttons.add(restartButton); + var vbox = new VerticalComp(buttons).styleClass("sidebar"); vbox.apply(struc -> { AppPrefs.get().getSelectedCategory().subscribe(val -> { diff --git a/app/src/main/java/io/xpipe/app/prefs/CloseBehaviourAlert.java b/app/src/main/java/io/xpipe/app/prefs/CloseBehaviourAlert.java index e403cb7c0..e3a423020 100644 --- a/app/src/main/java/io/xpipe/app/prefs/CloseBehaviourAlert.java +++ b/app/src/main/java/io/xpipe/app/prefs/CloseBehaviourAlert.java @@ -20,7 +20,7 @@ public class CloseBehaviourAlert { return true; } - boolean set = AppCache.get("closeBehaviourSet", Boolean.class, () -> false); + boolean set = AppCache.getBoolean("closeBehaviourSet", false); if (set) { return true; } diff --git a/app/src/main/java/io/xpipe/app/prefs/EditorCategory.java b/app/src/main/java/io/xpipe/app/prefs/EditorCategory.java index b49f0c819..5b8202c0d 100644 --- a/app/src/main/java/io/xpipe/app/prefs/EditorCategory.java +++ b/app/src/main/java/io/xpipe/app/prefs/EditorCategory.java @@ -49,9 +49,7 @@ public class EditorCategory extends AppPrefsCategory { .addComp(new TextFieldComp(prefs.customEditorCommand, true) .apply(struc -> struc.get().setPromptText("myeditor $FILE")) .hide(prefs.externalEditor.isNotEqualTo(ExternalEditorType.CUSTOM))) - .addComp(terminalTest) - .nameAndDescription("preferEditorTabs") - .addToggle(prefs.preferEditorTabs)) + .addComp(terminalTest)) .buildComp(); } } diff --git a/app/src/main/java/io/xpipe/app/prefs/LoggingCategory.java b/app/src/main/java/io/xpipe/app/prefs/LoggingCategory.java index 8a00e842b..91747958d 100644 --- a/app/src/main/java/io/xpipe/app/prefs/LoggingCategory.java +++ b/app/src/main/java/io/xpipe/app/prefs/LoggingCategory.java @@ -22,13 +22,10 @@ public class LoggingCategory extends AppPrefsCategory { @Override protected Comp create() { var prefs = AppPrefs.get(); - var feature = LicenseProvider.get().getFeature("logging"); - var supported = feature.isSupported() || feature.isPreviewSupported(); - var title = AppI18n.observable("sessionLogging").map(s -> s + (supported ? "" : " (Pro)")); return new OptionsBuilder() - .addTitle(title) + .addTitle("sessionLogging") .sub(new OptionsBuilder() - .nameAndDescription("enableTerminalLogging") + .pref(prefs.enableTerminalLogging) .addToggle(prefs.enableTerminalLogging) .nameAndDescription("terminalLoggingDirectory") .addComp(new ButtonComp(AppI18n.observable("openSessionLogs"), () -> { diff --git a/app/src/main/java/io/xpipe/app/prefs/SecurityCategory.java b/app/src/main/java/io/xpipe/app/prefs/SecurityCategory.java index deab13448..8c5757b1e 100644 --- a/app/src/main/java/io/xpipe/app/prefs/SecurityCategory.java +++ b/app/src/main/java/io/xpipe/app/prefs/SecurityCategory.java @@ -15,6 +15,8 @@ public class SecurityCategory extends AppPrefsCategory { var builder = new OptionsBuilder(); builder.addTitle("securityPolicy") .sub(new OptionsBuilder() + .pref(prefs.checkForSecurityUpdates) + .addToggle(prefs.checkForSecurityUpdates) .nameAndDescription("alwaysConfirmElevation") .addToggle(prefs.alwaysConfirmElevation) .nameAndDescription("dontCachePasswords") diff --git a/app/src/main/java/io/xpipe/app/prefs/SyncCategory.java b/app/src/main/java/io/xpipe/app/prefs/SyncCategory.java index 6e6e99336..d06ff4577 100644 --- a/app/src/main/java/io/xpipe/app/prefs/SyncCategory.java +++ b/app/src/main/java/io/xpipe/app/prefs/SyncCategory.java @@ -71,13 +71,7 @@ public class SyncCategory extends AppPrefsCategory { testButton.apply(struc -> button.set(struc.get())); testButton.padding(new Insets(6, 10, 6, 6)); - var restartButton = new ButtonComp(AppI18n.observable("restart"), new FontIcon("mdi2r-restart"), () -> { - OperationMode.restart(); - }); - restartButton.visible(canRestart); - restartButton.padding(new Insets(6, 10, 6, 6)); - - var testRow = new HorizontalComp(List.of(testButton, restartButton)) + var testRow = new HorizontalComp(List.of(testButton)) .spacing(10) .padding(new Insets(10, 0, 0, 0)) .apply(struc -> struc.get().setAlignment(Pos.CENTER_LEFT)); @@ -92,10 +86,9 @@ public class SyncCategory extends AppPrefsCategory { var builder = new OptionsBuilder(); builder.addTitle("sync") .sub(new OptionsBuilder() - .name("enableGitStorage") - .description("enableGitStorageDescription") + .pref(prefs.enableGitStorage) .addToggle(prefs.enableGitStorage) - .nameAndDescription("storageGitRemote") + .pref(prefs.storageGitRemote) .addComp(remoteRow, prefs.storageGitRemote) .disable(prefs.enableGitStorage.not()) .addComp(testRow) diff --git a/app/src/main/java/io/xpipe/app/prefs/TerminalCategory.java b/app/src/main/java/io/xpipe/app/prefs/TerminalCategory.java index cba814cee..e91969245 100644 --- a/app/src/main/java/io/xpipe/app/prefs/TerminalCategory.java +++ b/app/src/main/java/io/xpipe/app/prefs/TerminalCategory.java @@ -2,8 +2,8 @@ package io.xpipe.app.prefs; import io.xpipe.app.comp.base.ButtonComp; import io.xpipe.app.core.AppI18n; -import io.xpipe.app.ext.LocalStore; import io.xpipe.app.ext.PrefsChoiceValue; +import io.xpipe.app.ext.ProcessControlProvider; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.impl.ChoiceComp; import io.xpipe.app.fxcomps.impl.HorizontalComp; @@ -41,7 +41,10 @@ public class TerminalCategory extends AppPrefsCategory { var term = AppPrefs.get().terminalType().getValue(); if (term != null) { TerminalLauncher.open( - "Test", new LocalStore().control().command("echo Test")); + "Test", + ProcessControlProvider.get() + .createLocalProcessControl(true) + .command("echo Test")); } }); }))) diff --git a/app/src/main/java/io/xpipe/app/prefs/UpdateCheckComp.java b/app/src/main/java/io/xpipe/app/prefs/UpdateCheckComp.java index f04f9d94d..f894d63fa 100644 --- a/app/src/main/java/io/xpipe/app/prefs/UpdateCheckComp.java +++ b/app/src/main/java/io/xpipe/app/prefs/UpdateCheckComp.java @@ -29,13 +29,13 @@ public class UpdateCheckComp extends SimpleComp { } private void performUpdateAndRestart() { - XPipeDistributionType.get().getUpdateHandler().refreshUpdateCheckSilent(); + XPipeDistributionType.get().getUpdateHandler().refreshUpdateCheckSilent(false, false); UpdateAvailableAlert.showIfNeeded(); } private void refresh() { ThreadHelper.runFailableAsync(() -> { - XPipeDistributionType.get().getUpdateHandler().refreshUpdateCheck(); + XPipeDistributionType.get().getUpdateHandler().refreshUpdateCheck(false, false); XPipeDistributionType.get().getUpdateHandler().prepareUpdate(); }); } diff --git a/app/src/main/java/io/xpipe/app/prefs/VaultCategory.java b/app/src/main/java/io/xpipe/app/prefs/VaultCategory.java index 681e5ad72..7fa400e75 100644 --- a/app/src/main/java/io/xpipe/app/prefs/VaultCategory.java +++ b/app/src/main/java/io/xpipe/app/prefs/VaultCategory.java @@ -27,15 +27,6 @@ public class VaultCategory extends AppPrefsCategory { public Comp create() { var prefs = AppPrefs.get(); var builder = new OptionsBuilder(); - if (!STORAGE_DIR_FIXED) { - var sub = - new OptionsBuilder().nameAndDescription("storageDirectory").addPath(prefs.storageDirectory); - sub.withValidator(val -> { - sub.check(Validator.absolutePath(val, prefs.storageDirectory)); - sub.check(Validator.directory(val, prefs.storageDirectory)); - }); - builder.addTitle("storage").sub(sub); - } var encryptVault = new SimpleBooleanProperty(prefs.encryptAllVaultData().get()); encryptVault.addListener((observable, oldValue, newValue) -> { 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 ebc00a2aa..447e0decf 100644 --- a/app/src/main/java/io/xpipe/app/prefs/WorkspacesCategory.java +++ b/app/src/main/java/io/xpipe/app/prefs/WorkspacesCategory.java @@ -16,13 +16,7 @@ public class WorkspacesCategory extends AppPrefsCategory { @Override protected Comp create() { return new OptionsBuilder() - .addTitle(AppI18n.observable("manageWorkspaces") - .map(s -> s - + (LicenseProvider.get() - .getFeature("workspaces") - .isSupported() - ? "" - : " (Pro)"))) + .addTitle(LicenseProvider.get().getFeature("workspaces").suffixObservable("manageWorkspaces")) .sub(new OptionsBuilder() .nameAndDescription("workspaceAdd") .addComp(new ButtonComp(AppI18n.observable("addWorkspace"), WorkspaceCreationAlert::showAsync))) diff --git a/app/src/main/java/io/xpipe/app/storage/DataStateProviderImpl.java b/app/src/main/java/io/xpipe/app/storage/DataStateProviderImpl.java index fc3f39ead..df4903f14 100644 --- a/app/src/main/java/io/xpipe/app/storage/DataStateProviderImpl.java +++ b/app/src/main/java/io/xpipe/app/storage/DataStateProviderImpl.java @@ -52,7 +52,8 @@ public class DataStateProviderImpl extends DataStateProvider { return; } - var entry = DataStorage.get().getStoreEntryIfPresent(store, true); + var entry = DataStorage.get().getStoreEntryIfPresent(store, true).or(() -> DataStorage.get() + .getStoreEntryInProgressIfPresent(store)); if (entry.isEmpty()) { return; } @@ -66,7 +67,8 @@ public class DataStateProviderImpl extends DataStateProvider { return def.get(); } - var entry = DataStorage.get().getStoreEntryIfPresent(store, true); + var entry = DataStorage.get().getStoreEntryIfPresent(store, true).or(() -> DataStorage.get() + .getStoreEntryInProgressIfPresent(store)); if (entry.isEmpty()) { return def.get(); } 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 4ff1c28c0..2fcaa9a7f 100644 --- a/app/src/main/java/io/xpipe/app/storage/DataStorage.java +++ b/app/src/main/java/io/xpipe/app/storage/DataStorage.java @@ -10,7 +10,6 @@ import io.xpipe.app.util.ThreadHelper; import io.xpipe.core.store.DataStore; import io.xpipe.core.store.FixedChildStore; import io.xpipe.core.store.StorePath; -import io.xpipe.core.store.ValidationContext; import io.xpipe.core.util.UuidHelper; import javafx.util.Pair; @@ -365,30 +364,24 @@ public abstract class DataStorage { } @SneakyThrows - public boolean refreshChildren(DataStoreEntry e, ValidationContext context) { - return refreshChildren(e, context, false); + public boolean refreshChildren(DataStoreEntry e) { + return refreshChildren(e, false); } - @SuppressWarnings("unchecked") - public > boolean refreshChildren(DataStoreEntry e, T context, boolean throwOnFail) - throws Exception { - if (!(e.getStore() instanceof FixedHierarchyStore h)) { + public boolean refreshChildrenOrThrow(DataStoreEntry e) throws Exception { + return refreshChildren(e, true); + } + + public boolean refreshChildren(DataStoreEntry e, boolean throwOnFail) throws Exception { + if (!(e.getStore() instanceof FixedHierarchyStore h)) { return false; } e.incrementBusyCounter(); List> newChildren; - var hadContext = context != null; try { - if (context == null) { - context = (T) h.createContext(); - if (context == null) { - return false; - } - } - - newChildren = ((FixedHierarchyStore) h) - .listChildren(context).stream() + newChildren = ((FixedHierarchyStore) h) + .listChildren().stream() .filter(dataStoreEntryRef -> dataStoreEntryRef != null && dataStoreEntryRef.get() != null) .toList(); } catch (Exception ex) { @@ -399,9 +392,6 @@ public abstract class DataStorage { return false; } } finally { - if (context != null && !hadContext) { - context.close(); - } e.decrementBusyCounter(); } diff --git a/app/src/main/java/io/xpipe/app/storage/DataStoreEntry.java b/app/src/main/java/io/xpipe/app/storage/DataStoreEntry.java index b20ad891a..2f25148ea 100644 --- a/app/src/main/java/io/xpipe/app/storage/DataStoreEntry.java +++ b/app/src/main/java/io/xpipe/app/storage/DataStoreEntry.java @@ -516,47 +516,18 @@ public class DataStoreEntry extends StorageElement { } public void validateOrThrow() throws Throwable { - validateOrThrowAndClose(null); - } - - public boolean validateOrThrowAndClose(ValidationContext existingContext) throws Throwable { - var subContext = validateAndKeepOpenOrThrowAndClose(existingContext); - if (subContext != null) { - subContext.close(); - return true; - } else { - return false; - } - } - - @SuppressWarnings("unchecked") - public ValidationContext validateAndKeepOpenOrThrowAndClose(ValidationContext existingContext) - throws Throwable { if (store == null) { - return null; + return; } - if (!(store instanceof ValidatableStore l)) { - return null; + if (!(store instanceof ValidatableStore l)) { + return; } try { store.checkComplete(); incrementBusyCounter(); - ValidationContext context = existingContext != null - ? (ValidationContext) existingContext - : (ValidationContext) l.createContext(); - if (context == null) { - return null; - } - - try { - var r = ((ValidatableStore>) l).validate(context); - return r; - } catch (Throwable t) { - context.close(); - throw t; - } + l.validate(); } finally { decrementBusyCounter(); } 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 b5803dd2c..b44b9c8b6 100644 --- a/app/src/main/java/io/xpipe/app/terminal/ExternalTerminalType.java +++ b/app/src/main/java/io/xpipe/app/terminal/ExternalTerminalType.java @@ -154,7 +154,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue { } private boolean showInfo() { - boolean set = AppCache.get("xshellSetup", Boolean.class, () -> false); + boolean set = AppCache.getBoolean("xshellSetup", false); if (set) { return true; } @@ -368,7 +368,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue { } private boolean showInfo() throws IOException { - boolean set = AppCache.get("termiusSetup", Boolean.class, () -> false); + boolean set = AppCache.getBoolean("termiusSetup", false); if (set) { return true; } diff --git a/app/src/main/java/io/xpipe/app/terminal/KittyTerminalType.java b/app/src/main/java/io/xpipe/app/terminal/KittyTerminalType.java index 0ca65961a..2c28aeb8a 100644 --- a/app/src/main/java/io/xpipe/app/terminal/KittyTerminalType.java +++ b/app/src/main/java/io/xpipe/app/terminal/KittyTerminalType.java @@ -127,7 +127,7 @@ public interface KittyTerminalType extends ExternalTerminalType { var socket = getSocket(); try (var sc = LocalShell.getShell().start()) { if (sc.executeSimpleBooleanCommand( - "test -w " + sc.getShellDialect().fileArgument(socket))) { + "/usr/bin/test -w " + sc.getShellDialect().fileArgument(socket))) { return false; } @@ -174,7 +174,7 @@ public interface KittyTerminalType extends ExternalTerminalType { var socket = getSocket(); try (var sc = LocalShell.getShell().start()) { if (sc.executeSimpleBooleanCommand( - "test -w " + sc.getShellDialect().fileArgument(socket))) { + "/usr/bin/test -w " + sc.getShellDialect().fileArgument(socket))) { return false; } diff --git a/app/src/main/java/io/xpipe/app/terminal/WindowsTerminalType.java b/app/src/main/java/io/xpipe/app/terminal/WindowsTerminalType.java index 9e28987ae..b13ebcff3 100644 --- a/app/src/main/java/io/xpipe/app/terminal/WindowsTerminalType.java +++ b/app/src/main/java/io/xpipe/app/terminal/WindowsTerminalType.java @@ -33,7 +33,8 @@ public interface WindowsTerminalType extends ExternalTerminalType { // wt can't elevate a command consisting out of multiple parts if wt is configured to elevate by default // So work around it by just passing a script file if possible if (ShellDialects.isPowershell(configuration.getScriptDialect())) { - var usesPowershell = ShellDialects.isPowershell(ProcessControlProvider.get().getEffectiveLocalDialect()); + var usesPowershell = + ShellDialects.isPowershell(ProcessControlProvider.get().getEffectiveLocalDialect()); if (usesPowershell) { // We can't work around it in this case, so let's just hope that there's no elevation configured cmd.add(configuration.getDialectLaunchCommand()); @@ -41,7 +42,9 @@ public interface WindowsTerminalType extends ExternalTerminalType { // There might be a mismatch if we are for example using logging // In this case we can actually work around the problem cmd.addFile(shellControl -> { - var script = ScriptHelper.createExecScript(shellControl, configuration.getDialectLaunchCommand().buildFull(shellControl)); + var script = ScriptHelper.createExecScript( + shellControl, + configuration.getDialectLaunchCommand().buildFull(shellControl)); return script.toString(); }); } diff --git a/app/src/main/java/io/xpipe/app/test/TestModule.java b/app/src/main/java/io/xpipe/app/test/TestModule.java index 681e5f3cd..46f1fb94d 100644 --- a/app/src/main/java/io/xpipe/app/test/TestModule.java +++ b/app/src/main/java/io/xpipe/app/test/TestModule.java @@ -1,10 +1,11 @@ package io.xpipe.app.test; +import io.xpipe.core.util.FailableSupplier; + +import lombok.SneakyThrows; import org.junit.jupiter.api.Named; import java.util.*; -import java.util.function.Supplier; -import java.util.stream.Collectors; import java.util.stream.Stream; public abstract class TestModule { @@ -12,6 +13,7 @@ public abstract class TestModule { private static final Map, Map> values = new LinkedHashMap<>(); @SuppressWarnings({"unchecked", "rawtypes"}) + @SneakyThrows public static Map get(Class c, Module module, String... classes) { if (!values.containsKey(c)) { List> loadedClasses = Arrays.stream(classes) @@ -31,8 +33,13 @@ public abstract class TestModule { }); } - return (Map) values.get(c).entrySet().stream() - .collect(Collectors.toMap(o -> o.getKey(), o -> ((Supplier) o.getValue()).get())); + Map map = new HashMap<>(); + for (Map.Entry o : values.get(c).entrySet()) { + if (map.put(o.getKey(), ((FailableSupplier) o.getValue()).get()) != null) { + throw new IllegalStateException("Duplicate key"); + } + } + return (Map) map; } public static Stream> getArguments(Class c, Module module, String... classes) { @@ -43,7 +50,7 @@ public abstract class TestModule { return argumentBuilder.build(); } - protected abstract void init(Map> list) throws Exception; + protected abstract void init(Map> list) throws Exception; protected abstract Class getValueClass(); } diff --git a/app/src/main/java/io/xpipe/app/update/AppDownloads.java b/app/src/main/java/io/xpipe/app/update/AppDownloads.java index 9e5f03064..368ad3608 100644 --- a/app/src/main/java/io/xpipe/app/update/AppDownloads.java +++ b/app/src/main/java/io/xpipe/app/update/AppDownloads.java @@ -1,9 +1,11 @@ package io.xpipe.app.update; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; import io.xpipe.app.core.AppProperties; import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.issue.TrackEvent; import io.xpipe.app.util.HttpHelper; +import io.xpipe.core.process.OsType; import io.xpipe.core.util.JacksonMapper; import org.apache.commons.io.FileUtils; @@ -15,6 +17,9 @@ import org.kohsuke.github.authorization.AuthorizationProvider; import java.io.IOException; import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; @@ -112,30 +117,39 @@ public class AppDownloads { } } - public static Optional getTopReleaseIncludingPreRelease() throws IOException { - var repo = getRepository(); - return Optional.ofNullable(repo.listReleases().iterator().next()); + private static String queryLatestVersion(boolean first, boolean securityOnly) throws Exception { + var req = JsonNodeFactory.instance.objectNode(); + req.put("securityOnly", securityOnly); + req.put("ptb", AppProperties.get().isStaging()); + req.put("os", OsType.getLocal().getId()); + req.put("arch", AppProperties.get().getArch()); + req.put("uuid", AppProperties.get().getUuid().toString()); + req.put("version", AppProperties.get().getVersion()); + req.put("first", first); + var url = URI.create("https://api.xpipe.io/version"); + + var builder = HttpRequest.newBuilder(); + var httpRequest = builder.uri(url) + .POST(HttpRequest.BodyPublishers.ofString(req.toPrettyString())) + .build(); + var client = HttpClient.newHttpClient(); + var response = client.send(httpRequest, HttpResponse.BodyHandlers.ofString()); + if (response.statusCode() != 200) { + throw new IOException(response.body()); + } + + var json = JacksonMapper.getDefault().readTree(response.body()); + var ver = json.required("version").asText(); + return ver; } - public static Optional getMarkedLatestRelease() throws IOException { - var repo = getRepository(); - return Optional.ofNullable(repo.getLatestRelease()); - } - - public static Optional getLatestSuitableRelease() throws IOException { + public static Optional queryLatestRelease(boolean first, boolean securityOnly) throws Exception { try { - var preIncluding = getTopReleaseIncludingPreRelease(); - // If we are currently running a prerelease, always return this as the suitable release! - if (preIncluding.isPresent() - && preIncluding.get().isPrerelease() - && AppProperties.get() - .getVersion() - .equals(preIncluding.get().getTagName())) { - return preIncluding; - } - - return getMarkedLatestRelease(); - } catch (IOException e) { + var ver = queryLatestVersion(first, securityOnly); + var repo = getRepository(); + var rel = repo.getReleaseByTagName(ver); + return Optional.ofNullable(rel); + } catch (Exception e) { throw ErrorEvent.expected(e); } } diff --git a/app/src/main/java/io/xpipe/app/update/AppInstaller.java b/app/src/main/java/io/xpipe/app/update/AppInstaller.java index 4bf7a63a7..b4d50b8c5 100644 --- a/app/src/main/java/io/xpipe/app/update/AppInstaller.java +++ b/app/src/main/java/io/xpipe/app/update/AppInstaller.java @@ -3,7 +3,6 @@ package io.xpipe.app.update; import io.xpipe.app.core.AppLogs; import io.xpipe.app.core.AppProperties; import io.xpipe.app.core.mode.OperationMode; -import io.xpipe.app.ext.LocalStore; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.terminal.ExternalTerminalType; import io.xpipe.app.util.LocalShell; @@ -79,7 +78,6 @@ public class AppInstaller { @Override public void installLocal(Path file) throws Exception { - var shellProcessControl = new LocalStore().control().start(); var exec = (AppProperties.get().isDevelopmentEnvironment() ? Path.of(XPipeInstallation.getLocalDefaultInstallationBasePath()) : XPipeInstallation.getCurrentInstallationBasePath()) @@ -98,7 +96,7 @@ public class AppInstaller { + ScriptHelper.createLocalExecScript(command) + "`\"\""; runAndClose(() -> { - shellProcessControl.executeSimpleCommand(toRun); + LocalShell.getShell().executeSimpleCommand(toRun); }); } diff --git a/app/src/main/java/io/xpipe/app/update/ChocoUpdater.java b/app/src/main/java/io/xpipe/app/update/ChocoUpdater.java deleted file mode 100644 index affc965fa..000000000 --- a/app/src/main/java/io/xpipe/app/update/ChocoUpdater.java +++ /dev/null @@ -1,58 +0,0 @@ -package io.xpipe.app.update; - -import io.xpipe.app.core.AppProperties; -import io.xpipe.app.ext.LocalStore; -import io.xpipe.app.fxcomps.impl.CodeSnippet; -import io.xpipe.app.fxcomps.impl.CodeSnippetComp; - -import javafx.beans.property.SimpleObjectProperty; -import javafx.scene.layout.Region; - -import java.time.Instant; - -public class ChocoUpdater extends UpdateHandler { - - public ChocoUpdater() { - super(true); - } - - @Override - public Region createInterface() { - var snippet = CodeSnippet.builder() - .keyword("choco") - .space() - .identifier("install") - .space() - .string("xpipe") - .space() - .keyword("--version=" + getPreparedUpdate().getValue().getVersion()) - .build(); - return new CodeSnippetComp(false, new SimpleObjectProperty<>(snippet)).createRegion(); - } - - public AvailableRelease refreshUpdateCheckImpl() throws Exception { - try (var sc = new LocalStore().control().start()) { - var latest = sc.executeSimpleStringCommand("choco outdated -r --nocolor") - .lines() - .filter(s -> s.startsWith("xpipe")) - .findAny() - .map(string -> string.split("\\|")[2]); - if (latest.isEmpty()) { - return null; - } - - var isUpdate = isUpdate(latest.get()); - var rel = new AvailableRelease( - AppProperties.get().getVersion(), - XPipeDistributionType.get().getId(), - latest.get(), - "https://community.chocolatey.org/packages/xpipe/" + latest, - null, - null, - Instant.now(), - isUpdate); - lastUpdateCheckResult.setValue(rel); - return lastUpdateCheckResult.getValue(); - } - } -} 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 e256053f1..e4966f352 100644 --- a/app/src/main/java/io/xpipe/app/update/GitHubUpdater.java +++ b/app/src/main/java/io/xpipe/app/update/GitHubUpdater.java @@ -65,8 +65,8 @@ public class GitHubUpdater extends UpdateHandler { } } - public synchronized AvailableRelease refreshUpdateCheckImpl() throws Exception { - var rel = AppDownloads.getLatestSuitableRelease(); + public synchronized AvailableRelease refreshUpdateCheckImpl(boolean first, boolean securityOnly) throws Exception { + var rel = AppDownloads.queryLatestRelease(first, securityOnly); event("Determined latest suitable release " + rel.map(GHRelease::getName).orElse(null)); 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 13313b668..60a853427 100644 --- a/app/src/main/java/io/xpipe/app/update/PortableUpdater.java +++ b/app/src/main/java/io/xpipe/app/update/PortableUpdater.java @@ -29,8 +29,8 @@ public class PortableUpdater extends UpdateHandler { .createRegion(); } - public synchronized AvailableRelease refreshUpdateCheckImpl() throws Exception { - var rel = AppDownloads.getLatestSuitableRelease(); + public synchronized AvailableRelease refreshUpdateCheckImpl(boolean first, boolean securityOnly) throws Exception { + var rel = AppDownloads.queryLatestRelease(first, securityOnly); event("Determined latest suitable release " + rel.map(GHRelease::getName).orElse(null)); 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 77b17818b..f0d6fd393 100644 --- a/app/src/main/java/io/xpipe/app/update/UpdateAvailableAlert.java +++ b/app/src/main/java/io/xpipe/app/update/UpdateAvailableAlert.java @@ -3,6 +3,7 @@ package io.xpipe.app.update; import io.xpipe.app.comp.base.MarkdownComp; import io.xpipe.app.core.AppI18n; import io.xpipe.app.core.window.AppWindowHelper; +import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.util.Hyperlinks; import javafx.event.ActionEvent; @@ -22,7 +23,7 @@ public class UpdateAvailableAlert { } // Check whether we still have the latest version prepared - uh.refreshUpdateCheckSilent(); + uh.refreshUpdateCheckSilent(false, !AppPrefs.get().automaticallyUpdate().get()); 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 82f1ae293..62d3bcc2c 100644 --- a/app/src/main/java/io/xpipe/app/update/UpdateHandler.java +++ b/app/src/main/java/io/xpipe/app/update/UpdateHandler.java @@ -36,7 +36,7 @@ public abstract class UpdateHandler { protected final boolean updateSucceeded; protected UpdateHandler(boolean startBackgroundThread) { - performedUpdate = AppCache.get("performedUpdate", PerformedUpdate.class, () -> null); + performedUpdate = AppCache.getNonNull("performedUpdate", PerformedUpdate.class, () -> null); var hasUpdated = performedUpdate != null; event("Was updated is " + hasUpdated); if (hasUpdated) { @@ -48,7 +48,7 @@ public abstract class UpdateHandler { updateSucceeded = false; } - preparedUpdate.setValue(AppCache.get("preparedUpdate", PreparedUpdate.class, () -> null)); + preparedUpdate.setValue(AppCache.getNonNull("preparedUpdate", PreparedUpdate.class, () -> null)); // Check if the original version this was downloaded from is still the same if (preparedUpdate.getValue() != null @@ -99,12 +99,14 @@ public abstract class UpdateHandler { private void startBackgroundUpdater() { ThreadHelper.createPlatformThread("updater", true, () -> { + var checked = false; ThreadHelper.sleep(Duration.ofMinutes(5).toMillis()); event("Starting background updater thread"); while (true) { - if (AppPrefs.get().automaticallyUpdate().get()) { + if (AppPrefs.get().automaticallyUpdate().get() || AppPrefs.get().checkForSecurityUpdates().get()) { event("Performing background update"); - refreshUpdateCheckSilent(); + refreshUpdateCheckSilent(!checked, !AppPrefs.get().automaticallyUpdate().get()); + checked = true; prepareUpdate(); } @@ -134,17 +136,9 @@ public abstract class UpdateHandler { return false; } - public final void prepareUpdateAsync() { - ThreadHelper.runAsync(() -> prepareUpdate()); - } - - public final void refreshUpdateCheckAsync() { - ThreadHelper.runAsync(() -> refreshUpdateCheckSilent()); - } - - public final AvailableRelease refreshUpdateCheckSilent() { + public final AvailableRelease refreshUpdateCheckSilent(boolean first, boolean securityOnly) { try { - return refreshUpdateCheck(); + return refreshUpdateCheck(first, securityOnly); } catch (Exception ex) { ErrorEvent.fromThrowable(ex).discard().handle(); return null; @@ -214,7 +208,7 @@ public abstract class UpdateHandler { // Check if prepared update is still the latest. // We only do that here to minimize the sent requests by only executing when it's really necessary - var available = XPipeDistributionType.get().getUpdateHandler().refreshUpdateCheckSilent(); + var available = XPipeDistributionType.get().getUpdateHandler().refreshUpdateCheckSilent(false, !AppPrefs.get().automaticallyUpdate().get()); if (preparedUpdate.getValue() == null) { return; } @@ -233,17 +227,17 @@ public abstract class UpdateHandler { throw new UnsupportedOperationException(); } - public final AvailableRelease refreshUpdateCheck() throws Exception { + public final AvailableRelease refreshUpdateCheck(boolean first, boolean securityOnly) throws Exception { if (busy.getValue()) { return lastUpdateCheckResult.getValue(); } try (var ignored = new BooleanScope(busy).start()) { - return refreshUpdateCheckImpl(); + return refreshUpdateCheckImpl(first, securityOnly); } } - public abstract AvailableRelease refreshUpdateCheckImpl() throws Exception; + public abstract AvailableRelease refreshUpdateCheckImpl(boolean first, boolean securityOnly) throws Exception; @Value @Builder diff --git a/app/src/main/java/io/xpipe/app/update/XPipeDistributionType.java b/app/src/main/java/io/xpipe/app/update/XPipeDistributionType.java index 58c88c8a2..9a8036808 100644 --- a/app/src/main/java/io/xpipe/app/update/XPipeDistributionType.java +++ b/app/src/main/java/io/xpipe/app/update/XPipeDistributionType.java @@ -24,7 +24,7 @@ public enum XPipeDistributionType { NATIVE_INSTALLATION("install", true, () -> new GitHubUpdater(true)), HOMEBREW("homebrew", true, () -> new HomebrewUpdater()), WEBTOP("webtop", true, () -> new PortableUpdater(false)), - CHOCO("choco", true, () -> new ChocoUpdater()); + CHOCO("choco", true, () -> new PortableUpdater(true)); private static XPipeDistributionType type; @@ -54,7 +54,7 @@ public enum XPipeDistributionType { } if (!XPipeSession.get().isNewBuildSession()) { - var cached = AppCache.get("dist", String.class, () -> null); + var cached = AppCache.getNonNull("dist", String.class, () -> null); var cachedType = Arrays.stream(values()) .filter(xPipeDistributionType -> xPipeDistributionType.getId().equals(cached)) diff --git a/app/src/main/java/io/xpipe/app/util/DataStoreFormatter.java b/app/src/main/java/io/xpipe/app/util/DataStoreFormatter.java index cbf9d0103..815c7e6f5 100644 --- a/app/src/main/java/io/xpipe/app/util/DataStoreFormatter.java +++ b/app/src/main/java/io/xpipe/app/util/DataStoreFormatter.java @@ -1,13 +1,6 @@ package io.xpipe.app.util; -import io.xpipe.app.comp.store.StoreEntryWrapper; -import io.xpipe.app.fxcomps.util.BindingsHelper; import io.xpipe.app.storage.DataStoreEntry; -import io.xpipe.core.process.ShellDialects; -import io.xpipe.core.process.ShellStoreState; -import io.xpipe.core.process.ShellTtyState; - -import javafx.beans.value.ObservableValue; import java.util.Arrays; @@ -17,45 +10,6 @@ public class DataStoreFormatter { return String.join(" ", Arrays.stream(elements).filter(s -> s != null).toList()); } - public static String formattedOsName(String osName) { - osName = osName.replaceAll("^Microsoft ", ""); - - var proRequired = !LicenseProvider.get().checkOsName(osName); - if (!proRequired) { - return osName; - } - - return "[Pro] " + osName; - } - - public static ObservableValue shellInformation(StoreEntryWrapper w) { - return BindingsHelper.map(w.getPersistentState(), o -> { - if (o instanceof ShellStoreState s) { - if (s.getRunning() == null) { - return null; - } - - if (s.getShellDialect() != null - && !s.getShellDialect().getDumbMode().supportsAnyPossibleInteraction()) { - if (s.getOsName() != null) { - return formattedOsName(s.getOsName()); - } - - if (s.getShellDialect().equals(ShellDialects.NO_INTERACTION)) { - return null; - } - - return s.getShellDialect().getDisplayName(); - } - - var prefix = s.getTtyState() != null && s.getTtyState() != ShellTtyState.NONE ? "[PTY] " : ""; - return s.isRunning() ? prefix + formattedOsName(s.getOsName()) : "Connection failed"; - } - - return "?"; - }); - } - public static String capitalize(String name) { if (name == null) { return null; diff --git a/app/src/main/java/io/xpipe/app/util/FixedHierarchyStore.java b/app/src/main/java/io/xpipe/app/util/FixedHierarchyStore.java index f8104e303..7259e1089 100644 --- a/app/src/main/java/io/xpipe/app/util/FixedHierarchyStore.java +++ b/app/src/main/java/io/xpipe/app/util/FixedHierarchyStore.java @@ -3,22 +3,14 @@ package io.xpipe.app.util; import io.xpipe.app.storage.DataStoreEntryRef; import io.xpipe.core.store.DataStore; import io.xpipe.core.store.FixedChildStore; -import io.xpipe.core.store.ValidatableStore; -import io.xpipe.core.store.ValidationContext; import java.util.List; -public interface FixedHierarchyStore> extends ValidatableStore, DataStore { +public interface FixedHierarchyStore extends DataStore { default boolean removeLeftovers() { return true; } - @Override - default T validate(T context) throws Exception { - listChildren(context); - return null; - } - - List> listChildren(T context) throws Exception; + List> listChildren() throws Exception; } diff --git a/app/src/main/java/io/xpipe/app/util/HostHelper.java b/app/src/main/java/io/xpipe/app/util/HostHelper.java index 9e337ff01..12f5543fa 100644 --- a/app/src/main/java/io/xpipe/app/util/HostHelper.java +++ b/app/src/main/java/io/xpipe/app/util/HostHelper.java @@ -14,9 +14,11 @@ public class HostHelper { return p; } - public static int findRandomOpenPortOnAllLocalInterfaces() throws IOException { + public static int findRandomOpenPortOnAllLocalInterfaces() { try (ServerSocket socket = new ServerSocket(0)) { return socket.getLocalPort(); + } catch (IOException e) { + return randomPort(); } } 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 5bacad2c5..d590511f2 100644 --- a/app/src/main/java/io/xpipe/app/util/Hyperlinks.java +++ b/app/src/main/java/io/xpipe/app/util/Hyperlinks.java @@ -7,7 +7,7 @@ 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"; + public static final String GITHUB_PTB = "https://github.com/xpipe-io/xpipe-ptb"; 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"; diff --git a/app/src/main/java/io/xpipe/app/util/LicenseProvider.java b/app/src/main/java/io/xpipe/app/util/LicenseProvider.java index 78a2cae4f..80f3e2865 100644 --- a/app/src/main/java/io/xpipe/app/util/LicenseProvider.java +++ b/app/src/main/java/io/xpipe/app/util/LicenseProvider.java @@ -24,7 +24,7 @@ public abstract class LicenseProvider { public abstract LicensedFeature getFeature(String id); - public abstract boolean checkOsName(String name); + public abstract LicensedFeature checkOsName(String name); public abstract void checkOsNameOrThrow(String s); 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 9ade07951..71c0f73d8 100644 --- a/app/src/main/java/io/xpipe/app/util/LicensedFeature.java +++ b/app/src/main/java/io/xpipe/app/util/LicensedFeature.java @@ -1,19 +1,28 @@ package io.xpipe.app.util; +import io.xpipe.app.core.AppI18n; + +import javafx.beans.value.ObservableValue; + import java.util.Optional; public interface LicensedFeature { - default Optional getDescriptionSuffix() { - if (isSupported()) { - return Optional.empty(); - } + Optional getDescriptionSuffix(); - if (isPreviewSupported()) { - return Optional.of("Preview"); - } + public default ObservableValue suffixObservable(ObservableValue s) { + return s.map(s2 -> + getDescriptionSuffix().map(suffix -> s2 + " (" + suffix + "+)").orElse(s2)); + } - return Optional.of("Pro"); + public default ObservableValue suffixObservable(String key) { + return AppI18n.observable(key).map(s -> getDescriptionSuffix() + .map(suffix -> s + " (" + suffix + "+)") + .orElse(s)); + } + + public default String suffix(String s) { + return getDescriptionSuffix().map(suffix -> s + " (" + suffix + "+)").orElse(s); } String getId(); 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 5725b5a54..07242dcc1 100644 --- a/app/src/main/java/io/xpipe/app/util/OptionsBuilder.java +++ b/app/src/main/java/io/xpipe/app/util/OptionsBuilder.java @@ -5,6 +5,7 @@ import io.xpipe.app.core.AppI18n; import io.xpipe.app.ext.GuiDialog; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.impl.*; +import io.xpipe.app.prefs.AppPrefs; import io.xpipe.core.util.InPlaceSecretValue; import javafx.beans.property.*; @@ -147,6 +148,28 @@ public class OptionsBuilder { return this; } + public OptionsBuilder pref(Object property) { + var mapping = AppPrefs.get().getMapping(property); + var name = mapping.getKey(); + name(name); + if (mapping.isRequiresRestart()) { + description(AppI18n.observable(name + "Description").map(s -> s + "\n\n" + AppI18n.get("requiresRestart"))); + } else { + description(AppI18n.observable(name + "Description")); + } + if (mapping.getLicenseFeatureId() != null) { + licenseRequirement(mapping.getLicenseFeatureId()); + } + return this; + } + + public OptionsBuilder licenseRequirement(String featureId) { + var f = LicenseProvider.get().getFeature(featureId); + name = f.suffixObservable(name); + lastNameReference = name; + return this; + } + public OptionsBuilder check(Function c) { lastCompHeadReference.apply(s -> c.apply(ownValidator).decorates(s.get())); return this; diff --git a/app/src/main/java/io/xpipe/app/util/ScanAlert.java b/app/src/main/java/io/xpipe/app/util/ScanAlert.java index 93a5284c4..ba316969d 100644 --- a/app/src/main/java/io/xpipe/app/util/ScanAlert.java +++ b/app/src/main/java/io/xpipe/app/util/ScanAlert.java @@ -2,14 +2,12 @@ package io.xpipe.app.util; import io.xpipe.app.comp.base.DialogComp; import io.xpipe.app.ext.ScanProvider; +import io.xpipe.app.ext.ShellStore; import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.storage.DataStoreEntry; import io.xpipe.core.process.ShellControl; import io.xpipe.core.process.ShellStoreState; import io.xpipe.core.process.ShellTtyState; -import io.xpipe.core.store.ShellStore; -import io.xpipe.core.store.ShellValidationContext; -import io.xpipe.core.store.ValidationContext; import java.util.ArrayList; import java.util.List; @@ -17,7 +15,7 @@ import java.util.function.BiFunction; public class ScanAlert { - public static void showAsync(DataStoreEntry entry, ValidationContext context) { + public static void showAsync(DataStoreEntry entry) { ThreadHelper.runAsync(() -> { var showForCon = entry == null || (entry.getStore() instanceof ShellStore @@ -25,53 +23,48 @@ public class ScanAlert { || shellStoreState.getTtyState() == null || shellStoreState.getTtyState() == ShellTtyState.NONE)); if (showForCon) { - showForShellStore(entry, (ShellValidationContext) context); + showForShellStore(entry); } }); } - public static void showForShellStore(DataStoreEntry initial, ShellValidationContext context) { - show( - initial, - (DataStoreEntry entry, ShellControl sc) -> { - if (!sc.canHaveSubshells()) { - return null; - } + public static void showForShellStore(DataStoreEntry initial) { + show(initial, (DataStoreEntry entry, ShellControl sc) -> { + if (!sc.canHaveSubshells()) { + return null; + } - if (!sc.getShellDialect().getDumbMode().supportsAnyPossibleInteraction()) { - return null; - } + if (!sc.getShellDialect().getDumbMode().supportsAnyPossibleInteraction()) { + return null; + } - if (sc.getTtyState() != ShellTtyState.NONE) { - return null; - } + if (sc.getTtyState() != ShellTtyState.NONE) { + return null; + } - var providers = ScanProvider.getAll(); - var applicable = new ArrayList(); - for (ScanProvider scanProvider : providers) { - try { - // Previous scan operation could have exited the shell - sc.start(); - ScanProvider.ScanOperation operation = scanProvider.create(entry, sc); - if (operation != null) { - applicable.add(operation); - } - } catch (Exception ex) { - ErrorEvent.fromThrowable(ex).handle(); - } + var providers = ScanProvider.getAll(); + var applicable = new ArrayList(); + for (ScanProvider scanProvider : providers) { + try { + // Previous scan operation could have exited the shell + sc.start(); + ScanProvider.ScanOpportunity operation = scanProvider.create(entry, sc); + if (operation != null) { + applicable.add(operation); } - return applicable; - }, - context); + } catch (Exception ex) { + ErrorEvent.fromThrowable(ex).handle(); + } + } + return applicable; + }); } private static void show( DataStoreEntry initialStore, - BiFunction> applicable, - ShellValidationContext shellValidationContext) { + BiFunction> applicable) { DialogComp.showWindow( "scanAlertTitle", - stage -> new ScanDialog( - stage, initialStore != null ? initialStore.ref() : null, applicable, shellValidationContext)); + stage -> new ScanDialog(stage, initialStore != null ? initialStore.ref() : null, applicable)); } } diff --git a/app/src/main/java/io/xpipe/app/util/ScanDialog.java b/app/src/main/java/io/xpipe/app/util/ScanDialog.java index 7de23c25c..c5e2d558f 100644 --- a/app/src/main/java/io/xpipe/app/util/ScanDialog.java +++ b/app/src/main/java/io/xpipe/app/util/ScanDialog.java @@ -5,6 +5,7 @@ import io.xpipe.app.comp.base.ListSelectorComp; import io.xpipe.app.comp.store.StoreViewState; import io.xpipe.app.core.AppI18n; import io.xpipe.app.ext.ScanProvider; +import io.xpipe.app.ext.ShellStore; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.impl.DataStoreChoiceComp; import io.xpipe.app.issue.ErrorEvent; @@ -12,8 +13,6 @@ import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStoreEntry; import io.xpipe.app.storage.DataStoreEntryRef; import io.xpipe.core.process.ShellControl; -import io.xpipe.core.store.ShellStore; -import io.xpipe.core.store.ShellValidationContext; import javafx.application.Platform; import javafx.beans.property.*; @@ -34,24 +33,21 @@ import static javafx.scene.layout.Priority.ALWAYS; class ScanDialog extends DialogComp { private final DataStoreEntryRef initialStore; - private final BiFunction> applicable; + private final BiFunction> applicable; private final Stage window; private final ObjectProperty> entry; - private final ListProperty selected = + private final ListProperty selected = new SimpleListProperty<>(FXCollections.observableArrayList()); private final BooleanProperty busy = new SimpleBooleanProperty(); - private ShellValidationContext shellValidationContext; ScanDialog( Stage window, DataStoreEntryRef entry, - BiFunction> applicable, - ShellValidationContext shellValidationContext) { + BiFunction> applicable) { this.window = window; this.initialStore = entry; this.entry = new SimpleObjectProperty<>(entry); this.applicable = applicable; - this.shellValidationContext = shellValidationContext; } @Override @@ -62,55 +58,41 @@ class ScanDialog extends DialogComp { @Override protected void finish() { ThreadHelper.runFailableAsync(() -> { - try { - if (entry.get() == null) { - return; - } - - Platform.runLater(() -> { - window.close(); - }); - - BooleanScope.executeExclusive(busy, () -> { - entry.get().get().setExpanded(true); - var copy = new ArrayList<>(selected); - for (var a : copy) { - // If the user decided to remove the selected entry - // while the scan is running, just return instantly - if (!DataStorage.get() - .getStoreEntriesSet() - .contains(entry.get().get())) { - return; - } - - // Previous scan operation could have exited the shell - shellValidationContext.get().start(); - - try { - a.getScanner().run(); - } catch (Throwable ex) { - ErrorEvent.fromThrowable(ex).handle(); - } - } - }); - } finally { - if (shellValidationContext != null) { - shellValidationContext.close(); - shellValidationContext = null; - } + if (entry.get() == null) { + return; } + + Platform.runLater(() -> { + window.close(); + }); + + BooleanScope.executeExclusive(busy, () -> { + entry.get().get().setExpanded(true); + var copy = new ArrayList<>(selected); + for (var a : copy) { + // If the user decided to remove the selected entry + // while the scan is running, just return instantly + if (!DataStorage.get() + .getStoreEntriesSet() + .contains(entry.get().get())) { + return; + } + + // Previous scan operation could have exited the shell + var sc = initialStore.getStore().getOrStartSession(); + + try { + a.getProvider().scan(entry.get().getEntry(), sc); + } catch (Throwable ex) { + ErrorEvent.fromThrowable(ex).handle(); + } + } + }); }); } @Override - protected void discard() { - ThreadHelper.runAsync(() -> { - if (shellValidationContext != null) { - shellValidationContext.close(); - shellValidationContext = null; - } - }); - } + protected void discard() {} @Override protected Comp pane(Comp content) { @@ -161,22 +143,8 @@ class ScanDialog extends DialogComp { ThreadHelper.runFailableAsync(() -> { BooleanScope.executeExclusive(busy, () -> { - if (shellValidationContext != null) { - shellValidationContext.close(); - shellValidationContext = null; - } - - shellValidationContext = new ShellValidationContext( - newValue.getStore().control().withoutLicenseCheck().start()); - - // Handle window close while connection is established - if (!window.isShowing()) { - discard(); - return; - } - - var a = applicable.apply(entry.get().get(), shellValidationContext.get()); - + var sc = initialStore.getStore().getOrStartSession().withoutLicenseCheck(); + var a = applicable.apply(entry.get().get(), sc); Platform.runLater(() -> { if (a == null) { window.close(); @@ -186,7 +154,7 @@ class ScanDialog extends DialogComp { selected.setAll(a.stream() .filter(scanOperation -> scanOperation.isDefaultSelected() && !scanOperation.isDisabled()) .toList()); - Function nameFunc = (ScanProvider.ScanOperation s) -> { + Function nameFunc = (ScanProvider.ScanOpportunity s) -> { var n = AppI18n.get(s.getNameKey()); if (s.getLicensedFeatureId() == null) { return n; 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 a48fe484d..a081d634d 100644 --- a/app/src/main/java/io/xpipe/app/util/SecretRetrievalStrategy.java +++ b/app/src/main/java/io/xpipe/app/util/SecretRetrievalStrategy.java @@ -1,6 +1,6 @@ package io.xpipe.app.util; -import io.xpipe.app.ext.LocalStore; +import io.xpipe.app.ext.ProcessControlProvider; import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.storage.DataStoreSecret; @@ -180,7 +180,10 @@ public interface SecretRetrievalStrategy { throw ErrorEvent.expected(new IllegalStateException("No custom command specified")); } - try (var cc = new LocalStore().control().command(command).start()) { + try (var cc = ProcessControlProvider.get() + .createLocalProcessControl(true) + .command(command) + .start()) { return new SecretQueryResult( InPlaceSecretValue.of(cc.readStdoutOrThrow()), SecretQueryState.NORMAL); } catch (Exception ex) { diff --git a/app/src/main/java/io/xpipe/app/util/ShellStoreFormat.java b/app/src/main/java/io/xpipe/app/util/ShellStoreFormat.java new file mode 100644 index 000000000..eae88ad8b --- /dev/null +++ b/app/src/main/java/io/xpipe/app/util/ShellStoreFormat.java @@ -0,0 +1,102 @@ +package io.xpipe.app.util; + +import io.xpipe.app.comp.store.StoreSection; +import io.xpipe.app.core.AppI18n; +import io.xpipe.app.fxcomps.util.BindingsHelper; +import io.xpipe.app.prefs.AppPrefs; +import io.xpipe.core.process.ShellDialects; +import io.xpipe.core.process.ShellEnvironmentStoreState; +import io.xpipe.core.process.ShellStoreState; +import io.xpipe.core.process.ShellTtyState; + +import javafx.beans.binding.Bindings; +import javafx.beans.value.ObservableValue; + +import lombok.Value; + +import java.util.Arrays; +import java.util.function.Function; +import java.util.stream.Collectors; + +@Value +public class ShellStoreFormat { + + public static ObservableValue shellEnvironment(StoreSection section, boolean includeOsName) { + return Bindings.createStringBinding( + () -> { + var s = (ShellEnvironmentStoreState) + section.getWrapper().getPersistentState().getValue(); + var def = Boolean.TRUE.equals(s.getSetDefault()) ? AppI18n.get("default") : null; + var name = DataStoreFormatter.join( + (includeOsName ? formattedOsName(s.getOsName()) : null), s.getShellName()); + return new ShellStoreFormat(null, name, new String[] {def}).format(); + }, + AppPrefs.get().language(), + section.getWrapper().getPersistentState()); + } + + @SuppressWarnings("unchecked") + public static ObservableValue shellStore( + StoreSection section, Function f) { + return BindingsHelper.map(section.getWrapper().getPersistentState(), o -> { + var s = (T) o; + var info = f.apply(s); + if (s.getShellDialect() != null + && !s.getShellDialect().getDumbMode().supportsAnyPossibleInteraction()) { + if (s.getOsName() != null) { + return new ShellStoreFormat( + LicenseProvider.get().checkOsName(s.getOsName()), + formattedOsName(s.getOsName()), + new String[] {info}) + .format(); + } + + if (s.getShellDialect().equals(ShellDialects.NO_INTERACTION)) { + return new ShellStoreFormat(null, null, new String[] {info}).format(); + } + + return new ShellStoreFormat( + LicenseProvider.get() + .getFeature(s.getShellDialect().getLicenseFeatureId()), + s.getShellDialect().getDisplayName(), + new String[] {info}) + .format(); + } + + return new ShellStoreFormat( + LicenseProvider.get().checkOsName(s.getOsName()), + formattedOsName(s.getOsName()), + new String[] { + s.getTtyState() != null && s.getTtyState() != ShellTtyState.NONE ? "TTY" : null, info + }) + .format(); + }); + } + + LicensedFeature licensedFeature; + String name; + String[] states; + + public String format() { + var licenseReq = + licensedFeature != null ? licensedFeature.getDescriptionSuffix().orElse(null) : null; + var lic = licenseReq != null ? "[" + licenseReq + "+]" : null; + var name = this.name; + var state = getStates() != null + ? Arrays.stream(getStates()) + .filter(s -> s != null) + .map(s -> "[" + s + "]") + .collect(Collectors.joining(" ")) + : null; + if (state != null && state.isEmpty()) { + state = null; + } + return DataStoreFormatter.join(lic, state, name); + } + + public static String formattedOsName(String osName) { + osName = osName.replaceAll("^Microsoft ", ""); + osName = osName.replaceAll("Enterprise Evaluation", "Enterprise"); + return osName; + } +} diff --git a/app/src/main/java/io/xpipe/app/util/ShellTemp.java b/app/src/main/java/io/xpipe/app/util/ShellTemp.java index 5f4e99e1d..c8183cc57 100644 --- a/app/src/main/java/io/xpipe/app/util/ShellTemp.java +++ b/app/src/main/java/io/xpipe/app/util/ShellTemp.java @@ -83,7 +83,7 @@ public class ShellTemp { } var d = proc.getShellDialect(); - return proc.executeSimpleBooleanCommand("test -r %s && test -w %s && test -x %s" + return proc.executeSimpleBooleanCommand("/usr/bin/test -r %s && /usr/bin/test -w %s && /usr/bin/test -x %s" .formatted(d.fileArgument(dir), d.fileArgument(dir), d.fileArgument(dir))); } diff --git a/app/src/main/java/io/xpipe/app/util/XPipeSession.java b/app/src/main/java/io/xpipe/app/util/XPipeSession.java index c4e16b59c..f5a61ebbc 100644 --- a/app/src/main/java/io/xpipe/app/util/XPipeSession.java +++ b/app/src/main/java/io/xpipe/app/util/XPipeSession.java @@ -25,7 +25,7 @@ public class XPipeSession { return; } - var s = AppCache.get("lastBuildId", String.class, () -> null); + var s = AppCache.getNonNull("lastBuildId", String.class, () -> null); var isBuildChanged = !buildSessionId.toString().equals(s); AppCache.update("lastBuildId", buildSessionId.toString()); INSTANCE = new XPipeSession(isBuildChanged, UUID.randomUUID(), buildSessionId); diff --git a/app/src/main/java/module-info.java b/app/src/main/java/module-info.java index 3f714f216..9502d95e5 100644 --- a/app/src/main/java/module-info.java +++ b/app/src/main/java/module-info.java @@ -94,6 +94,7 @@ open module io.xpipe.app { // For debugging requires jdk.jdwp.agent; + requires java.net.http; uses TerminalLauncher; uses io.xpipe.app.ext.ActionProvider; diff --git a/app/src/main/resources/io/xpipe/app/resources/style/bookmark.css b/app/src/main/resources/io/xpipe/app/resources/style/bookmark.css index 94f1783df..435bc28e0 100644 --- a/app/src/main/resources/io/xpipe/app/resources/style/bookmark.css +++ b/app/src/main/resources/io/xpipe/app/resources/style/bookmark.css @@ -26,15 +26,15 @@ } .bookmarks-container { - -fx-background-color: -color-border-default, -color-bg-subtle; -fx-background-radius: 4 0 0 4; -fx-background-insets: 0 7 8 8, 1 8 9 9; -fx-padding: 1 0 9 9; + -fx-background-color: -color-border-default, -color-bg-default; } .bookmarks-header { - -fx-min-height: 3.3em; - -fx-pref-height: 3.3em; - -fx-max-height: 3.3em; - -fx-padding: 9 6 9 8; + -fx-min-height: 3.4em; + -fx-pref-height: 3.4em; + -fx-max-height: 3.4em; + -fx-padding: 11 6 9 8; } diff --git a/app/src/main/resources/io/xpipe/app/resources/style/browser.css b/app/src/main/resources/io/xpipe/app/resources/style/browser.css index 66a88f648..21dbe4121 100644 --- a/app/src/main/resources/io/xpipe/app/resources/style/browser.css +++ b/app/src/main/resources/io/xpipe/app/resources/style/browser.css @@ -20,7 +20,7 @@ -fx-background-radius: 4; -fx-border-color: -color-border-default; -fx-border-width: 1; - -fx-background-color: -color-bg-subtle; + -fx-background-color: -color-foreground-base; } .transfer:highlighted > .download-background { @@ -37,6 +37,10 @@ -fx-padding: 0.1em 0.2em; } +.browser .transfer .label .ikonli-font-icon { + -fx-icon-color: -color-fg-default; +} + .root.nord .transfer > * { -fx-background-radius: 0; -fx-border-radius: 0; @@ -49,10 +53,8 @@ .browser .top-spacer { -fx-background-color: -color-bg-inset; - -fx-border-width: 0 0 0.05em 0; + -fx-border-width: 0 0 1 0; -fx-border-color: -color-border-default; - -fx-pref-height: 2.65em; - -fx-max-height: 2.65em; } .root:seamless-frame .browser .top-spacer { @@ -95,10 +97,10 @@ } .browser .top-bar { - -fx-min-height: 3.3em; - -fx-pref-height: 3.3em; - -fx-max-height: 3.3em; - -fx-padding: 9px 6px; + -fx-min-height: 3.4em; + -fx-pref-height: 3.4em; + -fx-max-height: 3.4em; + -fx-padding: 11 6 9px 6px; } .browser .top-bar > .button { @@ -132,7 +134,7 @@ -fx-background-radius: 0 0 4 4; -fx-border-width: 1 0 0 0; -fx-border-color: -color-border-default; - -fx-background-color: -color-bg-subtle; + -fx-background-color: -color-foreground-base; -fx-padding: 5 8; } @@ -198,9 +200,6 @@ } .browser .tab-header-area, .browser .headers-region { - -fx-min-height: 2.65em; - -fx-pref-height: 2.65em; - -fx-max-height: 2.65em; } @@ -218,23 +217,12 @@ -fx-background-color: transparent; } -.browser .tab-pane.floating > .tab-header-area { - -fx-border-width: 0 0 0.05em 0; - -fx-border-color: -color-border-default; -} - -.browser .left { - -fx-border-color: -color-border-default, -color-bg-inset; - -fx-border-width: 2.7em 0 0 0, 2.65em 0 0 0; - -fx-background-color: transparent; -} - .browser.chooser .left { -fx-border-width: 0; } .browser .tab-header-area { - -fx-background-color: -color-bg-inset; + -fx-background-color: transparent; } .root:seamless-frame .browser .tab-header-area { @@ -245,20 +233,16 @@ -fx-padding: 6 0 0 0; -fx-border-radius: 4; -fx-background-radius: 4; - -fx-background-color: -color-bg-subtle, -color-bg-default; -fx-background-insets: 0, 7 0 0 0; -fx-border-width: 1; -fx-border-color: -color-border-default; + -fx-background-color: -color-foreground-base, -color-bg-default; } .browser .browser-content-container { -fx-padding: 0 10 7 0; } -.root.cupertino .browser .browser-content { - -fx-background-color: -color-bg-default, -color-bg-default; -} - .root.nord .browser .browser-content { -fx-border-radius: 0; -fx-background-radius: 0; @@ -270,9 +254,7 @@ } .browser .split-pane-divider { - -fx-border-color: -color-border-default, -color-bg-inset; -fx-padding: 0 2 0 3; - -fx-border-width: 2.7em 0 0 0, 2.65em 0 0 0; -fx-opacity: 1.0; -fx-background-color: transparent; } @@ -283,6 +265,11 @@ .table-view .column-header { -fx-pref-height: 2em; + -fx-background-color: -color-foreground-base; +} + +.table-view .column-header-background { + -fx-background-color: -color-foreground-base; } .table-view .column-header-background .label { @@ -335,6 +322,10 @@ -fx-background-radius: 4; } +.browser .tab-label:static { + -fx-padding: 0.4em 0.9em 0.4em 0.7em; +} + .browser .tab { -fx-opacity: 0.6; } diff --git a/app/src/main/resources/io/xpipe/app/resources/style/category.css b/app/src/main/resources/io/xpipe/app/resources/style/category.css index 57881105b..2bfb165b0 100644 --- a/app/src/main/resources/io/xpipe/app/resources/style/category.css +++ b/app/src/main/resources/io/xpipe/app/resources/style/category.css @@ -2,7 +2,7 @@ -fx-background-color: transparent; -fx-background-radius: 4px; -fx-border-radius: 4px; - -fx-border-width: 1px; + -fx-border-width: 0; -fx-padding: 0 0 0 2; -fx-background-insets: 0; } @@ -20,6 +20,10 @@ -fx-background-color: -color-bg-default; } +.category:selected .category-button .name { + -fx-font-weight: BOLD; +} + .root:light .category.yellow > .category-button .expand-button .ikonli-font-icon { -fx-icon-color: #888800; } diff --git a/app/src/main/resources/io/xpipe/app/resources/style/color-box.css b/app/src/main/resources/io/xpipe/app/resources/style/color-box.css index dad290e7e..b1426a3c8 100644 --- a/app/src/main/resources/io/xpipe/app/resources/style/color-box.css +++ b/app/src/main/resources/io/xpipe/app/resources/style/color-box.css @@ -19,12 +19,12 @@ } .root:dark .color-box.gray { - -fx-background-color: derive(-color-bg-default, 13%); + -fx-background-color: -color-foreground-base; -fx-border-color: -color-border-default; } .root:light .color-box.gray { - -fx-background-color: derive(-color-bg-default, -3%); + -fx-background-color: -color-foreground-base; -fx-border-color: derive(-color-border-default, -10%); } diff --git a/app/src/main/resources/io/xpipe/app/resources/style/header-bars.css b/app/src/main/resources/io/xpipe/app/resources/style/header-bars.css index 941f9e470..11a0e6238 100644 --- a/app/src/main/resources/io/xpipe/app/resources/style/header-bars.css +++ b/app/src/main/resources/io/xpipe/app/resources/style/header-bars.css @@ -3,10 +3,15 @@ -fx-padding: 0.8em 1.0em 0.8em 1.0em; } +.bar { + -fx-background-radius: 4; + -fx-border-radius: 4; + -fx-border-width: 1; + -fx-border-color: -color-border-default; + -fx-background-color: -color-bg-subtle; +} + .store-header-bar { - -fx-background-radius: 0 0 4px 0; - -fx-border-radius: 0 0 4px 0; - -fx-border-width: 0 0.05em 0.05em 0; -fx-spacing: 0.8em; } @@ -69,9 +74,6 @@ } .store-creation-bar, .store-sort-bar, .store-category-bar { - -fx-background-radius: 0 4px 4px 0; - -fx-border-radius: 0 4px 4px 0; - -fx-border-width: 0.05em 0.05em 0.05em 0; -fx-spacing: 0.2em; } @@ -85,19 +87,14 @@ } .store-sort-bar { - -fx-background-radius: 0 4px 4px 0; - -fx-border-radius: 0 4px 4px 0; - -fx-border-width: 0.05em 0.05em 0.05em 0; -fx-spacing: 0.2em; } .filler-bar { - -fx-background-radius: 0 4px 0 0; - -fx-border-radius: 0 4px 0 0; - -fx-border-width: 0.05em 0.05em 0 0; } .sidebar { + -fx-padding: 7 0 7 7; -fx-spacing: 0.4em; -fx-background-color: transparent; } 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 a7c05eab0..5bd864d78 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 @@ -33,21 +33,24 @@ .prefs .sidebar { -fx-spacing: 0; - -fx-background-color: -color-bg-subtle; - -fx-border-width: 0 1 0 0; + -fx-background-color: -color-foreground-base; -fx-border-color: -color-border-default; -fx-padding: 0.2em 0 0 0; + -fx-border-width: 1; + -fx-border-radius: 4; + -fx-background-radius: 4; } .prefs .sidebar .button { -fx-background-color: transparent; - -fx-padding: 0.6em 1em 0.6em 1em; + -fx-padding: 0.5em 1em 0.5em 1.0em; -fx-background-radius: 0, 4, 4; - -fx-background-insets: 0, 2 4 2 4, 3 5 3 5; + -fx-background-insets: 0, 1 4 1 4; } .prefs .sidebar .button:selected { -fx-background-color: transparent, -color-border-default, -color-bg-default; + -fx-font-weight: BOLD; } .prefs .sidebar .button:armed { diff --git a/app/src/main/resources/io/xpipe/app/resources/style/sidebar-comp.css b/app/src/main/resources/io/xpipe/app/resources/style/sidebar-comp.css index 855e4f9bc..ace344cbf 100644 --- a/app/src/main/resources/io/xpipe/app/resources/style/sidebar-comp.css +++ b/app/src/main/resources/io/xpipe/app/resources/style/sidebar-comp.css @@ -30,7 +30,7 @@ } .sidebar-comp .icon-button-comp { - -fx-padding: 1.1em; + -fx-padding: 1.1em 0.9em; } .sidebar-comp .icon-button-comp .vbox { diff --git a/app/src/main/resources/io/xpipe/app/resources/style/store-entry-comp.css b/app/src/main/resources/io/xpipe/app/resources/style/store-entry-comp.css index 196adcb76..31e5e27bb 100644 --- a/app/src/main/resources/io/xpipe/app/resources/style/store-entry-comp.css +++ b/app/src/main/resources/io/xpipe/app/resources/style/store-entry-comp.css @@ -1,10 +1,10 @@ .store-list-comp.scroll-pane > .viewport .list-box-content { - -fx-spacing: 8; - -fx-padding: 8 0 8 0; + -fx-spacing: 6; + -fx-padding: 7 0 7 0; } .store-list-comp.scroll-pane { - -fx-padding: 0 2 0 6; + -fx-padding: 0 2 0 4; } .store-list-comp.scroll-pane .scroll-bar:vertical { diff --git a/app/src/main/resources/io/xpipe/app/resources/style/style.css b/app/src/main/resources/io/xpipe/app/resources/style/style.css index ae8e1e256..ef0b124b9 100644 --- a/app/src/main/resources/io/xpipe/app/resources/style/style.css +++ b/app/src/main/resources/io/xpipe/app/resources/style/style.css @@ -14,7 +14,7 @@ } .root:dark:separate-frame .background { - -fx-background-color: derive(-color-bg-default, 1%); + -fx-background-color: derive(-color-bg-default, -3%); } .root:light:separate-frame .background { @@ -22,7 +22,7 @@ } .root:dark:separate-frame.background { - -fx-background-color: derive(-color-bg-default, 1%); + -fx-background-color: derive(-color-bg-default, -3%); } .root:light:separate-frame.background { @@ -148,3 +148,23 @@ -fx-padding: 15 0; -fx-cursor: hand; } + +.root:pretty:light .store-active-comp .dot { + -fx-fill: radial-gradient(radius 180%, rgb(30, 180, 30, 0.6), rgb(20, 120, 20, 0.65), rgb(37, 200, 37, 0.6)); +} + +.root:performance:light .store-active-comp .dot { + -fx-fill: rgb(30, 180, 30, 0.6); +} + +.root:pretty:dark .store-active-comp .dot { + -fx-fill: radial-gradient(radius 180%, rgb(30, 180, 30, 0.8), rgb(20, 120, 20, 0.85), rgb(37, 200, 37, 0.8)); +} + +.root:performance:dark .store-active-comp .dot { + -fx-fill: rgb(30, 180, 30, 0.7); +} + +.custom-text-field .font-icon, .custom-text-field .ikonli-font-icon { + -fx-icon-color: -color-fg-default; +} diff --git a/app/src/main/resources/io/xpipe/app/resources/theme/cupertinoDark.css b/app/src/main/resources/io/xpipe/app/resources/theme/cupertinoDark.css index 3a35500f7..4513aa99a 100644 --- a/app/src/main/resources/io/xpipe/app/resources/theme/cupertinoDark.css +++ b/app/src/main/resources/io/xpipe/app/resources/theme/cupertinoDark.css @@ -1,5 +1,20 @@ -.root { -color-bg-default-transparent: #1C1C1ED2; } +.root:windows { -color-bg-default-transparent: #1C1C1ED2; } -.root.cupertino .button { +.root:macos { -color-bg-default-transparent: #0d0d10D3; } + +.root .button { -fx-effect: NONE; } + +.root .table-view { + -color-cell-bg-odd: derive(-color-bg-subtle, -45%); + -color-cell-bg: derive(-color-bg-subtle, -30%); +} + +.root:dark * { + -color-foreground-base: derive(-color-bg-default, 9%); +} + +.root:light * { + -color-foreground-base: derive(-color-bg-default, -3%); +} diff --git a/app/src/main/resources/io/xpipe/app/resources/theme/cupertinoLight.css b/app/src/main/resources/io/xpipe/app/resources/theme/cupertinoLight.css index 2f4885598..94e1dae51 100644 --- a/app/src/main/resources/io/xpipe/app/resources/theme/cupertinoLight.css +++ b/app/src/main/resources/io/xpipe/app/resources/theme/cupertinoLight.css @@ -1,5 +1,17 @@ -.root { -color-bg-default-transparent: #FFFFFFCC; } +.root { -color-bg-default-transparent: #FFFFFFCF; } -.root.cupertino .button { +.root .button { -fx-effect: NONE; } + +.root .table-view { + -color-cell-bg-odd: derive(-color-bg-subtle, 35%); +} + +.root:dark * { + -color-foreground-base: derive(-color-bg-default, 13%); +} + +.root:light * { + -color-foreground-base: derive(-color-bg-default, -3%); +} \ No newline at end of file diff --git a/app/src/main/resources/io/xpipe/app/resources/theme/dark.css b/app/src/main/resources/io/xpipe/app/resources/theme/dark.css index e27a340b5..68b0f7a52 100644 --- a/app/src/main/resources/io/xpipe/app/resources/theme/dark.css +++ b/app/src/main/resources/io/xpipe/app/resources/theme/dark.css @@ -1 +1,16 @@ -.root { -color-bg-default-transparent: #0d1117d2; } \ No newline at end of file +.root:windows { -color-bg-default-transparent: #0d1117d2; } + +.root:macos { -color-bg-default-transparent: #080d13d3; } + +.root .table-view { + -color-cell-bg-odd: derive(-color-bg-subtle, -45%); + -color-cell-bg: derive(-color-bg-subtle, -30%); +} + +.root:dark * { + -color-foreground-base: derive(-color-bg-default, 10%); +} + +.root:light * { + -color-foreground-base: derive(-color-bg-default, -3%); +} \ No newline at end of file diff --git a/app/src/main/resources/io/xpipe/app/resources/theme/dracula.css b/app/src/main/resources/io/xpipe/app/resources/theme/dracula.css index 98caee1a0..6d09e818a 100644 --- a/app/src/main/resources/io/xpipe/app/resources/theme/dracula.css +++ b/app/src/main/resources/io/xpipe/app/resources/theme/dracula.css @@ -1 +1,16 @@ -.root { -color-bg-default-transparent: #282a36D2; } \ No newline at end of file +.root:windows { -color-bg-default-transparent: #282a36D2; } + +.root:macos { -color-bg-default-transparent: #20212cD3; } + +.root .table-view { + -color-cell-bg-odd: derive(-color-bg-subtle, -35%); + -color-cell-bg: derive(-color-bg-subtle, -28%); +} + +.root:dark * { + -color-foreground-base: derive(-color-bg-default, 9%); +} + +.root:light * { + -color-foreground-base: derive(-color-bg-default, -3%); +} \ No newline at end of file diff --git a/app/src/main/resources/io/xpipe/app/resources/theme/light.css b/app/src/main/resources/io/xpipe/app/resources/theme/light.css index fbbefc2be..d9d5ba770 100644 --- a/app/src/main/resources/io/xpipe/app/resources/theme/light.css +++ b/app/src/main/resources/io/xpipe/app/resources/theme/light.css @@ -1 +1,13 @@ -.root { -color-bg-default-transparent: #FFFFFFCC; } \ No newline at end of file +.root { -color-bg-default-transparent: #FFFFFFCF; } + +.root .table-view { + -color-cell-bg-odd: derive(-color-bg-subtle, 35%); +} + +.root:dark * { + -color-foreground-base: derive(-color-bg-default, 13%); +} + +.root:light * { + -color-foreground-base: derive(-color-bg-default, -3%); +} \ No newline at end of file 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 a6a726520..4587c84b1 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 @@ -1,16 +1,16 @@ .root { - -color-dark: rgb(255, 255, 255); - -color-light: rgb(0, 0, 0); - -color-base-0: #f2f2f7; - -color-base-1: #e5e5ea; - -color-base-2: #d1d1d6; - -color-base-3: #aeaeb2; - -color-base-4: rgb(142, 142, 147); - -color-base-5: rgb(99, 99, 102); - -color-base-6: rgb(72, 72, 74); - -color-base-7: rgb(58, 58, 60); - -color-base-8: rgb(44, 44, 46); - -color-base-9: rgb(28, 28, 30); + -color-dark: #010409; + -color-light: #ffffff; + -color-base-0: #f0f6fc; + -color-base-1: #c9d1d9; + -color-base-2: #b1bac4; + -color-base-3: #8b949e; + -color-base-4: #6e7681; + -color-base-5: #484f58; + -color-base-6: #30363d; + -color-base-7: #21262d; + -color-base-8: #161b22; + -color-base-9: #0d1117; -color-accent-0: #c2e0ff; -color-accent-1: #9dceff; -color-accent-2: #78bbff; @@ -110,7 +110,19 @@ -color-chart-8-alpha20: rgba(136, 136, 136, 0.2); -fx-background-color: -color-bg-default; -fx-font-size: 14px; - -fx-background-radius: inherit; - -fx-background-insets: inherit; - -fx-padding: inherit; -} \ No newline at end of file +} + +.root { -color-bg-default-transparent: #0d1117d2; } + +.root .table-view { + -color-cell-bg-odd: derive(-color-bg-subtle, -35%); + -color-cell-bg: derive(-color-bg-subtle, -30%); +} + +.root:dark * { + -color-foreground-base: derive(-color-bg-default, 9%); +} + +.root:light * { + -color-foreground-base: derive(-color-bg-default, -3%); +} diff --git a/app/src/main/resources/io/xpipe/app/resources/theme/nordDark.css b/app/src/main/resources/io/xpipe/app/resources/theme/nordDark.css index 971cb51fa..f18fa410f 100644 --- a/app/src/main/resources/io/xpipe/app/resources/theme/nordDark.css +++ b/app/src/main/resources/io/xpipe/app/resources/theme/nordDark.css @@ -1 +1,14 @@ -.root { -color-bg-default-transparent: #2E3440d2; } \ No newline at end of file +.root { -color-bg-default-transparent: #2E3440d2; } + +.root .table-view { + -color-cell-bg-odd: derive(-color-bg-subtle, -15%); + -color-cell-bg: derive(-color-bg-subtle, -10%); +} + +.root:dark * { + -color-foreground-base: derive(-color-bg-default, 9%); +} + +.root:light * { + -color-foreground-base: derive(-color-bg-default, -3%); +} \ No newline at end of file diff --git a/app/src/main/resources/io/xpipe/app/resources/theme/nordLight.css b/app/src/main/resources/io/xpipe/app/resources/theme/nordLight.css index a663e3dd9..61f9bfee8 100644 --- a/app/src/main/resources/io/xpipe/app/resources/theme/nordLight.css +++ b/app/src/main/resources/io/xpipe/app/resources/theme/nordLight.css @@ -1 +1,13 @@ -.root { -color-bg-default-transparent: #fafafcCC; } \ No newline at end of file +.root { -color-bg-default-transparent: #fafafcCF; } + +.root .table-view { + -color-cell-bg-odd: derive(-color-bg-subtle, 20%); +} + +.root:dark * { + -color-foreground-base: derive(-color-bg-default, 13%); +} + +.root:light * { + -color-foreground-base: derive(-color-bg-default, -3%); +} \ No newline at end of file diff --git a/beacon/build.gradle b/beacon/build.gradle index 2e3dcba45..5f2ffcd6c 100644 --- a/beacon/build.gradle +++ b/beacon/build.gradle @@ -17,8 +17,8 @@ repositories { dependencies { compileOnly 'org.hamcrest:hamcrest:3.0' - compileOnly 'org.junit.jupiter:junit-jupiter-api:5.11.0' - compileOnly 'org.junit.jupiter:junit-jupiter-params:5.11.0' + compileOnly 'org.junit.jupiter:junit-jupiter-api:5.11.3' + compileOnly 'org.junit.jupiter:junit-jupiter-params:5.11.3' api project(':core') } diff --git a/build.gradle b/build.gradle index f623415f9..350f0ebb2 100644 --- a/build.gradle +++ b/build.gradle @@ -13,7 +13,7 @@ buildscript { plugins { id("io.github.gradle-nexus.publish-plugin") version "2.0.0" - id 'org.gradlex.extra-java-module-info' version '1.8' apply false + id 'org.gradlex.extra-java-module-info' version '1.9' apply false id("com.diffplug.spotless") version "6.25.0" apply false } @@ -101,8 +101,7 @@ project.ext { os = org.gradle.internal.os.OperatingSystem.current() allExtensions = Stream.concat(Stream.of(project(':base')), Arrays.stream(file("$rootDir/ext").list()) .filter(s -> file("$rootDir/ext/$s/build.gradle").exists()) - .filter(s -> !s.equals('base') && !s.equals('csv') && !s.equals('office') && !s.equals('pdx') && !s.equals('jackson') && !s.equals( - 'collections')) + .filter(s -> !s.equals('base')) .map(l -> project(":$l"))).toList() fullVersion = file("$rootDir/private_files.txt").exists() arch = getArchName() @@ -125,7 +124,7 @@ project.ext { website = 'https://xpipe.io' sourceWebsite = isStage ? 'https://github.com/xpipe-io/xpipe-ptb' : 'https://github.com/xpipe-io/xpipe' authors = 'Christopher Schnick' - javafxVersion = '24-ea+5' + javafxVersion = '24-ea+15' platformName = getPlatformName() languages = ["en", "nl", "es", "fr", "de", "it", "pt", "ru", "ja", "zh", "tr", "da"] jvmRunArgs = [ @@ -208,7 +207,6 @@ def testTasks = [ project(':core').getTasksByName('test', true), project(':app').getTasksByName('test', true), project(':base').getTasksByName('localTest', true), - project(':jdbc').getTasksByName('localTest', true), project(':proc').getTasksByName('localTest', true), ] diff --git a/core/build.gradle b/core/build.gradle index c8478cb37..dda6b791a 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -13,8 +13,8 @@ compileJava { } dependencies { - api group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: "2.17.2" - implementation group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: "2.17.2" + api group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: "2.18.1" + implementation group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: "2.18.1" } version = rootProject.versionString 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 db402e2a7..a75bb4f1b 100644 --- a/core/src/main/java/io/xpipe/core/process/CommandBuilder.java +++ b/core/src/main/java/io/xpipe/core/process/CommandBuilder.java @@ -8,7 +8,6 @@ import lombok.Getter; import lombok.SneakyThrows; import java.util.*; -import java.util.function.Function; public class CommandBuilder { diff --git a/core/src/main/java/io/xpipe/core/process/ElevationFunction.java b/core/src/main/java/io/xpipe/core/process/ElevationFunction.java index 25afe2c94..fa09c7ff5 100644 --- a/core/src/main/java/io/xpipe/core/process/ElevationFunction.java +++ b/core/src/main/java/io/xpipe/core/process/ElevationFunction.java @@ -22,7 +22,7 @@ public interface ElevationFunction { return false; } - var isRoot = shellControl.executeSimpleBooleanCommand("test \"${EUID:-$(id -u)}\" -eq 0"); + var isRoot = shellControl.executeSimpleBooleanCommand("/usr/bin/test \"${EUID:-$(id -u)}\" -eq 0"); if (isRoot) { return false; } diff --git a/core/src/main/java/io/xpipe/core/process/ProcessControl.java b/core/src/main/java/io/xpipe/core/process/ProcessControl.java index ef489093d..38d79883a 100644 --- a/core/src/main/java/io/xpipe/core/process/ProcessControl.java +++ b/core/src/main/java/io/xpipe/core/process/ProcessControl.java @@ -17,6 +17,8 @@ public interface ProcessControl extends AutoCloseable { String prepareTerminalOpen(TerminalInitScriptConfig config, WorkingDirectoryFunction workingDirectory) throws Exception; + void refreshRunningState(); + void closeStdin() throws IOException; boolean isStdinClosed(); 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 55197b0c5..948ed80df 100644 --- a/core/src/main/java/io/xpipe/core/process/ShellControl.java +++ b/core/src/main/java/io/xpipe/core/process/ShellControl.java @@ -1,7 +1,7 @@ package io.xpipe.core.process; +import io.xpipe.core.store.DataStore; import io.xpipe.core.store.FilePath; -import io.xpipe.core.store.ShellStore; import io.xpipe.core.store.StatefulDataStore; import io.xpipe.core.util.FailableConsumer; import io.xpipe.core.util.FailableFunction; @@ -18,6 +18,8 @@ import java.util.function.Function; public interface ShellControl extends ProcessControl { + Optional getParentControl(); + ShellTtyState getTtyState(); void setNonInteractive(); @@ -32,9 +34,9 @@ public interface ShellControl extends ProcessControl { void setWorkingDirectory(WorkingDirectoryFunction workingDirectory); - Optional getSourceStore(); + Optional getSourceStore(); - ShellControl withSourceStore(ShellStore store); + ShellControl withSourceStore(DataStore store); List getInitCommands(); diff --git a/core/src/main/java/io/xpipe/core/process/ShellDumbMode.java b/core/src/main/java/io/xpipe/core/process/ShellDumbMode.java index d1df401bd..22989bb1a 100644 --- a/core/src/main/java/io/xpipe/core/process/ShellDumbMode.java +++ b/core/src/main/java/io/xpipe/core/process/ShellDumbMode.java @@ -24,7 +24,7 @@ public interface ShellDumbMode { default void prepareDumbInit(ShellControl shellControl) throws Exception {} default void prepareDumbExit(ShellControl shellControl) throws IOException { - shellControl.writeLine("exit"); + shellControl.writeLine(" exit"); } class Unsupported implements ShellDumbMode { diff --git a/core/src/main/java/io/xpipe/core/store/FileSystemStore.java b/core/src/main/java/io/xpipe/core/store/FileSystemStore.java index 1c8f01460..0eb636efa 100644 --- a/core/src/main/java/io/xpipe/core/store/FileSystemStore.java +++ b/core/src/main/java/io/xpipe/core/store/FileSystemStore.java @@ -2,5 +2,5 @@ package io.xpipe.core.store; public interface FileSystemStore extends DataStore { - FileSystem createFileSystem(); + FileSystem createFileSystem() throws Exception; } 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 27cbb81e5..7307143dd 100644 --- a/core/src/main/java/io/xpipe/core/store/NetworkTunnelStore.java +++ b/core/src/main/java/io/xpipe/core/store/NetworkTunnelStore.java @@ -17,7 +17,7 @@ public interface NetworkTunnelStore extends DataStore { interface TunnelFunction { - NetworkTunnelSession create(int localPort, int remotePort); + NetworkTunnelSession create(int localPort, int remotePort, String address) throws Exception; } DataStore getNetworkParent(); @@ -57,7 +57,7 @@ public interface NetworkTunnelStore extends DataStore { } } - default NetworkTunnelSession sessionChain(int local, int remotePort) throws Exception { + default NetworkTunnelSession sessionChain(int local, int remotePort, String address) throws Exception { if (!isLocallyTunneable()) { throw new IllegalStateException( "Unable to create tunnel chain as one intermediate system does not support tunneling"); @@ -75,7 +75,7 @@ public interface NetworkTunnelStore extends DataStore { var currentLocalPort = isLast(current) ? local : randomPort(); var currentRemotePort = sessions.isEmpty() ? remotePort : sessions.getLast().getLocalPort(); - var t = func.create(currentLocalPort, currentRemotePort); + var t = func.create(currentLocalPort, currentRemotePort, current == this ? address : "localhost"); t.start(); sessions.add(t); counter.incrementAndGet(); diff --git a/core/src/main/java/io/xpipe/core/store/ShellStore.java b/core/src/main/java/io/xpipe/core/store/ShellStore.java deleted file mode 100644 index 2292586b4..000000000 --- a/core/src/main/java/io/xpipe/core/store/ShellStore.java +++ /dev/null @@ -1,33 +0,0 @@ -package io.xpipe.core.store; - -import io.xpipe.core.process.ShellControl; - -public interface ShellStore extends DataStore, FileSystemStore, ValidatableStore { - - @Override - default FileSystem createFileSystem() { - return new ConnectionFileSystem(control()); - } - - ShellControl parentControl(); - - ShellControl control(ShellControl parent); - - default ShellControl control() { - return control(parentControl()); - } - - @Override - default ShellValidationContext validate(ShellValidationContext context) throws Exception { - var c = control(context.get()); - if (!isInStorage()) { - c.withoutLicenseCheck(); - } - return new ShellValidationContext(c.start()); - } - - @Override - default ShellValidationContext createContext() throws Exception { - return new ShellValidationContext(parentControl().start()); - } -} diff --git a/core/src/main/java/io/xpipe/core/store/ShellValidationContext.java b/core/src/main/java/io/xpipe/core/store/ShellValidationContext.java deleted file mode 100644 index 0357c497e..000000000 --- a/core/src/main/java/io/xpipe/core/store/ShellValidationContext.java +++ /dev/null @@ -1,24 +0,0 @@ -package io.xpipe.core.store; - -import io.xpipe.core.process.ShellControl; - -import lombok.Value; - -@Value -public class ShellValidationContext implements ValidationContext { - - ShellControl shellControl; - - @Override - public ShellControl get() { - return shellControl; - } - - @Override - public void close() { - try { - shellControl.shutdown(); - } catch (Exception ignored) { - } - } -} diff --git a/core/src/main/java/io/xpipe/core/store/SingletonSessionStore.java b/core/src/main/java/io/xpipe/core/store/SingletonSessionStore.java index aa9974ccd..a4cc9c69a 100644 --- a/core/src/main/java/io/xpipe/core/store/SingletonSessionStore.java +++ b/core/src/main/java/io/xpipe/core/store/SingletonSessionStore.java @@ -38,7 +38,6 @@ public interface SingletonSessionStore default void startSessionIfNeeded() throws Exception { synchronized (this) { var s = getSession(); - setSessionEnabled(true); if (s != null) { if (s.isRunning()) { return; @@ -50,9 +49,14 @@ public interface SingletonSessionStore try { s = newSession(); - s.start(); - setCache("session", s); - onStateChange(true); + if (s != null) { + setSessionEnabled(true); + s.start(); + setCache("session", s); + onStateChange(true); + } else { + setSessionEnabled(false); + } } catch (Exception ex) { onStateChange(false); throw ex; diff --git a/core/src/main/java/io/xpipe/core/store/ValidatableStore.java b/core/src/main/java/io/xpipe/core/store/ValidatableStore.java index 3fcde2c13..8e8ec65c3 100644 --- a/core/src/main/java/io/xpipe/core/store/ValidatableStore.java +++ b/core/src/main/java/io/xpipe/core/store/ValidatableStore.java @@ -1,6 +1,6 @@ package io.xpipe.core.store; -public interface ValidatableStore> extends DataStore { +public interface ValidatableStore extends DataStore { /** * Performs a validation of this data store. @@ -18,7 +18,5 @@ public interface ValidatableStore> extends DataSt * * @throws Exception if any part of the validation went wrong */ - T validate(T context) throws Exception; - - T createContext() throws Exception; + void validate() throws Exception; } diff --git a/core/src/main/java/io/xpipe/core/store/ValidationContext.java b/core/src/main/java/io/xpipe/core/store/ValidationContext.java deleted file mode 100644 index 690ab48b4..000000000 --- a/core/src/main/java/io/xpipe/core/store/ValidationContext.java +++ /dev/null @@ -1,8 +0,0 @@ -package io.xpipe.core.store; - -public interface ValidationContext { - - T get(); - - void close(); -} diff --git a/core/src/main/java/io/xpipe/core/util/Proxyable.java b/core/src/main/java/io/xpipe/core/util/Proxyable.java deleted file mode 100644 index 3d912e367..000000000 --- a/core/src/main/java/io/xpipe/core/util/Proxyable.java +++ /dev/null @@ -1,8 +0,0 @@ -package io.xpipe.core.util; - -import io.xpipe.core.store.ShellStore; - -public interface Proxyable { - - ShellStore getProxy(); -} diff --git a/dist/build.gradle b/dist/build.gradle index 2593a28c2..a173de9b2 100644 --- a/dist/build.gradle +++ b/dist/build.gradle @@ -2,7 +2,7 @@ plugins { id 'org.beryx.jlink' version '3.0.1' id "org.asciidoctor.jvm.convert" version "4.0.3" - id 'org.jreleaser' version '1.14.0' + id 'org.jreleaser' version '1.15.0' id("com.netflix.nebula.ospackage") version "11.10.0" id 'org.gradle.crypto.checksum' version '1.4.0' id 'signing' diff --git a/dist/changelogs/12.3.5_incremental.md b/dist/changelogs/12.3.5_incremental.md deleted file mode 100644 index cefc5419b..000000000 --- a/dist/changelogs/12.3.5_incremental.md +++ /dev/null @@ -1,5 +0,0 @@ -- Fix terminal session logging setting not being able to deactivated after the preview was done (Sorry for the inconvenience) -- Fix shell environment scan restarting parent shell, resulting in many connections -- Fix local zsh not starting on macOS if an extension had a pending update - -Next up will be XPipe 13 soon, you can already find early test builds at [https://github.com/xpipe-io/xpipe-ptb](https://github.com/xpipe-io/xpipe-ptb) \ No newline at end of file diff --git a/dist/changelogs/13.0.md b/dist/changelogs/13.0.md new file mode 100644 index 000000000..b4f970165 --- /dev/null +++ b/dist/changelogs/13.0.md @@ -0,0 +1,27 @@ +## Shell session caching + +A central change in XPipe 13 are the improvements of 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. + +A common example would be stopping and starting a container. Previously this would have resulted in two connections to the container host system and would have taken a while. Now, there will only be one connection to the host and all actions you perform on that host will be significantly quicker. + +## KVM + +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. + +## 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. + +## Other + +- There is now an intro to scripts to provide some more information before using scripts +- Some style elements have been reworked + +## Fixes + +- Fix vmware integration failing when files other than vmx were in the VM directories +- Fix issues with test command by using its absolute path +- Fix color contrast for some themes +- Fix system dark mode changes not being applied if they were changed while XPipe was not running +- Fix shell environment scan restarting shell connection multiple times +- Fix zsh local shell freezing if a zsh extension had a pending update diff --git a/dist/licenses/jackson.properties b/dist/licenses/jackson.properties index 96ea13235..d57ac11e2 100644 --- a/dist/licenses/jackson.properties +++ b/dist/licenses/jackson.properties @@ -1,4 +1,4 @@ name=Jackson Databind -version=2.17.2 +version=2.18.1 license=Apache License 2.0 link=https://github.com/FasterXML/jackson-databind \ No newline at end of file diff --git a/ext/base/src/main/java/io/xpipe/ext/base/action/BrowseStoreAction.java b/ext/base/src/main/java/io/xpipe/ext/base/action/BrowseStoreAction.java index c73332e51..f4ab490e4 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/action/BrowseStoreAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/action/BrowseStoreAction.java @@ -5,10 +5,10 @@ import io.xpipe.app.core.AppI18n; import io.xpipe.app.core.AppLayoutModel; import io.xpipe.app.ext.ActionProvider; import io.xpipe.app.ext.ProcessControlProvider; +import io.xpipe.app.ext.ShellStore; import io.xpipe.app.storage.DataStoreEntry; import io.xpipe.app.storage.DataStoreEntryRef; import io.xpipe.core.store.FileSystemStore; -import io.xpipe.core.store.ShellStore; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.value.ObservableValue; @@ -57,7 +57,7 @@ public class BrowseStoreAction implements ActionProvider { public void execute() throws Exception { DataStoreEntryRef replacement = ProcessControlProvider.get().replace(entry.ref()); - BrowserSessionModel.DEFAULT.openFileSystemSync(replacement, null, new SimpleBooleanProperty()); + BrowserSessionModel.DEFAULT.openFileSystemSync(replacement, null, new SimpleBooleanProperty(), true); AppLayoutModel.get().selectBrowser(); } } diff --git a/ext/base/src/main/java/io/xpipe/ext/base/action/EditScriptStoreAction.java b/ext/base/src/main/java/io/xpipe/ext/base/action/EditScriptStoreAction.java new file mode 100644 index 000000000..5da5585be --- /dev/null +++ b/ext/base/src/main/java/io/xpipe/ext/base/action/EditScriptStoreAction.java @@ -0,0 +1,67 @@ +package io.xpipe.ext.base.action; + +import io.xpipe.app.comp.store.StoreCreationComp; +import io.xpipe.app.core.AppI18n; +import io.xpipe.app.ext.ActionProvider; +import io.xpipe.app.storage.DataStoreEntry; +import io.xpipe.app.storage.DataStoreEntryRef; +import io.xpipe.ext.base.script.SimpleScriptStore; + +import javafx.beans.value.ObservableValue; + +import lombok.Value; + +public class EditScriptStoreAction implements ActionProvider { + + @Override + public LeafDataStoreCallSite getLeafDataStoreCallSite() { + return new LeafDataStoreCallSite() { + + @Override + public boolean isSystemAction() { + return true; + } + + @Override + public boolean isMajor(DataStoreEntryRef o) { + return true; + } + + @Override + public ActionProvider.Action createAction(DataStoreEntryRef store) { + return new Action(store.get()); + } + + @Override + public Class getApplicableClass() { + return SimpleScriptStore.class; + } + + @Override + public ObservableValue getName(DataStoreEntryRef store) { + return AppI18n.observable("base.edit"); + } + + @Override + public String getIcon(DataStoreEntryRef store) { + return "mdal-edit"; + } + + @Override + public boolean requiresValidStore() { + return false; + } + }; + } + + @Value + static class Action implements ActionProvider.Action { + + DataStoreEntry store; + + @Override + public void execute() { + StoreCreationComp.showEdit(store); + } + } +} diff --git a/ext/base/src/main/java/io/xpipe/ext/base/action/RefreshChildrenStoreAction.java b/ext/base/src/main/java/io/xpipe/ext/base/action/RefreshChildrenStoreAction.java index 4ee84ef54..f4f21895a 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/action/RefreshChildrenStoreAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/action/RefreshChildrenStoreAction.java @@ -72,7 +72,7 @@ public class RefreshChildrenStoreAction implements ActionProvider { @Override public void execute() { - DataStorage.get().refreshChildren(store, null); + DataStorage.get().refreshChildren(store); } } } diff --git a/ext/base/src/main/java/io/xpipe/ext/base/action/RunScriptActionMenu.java b/ext/base/src/main/java/io/xpipe/ext/base/action/RunScriptActionMenu.java index aa9dfed75..73cbe0b21 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/action/RunScriptActionMenu.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/action/RunScriptActionMenu.java @@ -4,12 +4,12 @@ import io.xpipe.app.comp.store.StoreViewState; import io.xpipe.app.core.AppI18n; import io.xpipe.app.ext.ActionProvider; import io.xpipe.app.ext.ProcessControlProvider; +import io.xpipe.app.ext.ShellStore; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.storage.DataStoreEntryRef; import io.xpipe.app.util.TerminalLauncher; import io.xpipe.core.process.ShellStoreState; import io.xpipe.core.process.ShellTtyState; -import io.xpipe.core.store.ShellStore; import io.xpipe.ext.base.script.ScriptHierarchy; import javafx.beans.property.SimpleStringProperty; @@ -33,15 +33,14 @@ public class RunScriptActionMenu implements ActionProvider { @Override public void execute() throws Exception { - try (var sc = shellStore.getStore().control().start()) { - var script = hierarchy.getLeafBase().getStore().assembleScriptChain(sc); - TerminalLauncher.open( - shellStore.getEntry(), - hierarchy.getLeafBase().get().getName() + " - " - + shellStore.get().getName(), - null, - sc.command(script)); - } + var sc = shellStore.getStore().getOrStartSession(); + var script = hierarchy.getLeafBase().getStore().assembleScriptChain(sc); + TerminalLauncher.open( + shellStore.getEntry(), + hierarchy.getLeafBase().get().getName() + " - " + + shellStore.get().getName(), + null, + sc.command(script)); } } @@ -86,10 +85,9 @@ public class RunScriptActionMenu implements ActionProvider { @Override public void execute() throws Exception { - try (var sc = shellStore.getStore().control().start()) { - var script = hierarchy.getLeafBase().getStore().assembleScriptChain(sc); - sc.command(script).execute(); - } + var sc = shellStore.getStore().getOrStartSession(); + var script = hierarchy.getLeafBase().getStore().assembleScriptChain(sc); + sc.command(script).execute(); } } diff --git a/ext/base/src/main/java/io/xpipe/ext/base/action/SampleStoreAction.java b/ext/base/src/main/java/io/xpipe/ext/base/action/SampleStoreAction.java index 98038f37e..95217baca 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/action/SampleStoreAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/action/SampleStoreAction.java @@ -3,13 +3,13 @@ package io.xpipe.ext.base.action; import io.xpipe.app.core.AppI18n; import io.xpipe.app.ext.ActionProvider; import io.xpipe.app.ext.LocalStore; +import io.xpipe.app.ext.ShellStore; import io.xpipe.app.storage.DataStoreEntry; import io.xpipe.app.storage.DataStoreEntryRef; import io.xpipe.core.process.CommandControl; import io.xpipe.core.process.ElevationFunction; import io.xpipe.core.process.ShellControl; import io.xpipe.core.process.ShellDialects; -import io.xpipe.core.store.ShellStore; import javafx.beans.value.ObservableValue; @@ -66,7 +66,7 @@ public class SampleStoreAction implements ActionProvider { public void execute() throws Exception { var docker = new LocalStore(); // Start a shell control from the docker connection store - try (ShellControl sc = docker.control().start()) { + try (ShellControl sc = docker.standaloneControl().start()) { // Once we are here, the shell connection is initialized and we can query all kinds of information // Query the detected shell dialect, e.g. cmd, powershell, sh, bash, etc. diff --git a/ext/base/src/main/java/io/xpipe/ext/base/action/ScanStoreAction.java b/ext/base/src/main/java/io/xpipe/ext/base/action/ScanStoreAction.java index 3e1a32636..a589edb7a 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/action/ScanStoreAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/action/ScanStoreAction.java @@ -2,12 +2,12 @@ package io.xpipe.ext.base.action; import io.xpipe.app.core.AppI18n; import io.xpipe.app.ext.ActionProvider; +import io.xpipe.app.ext.ShellStore; import io.xpipe.app.storage.DataStoreEntry; import io.xpipe.app.storage.DataStoreEntryRef; import io.xpipe.app.util.ScanAlert; import io.xpipe.core.process.ShellStoreState; import io.xpipe.core.process.ShellTtyState; -import io.xpipe.core.store.ShellStore; import javafx.beans.value.ObservableValue; @@ -70,7 +70,7 @@ public class ScanStoreAction implements ActionProvider { @Override public void execute() { if (entry == null || entry.getStore() instanceof ShellStore) { - ScanAlert.showForShellStore(entry, null); + ScanAlert.showForShellStore(entry); } } } diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/ChgrpAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/ChgrpAction.java index 40f9d01eb..8f7381bce 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/ChgrpAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/ChgrpAction.java @@ -45,7 +45,7 @@ public class ChgrpAction implements BranchAction { .filter(e -> !e.getValue().equals("nohome") && !e.getValue().equals("nogroup") && !e.getValue().equals("nobody") - && (e.getKey().equals(0) || e.getKey() >= 1000)) + && (e.getKey().equals(0) || e.getKey() >= 900)) .map(e -> e.getValue()) .map(s -> (LeafAction) new Chgrp(s)) .toList(); diff --git a/ext/base/src/main/java/io/xpipe/ext/base/browser/ChownAction.java b/ext/base/src/main/java/io/xpipe/ext/base/browser/ChownAction.java index 1c92292de..363e8e309 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/browser/ChownAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/browser/ChownAction.java @@ -44,7 +44,7 @@ public class ChownAction implements BranchAction { return model.getCache().getUsers().entrySet().stream() .filter(e -> !e.getValue().equals("nohome") && !e.getValue().equals("nobody") - && (e.getKey().equals(0) || e.getKey() >= 1000)) + && (e.getKey().equals(0) || e.getKey() >= 900)) .map(e -> e.getValue()) .map(s -> (LeafAction) new Chown(s)) .toList(); diff --git a/ext/base/src/main/java/io/xpipe/ext/base/service/AbstractServiceStore.java b/ext/base/src/main/java/io/xpipe/ext/base/service/AbstractServiceStore.java index 4e47171f8..83d48a145 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/service/AbstractServiceStore.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/service/AbstractServiceStore.java @@ -35,7 +35,7 @@ public abstract class AbstractServiceStore extends JacksonizedValue public NetworkTunnelSession newSession() throws Exception { LicenseProvider.get().getFeature("services").throwIfUnsupported(); var l = localPort != null ? localPort : HostHelper.findRandomOpenPortOnAllLocalInterfaces(); - return getHost().getStore().sessionChain(l, remotePort); + return getHost().getStore().sessionChain(l, remotePort, "localhost"); } @Override diff --git a/ext/base/src/main/java/io/xpipe/ext/base/service/FixedServiceGroupStore.java b/ext/base/src/main/java/io/xpipe/ext/base/service/FixedServiceGroupStore.java index dc7c193b2..cceb02202 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/service/FixedServiceGroupStore.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/service/FixedServiceGroupStore.java @@ -5,7 +5,6 @@ import io.xpipe.app.util.FixedHierarchyStore; import io.xpipe.app.util.Validators; import io.xpipe.core.store.DataStore; import io.xpipe.core.store.FixedChildStore; -import io.xpipe.core.store.ValidationContext; import com.fasterxml.jackson.annotation.JsonTypeName; import lombok.AccessLevel; @@ -22,7 +21,7 @@ import java.util.List; @Jacksonized @JsonTypeName("fixedServiceGroup") public class FixedServiceGroupStore extends AbstractServiceGroupStore - implements DataStore, FixedHierarchyStore> { + implements DataStore, FixedHierarchyStore { @Override public void checkComplete() throws Throwable { @@ -32,14 +31,8 @@ public class FixedServiceGroupStore extends AbstractServiceGroupStore> listChildren(ValidationContext context) - throws Exception { + public List> listChildren() throws Exception { return (List>) getParent().getStore().createFixedServices(); } - - @Override - public ValidationContext createContext() throws Exception { - return null; - } } diff --git a/ext/base/src/main/java/io/xpipe/ext/base/store/ShellStoreProvider.java b/ext/base/src/main/java/io/xpipe/ext/base/store/ShellStoreProvider.java index b88abc82e..e20c05c5b 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/store/ShellStoreProvider.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/store/ShellStoreProvider.java @@ -9,14 +9,14 @@ import io.xpipe.app.ext.ActionProvider; import io.xpipe.app.ext.DataStoreProvider; import io.xpipe.app.ext.DataStoreUsageCategory; import io.xpipe.app.ext.ProcessControlProvider; +import io.xpipe.app.ext.ShellStore; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.resources.SystemIcons; import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStoreEntry; -import io.xpipe.app.util.DataStoreFormatter; +import io.xpipe.app.util.ShellStoreFormat; import io.xpipe.app.util.TerminalLauncher; import io.xpipe.core.process.ShellStoreState; -import io.xpipe.core.store.ShellStore; import io.xpipe.ext.base.script.ScriptStore; import javafx.beans.property.BooleanProperty; @@ -31,7 +31,7 @@ public interface ShellStoreProvider extends DataStoreProvider { public void execute() throws Exception { var replacement = ProcessControlProvider.get().replace(entry.ref()); ShellStore store = replacement.getStore().asNeeded(); - var control = ScriptStore.controlWithDefaultScripts(store.control()); + var control = ScriptStore.controlWithDefaultScripts(store.tempControl()); control.onInit(sc -> { if (entry.getStorePersistentState() instanceof ShellStoreState shellStoreState && shellStoreState.getShellDialect() == null) { @@ -72,6 +72,6 @@ public interface ShellStoreProvider extends DataStoreProvider { @Override default ObservableValue informationString(StoreSection section) { - return DataStoreFormatter.shellInformation(section.getWrapper()); + return ShellStoreFormat.shellStore(section, state -> null); } } diff --git a/ext/base/src/main/java/io/xpipe/ext/base/store/StoreRestartAction.java b/ext/base/src/main/java/io/xpipe/ext/base/store/StoreRestartAction.java new file mode 100644 index 000000000..c65a7b792 --- /dev/null +++ b/ext/base/src/main/java/io/xpipe/ext/base/store/StoreRestartAction.java @@ -0,0 +1,61 @@ +package io.xpipe.ext.base.store; + +import io.xpipe.app.core.AppI18n; +import io.xpipe.app.ext.ActionProvider; +import io.xpipe.app.storage.DataStoreEntryRef; +import io.xpipe.core.store.DataStore; + +import javafx.beans.value.ObservableValue; + +import lombok.Value; + +public class StoreRestartAction implements ActionProvider { + + @Override + public LeafDataStoreCallSite getLeafDataStoreCallSite() { + return new LeafDataStoreCallSite() { + + @Override + public ActionProvider.Action createAction(DataStoreEntryRef store) { + return new Action(store); + } + + @Override + public Class getApplicableClass() { + return DataStore.class; + } + + @Override + public ObservableValue getName(DataStoreEntryRef store) { + return AppI18n.observable("restart"); + } + + @Override + public String getIcon(DataStoreEntryRef store) { + return "mdi2r-restart"; + } + + @Override + public boolean requiresValidStore() { + return false; + } + + @Override + public boolean isApplicable(DataStoreEntryRef o) { + return o.getStore() instanceof StartableStore && o.getStore() instanceof StoppableStore; + } + }; + } + + @Value + static class Action implements ActionProvider.Action { + + DataStoreEntryRef entry; + + @Override + public void execute() throws Exception { + ((StoppableStore) entry.getStore()).stop(); + ((StartableStore) entry.getStore()).start(); + } + } +} diff --git a/ext/base/src/main/java/module-info.java b/ext/base/src/main/java/module-info.java index ae81b087b..3fe581316 100644 --- a/ext/base/src/main/java/module-info.java +++ b/ext/base/src/main/java/module-info.java @@ -11,6 +11,7 @@ import io.xpipe.ext.base.desktop.DesktopEnvironmentStoreProvider; import io.xpipe.ext.base.script.*; import io.xpipe.ext.base.service.*; import io.xpipe.ext.base.store.StorePauseAction; +import io.xpipe.ext.base.store.StoreRestartAction; import io.xpipe.ext.base.store.StoreStartAction; import io.xpipe.ext.base.store.StoreStopAction; @@ -76,6 +77,7 @@ open module io.xpipe.ext.base { StoreStopAction, StoreStartAction, StorePauseAction, + StoreRestartAction, ServiceOpenAction, ServiceOpenHttpAction, ServiceOpenHttpsAction, @@ -86,6 +88,7 @@ open module io.xpipe.ext.base { LaunchStoreAction, XPipeUrlAction, EditStoreAction, + EditScriptStoreAction, BrowseStoreAction, ScanStoreAction, ChangeStoreIconAction; diff --git a/ext/jdbc/build.gradle b/ext/jdbc/build.gradle deleted file mode 100644 index 3e834dfae..000000000 --- a/ext/jdbc/build.gradle +++ /dev/null @@ -1,4 +0,0 @@ -plugins { id 'java' -} -apply from: "$rootDir/gradle/gradle_scripts/java.gradle" -apply from: "$rootDir/gradle/gradle_scripts/extension.gradle" diff --git a/ext/jdbc/src/main/java/module-info.java b/ext/jdbc/src/main/java/module-info.java deleted file mode 100644 index 84ec95b6e..000000000 --- a/ext/jdbc/src/main/java/module-info.java +++ /dev/null @@ -1 +0,0 @@ -module io.xpipe.ext.jdbc {} diff --git a/gradle/gradle_scripts/extension.gradle b/gradle/gradle_scripts/extension.gradle index 8b18a876c..fddff2d89 100644 --- a/gradle/gradle_scripts/extension.gradle +++ b/gradle/gradle_scripts/extension.gradle @@ -67,7 +67,7 @@ configurations { } dependencies { - compileOnly group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: "2.17.2" + compileOnly group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: "2.18.1" compileOnly project(':core') compileOnly project(':beacon') compileOnly project(':app') diff --git a/gradle/gradle_scripts/junit.gradle b/gradle/gradle_scripts/junit.gradle index 23917431f..1583591dc 100644 --- a/gradle/gradle_scripts/junit.gradle +++ b/gradle/gradle_scripts/junit.gradle @@ -2,9 +2,9 @@ import org.gradle.api.tasks.testing.logging.TestLogEvent dependencies { testImplementation 'org.hamcrest:hamcrest:3.0' - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.11.0' - testImplementation 'org.junit.jupiter:junit-jupiter-params:5.11.0' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.11.0' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.11.3' + testImplementation 'org.junit.jupiter:junit-jupiter-params:5.11.3' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.11.3' testRuntimeOnly "org.junit.platform:junit-platform-launcher" } diff --git a/img/proc/virsh_icon-16.png b/img/proc/virsh_icon-16.png new file mode 100644 index 000000000..203a6ec4c Binary files /dev/null and b/img/proc/virsh_icon-16.png differ diff --git a/img/proc/virsh_icon-24.png b/img/proc/virsh_icon-24.png new file mode 100644 index 000000000..93a363048 Binary files /dev/null and b/img/proc/virsh_icon-24.png differ diff --git a/img/proc/virsh_icon-40.png b/img/proc/virsh_icon-40.png new file mode 100644 index 000000000..6503a9650 Binary files /dev/null and b/img/proc/virsh_icon-40.png differ diff --git a/img/proc/virsh_icon-80.png b/img/proc/virsh_icon-80.png new file mode 100644 index 000000000..9f2d7290b Binary files /dev/null and b/img/proc/virsh_icon-80.png differ diff --git a/lang/app/strings/translations_da.properties b/lang/app/strings/translations_da.properties index bc2763563..24e14da99 100644 --- a/lang/app/strings/translations_da.properties +++ b/lang/app/strings/translations_da.properties @@ -29,7 +29,7 @@ addService=Service ... addScript=Script ... addHost=Fjernvært ... addShell=Shell-miljø ... -addCommand=Shell-kommando ... +addCommand=Kommando ... addAutomatically=Søg automatisk ... addOther=Tilføj andet ... addConnection=Tilføj forbindelse @@ -288,7 +288,7 @@ performanceModeDescription=Deaktiverer alle visuelle effekter, der ikke er nødv dontAcceptNewHostKeys=Accepterer ikke nye SSH-værtsnøgler automatisk dontAcceptNewHostKeysDescription=XPipe accepterer automatisk værtsnøgler som standard fra systemer, hvor din SSH-klient ikke allerede har gemt en kendt værtsnøgle. Hvis en kendt værtsnøgle er ændret, vil den dog nægte at oprette forbindelse, medmindre du accepterer den nye.\n\nHvis du deaktiverer denne adfærd, kan du kontrollere alle værtsnøgler, selv om der ikke er nogen konflikt i første omgang. uiScale=UI-skala -uiScaleDescription=En brugerdefineret skaleringsværdi, der kan indstilles uafhængigt af din systemdækkende displayskala. Værdierne er i procent, så f.eks. en værdi på 150 vil resultere i en UI-skala på 150%.\n\nKræver en genstart for at blive anvendt. +uiScaleDescription=En brugerdefineret skaleringsværdi, der kan indstilles uafhængigt af din systemdækkende skærmskala. Værdierne er i procent, så f.eks. vil en værdi på 150 resultere i en UI-skala på 150%. editorProgram=Editor-program editorProgramDescription=Den standardteksteditor, man bruger til at redigere enhver form for tekstdata. windowOpacity=Vinduets uigennemsigtighed @@ -308,9 +308,9 @@ workspaceLock=Master-passphrase enableGitStorage=Aktivér git-synkronisering sharing=Deling sync=Synkronisering -enableGitStorageDescription=Når den er aktiveret, vil XPipe initialisere et git-arkiv til lagring af forbindelsesdata og overføre eventuelle ændringer til det. Bemærk, at dette kræver, at git er installeret, og at det kan gøre indlæsning og lagring langsommere.\n\nAlle kategorier, der skal synkroniseres, skal udtrykkeligt udpeges som delte.\n\nKræver en genstart for at blive anvendt. +enableGitStorageDescription=Når det er aktiveret, vil XPipe initialisere et git-arkiv til lagring af forbindelsesdata og overføre alle ændringer til det. Bemærk, at dette kræver, at git er installeret, og at det kan gøre indlæsning og lagring langsommere.\n\nAlle kategorier, der skal synkroniseres, skal udtrykkeligt angives som delte. storageGitRemote=Git fjern-URL -storageGitRemoteDescription=Når det er indstillet, vil XPipe automatisk trække alle ændringer, når det indlæses, og skubbe alle ændringer til fjernarkivet, når det gemmes.\n\nDette giver dig mulighed for at dele dine konfigurationsdata mellem flere XPipe-installationer. Både HTTP- og SSH-URL'er understøttes. Bemærk, at dette kan gøre indlæsning og lagring langsommere.\n\nKræver en genstart for at blive anvendt. +storageGitRemoteDescription=Når den er indstillet, vil XPipe automatisk trække alle ændringer, når den indlæses, og skubbe alle ændringer til fjernlageret, når den gemmes.\n\nDette giver dig mulighed for at dele dine konfigurationsdata mellem flere XPipe-installationer. Både HTTP- og SSH-URL'er understøttes. Bemærk, at dette kan gøre indlæsning og lagring langsommere. vault=Vault workspaceLockDescription=Indstiller en brugerdefineret adgangskode til at kryptere alle følsomme oplysninger, der er gemt i XPipe.\n\nDette resulterer i øget sikkerhed, da det giver et ekstra lag af kryptering for dine lagrede følsomme oplysninger. Du vil derefter blive bedt om at indtaste adgangskoden, når XPipe starter. useSystemFontDescription=Styrer, om du vil bruge din systemskrifttype eller Roboto-skrifttypen, som følger med XPipe. @@ -361,7 +361,7 @@ notAnAbsolutePath=Ikke en absolut sti notADirectory=Ikke en mappe notAnEmptyDirectory=Ikke en tom mappe automaticallyUpdate=Tjek for opdateringer -automaticallyUpdateDescription=Når denne funktion er aktiveret, hentes oplysninger om nye udgivelser automatisk, mens XPipe kører. Ingen updater kører i baggrunden, og du skal stadig udtrykkeligt bekræfte enhver opdateringsinstallation. +automaticallyUpdateDescription=Når det er aktiveret, hentes oplysninger om nye udgivelser automatisk, mens XPipe kører efter et stykke tid. Du skal stadig eksplicit bekræfte enhver installation af opdateringer. sendAnonymousErrorReports=Send anonyme fejlrapporter sendUsageStatistics=Send anonym brugsstatistik storageDirectory=Opbevaringskatalog @@ -420,7 +420,7 @@ denyTempScriptCreation=Nægt midlertidig oprettelse af script denyTempScriptCreationDescription=For at realisere nogle af sine funktioner opretter XPipe nogle gange midlertidige shell-scripts på et målsystem for at gøre det nemt at udføre simple kommandoer. Disse indeholder ingen følsomme oplysninger og er kun oprettet til implementeringsformål.\n\nHvis denne adfærd er deaktiveret, vil XPipe ikke oprette midlertidige filer på et fjernsystem. Denne indstilling er nyttig i højsikkerhedssammenhænge, hvor hver filsystemændring overvåges. Hvis dette er deaktiveret, vil nogle funktioner, f.eks. shell-miljøer og scripts, ikke fungere efter hensigten. disableCertutilUse=Deaktiver brug af certutil på Windows useLocalFallbackShell=Brug lokal fallback-shell -useLocalFallbackShellDescription=Skift til at bruge en anden lokal shell til at håndtere lokale operationer. Det kan være PowerShell på Windows og bourne shell på andre systemer.\n\nDenne indstilling kan bruges, hvis den normale lokale standardskal er deaktiveret eller ødelagt i en eller anden grad. Nogle funktioner fungerer dog måske ikke som forventet, når denne indstilling er aktiveret.\n\nKræver en genstart for at blive anvendt. +useLocalFallbackShellDescription=Skift til at bruge en anden lokal shell til at håndtere lokale operationer. Det kan være PowerShell på Windows og bourne shell på andre systemer.\n\nDenne indstilling kan bruges, hvis den normale lokale standard-shell er deaktiveret eller ødelagt i en eller anden grad. Nogle funktioner fungerer dog muligvis ikke som forventet, når denne mulighed er aktiveret. disableCertutilUseDescription=På grund af flere mangler og fejl i cmd.exe oprettes midlertidige shell-scripts med certutil ved at bruge det til at afkode base64-input, da cmd.exe bryder på ikke-ASCII-input. XPipe kan også bruge PowerShell til det, men det vil være langsommere.\n\nDette deaktiverer enhver brug af certutil på Windows-systemer til at realisere nogle funktioner og falder tilbage til PowerShell i stedet. Det vil måske glæde nogle AV'er, da nogle af dem blokerer brugen af certutil. disableTerminalRemotePasswordPreparation=Deaktiver forberedelse af terminalens fjernadgangskode disableTerminalRemotePasswordPreparationDescription=I situationer, hvor en remote shell-forbindelse, der går gennem flere mellemliggende systemer, skal etableres i terminalen, kan der være et krav om at forberede alle nødvendige adgangskoder på et af de mellemliggende systemer for at muliggøre en automatisk udfyldning af eventuelle prompter.\n\nHvis du ikke ønsker, at adgangskoderne nogensinde skal overføres til et mellemliggende system, kan du deaktivere denne adfærd. Alle nødvendige mellemliggende adgangskoder vil så blive spurgt i selve terminalen, når den åbnes. @@ -465,7 +465,7 @@ orderAheadOf=Bestil på forhånd ... httpServer=HTTP-server httpServerConfiguration=Konfiguration af HTTP-server apiKey=API-nøgle -apiKeyDescription=API-nøglen til godkendelse af XPipe-dæmonens API-anmodninger. Se den generelle API-dokumentation for at få flere oplysninger om, hvordan du godkender.\n\nKræver en genstart for at blive anvendt. +apiKeyDescription=API-nøglen til godkendelse af XPipe-dæmonens API-anmodninger. Se den generelle API-dokumentation for at få flere oplysninger om, hvordan du godkender. disableApiAuthentication=Deaktiver API-godkendelse disableApiAuthenticationDescription=Deaktiverer alle nødvendige godkendelsesmetoder, så enhver uautoriseret anmodning vil blive håndteret.\n\nAutentificering bør kun deaktiveres til udviklingsformål.\n\nKræver en genstart for at blive anvendt. api=API @@ -538,3 +538,12 @@ terminalLoggingDirectory=Logfiler for terminalsessioner terminalLoggingDirectoryDescription=Alle logfiler gemmes i XPipe-databiblioteket på dit lokale system. openSessionLogs=Åbne sessionslogfiler sessionLogging=Logning af sessioner +sessionActive=Der kører en baggrundssession for denne forbindelse.\n\nKlik på statusindikatoren for at stoppe denne session manuelt. +skipValidation=Spring validering over +scriptsIntroTitle=Om scripts +scriptsIntroText=Du kan køre scripts ved shell-init, i filbrowseren og efter behov. Du kan bringe dine brugerdefinerede prompter, aliaser og andre brugerdefinerede funktioner til alle dine systemer uden selv at skulle sætte dem op på eksterne systemer - XPipes scripting-system klarer det hele for dig. +scriptsIntroBottomTitle=Brug af scripts +scriptsIntroBottomText=Der er en række eksempler på scripts til at starte med. Du kan klikke på redigeringsknappen for de enkelte scripts for at se, hvordan de er implementeret. Scripts skal aktiveres for at køre og dukke op i menuer, der er et skifte på hvert script til det. +scriptsIntroStart=Kom godt i gang +checkForSecurityUpdates=Tjek for sikkerhedsopdateringer +checkForSecurityUpdatesDescription=XPipe kan tjekke for potentielle sikkerhedsopdateringer separat fra normale funktionsopdateringer. Når dette er aktiveret, vil i det mindste vigtige sikkerhedsopdateringer blive anbefalet til installation, selv om den normale opdateringskontrol er deaktiveret.\n\nHvis du deaktiverer denne indstilling, vil der ikke blive udført nogen ekstern versionsanmodning, og du vil ikke få besked om nogen sikkerhedsopdateringer. diff --git a/lang/app/strings/translations_de.properties b/lang/app/strings/translations_de.properties index be853a10c..6907c11a9 100644 --- a/lang/app/strings/translations_de.properties +++ b/lang/app/strings/translations_de.properties @@ -30,7 +30,7 @@ addScript=Skript ... #custom addHost=Remote Host ... addShell=Shell-Umgebung ... -addCommand=Shell-Befehl ... +addCommand=Befehl ... addAutomatically=Automatisch suchen ... addOther=Andere hinzufügen ... addConnection=Verbindung hinzufügen @@ -282,7 +282,7 @@ performanceModeDescription=Deaktiviert alle visuellen Effekte, die nicht benöti dontAcceptNewHostKeys=Neue SSH-Hostschlüssel nicht automatisch akzeptieren dontAcceptNewHostKeysDescription=XPipe akzeptiert standardmäßig automatisch Host-Schlüssel von Systemen, für die dein SSH-Client noch keinen bekannten Host-Schlüssel gespeichert hat. Wenn sich jedoch ein bekannter Host-Schlüssel geändert hat, wird die Verbindung verweigert, bis du den neuen Schlüssel akzeptierst.\n\nWenn du dieses Verhalten deaktivierst, kannst du alle Host-Schlüssel überprüfen, auch wenn es zunächst keinen Konflikt gibt. uiScale=UI-Skala -uiScaleDescription=Ein benutzerdefinierter Skalierungswert, der unabhängig von der systemweiten Anzeigeskala eingestellt werden kann. Die Werte sind in Prozent angegeben, d.h. ein Wert von 150 ergibt eine UI-Skalierung von 150%.\n\nZur Anwendung ist ein Neustart erforderlich. +uiScaleDescription=Ein benutzerdefinierter Skalierungswert, der unabhängig von der systemweiten Anzeigeskala eingestellt werden kann. Die Werte sind in Prozent angegeben, d.h. ein Wert von 150 ergibt eine UI-Skalierung von 150%. editorProgram=Editor Programm editorProgramDescription=Der Standard-Texteditor, der beim Bearbeiten von Textdaten aller Art verwendet wird. windowOpacity=Fenster-Opazität @@ -303,9 +303,9 @@ workspaceLock=Master-Passphrase enableGitStorage=Git-Synchronisation einschalten sharing=Teilen sync=Synchronisation -enableGitStorageDescription=Wenn diese Option aktiviert ist, initialisiert XPipe ein Git-Repository für die Speicherung der Verbindungsdaten und überträgt alle Änderungen in dieses Repository. Beachte, dass dafür Git installiert sein muss und dass dies die Lade- und Speichervorgänge verlangsamen kann.\n\nAlle Kategorien, die synchronisiert werden sollen, müssen explizit als freigegeben gekennzeichnet werden.\n\nErfordert einen Neustart zur Anwendung. +enableGitStorageDescription=Wenn diese Option aktiviert ist, initialisiert XPipe ein Git-Repository für die Speicherung der Verbindungsdaten und überträgt alle Änderungen in dieses Repository. Beachte, dass dafür Git installiert sein muss und dass dies die Lade- und Speichervorgänge verlangsamen kann.\n\nAlle Kategorien, die synchronisiert werden sollen, müssen explizit als freigegeben gekennzeichnet werden. storageGitRemote=Git Remote URL -storageGitRemoteDescription=Wenn diese Option aktiviert ist, zieht XPipe beim Laden automatisch alle Änderungen und überträgt sie beim Speichern in das entfernte Repository.\n\nSo kannst du deine Konfigurationsdaten zwischen mehreren XPipe-Installationen austauschen. Es werden sowohl HTTP- als auch SSH-URLs unterstützt. Beachte, dass dies die Lade- und Speichervorgänge verlangsamen kann.\n\nZur Anwendung ist ein Neustart erforderlich. +storageGitRemoteDescription=Wenn diese Option aktiviert ist, zieht XPipe beim Laden automatisch alle Änderungen und überträgt sie beim Speichern an das entfernte Repository.\n\nSo kannst du deine Konfigurationsdaten zwischen mehreren XPipe-Installationen austauschen. Es werden sowohl HTTP- als auch SSH-URLs unterstützt. Beachte, dass dies die Lade- und Speichervorgänge verlangsamen kann. vault=Tresor workspaceLockDescription=Legt ein benutzerdefiniertes Passwort fest, um alle in XPipe gespeicherten vertraulichen Informationen zu verschlüsseln.\n\nDies erhöht die Sicherheit, da es eine zusätzliche Verschlüsselungsebene für deine gespeicherten sensiblen Daten bietet. Du wirst dann beim Start von XPipe aufgefordert, das Passwort einzugeben. useSystemFontDescription=Legt fest, ob die Systemschriftart oder die Roboto-Schriftart, die mit XPipe mitgeliefert wird, verwendet werden soll. @@ -356,7 +356,7 @@ notAnAbsolutePath=Kein absoluter Pfad notADirectory=Nicht ein Verzeichnis notAnEmptyDirectory=Kein leeres Verzeichnis automaticallyUpdate=Nach Updates suchen -automaticallyUpdateDescription=Wenn diese Funktion aktiviert ist, werden Informationen über neue Versionen automatisch abgerufen, während XPipe läuft. Es wird kein Updater im Hintergrund ausgeführt, und du musst die Installation von Updates immer noch explizit bestätigen. +automaticallyUpdateDescription=Wenn diese Funktion aktiviert ist, werden die Informationen zu neuen Versionen automatisch abgerufen, während XPipe nach einer Weile läuft. Du musst die Installation von Updates immer noch explizit bestätigen. sendAnonymousErrorReports=Anonyme Fehlerberichte senden sendUsageStatistics=Anonyme Nutzungsstatistiken senden storageDirectory=Speicherverzeichnis @@ -415,7 +415,7 @@ denyTempScriptCreation=Temporäre Skripterstellung verweigern denyTempScriptCreationDescription=Um einige seiner Funktionen zu realisieren, erstellt XPipe manchmal temporäre Shell-Skripte auf einem Zielsystem, um die einfache Ausführung einfacher Befehle zu ermöglichen. Diese enthalten keine sensiblen Informationen und werden nur zu Implementierungszwecken erstellt.\n\nWenn dieses Verhalten deaktiviert ist, erstellt XPipe keine temporären Dateien auf einem entfernten System. Diese Option ist in hochsicheren Kontexten nützlich, in denen jede Dateisystemänderung überwacht wird. Wenn diese Option deaktiviert ist, funktionieren einige Funktionen, z. B. Shell-Umgebungen und Skripte, nicht wie vorgesehen. disableCertutilUse=Die Verwendung von certutil unter Windows deaktivieren useLocalFallbackShell=Lokale Fallback-Shell verwenden -useLocalFallbackShellDescription=Wechsle zur Verwendung einer anderen lokalen Shell, um lokale Operationen durchzuführen. Das wäre die PowerShell unter Windows und die Bourne Shell auf anderen Systemen.\n\nDiese Option kann verwendet werden, wenn die normale lokale Standardshell deaktiviert oder in gewissem Maße beschädigt ist. Einige Funktionen funktionieren möglicherweise nicht wie erwartet, wenn diese Option aktiviert ist.\n\nZur Anwendung ist ein Neustart erforderlich. +useLocalFallbackShellDescription=Wechsle zur Verwendung einer anderen lokalen Shell, um lokale Operationen durchzuführen. Das wäre die PowerShell unter Windows und die Bourne Shell auf anderen Systemen.\n\nDiese Option kann verwendet werden, wenn die normale lokale Standardshell deaktiviert oder in gewissem Maße beschädigt ist. Einige Funktionen funktionieren möglicherweise nicht wie erwartet, wenn diese Option aktiviert ist. disableCertutilUseDescription=Aufgrund verschiedener Unzulänglichkeiten und Bugs in cmd.exe werden temporäre Shell-Skripte mit certutil erstellt, indem es zur Dekodierung von base64-Eingaben verwendet wird, da cmd.exe bei Nicht-ASCII-Eingaben versagt. XPipe kann auch die PowerShell dafür verwenden, aber das ist langsamer.\n\nDadurch wird die Verwendung von certutil auf Windows-Systemen deaktiviert, um einige Funktionen zu realisieren und stattdessen auf die PowerShell zurückzugreifen. Das könnte einige AVs freuen, da einige von ihnen die Verwendung von certutil blockieren. disableTerminalRemotePasswordPreparation=Terminal-Fernpasswortvorbereitung deaktivieren disableTerminalRemotePasswordPreparationDescription=In Situationen, in denen eine Remote-Shell-Verbindung über mehrere Zwischensysteme im Terminal hergestellt werden soll, kann es erforderlich sein, alle erforderlichen Passwörter auf einem der Zwischensysteme vorzubereiten, um ein automatisches Ausfüllen der Eingabeaufforderungen zu ermöglichen.\n\nWenn du nicht möchtest, dass die Passwörter jemals an ein Zwischensystem übertragen werden, kannst du dieses Verhalten deaktivieren. Jedes erforderliche Zwischen-System-Passwort wird dann beim Öffnen des Terminals selbst abgefragt. @@ -459,7 +459,7 @@ orderAheadOf=Vorbestellen ... httpServer=HTTP-Server httpServerConfiguration=HTTP-Server-Konfiguration apiKey=API-Schlüssel -apiKeyDescription=Der API-Schlüssel zur Authentifizierung von XPipe Daemon API-Anfragen. Weitere Informationen zur Authentifizierung findest du in der allgemeinen API-Dokumentation.\n\nErfordert einen Neustart zur Anwendung. +apiKeyDescription=Der API-Schlüssel zur Authentifizierung von XPipe Daemon API-Anfragen. Weitere Informationen zur Authentifizierung findest du in der allgemeinen API-Dokumentation. disableApiAuthentication=API-Authentifizierung deaktivieren disableApiAuthenticationDescription=Deaktiviert alle erforderlichen Authentifizierungsmethoden, so dass jede nicht authentifizierte Anfrage bearbeitet wird.\n\nDie Authentifizierung sollte nur zu Entwicklungszwecken deaktiviert werden.\n\nErfordert einen Neustart zur Anwendung. api=API @@ -532,3 +532,12 @@ terminalLoggingDirectory=Terminal-Sitzungsprotokolle terminalLoggingDirectoryDescription=Alle Protokolle werden in dem XPipe-Datenverzeichnis auf deinem lokalen System gespeichert. openSessionLogs=Sitzungsprotokolle öffnen sessionLogging=Sitzungsprotokollierung +sessionActive=Für diese Verbindung wird eine Hintergrundsitzung durchgeführt.\n\nUm diese Sitzung manuell zu beenden, klicke auf die Statusanzeige. +skipValidation=Validierung überspringen +scriptsIntroTitle=Über Skripte +scriptsIntroText=Du kannst Skripte bei Shell-Init, im Dateibrowser und bei Bedarf ausführen. Du kannst deine benutzerdefinierten Prompts, Aliase und andere benutzerdefinierte Funktionen auf all deine Systeme bringen, ohne sie selbst auf den entfernten Systemen einrichten zu müssen. Das Skripting-System von XPipe übernimmt alles für dich. +scriptsIntroBottomTitle=Skripte verwenden +scriptsIntroBottomText=Für den Anfang gibt es eine Reihe von Beispielskripten. Du kannst auf die Bearbeitungsschaltfläche der einzelnen Skripte klicken, um zu sehen, wie sie implementiert sind. Skripte müssen aktiviert werden, damit sie ausgeführt und in Menüs angezeigt werden. +scriptsIntroStart=Anfangen +checkForSecurityUpdates=Nach Sicherheitsupdates suchen +checkForSecurityUpdatesDescription=XPipe kann getrennt von den normalen Funktionsupdates auf mögliche Sicherheitsupdates prüfen. Wenn dies aktiviert ist, werden zumindest wichtige Sicherheitsupdates zur Installation empfohlen, auch wenn die normale Updateprüfung deaktiviert ist.\n\nWenn du diese Einstellung deaktivierst, wird keine externe Versionsabfrage durchgeführt und du wirst nicht über Sicherheitsaktualisierungen benachrichtigt. diff --git a/lang/app/strings/translations_en.properties b/lang/app/strings/translations_en.properties index 1bfdfa46a..4c789e481 100644 --- a/lang/app/strings/translations_en.properties +++ b/lang/app/strings/translations_en.properties @@ -29,7 +29,7 @@ addService=Service ... addScript=Script ... addHost=Remote Host ... addShell=Shell Environment ... -addCommand=Shell Command ... +addCommand=Command ... addAutomatically=Search Automatically ... addOther=Add Other ... addConnection=Add Connection @@ -284,7 +284,7 @@ performanceModeDescription=Disables all visual effects that are not required in dontAcceptNewHostKeys=Don't accept new SSH host keys automatically dontAcceptNewHostKeysDescription=XPipe will automatically accept host keys by default from systems where your SSH client has no known host key already saved. If any known host key has changed however, it will refuse to connect unless you accept the new one.\n\nDisabling this behavior allows you to check all host keys, even if there is no conflict initially. uiScale=UI Scale -uiScaleDescription=A custom scaling value that can be set independently of your system-wide display scale. Values are in percent, so e.g. value of 150 will result in a UI scale of 150%.\n\nRequires a restart to apply. +uiScaleDescription=A custom scaling value that can be set independently of your system-wide display scale. Values are in percent, so e.g. value of 150 will result in a UI scale of 150%. editorProgram=Editor Program editorProgramDescription=The default text editor to use when editing any kind of text data. windowOpacity=Window opacity @@ -304,9 +304,9 @@ workspaceLock=Master passphrase enableGitStorage=Enable git synchronization sharing=Sharing sync=Synchronization -enableGitStorageDescription=When enabled, XPipe will initialize a git repository for the connection data storage and commit any changes to it. Note that this requires git to be installed and might slow down loading and saving operations.\n\nAny categories that should be synced must be explicitly designated as shared.\n\nRequires a restart to apply. +enableGitStorageDescription=When enabled, XPipe will initialize a git repository for the connection data storage and commit any changes to it. Note that this requires git to be installed and might slow down loading and saving operations.\n\nAny categories that should be synced must be explicitly designated as shared. storageGitRemote=Git remote URL -storageGitRemoteDescription=When set, XPipe will automatically pull any changes when loading and push any changes to the remote repository when saving.\n\nThis allows you to share your configuration data between multiple XPipe installations. Both HTTP and SSH URLs are supported. Note that this might slow down loading and saving operations.\n\nRequires a restart to apply. +storageGitRemoteDescription=When set, XPipe will automatically pull any changes when loading and push any changes to the remote repository when saving.\n\nThis allows you to share your configuration data between multiple XPipe installations. Both HTTP and SSH URLs are supported. Note that this might slow down loading and saving operations. vault=Vault workspaceLockDescription=Sets a custom password to encrypt any sensitive information stored in XPipe.\n\nThis results in increased security as it provides an additional layer of encryption for your stored sensitive information. You will then be prompted to enter the password when XPipe starts. useSystemFontDescription=Controls whether to use your system font or the Roboto font which is bundled with XPipe. @@ -360,7 +360,7 @@ notAnAbsolutePath=Not an absolute path notADirectory=Not a directory notAnEmptyDirectory=Not an empty directory automaticallyUpdate=Check for updates -automaticallyUpdateDescription=When enabled, new release information is automatically fetched while XPipe is running. No updater is run in the background, and you still have to explicitly confirm any update installation. +automaticallyUpdateDescription=When enabled, new release information is automatically fetched while XPipe is running after a while. You still have to explicitly confirm any update installation. sendAnonymousErrorReports=Send anonymous error reports sendUsageStatistics=Send anonymous usage statistics storageDirectory=Storage directory @@ -418,7 +418,7 @@ denyTempScriptCreation=Deny temporary script creation denyTempScriptCreationDescription=To realize some of its functionality, XPipe sometimes creates temporary shell scripts on a target system to allow for an easy execution of simple commands. These do not contain any sensitive information and are just created for implementation purposes.\n\nIf this behavior is disabled, XPipe will not create any temporary files on a remote system. This option is useful in high-security contexts where every file system change is monitored. If this is disabled, some functionality, e.g. shell environments and scripts, will not work as intended. disableCertutilUse=Disable certutil use on Windows useLocalFallbackShell=Use local fallback shell -useLocalFallbackShellDescription=Switch to using another local shell to handle local operations. This would be PowerShell on Windows and bourne shell on other systems.\n\nThis option can be used in case the normal local default shell is disabled or broken to some degree. Some features might not work as expected though when this is option is enabled.\n\nRequires a restart to apply. +useLocalFallbackShellDescription=Switch to using another local shell to handle local operations. This would be PowerShell on Windows and bourne shell on other systems.\n\nThis option can be used in case the normal local default shell is disabled or broken to some degree. Some features might not work as expected though when this is option is enabled. disableCertutilUseDescription=Due to several shortcomings and bugs in cmd.exe, temporary shell scripts are created with certutil by using it to decode base64 input as cmd.exe breaks on non-ASCII input. XPipe can also use PowerShell for that but this will be slower.\n\nThis disables any use of certutil on Windows systems to realize some functionality and fall back to PowerShell instead. This might please some AVs as some of them block certutil usage. disableTerminalRemotePasswordPreparation=Disable terminal remote password preparation disableTerminalRemotePasswordPreparationDescription=In situations where a remote shell connection that goes through multiple intermediate systems should be established in the terminal, there might be a requirement to prepare any required passwords on one of the intermediate systems to allow for an automatic filling of any prompts.\n\nIf you don't want the passwords to ever be transferred to any intermediate system, you can disable this behavior. Any required intermediate password will then be queried in the terminal itself when opened. @@ -463,9 +463,9 @@ orderAheadOf=Order ahead of ... httpServer=HTTP server httpServerConfiguration=HTTP server configuration apiKey=API key -apiKeyDescription=The API key to authenticate XPipe daemon API requests. For more information on how to authenticate, see the general API documentation.\n\nRequires a restart to apply. +apiKeyDescription=The API key to authenticate XPipe daemon API requests. For more information on how to authenticate, see the general API documentation. disableApiAuthentication=Disable API authentication -disableApiAuthenticationDescription=Disables all required authentication methods so that any unauthenticated request will be handled.\n\nAuthentication should only be disabled for development purposes.\n\nRequires a restart to apply. +disableApiAuthenticationDescription=Disables all required authentication methods so that any unauthenticated request will be handled.\n\nAuthentication should only be disabled for development purposes. api=API storeIntroImportDescription=Already using XPipe on another system? Synchronize your existing connections across multiple systems through a remote git repository. You can also sync later at any time if it is not set up yet. importConnections=Sync connections ... @@ -538,3 +538,15 @@ terminalLoggingDirectory=Terminal session logs terminalLoggingDirectoryDescription=All logs are stored in the XPipe data directory on your local system. openSessionLogs=Open session logs sessionLogging=Session logging +sessionActive=A background session is running for this connection.\n\nTo stop this session manually, click on the status indicator. +skipValidation=Skip validation +scriptsIntroTitle=About scripts +scriptsIntroText=You can run scripts on shell init, in the file browser, and on demand. You can bring your custom prompts, aliases, and other custom functionality to all your systems without having to set them up on remote systems yourself, XPipe's scripting system will handle everything for you. +scriptsIntroBottomTitle=Using scripts +scriptsIntroBottomText=There are a variety of sample scripts to start out. You can click on the edit button of the individual scripts to see how they are implemented. Scripts have to be enabled to run and show up in menus, there is a toggle on every script for that. +scriptsIntroStart=Get started +checkForSecurityUpdates=Check for security updates +checkForSecurityUpdatesDescription=XPipe can check for potential security updates separately from normal feature updates. When this is enabled, at least important security updates will be recommended for installation even if the normal update check is disabled.\n\nDisabling this setting will result in no external version request being performed, and you won't be notified about any security updates. +pinTab=Pin tab +unpinTab=Unpin tab +pinned=Pinned diff --git a/lang/app/strings/translations_es.properties b/lang/app/strings/translations_es.properties index e9be041f3..0fa504869 100644 --- a/lang/app/strings/translations_es.properties +++ b/lang/app/strings/translations_es.properties @@ -28,7 +28,7 @@ addService=Servicio ... addScript=Script ... addHost=Host remoto ... addShell=Entorno Shell ... -addCommand=Comandos Shell ... +addCommand=Comando ... addAutomatically=Buscar automáticamente ... addOther=Añadir otros ... addConnection=Añadir conexión @@ -273,7 +273,7 @@ performanceModeDescription=Desactiva todos los efectos visuales que no sean nece dontAcceptNewHostKeys=No aceptar automáticamente nuevas claves de host SSH dontAcceptNewHostKeysDescription=XPipe aceptará automáticamente por defecto claves de host de sistemas en los que su cliente SSH no tenga ya guardada ninguna clave de host conocida. Sin embargo, si alguna clave de host conocida ha cambiado, se negará a conectarse a menos que aceptes la nueva.\n\nDesactivar este comportamiento te permite comprobar todas las claves de host, aunque inicialmente no haya ningún conflicto. uiScale=Escala de IU -uiScaleDescription=Un valor de escala personalizado que puede establecerse independientemente de la escala de visualización de todo el sistema. Los valores están en porcentaje, por lo que, por ejemplo, un valor de 150 dará como resultado una escala de interfaz de usuario del 150%.\n\nRequiere un reinicio para aplicarse. +uiScaleDescription=Un valor de escala personalizado que puede establecerse independientemente de la escala de visualización de todo el sistema. Los valores están en porcentaje, por lo que, por ejemplo, un valor de 150 dará como resultado una escala de interfaz de usuario del 150%. editorProgram=Programa Editor editorProgramDescription=El editor de texto predeterminado que se utiliza al editar cualquier tipo de datos de texto. windowOpacity=Opacidad de la ventana @@ -293,9 +293,9 @@ workspaceLock=Frase maestra enableGitStorage=Activar la sincronización git sharing=Compartir sync=Sincronización -enableGitStorageDescription=Cuando está activado, XPipe inicializará un repositorio git para el almacenamiento de datos de conexión y consignará en él cualquier cambio. Ten en cuenta que esto requiere que git esté instalado y puede ralentizar las operaciones de carga y guardado.\n\nLas categorías que deban sincronizarse deben designarse explícitamente como compartidas.\n\nRequiere un reinicio para aplicarse. +enableGitStorageDescription=Cuando está activado, XPipe inicializará un repositorio git para el almacenamiento de datos de conexión y consignará en él cualquier cambio. Ten en cuenta que esto requiere que git esté instalado y puede ralentizar las operaciones de carga y guardado.\n\nLas categorías que deban sincronizarse deben designarse explícitamente como compartidas. storageGitRemote=URL remota de Git -storageGitRemoteDescription=Cuando se establece, XPipe extraerá automáticamente cualquier cambio al cargar y empujará cualquier cambio al repositorio remoto al guardar.\n\nEsto te permite compartir tus datos de configuración entre varias instalaciones de XPipe. Se admiten tanto URL HTTP como SSH. Ten en cuenta que esto puede ralentizar las operaciones de carga y guardado.\n\nRequiere un reinicio para aplicarse. +storageGitRemoteDescription=Cuando se establece, XPipe extraerá automáticamente cualquier cambio al cargar y empujará cualquier cambio al repositorio remoto al guardar.\n\nEsto te permite compartir tus datos de configuración entre varias instalaciones de XPipe. Se admiten tanto URL HTTP como SSH. Ten en cuenta que esto puede ralentizar las operaciones de carga y guardado. vault=Bóveda workspaceLockDescription=Establece una contraseña personalizada para encriptar cualquier información sensible almacenada en XPipe.\n\nEsto aumenta la seguridad, ya que proporciona una capa adicional de encriptación para tu información sensible almacenada. Se te pedirá que introduzcas la contraseña cuando se inicie XPipe. useSystemFontDescription=Controla si utilizar la fuente de tu sistema o la fuente Roboto que se incluye con XPipe. @@ -346,7 +346,7 @@ notAnAbsolutePath=No es una ruta absoluta notADirectory=No es un directorio notAnEmptyDirectory=No es un directorio vacío automaticallyUpdate=Buscar actualizaciones -automaticallyUpdateDescription=Cuando está activada, la información de las nuevas versiones se obtiene automáticamente mientras XPipe se está ejecutando. No se ejecuta ningún actualizador en segundo plano, y sigues teniendo que confirmar explícitamente la instalación de cualquier actualización. +automaticallyUpdateDescription=Cuando está activada, la información de las nuevas versiones se obtiene automáticamente mientras XPipe se está ejecutando al cabo de un rato. Aún así, tienes que confirmar explícitamente la instalación de cualquier actualización. sendAnonymousErrorReports=Enviar informes de error anónimos sendUsageStatistics=Enviar estadísticas de uso anónimas storageDirectory=Directorio de almacenamiento @@ -404,7 +404,7 @@ denyTempScriptCreation=Denegar la creación de un script temporal denyTempScriptCreationDescription=Para realizar algunas de sus funciones, XPipe a veces crea scripts shell temporales en un sistema de destino para permitir una fácil ejecución de comandos sencillos. Éstos no contienen ninguna información sensible y sólo se crean con fines de implementación.\n\nSi se desactiva este comportamiento, XPipe no creará ningún archivo temporal en un sistema remoto. Esta opción es útil en contextos de alta seguridad en los que se supervisa cada cambio en el sistema de archivos. Si se desactiva, algunas funcionalidades, como los entornos shell y los scripts, no funcionarán como está previsto. disableCertutilUse=Desactivar el uso de certutil en Windows useLocalFallbackShell=Utilizar el shell local de reserva -useLocalFallbackShellDescription=Pasa a utilizar otro shell local para gestionar las operaciones locales. Esto sería PowerShell en Windows y bourne shell en otros sistemas.\n\nEsta opción puede utilizarse en caso de que el shell local normal por defecto esté desactivado o roto en algún grado. Sin embargo, algunas funciones pueden no funcionar como se espera cuando esta opción está activada.\n\nRequiere un reinicio para aplicarse. +useLocalFallbackShellDescription=Pasa a utilizar otro shell local para gestionar las operaciones locales. Sería PowerShell en Windows y bourne shell en otros sistemas.\n\nEsta opción puede utilizarse en caso de que el shell local normal por defecto esté desactivado o roto en algún grado. Sin embargo, algunas funciones pueden no funcionar como se espera cuando esta opción está activada. disableCertutilUseDescription=Debido a varias deficiencias y errores de cmd.exe, se crean scripts shell temporales con certutil utilizándolo para descodificar la entrada base64, ya que cmd.exe se rompe con la entrada no ASCII. XPipe también puede utilizar PowerShell para ello, pero será más lento.\n\nEsto deshabilita cualquier uso de certutil en sistemas Windows para realizar algunas funciones y recurrir a PowerShell en su lugar. Esto podría complacer a algunos antivirus, ya que algunos bloquean el uso de certutil. disableTerminalRemotePasswordPreparation=Desactivar la preparación de la contraseña remota del terminal disableTerminalRemotePasswordPreparationDescription=En situaciones en las que deba establecerse en el terminal una conexión shell remota que atraviese varios sistemas intermedios, puede ser necesario preparar las contraseñas necesarias en uno de los sistemas intermedios para permitir la cumplimentación automática de cualquier solicitud.\n\nSi no quieres que las contraseñas se transfieran nunca a ningún sistema intermedio, puedes desactivar este comportamiento. Cualquier contraseña intermedia requerida se consultará entonces en el propio terminal cuando se abra. @@ -446,7 +446,7 @@ orderAheadOf=Haz tu pedido antes de ... httpServer=Servidor HTTP httpServerConfiguration=Configuración del servidor HTTP apiKey=Clave API -apiKeyDescription=La clave API para autenticar las peticiones API del demonio XPipe. Para más información sobre cómo autenticarse, consulta la documentación general de la API.\n\nRequiere un reinicio para aplicarse. +apiKeyDescription=La clave API para autenticar las peticiones API del demonio XPipe. Para más información sobre cómo autenticarse, consulta la documentación general de la API. disableApiAuthentication=Desactivar la autenticación de la API disableApiAuthenticationDescription=Desactiva todos los métodos de autenticación requeridos para que se gestione cualquier solicitud no autenticada.\n\nLa autenticación sólo debe desactivarse con fines de desarrollo.\n\nRequiere un reinicio para aplicarse. api=API @@ -519,3 +519,12 @@ terminalLoggingDirectory=Registros de sesión de terminal terminalLoggingDirectoryDescription=Todos los registros se almacenan en el directorio de datos de XPipe en tu sistema local. openSessionLogs=Registros de sesión abiertos sessionLogging=Registro de sesión +sessionActive=Se está ejecutando una sesión en segundo plano para esta conexión.\n\nPara detener esta sesión manualmente, pulsa sobre el indicador de estado. +skipValidation=Omitir validación +scriptsIntroTitle=Acerca de los guiones +scriptsIntroText=Puedes ejecutar scripts en shell init, en el explorador de archivos y bajo demanda. Puedes llevar tus avisos personalizados, alias y otras funcionalidades personalizadas a todos tus sistemas sin tener que configurarlos tú mismo en los sistemas remotos, el sistema de scripts de XPipe se encargará de todo por ti. +scriptsIntroBottomTitle=Utilizar guiones +scriptsIntroBottomText=Hay una variedad de scripts de ejemplo para empezar. Puedes hacer clic en el botón de edición de los scripts individuales para ver cómo se implementan. Los scripts tienen que estar habilitados para ejecutarse y aparecer en los menús, hay un conmutador en cada script para ello. +scriptsIntroStart=Empezar +checkForSecurityUpdates=Buscar actualizaciones de seguridad +checkForSecurityUpdatesDescription=XPipe puede buscar posibles actualizaciones de seguridad separadamente de las actualizaciones normales de funciones. Cuando esto está activado, se recomendará la instalación de al menos las actualizaciones de seguridad importantes, incluso si la comprobación de actualizaciones normales está desactivada.\n\nSi desactivas esta opción, no se realizará ninguna solicitud de versión externa y no se te notificará ninguna actualización de seguridad. diff --git a/lang/app/strings/translations_fr.properties b/lang/app/strings/translations_fr.properties index 2742d7600..d8653757e 100644 --- a/lang/app/strings/translations_fr.properties +++ b/lang/app/strings/translations_fr.properties @@ -28,7 +28,7 @@ addService=Service ... addScript=Script ... addHost=Hôte distant ... addShell=Environnement Shell ... -addCommand=Commande Shell ... +addCommand=Commande ... addAutomatically=Recherche automatique ... addOther=Ajouter d'autres... addConnection=Ajouter une connexion @@ -273,7 +273,7 @@ performanceModeDescription=Désactive tous les effets visuels qui ne sont pas n dontAcceptNewHostKeys=N'accepte pas automatiquement les nouvelles clés d'hôte SSH dontAcceptNewHostKeysDescription=XPipe acceptera automatiquement par défaut les clés d'hôte des systèmes pour lesquels ton client SSH n'a pas de clé d'hôte connue déjà enregistrée. Cependant, si une clé d'hôte connue a changé, il refusera de se connecter si tu n'acceptes pas la nouvelle.\n\nLa désactivation de ce comportement te permet de vérifier toutes les clés d'hôte, même s'il n'y a pas de conflit au départ. uiScale=Échelle de l'interface utilisateur -uiScaleDescription=Une valeur d'échelle personnalisée qui peut être définie indépendamment de l'échelle d'affichage du système. Les valeurs sont exprimées en pourcentage. Ainsi, une valeur de 150 se traduira par une échelle d'affichage de 150 %.\n\nIl faut redémarrer l'ordinateur pour l'appliquer. +uiScaleDescription=Une valeur d'échelle personnalisée qui peut être définie indépendamment de l'échelle d'affichage du système. Les valeurs sont exprimées en pourcentage. Ainsi, une valeur de 150 se traduira par une échelle d'affichage de 150 %. editorProgram=Programme d'édition editorProgramDescription=L'éditeur de texte par défaut à utiliser lors de l'édition de n'importe quel type de données textuelles. windowOpacity=Opacité de la fenêtre @@ -293,9 +293,9 @@ workspaceLock=Phrase de passe principale enableGitStorage=Activer la synchronisation git sharing=Partage sync=Synchronisation -enableGitStorageDescription=Lorsqu'il est activé, XPipe initialisera un dépôt git pour le stockage des données de connexion et y livrera toutes les modifications. Note que cela nécessite l'installation de git et peut ralentir les opérations de chargement et d'enregistrement.\n\nToutes les catégories qui doivent être synchronisées doivent être explicitement désignées comme partagées.\n\nNécessite un redémarrage pour être appliqué. +enableGitStorageDescription=Lorsqu'il est activé, XPipe initialisera un dépôt git pour le stockage des données de connexion et y livrera toutes les modifications. Note que cela nécessite l'installation de git et peut ralentir les opérations de chargement et d'enregistrement.\n\nToutes les catégories qui doivent être synchronisées doivent être explicitement désignées comme partagées. storageGitRemote=URL distante de Git -storageGitRemoteDescription=Lorsque cette option est activée, XPipe récupère automatiquement toutes les modifications lors du chargement et les transfère vers le référentiel distant lors de l'enregistrement.\n\nCela te permet de partager tes données de configuration entre plusieurs installations de XPipe. Les URL HTTP et SSH sont prises en charge. Note que cela peut ralentir les opérations de chargement et d'enregistrement.\n\nL'application nécessite un redémarrage. +storageGitRemoteDescription=Lorsque cette option est activée, XPipe récupère automatiquement toutes les modifications lors du chargement et les transfère vers le référentiel distant lors de l'enregistrement.\n\nCela te permet de partager tes données de configuration entre plusieurs installations de XPipe. Les URL HTTP et SSH sont prises en charge. Note que cela peut ralentir les opérations de chargement et d'enregistrement. vault=Voûte workspaceLockDescription=Définit un mot de passe personnalisé pour crypter toute information sensible stockée dans XPipe.\n\nCela se traduit par une sécurité accrue car cela fournit une couche supplémentaire de cryptage pour tes informations sensibles stockées. Tu seras alors invité à saisir le mot de passe au démarrage de XPipe. useSystemFontDescription=Contrôle l'utilisation de la police de ton système ou de la police Roboto fournie avec XPipe. @@ -346,7 +346,7 @@ notAnAbsolutePath=Pas un chemin absolu notADirectory=Pas un répertoire notAnEmptyDirectory=Pas un répertoire vide automaticallyUpdate=Vérifier les mises à jour -automaticallyUpdateDescription=Lorsque cette option est activée, les informations sur les nouvelles versions sont automatiquement récupérées lorsque XPipe est en cours d'exécution. Aucun programme de mise à jour n'est exécuté en arrière-plan, et tu dois toujours confirmer explicitement l'installation d'une mise à jour. +automaticallyUpdateDescription=Lorsqu'elle est activée, l'information sur les nouvelles versions est automatiquement récupérée lorsque XPipe est en cours d'exécution après un certain temps. Tu dois toujours confirmer explicitement l'installation d'une mise à jour. sendAnonymousErrorReports=Envoyer des rapports d'erreur anonymes sendUsageStatistics=Envoyer des statistiques d'utilisation anonymes storageDirectory=Répertoire de stockage @@ -404,7 +404,7 @@ denyTempScriptCreation=Refuser la création de scripts temporaires denyTempScriptCreationDescription=Pour réaliser certaines de ses fonctionnalités, XPipe crée parfois des scripts shell temporaires sur un système cible pour permettre une exécution facile de commandes simples. Ceux-ci ne contiennent aucune information sensible et sont simplement créés à des fins de mise en œuvre.\n\nSi ce comportement est désactivé, XPipe ne créera aucun fichier temporaire sur un système distant. Cette option est utile dans les contextes de haute sécurité où chaque modification du système de fichiers est surveillée. Si cette option est désactivée, certaines fonctionnalités, par exemple les environnements shell et les scripts, ne fonctionneront pas comme prévu. disableCertutilUse=Désactiver l'utilisation de certutil sur Windows useLocalFallbackShell=Utiliser le shell local de secours -useLocalFallbackShellDescription=Passe à l'utilisation d'un autre shell local pour gérer les opérations locales. Il s'agirait de PowerShell sur Windows et de l'interpréteur de commandes bourne sur d'autres systèmes.\n\nCette option peut être utilisée dans le cas où le shell local normal par défaut est désactivé ou cassé dans une certaine mesure. Certaines fonctionnalités peuvent ne pas fonctionner comme prévu lorsque cette option est activée.\n\nUn redémarrage est nécessaire pour l'appliquer. +useLocalFallbackShellDescription=Passe à l'utilisation d'un autre shell local pour gérer les opérations locales. Il s'agirait de PowerShell sur Windows et de l'interpréteur de commandes bourne sur d'autres systèmes.\n\nCette option peut être utilisée dans le cas où le shell local normal par défaut est désactivé ou cassé dans une certaine mesure. Certaines fonctions peuvent ne pas fonctionner comme prévu lorsque cette option est activée. disableCertutilUseDescription=En raison de plusieurs lacunes et bogues dans cmd.exe, des scripts shell temporaires sont créés avec certutil en l'utilisant pour décoder l'entrée base64 car cmd.exe s'interrompt sur l'entrée non ASCII. XPipe peut également utiliser PowerShell pour cela, mais cela sera plus lent.\n\nCela désactive toute utilisation de certutil sur les systèmes Windows pour réaliser certaines fonctionnalités et se rabat sur PowerShell à la place. Cela pourrait plaire à certains antivirus, car certains d'entre eux bloquent l'utilisation de certutil. disableTerminalRemotePasswordPreparation=Désactiver la préparation du mot de passe à distance du terminal disableTerminalRemotePasswordPreparationDescription=Dans les situations où une connexion shell à distance qui passe par plusieurs systèmes intermédiaires doit être établie dans le terminal, il peut être nécessaire de préparer tous les mots de passe requis sur l'un des systèmes intermédiaires pour permettre un remplissage automatique de toutes les invites.\n\nSi tu ne veux pas que les mots de passe soient transférés vers un système intermédiaire, tu peux désactiver ce comportement. Tout mot de passe intermédiaire requis sera alors demandé dans le terminal lui-même lorsqu'il sera ouvert. @@ -446,7 +446,7 @@ orderAheadOf=Commande en avance... httpServer=Serveur HTTP httpServerConfiguration=Configuration du serveur HTTP apiKey=Clé API -apiKeyDescription=La clé API pour authentifier les demandes API du démon XPipe. Pour plus d'informations sur la manière de s'authentifier, voir la documentation générale de l'API.\n\nNécessite un redémarrage pour être appliquée. +apiKeyDescription=La clé API pour authentifier les demandes API du démon XPipe. Pour plus d'informations sur la manière de s'authentifier, voir la documentation générale de l'API. disableApiAuthentication=Désactiver l'authentification de l'API disableApiAuthenticationDescription=Désactive toutes les méthodes d'authentification requises, de sorte que toute demande non authentifiée sera traitée.\n\nL'authentification ne doit être désactivée qu'à des fins de développement.\n\nNécessite un redémarrage pour être appliqué. api=API @@ -519,3 +519,12 @@ terminalLoggingDirectory=Journaux de session de terminal terminalLoggingDirectoryDescription=Tous les journaux sont stockés dans le répertoire de données de XPipe sur ton système local. openSessionLogs=Ouvrir les journaux de session sessionLogging=Enregistrement de session +sessionActive=Une session en arrière-plan est en cours pour cette connexion.\n\nPour arrêter cette session manuellement, clique sur l'indicateur d'état. +skipValidation=Sauter la validation +scriptsIntroTitle=A propos des scripts +scriptsIntroText=Tu peux exécuter des scripts sur le shell init, dans le navigateur de fichiers et à la demande. Tu peux apporter tes invites, alias et autres fonctionnalités personnalisées à tous tes systèmes sans avoir à les configurer toi-même sur les systèmes distants, le système de scripts de XPipe s'occupe de tout pour toi. +scriptsIntroBottomTitle=Utilisation de scripts +scriptsIntroBottomText=Il existe une variété d'exemples de scripts pour commencer. Tu peux cliquer sur le bouton d'édition des scripts individuels pour voir comment ils sont mis en œuvre. Les scripts doivent être activés pour être exécutés et apparaître dans les menus. +scriptsIntroStart=Commence +checkForSecurityUpdates=Vérifier les mises à jour de sécurité +checkForSecurityUpdatesDescription=XPipe peut vérifier les mises à jour de sécurité potentielles séparément des mises à jour normales des fonctionnalités. Lorsque cette fonction est activée, il est recommandé d'installer au moins les mises à jour de sécurité importantes, même si la vérification normale des mises à jour est désactivée.\n\nEn désactivant ce paramètre, aucune demande de version externe ne sera effectuée et tu ne seras pas informé des mises à jour de sécurité. diff --git a/lang/app/strings/translations_it.properties b/lang/app/strings/translations_it.properties index 396ec6063..9df09bc0e 100644 --- a/lang/app/strings/translations_it.properties +++ b/lang/app/strings/translations_it.properties @@ -28,7 +28,7 @@ addService=Servizio ... addScript=Script ... addHost=Host remoto ... addShell=Ambiente Shell ... -addCommand=Comando Shell ... +addCommand=Comando ... addAutomatically=Ricerca automatica ... addOther=Aggiungi altro ... addConnection=Aggiungi connessione @@ -273,7 +273,7 @@ performanceModeDescription=Disattiva tutti gli effetti visivi non necessari per dontAcceptNewHostKeys=Non accettare automaticamente le nuove chiavi host SSH dontAcceptNewHostKeysDescription=XPipe accetta automaticamente le chiavi host per impostazione predefinita dai sistemi in cui il tuo client SSH non ha una chiave host nota già salvata. Tuttavia, se la chiave host conosciuta è cambiata, si rifiuterà di connettersi a meno che tu non accetti quella nuova.\n\nDisabilitare questo comportamento ti permette di controllare tutte le chiavi host, anche se inizialmente non c'è alcun conflitto. uiScale=Scala UI -uiScaleDescription=Un valore di scala personalizzato che può essere impostato indipendentemente dalla scala di visualizzazione del sistema. I valori sono espressi in percentuale, quindi, ad esempio, un valore di 150 corrisponde a una scala dell'interfaccia utente del 150%.\n\nRichiede un riavvio per essere applicato. +uiScaleDescription=Un valore di scala personalizzato che può essere impostato indipendentemente dalla scala di visualizzazione del sistema. I valori sono espressi in percentuale, quindi, ad esempio, un valore di 150 si tradurrà in una scala dell'interfaccia utente del 150%. editorProgram=Programma Editor editorProgramDescription=L'editor di testo predefinito da utilizzare per modificare qualsiasi tipo di dato testuale. windowOpacity=Opacità della finestra @@ -293,9 +293,9 @@ workspaceLock=Passphrase principale enableGitStorage=Abilita la sincronizzazione git sharing=Condivisione sync=Sincronizzazione -enableGitStorageDescription=Se abilitato, XPipe inizializzerà un repository git per l'archiviazione dei dati di connessione e vi apporterà tutte le modifiche. Questo richiede l'installazione di git e potrebbe rallentare le operazioni di caricamento e salvataggio.\n\nTutte le categorie che devono essere sincronizzate devono essere esplicitamente designate come condivise.\n\nRichiede un riavvio per essere applicato. +enableGitStorageDescription=Se abilitato, XPipe inizializzerà un repository git per l'archiviazione dei dati di connessione e vi apporterà tutte le modifiche. Questo richiede l'installazione di git e potrebbe rallentare le operazioni di caricamento e salvataggio.\n\nTutte le categorie che devono essere sincronizzate devono essere esplicitamente designate come condivise. storageGitRemote=URL remoto di Git -storageGitRemoteDescription=Se impostato, XPipe preleverà automaticamente le modifiche al momento del caricamento e le invierà al repository remoto al momento del salvataggio.\n\nQuesto ti permette di condividere i dati di configurazione tra più installazioni di XPipe. Sono supportati sia gli URL HTTP che SSH. Si noti che questo potrebbe rallentare le operazioni di caricamento e salvataggio.\n\nRichiede un riavvio per essere applicata. +storageGitRemoteDescription=Se impostato, XPipe preleverà automaticamente le modifiche al momento del caricamento e le invierà al repository remoto al momento del salvataggio.\n\nQuesto ti permette di condividere i dati di configurazione tra più installazioni di XPipe. Sono supportati sia gli URL HTTP che SSH. Si noti che questo potrebbe rallentare le operazioni di caricamento e salvataggio. vault=Volta workspaceLockDescription=Imposta una password personalizzata per criptare le informazioni sensibili memorizzate in XPipe.\n\nQuesto aumenta la sicurezza in quanto fornisce un ulteriore livello di crittografia per le informazioni sensibili memorizzate. All'avvio di XPipe ti verrà richiesto di inserire la password. useSystemFontDescription=Controlla se utilizzare il font di sistema o il font Roboto fornito con XPipe. @@ -346,7 +346,7 @@ notAnAbsolutePath=Non è un percorso assoluto notADirectory=Non una directory notAnEmptyDirectory=Non una directory vuota automaticallyUpdate=Controlla gli aggiornamenti -automaticallyUpdateDescription=Se abilitato, le informazioni sulle nuove versioni vengono recuperate automaticamente mentre XPipe è in esecuzione. Non viene eseguito alcun programma di aggiornamento in background e devi comunque confermare esplicitamente l'installazione di qualsiasi aggiornamento. +automaticallyUpdateDescription=Se abilitato, le informazioni sulle nuove versioni vengono recuperate automaticamente durante l'esecuzione di XPipe dopo un po' di tempo. Dovrai comunque confermare esplicitamente l'installazione di ogni aggiornamento. sendAnonymousErrorReports=Invia segnalazioni di errore anonime sendUsageStatistics=Inviare statistiche d'uso anonime storageDirectory=Directory di archiviazione @@ -404,7 +404,7 @@ denyTempScriptCreation=Rifiuta la creazione di script temporanei denyTempScriptCreationDescription=Per realizzare alcune delle sue funzionalità, XPipe a volte crea degli script di shell temporanei sul sistema di destinazione per consentire una facile esecuzione di semplici comandi. Questi non contengono informazioni sensibili e vengono creati solo a scopo di implementazione.\n\nSe questo comportamento è disattivato, XPipe non creerà alcun file temporaneo su un sistema remoto. Questa opzione è utile in contesti ad alta sicurezza in cui ogni modifica del file system viene monitorata. Se questa opzione è disattivata, alcune funzionalità, ad esempio gli ambienti di shell e gli script, non funzioneranno come previsto. disableCertutilUse=Disabilitare l'uso di certutil su Windows useLocalFallbackShell=Usa la shell di fallback locale -useLocalFallbackShellDescription=Passa all'utilizzo di un'altra shell locale per gestire le operazioni locali. Si tratta di PowerShell su Windows e di bourne shell su altri sistemi.\n\nQuesta opzione può essere utilizzata nel caso in cui la normale shell locale predefinita sia disabilitata o in qualche modo danneggiata. Alcune funzioni potrebbero però non funzionare come previsto quando questa opzione è attivata.\n\nRichiede un riavvio per essere applicata. +useLocalFallbackShellDescription=Passa all'utilizzo di un'altra shell locale per gestire le operazioni locali. Si tratta di PowerShell su Windows e di bourne shell su altri sistemi.\n\nQuesta opzione può essere utilizzata nel caso in cui la normale shell locale predefinita sia disabilitata o in qualche modo danneggiata. Alcune funzioni potrebbero però non funzionare come previsto quando questa opzione è abilitata. disableCertutilUseDescription=A causa di diverse carenze e bug di cmd.exe, gli script di shell temporanei vengono creati con certutil utilizzandolo per decodificare l'input base64, dato che cmd.exe si interrompe in caso di input non ASCII. XPipe può anche utilizzare PowerShell per questo scopo, ma sarà più lento.\n\nQuesto disabilita l'uso di certutil sui sistemi Windows per realizzare alcune funzionalità e si ripiega su PowerShell. Questo potrebbe far piacere ad alcuni AV che bloccano l'uso di certutil. disableTerminalRemotePasswordPreparation=Disabilita la preparazione della password remota del terminale disableTerminalRemotePasswordPreparationDescription=Nelle situazioni in cui è necessario stabilire nel terminale una connessione shell remota che attraversa più sistemi intermedi, potrebbe essere necessario preparare le password richieste su uno dei sistemi intermedi per consentire la compilazione automatica di eventuali richieste.\n\nSe non vuoi che le password vengano mai trasferite a un sistema intermedio, puoi disabilitare questo comportamento. Le password intermedie richieste verranno quindi richieste nel terminale stesso all'apertura. @@ -446,7 +446,7 @@ orderAheadOf=Ordina prima di ... httpServer=Server HTTP httpServerConfiguration=Configurazione del server HTTP apiKey=Chiave API -apiKeyDescription=La chiave API per autenticare le richieste API del demone XPipe. Per ulteriori informazioni sulle modalità di autenticazione, consulta la documentazione generale dell'API.\n\nRichiede un riavvio per essere applicata. +apiKeyDescription=La chiave API per autenticare le richieste API del demone XPipe. Per ulteriori informazioni sulle modalità di autenticazione, consulta la documentazione generale dell'API. disableApiAuthentication=Disabilita l'autenticazione API disableApiAuthenticationDescription=Disabilita tutti i metodi di autenticazione richiesti in modo che qualsiasi richiesta non autenticata venga gestita.\n\nL'autenticazione dovrebbe essere disabilitata solo per scopi di sviluppo.\n\nRichiede un riavvio per essere applicata. api=API @@ -519,3 +519,12 @@ terminalLoggingDirectory=Registri di sessione del terminale terminalLoggingDirectoryDescription=Tutti i registri vengono memorizzati nella directory dei dati di XPipe sul tuo sistema locale. openSessionLogs=Registri di sessione aperti sessionLogging=Registrazione della sessione +sessionActive=Per questa connessione è in corso una sessione in background.\n\nPer interrompere manualmente questa sessione, clicca sull'indicatore di stato. +skipValidation=Convalida del salto +scriptsIntroTitle=Informazioni sugli script +scriptsIntroText=Puoi eseguire gli script all'avvio della shell, nel browser dei file e su richiesta. Puoi portare i tuoi prompt personalizzati, gli alias e altre funzionalità personalizzate su tutti i tuoi sistemi senza doverli impostare da solo sui sistemi remoti: il sistema di scripting di XPipe si occuperà di tutto per te. +scriptsIntroBottomTitle=Utilizzo di script +scriptsIntroBottomText=Ci sono diversi esempi di script per iniziare. Puoi cliccare sul pulsante di modifica dei singoli script per vedere come sono stati implementati. Gli script devono essere abilitati per essere eseguiti e visualizzati nei menu; in ogni script è presente una levetta per questo scopo. +scriptsIntroStart=Iniziare +checkForSecurityUpdates=Controlla gli aggiornamenti di sicurezza +checkForSecurityUpdatesDescription=XPipe può verificare la presenza di potenziali aggiornamenti di sicurezza separatamente dai normali aggiornamenti delle funzioni. Se questa opzione è attivata, l'installazione degli aggiornamenti di sicurezza più importanti viene consigliata anche se il normale controllo degli aggiornamenti è disattivato.\n\nDisattivando questa impostazione, non verrà eseguita alcuna richiesta di versione esterna e non riceverai alcuna notifica sugli aggiornamenti di sicurezza. diff --git a/lang/app/strings/translations_ja.properties b/lang/app/strings/translations_ja.properties index 201cddaff..2162421b3 100644 --- a/lang/app/strings/translations_ja.properties +++ b/lang/app/strings/translations_ja.properties @@ -28,7 +28,7 @@ addService=サービス ... addScript=スクリプト ... addHost=リモートホスト ... addShell=シェル環境 ... -addCommand=シェルコマンド ... +addCommand=コマンド ... addAutomatically=自動的に検索する addOther=その他を追加する addConnection=接続を追加する @@ -273,7 +273,7 @@ performanceModeDescription=アプリケーションのパフォーマンスを dontAcceptNewHostKeys=新しいSSHホスト鍵を自動的に受け取らない dontAcceptNewHostKeysDescription=XPipeは、SSHクライアントに既知のホスト鍵が保存されていない場合、デフォルトで自動的にホスト鍵を受け付ける。しかし、既知のホスト鍵が変更されている場合は、新しいものを受け入れない限り接続を拒否する。\n\nこの動作を無効にすると、最初は競合していなくても、すべてのホスト鍵をチェックできるようになる。 uiScale=UIスケール -uiScaleDescription=システム全体の表示スケールとは別に設定できるカスタムスケーリング値。値の単位はパーセントで、例えば150を指定するとUIのスケールは150%になる。\n\n適用には再起動が必要。 +uiScaleDescription=システム全体の表示スケールとは別に設定できるカスタムスケーリング値。値の単位はパーセントで、例えば150を指定するとUIのスケールは150%になる。 editorProgram=エディタプログラム editorProgramDescription=あらゆる種類のテキストデータを編集する際に使用するデフォルトのテキストエディタ。 windowOpacity=ウィンドウの不透明度 @@ -293,9 +293,9 @@ workspaceLock=マスターパスフレーズ enableGitStorage=git同期を有効にする sharing=共有 sync=同期 -enableGitStorageDescription=有効にすると、XPipeは接続データ保存用のgitリポジトリを初期化し、変更があればコミットする。これにはgitがインストールされている必要があり、読み込みや保存の動作が遅くなる可能性があることに注意。\n\n同期するカテゴリーは、明示的に共有として指定する必要がある。\n\n適用には再起動が必要である。 +enableGitStorageDescription=有効にすると、XPipeは接続データ保存用のgitリポジトリを初期化し、変更があればコミットする。これにはgitがインストールされている必要があり、読み込みや保存の動作が遅くなる可能性があることに注意。\n\n同期するカテゴリーは、明示的に共有として指定する必要がある。 storageGitRemote=GitリモートURL -storageGitRemoteDescription=設定すると、XPipeは読み込み時に変更点を自動的にプルし、保存時に変更点をリモートリポジトリにプッシュする。\n\nこれにより、複数のXPipeインストール間で設定データを共有することができる。HTTPとSSH URLの両方がサポートされている。読み込みと保存の動作が遅くなる可能性があることに注意。\n\n適用には再起動が必要。 +storageGitRemoteDescription=設定すると、XPipeは読み込み時に変更点を自動的にプルし、保存時に変更点をリモートリポジトリにプッシュする。\n\nこれにより、複数のXPipeインストール間で設定データを共有することができる。HTTPとSSH URLの両方がサポートされている。読み込みと保存の動作が遅くなる可能性があることに注意。 vault=金庫 workspaceLockDescription=XPipeに保存されている機密情報を暗号化するためのカスタムパスワードを設定する。\n\nこれにより、保存された機密情報の暗号化レイヤーが追加され、セキュリティが向上する。XPipe起動時にパスワードの入力を求められる。 useSystemFontDescription=システムフォントを使用するか、XPipeにバンドルされているRobotoフォントを使用するかを制御する。 @@ -346,7 +346,7 @@ notAnAbsolutePath=絶対パスではない notADirectory=ディレクトリではない notAnEmptyDirectory=空のディレクトリではない automaticallyUpdate=アップデートを確認する -automaticallyUpdateDescription=有効にすると、XPipeの実行中に新しいリリース情報が自動的に取得される。アップデータはバックグラウンドで実行されず、アップデートのインストールを明示的に確認する必要がある。 +automaticallyUpdateDescription=有効にすると、XPipeの実行中に、しばらくすると新しいリリース情報が自動的に取得される。それでも、アップデートのインストールを明示的に確認する必要がある。 sendAnonymousErrorReports=匿名でエラーレポートを送信する sendUsageStatistics=匿名で利用統計を送信する storageDirectory=ストレージディレクトリ @@ -404,7 +404,7 @@ denyTempScriptCreation=一時的なスクリプトの作成を拒否する denyTempScriptCreationDescription=XPipeは、その機能の一部を実現するために、ターゲットシステム上に一時的なシェルスクリプトを作成し、簡単なコマンドを簡単に実行できるようにすることがある。これらには機密情報は含まれておらず、単に実装のために作成される。\n\nこの動作を無効にすると、XPipeはリモートシステム上に一時ファイルを作成しない。このオプションは、ファイルシステムの変更がすべて監視されるようなセキュリティの高い状況で有用である。このオプションを無効にすると、シェル環境やスクリプトなど、一部の機能が意図したとおりに動作しなくなる。 disableCertutilUse=Windowsでcertutilの使用を無効にする useLocalFallbackShell=ローカルのフォールバックシェルを使う -useLocalFallbackShellDescription=ローカル操作を処理するために、別のローカルシェルを使うように切り替える。WindowsではPowerShell、その他のシステムではボーンシェルがこれにあたる。\n\nこのオプションは、通常のローカル・デフォルト・シェルが無効になっているか、ある程度壊れている場合に使用できる。このオプションが有効になっている場合、一部の機能は期待通りに動作しないかもしれない。\n\n適用には再起動が必要である。 +useLocalFallbackShellDescription=ローカル操作を処理するために、別のローカルシェルを使うように切り替える。WindowsではPowerShell、その他のシステムではボーンシェルがこれにあたる。\n\nこのオプションは、通常のローカルデフォルトのシェルが無効になっているか、ある程度壊れている場合に使用できる。このオプションが有効になっている場合、一部の機能は期待通りに動作しないかもしれない。 disableCertutilUseDescription=cmd.exeにはいくつかの欠点やバグがあるため、cmd.exeが非ASCII入力で壊れるように、certutilを使って一時的なシェルスクリプトを作成し、base64入力をデコードする。XPipeはPowerShellを使用することもできるが、その場合は動作が遅くなる。\n\nこれにより、Windowsシステムでcertutilを使用して一部の機能を実現することができなくなり、代わりにPowerShellにフォールバックする。AVの中にはcertutilの使用をブロックするものもあるので、これは喜ぶかもしれない。 disableTerminalRemotePasswordPreparation=端末のリモートパスワードの準備を無効にする disableTerminalRemotePasswordPreparationDescription=複数の中間システムを経由するリモートシェル接続をターミナルで確立する必要がある状況では、プロンプトを自動的に埋めることができるように、中間システムの1つに必要なパスワードを準備する必要があるかもしれない。\n\n中間システムにパスワードを転送したくない場合は、この動作を無効にすることができる。中間システムで必要なパスワードは、ターミナルを開いたときに照会される。 @@ -446,7 +446,7 @@ orderAheadOf=先に注文する httpServer=HTTPサーバー httpServerConfiguration=HTTPサーバーの設定 apiKey=APIキー -apiKeyDescription=XPipeデーモンAPIリクエストを認証するためのAPIキー。認証方法の詳細については、一般的なAPIドキュメントを参照のこと。\n\n適用には再起動が必要。 +apiKeyDescription=XPipeデーモンAPIリクエストを認証するためのAPIキー。認証方法の詳細については、一般的なAPIドキュメントを参照のこと。 disableApiAuthentication=API認証を無効にする disableApiAuthenticationDescription=認証されていないリクエストが処理されるように、必要な認証方法をすべて無効にする。\n\n認証は開発目的でのみ無効にすべきである。\n\n適用するには再起動が必要である。 api=API @@ -519,3 +519,12 @@ terminalLoggingDirectory=端末のセッションログ terminalLoggingDirectoryDescription=すべてのログは、ローカルシステムのXPipeデータディレクトリに保存される。 openSessionLogs=セッションログを開く sessionLogging=セッションロギング +sessionActive=この接続ではバックグラウンドセッションが実行されている。\n\nこのセッションを手動で停止するには、ステータスインジケータをクリックする。 +skipValidation=検証をスキップする +scriptsIntroTitle=スクリプトについて +scriptsIntroText=シェルinit、ファイルブラウザ、オンデマンドでスクリプトを実行できる。カスタムプロンプト、エイリアス、その他のカスタム機能を、リモートシステムに自分でセットアップすることなく、すべてのシステムに導入することができる。 +scriptsIntroBottomTitle=スクリプトを使用する +scriptsIntroBottomText=スクリプトには様々なサンプルが用意されている。個々のスクリプトの編集ボタンをクリックして、どのように実装されているかを見ることができる。スクリプトを実行してメニューに表示するには、スクリプトを有効にする必要がある。 +scriptsIntroStart=始める +checkForSecurityUpdates=セキュリティアップデートを確認する +checkForSecurityUpdatesDescription=XPipeは、通常の機能アップデートとは別に、潜在的なセキュリティアップデートをチェックすることができる。これを有効にすると、通常のアップデートチェックが無効になっている場合でも、少なくとも重要なセキュリティアップデートのインストールが推奨される。\n\nこの設定を無効にすると、外部バージョン要求が実行されなくなり、セキュリティアップデートが通知されなくなる。 diff --git a/lang/app/strings/translations_nl.properties b/lang/app/strings/translations_nl.properties index 7243d8276..a57b7058e 100644 --- a/lang/app/strings/translations_nl.properties +++ b/lang/app/strings/translations_nl.properties @@ -28,7 +28,7 @@ addService=Service ... addScript=Script ... addHost=Externe host ... addShell=Shell-omgeving ... -addCommand=Shell-commando ... +addCommand=Opdracht ... addAutomatically=Automatisch zoeken ... addOther=Andere toevoegen ... addConnection=Verbinding toevoegen @@ -273,7 +273,7 @@ performanceModeDescription=Schakelt alle visuele effecten uit die niet nodig zij dontAcceptNewHostKeys=Nieuwe SSH-hostsleutels niet automatisch accepteren dontAcceptNewHostKeysDescription=XPipe accepteert standaard automatisch hostsleutels van systemen waar je SSH-client nog geen bekende hostsleutel heeft opgeslagen. Als een bekende hostsleutel echter is gewijzigd, zal het weigeren om verbinding te maken tenzij je de nieuwe accepteert.\n\nDoor dit gedrag uit te schakelen kun je alle hostsleutels controleren, zelfs als er in eerste instantie geen conflict is. uiScale=UI Schaal -uiScaleDescription=Een aangepaste schaalwaarde die onafhankelijk van de systeembrede schermschaal kan worden ingesteld. Waarden zijn in procenten, dus bijvoorbeeld een waarde van 150 resulteert in een UI-schaal van 150%.\n\nVereist een herstart om toe te passen. +uiScaleDescription=Een aangepaste schaalwaarde die onafhankelijk van je systeembrede schermschaal kan worden ingesteld. Waarden zijn in procenten, dus bijvoorbeeld een waarde van 150 resulteert in een UI-schaal van 150%. editorProgram=Bewerkingsprogramma editorProgramDescription=De standaard teksteditor om te gebruiken bij het bewerken van tekstgegevens. windowOpacity=Venster ondoorzichtigheid @@ -293,9 +293,9 @@ workspaceLock=Hoofdwachtzin enableGitStorage=Git synchronisatie inschakelen sharing=Delen sync=Synchronisatie -enableGitStorageDescription=Als dit is ingeschakeld zal XPipe een git repository initialiseren voor de opslag van de verbindingsgegevens en alle wijzigingen daarop vastleggen. Merk op dat hiervoor git geïnstalleerd moet zijn en dat dit het laden en opslaan kan vertragen.\n\nAlle categorieën die gesynchroniseerd moeten worden, moeten expliciet als gedeeld worden aangemerkt.\n\nVereist een herstart om toe te passen. +enableGitStorageDescription=Als dit is ingeschakeld zal XPipe een git repository initialiseren voor de opslag van de verbindingsgegevens en alle wijzigingen daarop vastleggen. Merk op dat hiervoor git geïnstalleerd moet zijn en dat dit het laden en opslaan kan vertragen.\n\nAlle categorieën die gesynchroniseerd moeten worden, moeten expliciet als gedeeld worden aangemerkt. storageGitRemote=Git URL op afstand -storageGitRemoteDescription=Als dit is ingesteld, haalt XPipe automatisch wijzigingen op bij het laden en pusht wijzigingen naar het externe archief bij het opslaan.\n\nHierdoor kun je configuratiegegevens delen tussen meerdere XPipe installaties. Zowel HTTP als SSH URL's worden ondersteund. Merk op dat dit het laden en opslaan kan vertragen.\n\nVereist een herstart om toe te passen. +storageGitRemoteDescription=Als dit is ingesteld, haalt XPipe automatisch wijzigingen op bij het laden en pusht wijzigingen naar het externe archief bij het opslaan.\n\nHierdoor kun je configuratiegegevens delen tussen meerdere XPipe installaties. Zowel HTTP als SSH URL's worden ondersteund. Merk op dat dit het laden en opslaan kan vertragen. vault=Kluis workspaceLockDescription=Stelt een aangepast wachtwoord in om gevoelige informatie die is opgeslagen in XPipe te versleutelen.\n\nDit resulteert in een verhoogde beveiliging omdat het een extra coderingslaag biedt voor je opgeslagen gevoelige informatie. Je wordt dan gevraagd om het wachtwoord in te voeren wanneer XPipe start. useSystemFontDescription=Bepaalt of je het systeemlettertype gebruikt of het Roboto-lettertype dat met XPipe wordt meegeleverd. @@ -346,7 +346,7 @@ notAnAbsolutePath=Geen absoluut pad notADirectory=Geen directory notAnEmptyDirectory=Geen lege map automaticallyUpdate=Controleren op updates -automaticallyUpdateDescription=Als deze optie is ingeschakeld, wordt nieuwe release-informatie automatisch opgehaald terwijl XPipe actief is. Er wordt geen updateprogramma op de achtergrond uitgevoerd en je moet de installatie van een update nog steeds expliciet bevestigen. +automaticallyUpdateDescription=Als deze optie is ingeschakeld, wordt na een tijdje automatisch nieuwe release-informatie opgehaald terwijl XPipe wordt uitgevoerd. Je moet nog steeds elke installatie van een update expliciet bevestigen. sendAnonymousErrorReports=Anoniem foutrapporten versturen sendUsageStatistics=Anonieme gebruiksstatistieken verzenden storageDirectory=Opslagmap @@ -404,7 +404,7 @@ denyTempScriptCreation=Het maken van een tijdelijk script weigeren denyTempScriptCreationDescription=Om sommige functionaliteiten te realiseren, maakt XPipe soms tijdelijke shell scripts aan op een doelsysteem om eenvoudige commando's eenvoudig uit te kunnen voeren. Deze bevatten geen gevoelige informatie en worden alleen gemaakt voor implementatiedoeleinden.\n\nAls dit gedrag is uitgeschakeld, maakt XPipe geen tijdelijke bestanden aan op een systeem op afstand. Deze optie is handig in omgevingen met een hoge beveiligingsgraad waar elke wijziging aan het bestandssysteem wordt gecontroleerd. Als dit is uitgeschakeld, zullen sommige functionaliteiten, zoals shell omgevingen en scripts, niet werken zoals bedoeld. disableCertutilUse=Het gebruik van certutil onder Windows uitschakelen useLocalFallbackShell=Lokale fallback-shell gebruiken -useLocalFallbackShellDescription=Schakel over op het gebruik van een andere lokale shell om lokale bewerkingen uit te voeren. Dit is PowerShell op Windows en bourne shell op andere systemen.\n\nDeze optie kan worden gebruikt als de normale lokale standaard shell is uitgeschakeld of tot op zekere hoogte kapot is. Sommige functies kunnen echter niet werken zoals verwacht wanneer deze optie is ingeschakeld.\n\nVereist een herstart om toe te passen. +useLocalFallbackShellDescription=Schakel over op het gebruik van een andere lokale shell om lokale operaties af te handelen. Dit is PowerShell op Windows en bourne shell op andere systemen.\n\nDeze optie kan worden gebruikt als de normale lokale standaard shell is uitgeschakeld of tot op zekere hoogte kapot is. Sommige functies kunnen echter niet werken zoals verwacht wanneer deze optie is ingeschakeld. disableCertutilUseDescription=Vanwege verschillende tekortkomingen en bugs in cmd.exe worden tijdelijke shellscripts gemaakt met certutil door het te gebruiken om base64 invoer te decoderen, omdat cmd.exe breekt op niet-ASCII invoer. XPipe kan hiervoor ook PowerShell gebruiken, maar dit is langzamer.\n\nDit schakelt elk gebruik van certutil op Windows systemen uit om bepaalde functionaliteit te realiseren en in plaats daarvan terug te vallen op PowerShell. Dit zou sommige AV's kunnen plezieren, omdat sommige AV's het gebruik van certutil blokkeren. disableTerminalRemotePasswordPreparation=Voorbereiding voor wachtwoord op afstand van terminal uitschakelen disableTerminalRemotePasswordPreparationDescription=In situaties waar een remote shell verbinding die via meerdere intermediaire systemen loopt in de terminal tot stand moet worden gebracht, kan het nodig zijn om alle vereiste wachtwoorden op een van de intermediaire systemen voor te bereiden, zodat eventuele prompts automatisch kunnen worden ingevuld.\n\nAls je niet wilt dat de wachtwoorden ooit worden verzonden naar een tussenliggend systeem, dan kun je dit gedrag uitschakelen. Elk vereist tussenliggend wachtwoord zal dan worden opgevraagd in de terminal zelf wanneer deze wordt geopend. @@ -446,7 +446,7 @@ orderAheadOf=Vooruitbestellen ... httpServer=HTTP-server httpServerConfiguration=HTTP-server configuratie apiKey=API-sleutel -apiKeyDescription=De API sleutel om XPipe daemon API verzoeken te authenticeren. Voor meer informatie over hoe te authenticeren, zie de algemene API documentatie.\n\nVereist een herstart om toe te passen. +apiKeyDescription=De API sleutel om XPipe daemon API verzoeken te authenticeren. Voor meer informatie over hoe te authenticeren, zie de algemene API documentatie. disableApiAuthentication=API-authenticatie uitschakelen disableApiAuthenticationDescription=Schakelt alle vereiste authenticatiemethoden uit, zodat elk niet-geauthenticeerd verzoek wordt afgehandeld.\n\nAuthenticatie zou alleen uitgeschakeld moeten worden voor ontwikkelingsdoeleinden.\n\nVereist een herstart om toe te passen. api=API @@ -519,3 +519,12 @@ terminalLoggingDirectory=Terminal sessie logs terminalLoggingDirectoryDescription=Alle logs worden opgeslagen in de XPipe datamap op je lokale systeem. openSessionLogs=Open sessie logs sessionLogging=Sessie loggen +sessionActive=Er wordt een achtergrondsessie uitgevoerd voor deze verbinding.\n\nKlik op de statusindicator om deze sessie handmatig te stoppen. +skipValidation=Validatie overslaan +scriptsIntroTitle=Over scripts +scriptsIntroText=Je kunt scripts uitvoeren op shell init, in de bestandsbrowser en op aanvraag. Je kunt je aangepaste prompts, aliassen en andere aangepaste functionaliteit naar al je systemen brengen zonder dat je ze zelf op externe systemen hoeft in te stellen, het scriptsysteem van XPipe regelt alles voor je. +scriptsIntroBottomTitle=Scripts gebruiken +scriptsIntroBottomText=Er zijn verschillende voorbeeldscripts om mee te beginnen. Je kunt op de bewerkknop van de individuele scripts klikken om te zien hoe ze zijn geïmplementeerd. Scripts moeten worden ingeschakeld om te worden uitgevoerd en om te worden weergegeven in menu's. Elk script heeft daarvoor een schakelaartje. +scriptsIntroStart=Aan de slag +checkForSecurityUpdates=Controleren op beveiligingsupdates +checkForSecurityUpdatesDescription=XPipe kan apart van normale functie-updates controleren op mogelijke beveiligingsupdates. Als dit is ingeschakeld, worden ten minste belangrijke beveiligingsupdates aanbevolen voor installatie, zelfs als de normale updatecontrole is uitgeschakeld.\n\nAls je deze instelling uitschakelt, wordt er geen externe versie opgevraagd en krijg je geen melding over beveiligingsupdates. diff --git a/lang/app/strings/translations_pt.properties b/lang/app/strings/translations_pt.properties index 7c9d4d1dd..b37a107e9 100644 --- a/lang/app/strings/translations_pt.properties +++ b/lang/app/strings/translations_pt.properties @@ -28,7 +28,7 @@ addService=Serviço ... addScript=Script ... addHost=Anfitrião remoto ... addShell=Ambiente Shell ... -addCommand=Comando Shell ... +addCommand=Comando ... addAutomatically=Pesquisa automaticamente ... addOther=Adiciona outro ... addConnection=Adicionar ligação @@ -273,7 +273,7 @@ performanceModeDescription=Desactiva todos os efeitos visuais que não são nece dontAcceptNewHostKeys=Não aceita automaticamente novas chaves de anfitrião SSH dontAcceptNewHostKeysDescription=O XPipe aceitará automaticamente chaves de anfitrião por defeito de sistemas onde o teu cliente SSH não tem nenhuma chave de anfitrião conhecida já guardada. No entanto, se alguma chave de anfitrião conhecida tiver sido alterada, recusará a ligação a menos que aceites a nova chave.\n\nDesativar este comportamento permite-te verificar todas as chaves de anfitrião, mesmo que não haja conflito inicialmente. uiScale=Escala UI -uiScaleDescription=Um valor de escala personalizado que pode ser definido independentemente da escala de exibição de todo o sistema. Os valores estão em percentagem, por isso, por exemplo, o valor de 150 resultará numa escala da IU de 150%.\n\nRequer uma reinicialização para ser aplicado. +uiScaleDescription=Um valor de escala personalizado que pode ser definido independentemente da escala de exibição de todo o sistema. Os valores estão em percentagem, pelo que, por exemplo, o valor de 150 resultará numa escala da IU de 150%. editorProgram=Programa editor editorProgramDescription=O editor de texto predefinido a utilizar quando edita qualquer tipo de dados de texto. windowOpacity=Opacidade de uma janela @@ -293,9 +293,9 @@ workspaceLock=Palavra-passe principal enableGitStorage=Ativar a sincronização do git sharing=Partilha sync=Sincronização -enableGitStorageDescription=Quando ativado, o XPipe inicializa um repositório git para o armazenamento de dados de conexão e confirma quaisquer alterações nele. Tem em atenção que isto requer que o git esteja instalado e pode tornar as operações de carregamento e gravação mais lentas.\n\nTodas as categorias que devem ser sincronizadas têm de ser explicitamente designadas como partilhadas.\n\nRequer uma reinicialização para ser aplicado. +enableGitStorageDescription=Quando ativado, o XPipe inicializará um repositório git para o armazenamento de dados de conexão e confirmará quaisquer alterações nele. Nota que isto requer que o git esteja instalado e pode tornar as operações de carregamento e gravação mais lentas.\n\nQuaisquer categorias que devam ser sincronizadas têm de ser explicitamente designadas como partilhadas. storageGitRemote=URL remoto do Git -storageGitRemoteDescription=Quando definido, o XPipe extrai automaticamente quaisquer alterações ao carregar e empurra quaisquer alterações para o repositório remoto ao guardar.\n\nIsto permite-te partilhar os teus dados de configuração entre várias instalações XPipe. São suportados URLs HTTP e SSH. Tem em atenção que isto pode tornar as operações de carregamento e gravação mais lentas.\n\nRequer uma reinicialização para ser aplicado. +storageGitRemoteDescription=Quando definido, o XPipe extrai automaticamente quaisquer alterações ao carregar e empurra quaisquer alterações para o repositório remoto ao guardar.\n\nIsto permite-te partilhar os teus dados de configuração entre várias instalações XPipe. São suportados URLs HTTP e SSH. Tem em atenção que isto pode tornar as operações de carregamento e gravação mais lentas. vault=Cofre workspaceLockDescription=Define uma palavra-passe personalizada para encriptar qualquer informação sensível armazenada no XPipe.\n\nIsto resulta numa maior segurança, uma vez que fornece uma camada adicional de encriptação para as informações sensíveis armazenadas. Ser-te-á pedido que introduzas a palavra-passe quando o XPipe for iniciado. useSystemFontDescription=Controla se deve ser utilizado o tipo de letra do sistema ou o tipo de letra Roboto que é fornecido com o XPipe. @@ -346,7 +346,7 @@ notAnAbsolutePath=Não é um caminho absoluto notADirectory=Não é um diretório notAnEmptyDirectory=Não é um diretório vazio automaticallyUpdate=Verifica se há actualizações -automaticallyUpdateDescription=Quando ativado, as informações de novas versões são obtidas automaticamente enquanto o XPipe está em execução. Nenhum atualizador é executado em segundo plano e tens de confirmar explicitamente a instalação de qualquer atualização. +automaticallyUpdateDescription=Quando ativado, as informações de novas versões são obtidas automaticamente enquanto o XPipe está a ser executado após algum tempo. Continua a ter de confirmar explicitamente qualquer instalação de atualização. sendAnonymousErrorReports=Envia relatórios de erro anónimos sendUsageStatistics=Envia estatísticas de utilização anónimas storageDirectory=Diretório de armazenamento @@ -404,7 +404,7 @@ denyTempScriptCreation=Recusa a criação de scripts temporários denyTempScriptCreationDescription=Para realizar algumas das suas funcionalidades, o XPipe cria por vezes scripts de shell temporários num sistema de destino para permitir uma execução fácil de comandos simples. Estes não contêm qualquer informação sensível e são criados apenas para efeitos de implementação.\n\nSe este comportamento for desativado, o XPipe não criará quaisquer ficheiros temporários num sistema remoto. Esta opção é útil em contextos de alta segurança onde cada mudança no sistema de arquivos é monitorada. Se esta opção for desactivada, algumas funcionalidades, por exemplo, ambientes shell e scripts, não funcionarão como pretendido. disableCertutilUse=Desativar a utilização do certutil no Windows useLocalFallbackShell=Utiliza a shell de recurso local -useLocalFallbackShellDescription=Passa a usar outro shell local para lidar com operações locais. Seria o PowerShell no Windows e o bourne shell noutros sistemas.\n\nEsta opção pode ser usada no caso de o shell local padrão normal estar desativado ou quebrado em algum grau. No entanto, alguns recursos podem não funcionar como esperado quando esta opção está ativada.\n\nRequer uma reinicialização para ser aplicada. +useLocalFallbackShellDescription=Passa a usar outro shell local para lidar com operações locais. Seria o PowerShell no Windows e o bourne shell noutros sistemas.\n\nEsta opção pode ser usada no caso de o shell local padrão normal estar desativado ou quebrado em algum grau. No entanto, alguns recursos podem não funcionar como esperado quando esta opção está ativada. disableCertutilUseDescription=Devido a várias falhas e bugs no cmd.exe, são criados scripts de shell temporários com o certutil, utilizando-o para descodificar a entrada base64, uma vez que o cmd.exe quebra em entradas não ASCII. O XPipe também pode usar o PowerShell para isso, mas será mais lento.\n\nIsso desabilita qualquer uso do certutil em sistemas Windows para realizar alguma funcionalidade e volta para o PowerShell. Isso pode agradar alguns AVs, pois alguns deles bloqueiam o uso do certutil. disableTerminalRemotePasswordPreparation=Desativar a preparação da palavra-passe remota do terminal disableTerminalRemotePasswordPreparationDescription=Em situações em que uma ligação shell remota que passa por vários sistemas intermédios deva ser estabelecida no terminal, pode ser necessário preparar quaisquer palavras-passe necessárias num dos sistemas intermédios para permitir o preenchimento automático de quaisquer prompts.\n\nSe não pretender que as palavras-passe sejam transferidas para qualquer sistema intermédio, pode desativar este comportamento. Qualquer senha intermediária necessária será então consultada no próprio terminal quando aberto. @@ -446,7 +446,7 @@ orderAheadOf=Encomenda antes de ... httpServer=Servidor HTTP httpServerConfiguration=Configuração do servidor HTTP apiKey=Chave API -apiKeyDescription=A chave da API para autenticar os pedidos de API do daemon XPipe. Para mais informações sobre como autenticar, vê a documentação geral da API.\n\nRequer um reinício para ser aplicado. +apiKeyDescription=A chave da API para autenticar os pedidos de API do daemon XPipe. Para mais informações sobre como autenticar, vê a documentação geral da API. disableApiAuthentication=Desativar a autenticação da API disableApiAuthenticationDescription=Desactiva todos os métodos de autenticação necessários para que qualquer pedido não autenticado seja tratado.\n\nA autenticação só deve ser desactivada para fins de desenvolvimento.\n\nRequer um reinício para ser aplicado. api=API @@ -519,3 +519,12 @@ terminalLoggingDirectory=Registos de sessões de terminal terminalLoggingDirectoryDescription=Todos os registos são armazenados no diretório de dados do XPipe no teu sistema local. openSessionLogs=Abre os registos da sessão sessionLogging=Registo de sessões +sessionActive=Está a decorrer uma sessão em segundo plano para esta ligação.\n\nPara parar esta sessão manualmente, clica no indicador de estado. +skipValidation=Salta a validação +scriptsIntroTitle=Sobre scripts +scriptsIntroText=Podes executar scripts no shell init, no navegador de ficheiros e a pedido. Podes trazer os teus prompts personalizados, aliases, e outras funcionalidades personalizadas para todos os teus sistemas sem teres de os configurar em sistemas remotos, o sistema de scripts do XPipe trata de tudo por ti. +scriptsIntroBottomTitle=Utilizar scripts +scriptsIntroBottomText=Há uma variedade de exemplos de scripts para começares. Podes clicar no botão de edição dos scripts individuais para veres como são implementados. Os scripts têm de ser activados para serem executados e aparecerem nos menus; para isso, há uma opção em cada script. +scriptsIntroStart=Começa a trabalhar +checkForSecurityUpdates=Verifica se existem actualizações de segurança +checkForSecurityUpdatesDescription=O XPipe pode verificar potenciais actualizações de segurança separadamente das actualizações de funcionalidades normais. Quando esta opção está activada, pelo menos as actualizações de segurança importantes serão recomendadas para instalação, mesmo que a verificação de atualização normal esteja desactivada.\n\nSe desativar esta definição, não será efectuado qualquer pedido de versão externa e não serás notificado sobre quaisquer actualizações de segurança. diff --git a/lang/app/strings/translations_ru.properties b/lang/app/strings/translations_ru.properties index 67338fa8f..3996d8a3a 100644 --- a/lang/app/strings/translations_ru.properties +++ b/lang/app/strings/translations_ru.properties @@ -28,7 +28,7 @@ addService=Сервис ... addScript=Скрипт ... addHost=Удаленный хост ... addShell=Shell Environment ... -addCommand=Shell Command ... +addCommand=Command ... addAutomatically=Поиск в автоматическом режиме ... addOther=Add Other ... addConnection=Добавить соединение @@ -273,7 +273,7 @@ performanceModeDescription=Отключи все визуальные эффек dontAcceptNewHostKeys=Не принимай новые ключи хоста SSH автоматически dontAcceptNewHostKeysDescription=XPipe по умолчанию автоматически принимает хост-ключи от систем, в которых у твоего SSH-клиента нет уже сохраненного известного хост-ключа. Однако если какой-либо известный ключ хоста изменился, он откажется подключаться, пока ты не примешь новый.\n\nОтключение этого поведения позволяет тебе проверять все хост-ключи, даже если изначально конфликта нет. uiScale=Шкала пользовательского интерфейса -uiScaleDescription=Пользовательское значение масштабирования, которое может быть установлено независимо от общесистемного масштаба отображения. Значения указываются в процентах, поэтому, например, значение 150 приведет к масштабированию пользовательского интерфейса на 150%.\n\nДля применения требуется перезагрузка. +uiScaleDescription=Пользовательское значение масштабирования, которое может быть установлено независимо от общесистемного масштаба отображения. Значения указываются в процентах, поэтому, например, значение 150 приведет к масштабированию пользовательского интерфейса на 150%. editorProgram=Программа-редактор editorProgramDescription=Текстовый редактор по умолчанию, который используется при редактировании любого вида текстовых данных. windowOpacity=Непрозрачность окна @@ -293,9 +293,9 @@ workspaceLock=Мастер-пароль enableGitStorage=Включить синхронизацию git sharing=Обмен sync=Синхронизация -enableGitStorageDescription=Когда эта функция включена, XPipe инициализирует git-репозиторий для хранения данных о соединении и фиксирует в нем все изменения. Учти, что это требует установки git и может замедлить операции загрузки и сохранения.\n\nВсе категории, которые должны синхронизироваться, должны быть явно обозначены как общие.\n\nТребуется перезапуск для применения. +enableGitStorageDescription=Когда эта функция включена, XPipe инициализирует git-репозиторий для хранения данных о соединении и фиксирует в нем все изменения. Учти, что это требует установки git и может замедлить операции загрузки и сохранения.\n\nВсе категории, которые должны синхронизироваться, должны быть явно обозначены как общие. storageGitRemote=Удаленный URL-адрес Git -storageGitRemoteDescription=Если установить эту настройку, XPipe будет автоматически вытаскивать любые изменения при загрузке и выталкивать их в удаленный репозиторий при сохранении.\n\nЭто позволяет тебе обмениваться конфигурационными данными между несколькими установками XPipe. Поддерживаются как HTTP, так и SSH-адреса. Учти, что это может замедлить операции загрузки и сохранения.\n\nДля применения требуется перезагрузка. +storageGitRemoteDescription=Если установить эту настройку, XPipe будет автоматически вытаскивать любые изменения при загрузке и выталкивать их в удаленный репозиторий при сохранении.\n\nЭто позволяет тебе обмениваться конфигурационными данными между несколькими установками XPipe. Поддерживаются как HTTP, так и SSH-адреса. Учти, что это может замедлить операции загрузки и сохранения. vault=Vault workspaceLockDescription=Устанавливает пользовательский пароль для шифрования любой конфиденциальной информации, хранящейся в XPipe.\n\nЭто повышает безопасность, так как обеспечивает дополнительный уровень шифрования хранимой тобой конфиденциальной информации. При запуске XPipe тебе будет предложено ввести пароль. useSystemFontDescription=Контролирует, использовать ли системный шрифт или шрифт Roboto, который поставляется в комплекте с XPipe. @@ -346,7 +346,7 @@ notAnAbsolutePath=Не абсолютный путь notADirectory=Не каталог notAnEmptyDirectory=Не пустая директория automaticallyUpdate=Проверьте наличие обновлений -automaticallyUpdateDescription=Если эта функция включена, то информация о новых релизах автоматически подхватывается во время работы XPipe. Никакой программы обновления не запускается в фоновом режиме, и тебе все равно придется явно подтверждать установку любого обновления. +automaticallyUpdateDescription=Если эта функция включена, информация о новых релизах автоматически подхватывается во время работы XPipe через некоторое время. При этом тебе все равно придется явно подтверждать установку любого обновления. sendAnonymousErrorReports=Отправлять анонимные сообщения об ошибках sendUsageStatistics=Отправляйте анонимную статистику использования storageDirectory=Каталог хранилищ @@ -404,7 +404,7 @@ denyTempScriptCreation=Запрет на создание временных с denyTempScriptCreationDescription=Для реализации некоторых своих функций XPipe иногда создает временные shell-скрипты на целевой системе, чтобы обеспечить легкое выполнение простых команд. Они не содержат никакой конфиденциальной информации и создаются просто в целях реализации.\n\nЕсли отключить это поведение, XPipe не будет создавать никаких временных файлов на удаленной системе. Эта опция полезна в условиях повышенной безопасности, когда отслеживается каждое изменение файловой системы. Если эта опция отключена, некоторые функции, например, окружения оболочки и скрипты, не будут работать так, как задумано. disableCertutilUse=Отключите использование certutil в Windows useLocalFallbackShell=Использовать локальную резервную оболочку -useLocalFallbackShellDescription=Переключись на использование другой локальной оболочки для выполнения локальных операций. Это может быть PowerShell в Windows и bourne shell в других системах.\n\nЭту опцию можно использовать в том случае, если обычная локальная оболочка по умолчанию отключена или в какой-то степени сломана. Однако при включении этой опции некоторые функции могут работать не так, как ожидалось.\n\nДля применения требуется перезагрузка. +useLocalFallbackShellDescription=Переключись на использование другой локальной оболочки для выполнения локальных операций. Это может быть PowerShell в Windows и bourne shell в других системах.\n\nЭту опцию можно использовать в том случае, если обычная локальная оболочка по умолчанию отключена или в какой-то степени сломана. Однако при включении этой опции некоторые функции могут работать не так, как ожидалось. disableCertutilUseDescription=Из-за ряда недостатков и ошибок в cmd.exe временные shell-скрипты создаются с помощью certutil, используя его для декодирования ввода base64, так как cmd.exe ломается при вводе не ASCII. XPipe также может использовать для этого PowerShell, но это будет медленнее.\n\nТаким образом, на Windows-системах отменяется использование certutil для реализации некоторой функциональности, и вместо него используется PowerShell. Это может порадовать некоторые антивирусы, так как некоторые из них блокируют использование certutil. disableTerminalRemotePasswordPreparation=Отключить подготовку удаленного пароля терминала disableTerminalRemotePasswordPreparationDescription=В ситуациях, когда в терминале необходимо установить удаленное shell-соединение, проходящее через несколько промежуточных систем, может возникнуть необходимость подготовить все необходимые пароли на одной из промежуточных систем, чтобы обеспечить автоматическое заполнение любых подсказок.\n\nЕсли ты не хочешь, чтобы пароли когда-либо передавались в какую-либо промежуточную систему, ты можешь отключить это поведение. Тогда любой требуемый промежуточный пароль будет запрашиваться в самом терминале при его открытии. @@ -446,7 +446,7 @@ orderAheadOf=Заказать заранее ... httpServer=HTTP-сервер httpServerConfiguration=Конфигурация HTTP-сервера apiKey=Ключ API -apiKeyDescription=API-ключ для аутентификации API-запросов демона XPipe. Подробнее о том, как проходить аутентификацию, читай в общей документации по API.\n\nТребуется перезагрузка для применения. +apiKeyDescription=API-ключ для аутентификации API-запросов демона XPipe. Подробнее о том, как проходить аутентификацию, читай в общей документации по API. disableApiAuthentication=Отключить аутентификацию API disableApiAuthenticationDescription=Отключает все необходимые методы аутентификации, так что любой неаутентифицированный запрос будет обработан.\n\nАутентификацию следует отключать только в целях разработки.\n\nТребуется перезагрузка для применения. api=API @@ -519,3 +519,12 @@ terminalLoggingDirectory=Журналы терминальных сессий terminalLoggingDirectoryDescription=Все журналы хранятся в каталоге данных XPipe в твоей локальной системе. openSessionLogs=Открытые журналы сеансов sessionLogging=Ведение журнала сеансов +sessionActive=Для этого соединения запущена фоновая сессия.\n\nЧтобы остановить эту сессию вручную, щелкни по индикатору состояния. +skipValidation=Проверка пропуска +scriptsIntroTitle=О скриптах +scriptsIntroText=Ты можешь запускать скрипты в shell init, в браузере файлов и по требованию. Ты можешь привнести во все свои системы пользовательские подсказки, псевдонимы и другие пользовательские функции, не настраивая их на удаленных системах самостоятельно - система скриптов XPipe сделает все за тебя. +scriptsIntroBottomTitle=Использование скриптов +scriptsIntroBottomText=Для начала есть множество примеров скриптов. Ты можешь нажать на кнопку редактирования отдельных скриптов, чтобы посмотреть, как они реализованы. Скрипты должны быть включены, чтобы запускаться и отображаться в меню, для этого в каждом скрипте есть тумблер. +scriptsIntroStart=Приступай к работе +checkForSecurityUpdates=Проверьте наличие обновлений безопасности +checkForSecurityUpdatesDescription=XPipe может проверять потенциальные обновления безопасности отдельно от обычных обновлений функций. Когда эта функция включена, по крайней мере важные обновления безопасности будут рекомендованы к установке, даже если обычная проверка обновлений отключена.\n\nОтключение этой настройки приведет к тому, что внешний запрос версии не будет выполняться, и ты не будешь получать уведомления о каких-либо обновлениях безопасности. diff --git a/lang/app/strings/translations_tr.properties b/lang/app/strings/translations_tr.properties index 45e1e471f..73ac29eaf 100644 --- a/lang/app/strings/translations_tr.properties +++ b/lang/app/strings/translations_tr.properties @@ -28,7 +28,7 @@ addService=Hizmet ... addScript=Senaryo ... addHost=Uzak Ana Bilgisayar ... addShell=Shell Çevre ... -addCommand=Kabuk Komutu ... +addCommand=Komut ... addAutomatically=Otomatik Olarak Ara ... addOther=Diğerlerini Ekle ... addConnection=Bağlantı Ekle @@ -273,7 +273,7 @@ performanceModeDescription=Uygulama performansını artırmak için gerekli olma dontAcceptNewHostKeys=Yeni SSH ana bilgisayar anahtarlarını otomatik olarak kabul etme dontAcceptNewHostKeysDescription=XPipe, SSH istemcinizin bilinen bir ana bilgisayar anahtarı kaydetmediği sistemlerden ana bilgisayar anahtarlarını varsayılan olarak otomatik olarak kabul edecektir. Ancak bilinen herhangi bir ana bilgisayar anahtarı değişmişse, yenisini kabul etmediğiniz sürece bağlanmayı reddedecektir.\n\nBu davranışın devre dışı bırakılması, başlangıçta herhangi bir çakışma olmasa bile tüm ana bilgisayar anahtarlarını kontrol etmenizi sağlar. uiScale=UI Ölçeği -uiScaleDescription=Sistem genelindeki ekran ölçeğinizden bağımsız olarak ayarlanabilen özel bir ölçeklendirme değeri. Değerler yüzde cinsindendir, bu nedenle örneğin 150 değeri %150'lik bir UI ölçeği ile sonuçlanacaktır.\n\nUygulamak için yeniden başlatma gerekir. +uiScaleDescription=Sistem genelindeki ekran ölçeğinizden bağımsız olarak ayarlanabilen özel bir ölçeklendirme değeri. Değerler yüzde cinsindendir, bu nedenle örneğin 150 değeri %150'lik bir UI ölçeği ile sonuçlanacaktır. editorProgram=Editör Programı editorProgramDescription=Her türlü metin verisini düzenlerken kullanılacak varsayılan metin düzenleyicisi. windowOpacity=Pencere opaklığı @@ -293,9 +293,9 @@ workspaceLock=Ana parola enableGitStorage=Git senkronizasyonunu etkinleştir sharing=Paylaşım sync=Senkronizasyon -enableGitStorageDescription=Etkinleştirildiğinde, XPipe bağlantı veri deposu için bir git deposu başlatır ve değişiklikleri bu depoya işler. Bunun için git'in yüklü olması gerektiğini ve yükleme ve kaydetme işlemlerini yavaşlatabileceğini unutmayın.\n\nSenkronize edilmesi gereken tüm kategoriler açıkça paylaşılan olarak belirlenmelidir.\n\nUygulamak için yeniden başlatma gerekir. +enableGitStorageDescription=Etkinleştirildiğinde, XPipe bağlantı veri depolaması için bir git deposu başlatır ve tüm değişiklikleri bu depoya işler. Bunun için git'in yüklü olması gerektiğini ve yükleme ve kaydetme işlemlerini yavaşlatabileceğini unutmayın.\n\nSenkronize edilmesi gereken tüm kategoriler açıkça paylaşılan olarak belirlenmelidir. storageGitRemote=Git uzak URL'si -storageGitRemoteDescription=Ayarlandığında, XPipe yükleme sırasında tüm değişiklikleri otomatik olarak çekecek ve kaydetme sırasında tüm değişiklikleri uzak depoya itecektir.\n\nBu, yapılandırma verilerinizi birden fazla XPipe kurulumu arasında paylaşmanıza olanak tanır. Hem HTTP hem de SSH URL'leri desteklenir. Bunun yükleme ve kaydetme işlemlerini yavaşlatabileceğini unutmayın.\n\nUygulamak için yeniden başlatma gerekir. +storageGitRemoteDescription=Ayarlandığında, XPipe yükleme sırasında tüm değişiklikleri otomatik olarak çekecek ve kaydetme sırasında tüm değişiklikleri uzak depoya itecektir.\n\nBu, yapılandırma verilerinizi birden fazla XPipe kurulumu arasında paylaşmanıza olanak tanır. Hem HTTP hem de SSH URL'leri desteklenir. Bunun yükleme ve kaydetme işlemlerini yavaşlatabileceğini unutmayın. vault=Kasa workspaceLockDescription=XPipe'da saklanan hassas bilgileri şifrelemek için özel bir parola belirler.\n\nBu, depolanan hassas bilgileriniz için ek bir şifreleme katmanı sağladığından daha fazla güvenlikle sonuçlanır. Daha sonra XPipe başlatıldığında şifreyi girmeniz istenecektir. useSystemFontDescription=Sistem fontunuzun mu yoksa XPipe ile birlikte gelen Roboto fontunun mu kullanılacağını kontrol eder. @@ -347,7 +347,7 @@ notAnAbsolutePath=Mutlak bir yol değil notADirectory=Dizin değil notAnEmptyDirectory=Boş bir dizin değil automaticallyUpdate=Güncellemeleri kontrol edin -automaticallyUpdateDescription=Etkinleştirildiğinde, XPipe çalışırken yeni sürüm bilgileri otomatik olarak alınır. Arka planda hiçbir güncelleyici çalışmaz ve yine de herhangi bir güncelleme yüklemesini açıkça onaylamanız gerekir. +automaticallyUpdateDescription=Etkinleştirildiğinde, XPipe çalışırken yeni sürüm bilgileri bir süre sonra otomatik olarak getirilir. Yine de herhangi bir güncelleme yüklemesini açıkça onaylamanız gerekir. sendAnonymousErrorReports=Anonim hata raporları gönderin sendUsageStatistics=Anonim kullanım istatistikleri gönderin storageDirectory=Depolama dizini @@ -405,7 +405,7 @@ denyTempScriptCreation=Geçici komut dosyası oluşturmayı reddetme denyTempScriptCreationDescription=XPipe, bazı işlevlerini gerçekleştirmek için bazen basit komutların kolayca yürütülmesini sağlamak üzere hedef sistemde geçici kabuk komut dosyaları oluşturur. Bunlar herhangi bir hassas bilgi içermez ve sadece uygulama amacıyla oluşturulur.\n\nBu davranış devre dışı bırakılırsa, XPipe uzak bir sistemde herhangi bir geçici dosya oluşturmaz. Bu seçenek, her dosya sistemi değişikliğinin izlendiği yüksek güvenlikli bağlamlarda kullanışlıdır. Bu devre dışı bırakılırsa, kabuk ortamları ve komut dosyaları gibi bazı işlevler amaçlandığı gibi çalışmayacaktır. disableCertutilUse=Windows'ta certutil kullanımını devre dışı bırakma useLocalFallbackShell=Yerel yedek kabuk kullan -useLocalFallbackShellDescription=Yerel işlemleri gerçekleştirmek için başka bir yerel kabuk kullanmaya geçin. Bu, Windows'ta PowerShell ve diğer sistemlerde bourne shell olabilir.\n\nBu seçenek, normal yerel varsayılan kabuğun devre dışı bırakılması veya bir dereceye kadar bozulması durumunda kullanılabilir. Bu seçenek etkinleştirildiğinde bazı özellikler beklendiği gibi çalışmayabilir.\n\nUygulamak için yeniden başlatma gerekir. +useLocalFallbackShellDescription=Yerel işlemleri gerçekleştirmek için başka bir yerel kabuk kullanmaya geçin. Bu, Windows'ta PowerShell ve diğer sistemlerde bourne shell olabilir.\n\nBu seçenek, normal yerel varsayılan kabuğun devre dışı bırakılması veya bir dereceye kadar bozulması durumunda kullanılabilir. Bu seçenek etkinleştirildiğinde bazı özellikler beklendiği gibi çalışmayabilir. disableCertutilUseDescription=Cmd.exe'deki çeşitli eksiklikler ve hatalar nedeniyle, geçici kabuk betikleri certutil ile oluşturulur ve cmd.exe ASCII olmayan girdilerde bozulduğu için base64 girdisinin kodunu çözmek için kullanılır. XPipe bunun için PowerShell de kullanabilir ancak bu daha yavaş olacaktır.\n\nBu, bazı işlevleri gerçekleştirmek ve bunun yerine PowerShell'e geri dönmek için Windows sistemlerinde herhangi bir certutil kullanımını devre dışı bırakır. Bu, bazıları certutil kullanımını engellediği için bazı AV'leri memnun edebilir. disableTerminalRemotePasswordPreparation=Terminal uzaktan parola hazırlamayı devre dışı bırakma disableTerminalRemotePasswordPreparationDescription=Terminalde birden fazla ara sistemden geçen bir uzak kabuk bağlantısının kurulması gereken durumlarda, herhangi bir sorgunun otomatik olarak doldurulmasına izin vermek için ara sistemlerden birinde gerekli parolaların hazırlanması gerekebilir.\n\nParolaların herhangi bir ara sisteme aktarılmasını istemiyorsanız, bu davranışı devre dışı bırakabilirsiniz. Gerekli herhangi bir ara parola daha sonra açıldığında terminalin kendisinde sorgulanacaktır. @@ -447,7 +447,7 @@ orderAheadOf=Önceden sipariş verin ... httpServer=HTTP sunucusu httpServerConfiguration=HTTP sunucu yapılandırması apiKey=API anahtarı -apiKeyDescription=XPipe daemon API isteklerinin kimliğini doğrulamak için API anahtarı. Kimlik doğrulamanın nasıl yapılacağı hakkında daha fazla bilgi için genel API belgelerine bakın.\n\nUygulamak için yeniden başlatma gerekir. +apiKeyDescription=XPipe daemon API isteklerinin kimliğini doğrulamak için API anahtarı. Kimlik doğrulamanın nasıl yapılacağı hakkında daha fazla bilgi için genel API belgelerine bakın. disableApiAuthentication=API kimlik doğrulamasını devre dışı bırakma disableApiAuthenticationDescription=Gerekli tüm kimlik doğrulama yöntemlerini devre dışı bırakır, böylece kimliği doğrulanmamış herhangi bir istek işlenir.\n\nKimlik doğrulama yalnızca geliştirme amacıyla devre dışı bırakılmalıdır.\n\nUygulamak için yeniden başlatma gerekir. api=API @@ -520,3 +520,12 @@ terminalLoggingDirectory=Terminal oturum günlükleri terminalLoggingDirectoryDescription=Tüm günlükler yerel sisteminizdeki XPipe veri dizininde saklanır. openSessionLogs=Oturum günlüklerini açın sessionLogging=Oturum kaydı +sessionActive=Bu bağlantı için bir arka plan oturumu çalışıyor.\n\nBu oturumu manuel olarak durdurmak için durum göstergesine tıklayın. +skipValidation=Doğrulamayı atla +scriptsIntroTitle=Senaryolar hakkında +scriptsIntroText=Komut dosyalarını kabuk başlangıcında, dosya tarayıcısında ve isteğe bağlı olarak çalıştırabilirsiniz. Özel istemlerinizi, takma adlarınızı ve diğer özel işlevlerinizi uzak sistemlerde kendiniz ayarlamak zorunda kalmadan tüm sistemlerinize getirebilirsiniz, XPipe'ın komut dosyası sistemi sizin için her şeyi halledecektir. +scriptsIntroBottomTitle=Komut dosyalarını kullanma +scriptsIntroBottomText=Başlangıç için çeşitli örnek komut dosyaları vardır. Nasıl uygulandıklarını görmek için tek tek komut dosyalarının düzenleme düğmesine tıklayabilirsiniz. Komut dosyalarının çalışması ve menülerde görünmesi için etkinleştirilmesi gerekir, bunun için her komut dosyasında bir geçiş vardır. +scriptsIntroStart=Başlayın +checkForSecurityUpdates=Güvenlik güncellemelerini kontrol edin +checkForSecurityUpdatesDescription=XPipe olası güvenlik güncellemelerini normal özellik güncellemelerinden ayrı olarak kontrol edebilir. Bu etkinleştirildiğinde, normal güncelleme denetimi devre dışı bırakılsa bile en azından önemli güvenlik güncellemeleri yükleme için önerilecektir.\n\nBu ayarın devre dışı bırakılması, harici sürüm talebinin gerçekleştirilmemesine neden olur ve herhangi bir güvenlik güncellemesi hakkında bilgilendirilmezsiniz. diff --git a/lang/app/strings/translations_zh.properties b/lang/app/strings/translations_zh.properties index aacd7a1d0..1f2797a50 100644 --- a/lang/app/strings/translations_zh.properties +++ b/lang/app/strings/translations_zh.properties @@ -28,7 +28,7 @@ addService=服务 ... addScript=脚本 ... addHost=远程主机 ... addShell=外壳环境 ... -addCommand=Shell 命令 ... +addCommand=命令 ... addAutomatically=自动搜索 ... addOther=添加其他 ... addConnection=添加连接 @@ -273,7 +273,7 @@ performanceModeDescription=禁用所有不需要的视觉效果,以提高应 dontAcceptNewHostKeys=不自动接受新的 SSH 主机密钥 dontAcceptNewHostKeysDescription=如果 SSH 客户端没有保存已知主机密钥,XPipe 默认会自动接受来自系统的主机密钥。但是,如果任何已知主机密钥发生变化,除非您接受新密钥,否则它将拒绝连接。\n\n禁用该行为可让您检查所有主机密钥,即使最初没有冲突。 uiScale=用户界面比例 -uiScaleDescription=自定义缩放值,可独立于系统范围内的显示比例进行设置。数值以百分比为单位,例如,数值为 150 时,用户界面的缩放比例为 150%。\n\n需要重新启动才能应用。 +uiScaleDescription=自定义缩放值,可独立于系统范围内的显示比例进行设置。数值以百分比为单位,例如,数值为 150 时,用户界面的缩放比例为 150%。 editorProgram=编辑程序 editorProgramDescription=编辑任何文本数据时使用的默认文本编辑器。 windowOpacity=窗口不透明度 @@ -293,9 +293,9 @@ workspaceLock=主密码 enableGitStorage=启用 git 同步 sharing=共享 sync=同步 -enableGitStorageDescription=启用后,XPipe 将为连接数据存储初始化一个 git 仓库,并将任何更改提交至该仓库。请注意,这需要安装 git,并且可能会降低加载和保存操作的速度。\n\n任何需要同步的类别都必须明确指定为共享类别。\n\n需要重新启动才能应用。 +enableGitStorageDescription=启用后,XPipe 将为连接数据存储初始化一个 git 仓库,并将任何更改提交至该仓库。请注意,这需要安装 git,并且可能会降低加载和保存操作的速度。\n\n任何需要同步的类别都必须明确指定为共享类别。 storageGitRemote=Git 远程 URL -storageGitRemoteDescription=设置后,XPipe 将在加载时自动提取任何更改,并在保存时将任何更改推送到远程资源库。\n\n这样,您就可以在多个 XPipe 安装之间共享配置数据。支持 HTTP 和 SSH URL。请注意,这可能会降低加载和保存操作的速度。\n\n需要重新启动才能应用。 +storageGitRemoteDescription=设置后,XPipe 将在加载时自动提取任何更改,并在保存时将任何更改推送到远程资源库。\n\n这样,您就可以在多个 XPipe 安装之间共享配置数据。支持 HTTP 和 SSH URL。请注意,这可能会降低加载和保存操作的速度。 vault=拱顶 workspaceLockDescription=设置自定义密码,对存储在 XPipe 中的任何敏感信息进行加密。\n\n这将提高安全性,因为它为您存储的敏感信息提供了额外的加密层。当 XPipe 启动时,系统会提示您输入密码。 useSystemFontDescription=控制使用系统字体还是 XPipe 附带的 Roboto 字体。 @@ -346,7 +346,7 @@ notAnAbsolutePath=非绝对路径 notADirectory=不是目录 notAnEmptyDirectory=不是空目录 automaticallyUpdate=检查更新 -automaticallyUpdateDescription=启用后,XPipe 运行时会自动获取新版本信息。没有更新程序在后台运行,您仍需明确确认任何更新安装。 +automaticallyUpdateDescription=启用后,XPipe 会在运行一段时间后自动获取新版本信息。您仍需明确确认任何更新安装。 sendAnonymousErrorReports=发送匿名错误报告 sendUsageStatistics=发送匿名使用统计数据 storageDirectory=存储目录 @@ -404,7 +404,7 @@ denyTempScriptCreation=拒绝创建临时脚本 denyTempScriptCreationDescription=为了实现某些功能,XPipe 有时会在目标系统上创建临时 shell 脚本,以便轻松执行简单命令。这些脚本不包含任何敏感信息,只是为了实现目的而创建的。\n\n如果禁用该行为,XPipe 将不会在远程系统上创建任何临时文件。该选项在高度安全的情况下非常有用,因为在这种情况下,文件系统的每次更改都会受到监控。如果禁用,某些功能(如 shell 环境和脚本)将无法正常工作。 disableCertutilUse=禁止在 Windows 上使用 certutil useLocalFallbackShell=使用本地备用 shell -useLocalFallbackShellDescription=改用其他本地 shell 来处理本地操作。在 Windows 系统上是 PowerShell,在其他系统上是 bourne shell。\n\n如果正常的本地默认 shell 在某种程度上被禁用或损坏,则可以使用此选项。启用该选项后,某些功能可能无法正常工作。\n\n需要重新启动才能应用。 +useLocalFallbackShellDescription=改用其他本地 shell 来处理本地操作。在 Windows 系统上是 PowerShell,在其他系统上是 bourne shell。\n\n如果正常的本地默认 shell 在某种程度上被禁用或损坏,则可以使用此选项。启用该选项后,某些功能可能无法正常工作。 disableCertutilUseDescription=由于 cmd.exe 中存在一些缺陷和错误,因此使用 certutil 创建临时 shell 脚本,用它来解码 base64 输入,因为 cmd.exe 会在非 ASCII 输入时中断。XPipe 也可以使用 PowerShell 来实现这一功能,但速度会慢一些。\n\n这将禁止在 Windows 系统上使用 certutil 来实现某些功能,转而使用 PowerShell。这可能会让一些反病毒软件感到满意,因为有些反病毒软件会阻止使用 certutil。 disableTerminalRemotePasswordPreparation=禁用终端远程密码准备 disableTerminalRemotePasswordPreparationDescription=如果要在终端中建立一个经过多个中间系统的远程 shell 连接,可能需要在其中一个中间系统上准备所需的密码,以便自动填写任何提示。\n\n如果不想将密码传送到任何中间系统,可以禁用此行为。任何所需的中间系统密码都将在终端打开时进行查询。 @@ -446,7 +446,7 @@ orderAheadOf=提前订购... httpServer=HTTP 服务器 httpServerConfiguration=HTTP 服务器配置 apiKey=应用程序接口密钥 -apiKeyDescription=用于验证 XPipe 守护进程 API 请求的 API 密钥。有关如何验证的更多信息,请参阅一般 API 文档。\n\n需要重新启动才能应用。 +apiKeyDescription=用于验证 XPipe 守护进程 API 请求的 API 密钥。有关如何验证的更多信息,请参阅一般 API 文档。 disableApiAuthentication=禁用 API 身份验证 disableApiAuthenticationDescription=禁用所有必要的身份验证方法,以便处理任何未经身份验证的请求。\n\n只有出于开发目的才可禁用身份验证。\n\n需要重新启动才能应用。 api=应用程序接口 @@ -519,3 +519,12 @@ terminalLoggingDirectory=终端会话日志 terminalLoggingDirectoryDescription=所有日志都存储在本地系统的 XPipe 数据目录中。 openSessionLogs=打开会话日志 sessionLogging=会话记录 +sessionActive=此连接正在运行后台会话。\n\n要手动停止此会话,请单击状态指示器。 +skipValidation=跳过验证 +scriptsIntroTitle=关于脚本 +scriptsIntroText=您可以在 shell init、文件浏览器和按需运行脚本。您可以将自定义提示、别名和其他自定义功能带到您的所有系统中,而无需在远程系统中自行设置,XPipe 的脚本系统将为您处理一切。 +scriptsIntroBottomTitle=使用脚本 +scriptsIntroBottomText=这里有各种示例脚本供您开始使用。你可以点击各个脚本的编辑按钮,查看它们是如何实现的。脚本必须启用才能运行并显示在菜单中,每个脚本上都有一个切换按钮。 +scriptsIntroStart=开始使用 +checkForSecurityUpdates=检查安全更新 +checkForSecurityUpdatesDescription=XPipe 可与正常功能更新分开检查潜在的安全更新。启用此功能后,即使正常的更新检查被禁用,至少也会推荐安装重要的安全更新。\n\n禁用此设置后,将不会执行外部版本请求,也不会通知您任何安全更新。 diff --git a/lang/base/strings/translations_da.properties b/lang/base/strings/translations_da.properties index 9915359cc..3350129b5 100644 --- a/lang/base/strings/translations_da.properties +++ b/lang/base/strings/translations_da.properties @@ -5,6 +5,7 @@ launch=Start start=Start stop=Stop pause=Pause +restart=Genstart #custom refresh=Genindlæs options=Muligheder @@ -185,3 +186,4 @@ untarHere=Untar her untarDirectory=Untar to $DIR$ unzipDirectory=Pak ud til $DIR$ unzipHere=Pak ud her +requiresRestart=Kræver en genstart for at kunne anvendes. diff --git a/lang/base/strings/translations_de.properties b/lang/base/strings/translations_de.properties index d8da3a141..f6139f1d7 100644 --- a/lang/base/strings/translations_de.properties +++ b/lang/base/strings/translations_de.properties @@ -5,6 +5,7 @@ launch=Starten start=Start stop=Stopp pause=Pause +restart=Neustart refresh=Aktualisieren options=Optionen newFile=Neue Datei @@ -176,3 +177,4 @@ untarHere=Untar hier untarDirectory=Untar zu $DIR$ unzipDirectory=Entpacken nach $DIR$ unzipHere=Hier entpacken +requiresRestart=Erfordert einen Neustart zur Anwendung. diff --git a/lang/base/strings/translations_en.properties b/lang/base/strings/translations_en.properties index 89742360b..934247690 100644 --- a/lang/base/strings/translations_en.properties +++ b/lang/base/strings/translations_en.properties @@ -5,6 +5,7 @@ launch=Launch start=Start stop=Stop pause=Pause +restart=Restart refresh=Refresh options=Options newFile=New file @@ -68,9 +69,9 @@ terminalOnly=Terminal both=Both shouldElevate=Should elevate shouldElevateDescription=Whether to run this script with elevated permissions -script.displayName=Script +script.displayName=Script snippet script.displayDescription=Create a reusable script -scriptGroup.displayName=Script Group +scriptGroup.displayName=Script group scriptGroup.displayDescription=Create a group for scripts scriptGroup=Group scriptGroupDescription=The group to assign this script to @@ -175,4 +176,5 @@ untarHere=Untar here untarDirectory=Untar to $DIR$ unzipDirectory=Unzip to $DIR$ unzipHere=Unzip here +requiresRestart=Requires a restart to apply. diff --git a/lang/base/strings/translations_es.properties b/lang/base/strings/translations_es.properties index 2e548bffc..f14a60d88 100644 --- a/lang/base/strings/translations_es.properties +++ b/lang/base/strings/translations_es.properties @@ -5,6 +5,7 @@ launch=Inicia start=Inicia stop=Para pause=Pausa +restart=Reinicia refresh=Actualizar options=Opciones newFile=Nuevo archivo @@ -174,3 +175,4 @@ untarHere=Untar aquí untarDirectory=Untar a $DIR$ unzipDirectory=Descomprimir a $DIR$ unzipHere=Descomprimir aquí +requiresRestart=Requiere un reinicio para aplicarse. diff --git a/lang/base/strings/translations_fr.properties b/lang/base/strings/translations_fr.properties index 74e2cabc6..57d1eee38 100644 --- a/lang/base/strings/translations_fr.properties +++ b/lang/base/strings/translations_fr.properties @@ -5,6 +5,7 @@ launch=Lancer start=Démarrer stop=Arrêter pause=Pause +restart=Redémarrer refresh=Rafraîchir options=Options newFile=Nouveau fichier @@ -174,3 +175,4 @@ untarHere=Untar ici untarDirectory=Untar to $DIR$ unzipDirectory=Décompresser pour $DIR$ unzipHere=Décompresse ici +requiresRestart=Nécessite un redémarrage pour s'appliquer. diff --git a/lang/base/strings/translations_it.properties b/lang/base/strings/translations_it.properties index be63f9329..473cf3e28 100644 --- a/lang/base/strings/translations_it.properties +++ b/lang/base/strings/translations_it.properties @@ -5,6 +5,7 @@ launch=Lancio start=Iniziare stop=Fermati pause=Pausa +restart=Riavvio refresh=Aggiornare options=Opzioni newFile=Nuovo file @@ -174,3 +175,4 @@ untarHere=Non scrivere qui untarDirectory=Untar a $DIR$ unzipDirectory=Decomprimere in $DIR$ unzipHere=Decomprimi qui +requiresRestart=Richiede un riavvio per essere applicato. diff --git a/lang/base/strings/translations_ja.properties b/lang/base/strings/translations_ja.properties index 2e707db11..d7a0be9a5 100644 --- a/lang/base/strings/translations_ja.properties +++ b/lang/base/strings/translations_ja.properties @@ -5,6 +5,7 @@ launch=起動 start=スタート stop=停止する pause=一時停止 +restart=再起動 refresh=リフレッシュする options=オプション newFile=新規ファイル @@ -174,3 +175,4 @@ untarHere=ここをクリック untarDirectory=未対応$DIR$ unzipDirectory=解凍先$DIR$ unzipHere=ここで解凍する +requiresRestart=適用には再起動が必要である。 diff --git a/lang/base/strings/translations_nl.properties b/lang/base/strings/translations_nl.properties index 32ff04bbe..c131bc643 100644 --- a/lang/base/strings/translations_nl.properties +++ b/lang/base/strings/translations_nl.properties @@ -5,6 +5,7 @@ launch=Start start=Start stop=Stop pause=Pauze +restart=Herstart refresh=Vernieuwen options=Opties newFile=Nieuw bestand @@ -174,3 +175,4 @@ untarHere=Untar hier untarDirectory=Naar $DIR$ unzipDirectory=Uitpakken naar $DIR$ unzipHere=Hier uitpakken +requiresRestart=Vereist een herstart om toe te passen. diff --git a/lang/base/strings/translations_pt.properties b/lang/base/strings/translations_pt.properties index ee7c33b4d..69f3e4918 100644 --- a/lang/base/strings/translations_pt.properties +++ b/lang/base/strings/translations_pt.properties @@ -5,6 +5,7 @@ launch=Lança start=Começa stop=Pára pause=Pausa +restart=Reinicia refresh=Actualiza options=Opções newFile=Novo ficheiro @@ -174,3 +175,4 @@ untarHere=Untar aqui untarDirectory=Untar para $DIR$ unzipDirectory=Descompacta para $DIR$ unzipHere=Descompacta aqui +requiresRestart=Requer um reinício para ser aplicado. diff --git a/lang/base/strings/translations_ru.properties b/lang/base/strings/translations_ru.properties index 498e81166..a6b217c6f 100644 --- a/lang/base/strings/translations_ru.properties +++ b/lang/base/strings/translations_ru.properties @@ -5,6 +5,7 @@ launch=Запустите start=Начни stop=Стоп pause=Пауза +restart=Перезапустите refresh=Обновить options=Опции newFile=Новый файл @@ -174,3 +175,4 @@ untarHere=Унтар здесь untarDirectory=Унтар к $DIR$ unzipDirectory=Разархивировать в $DIR$ unzipHere=Распакуйте здесь +requiresRestart=Требует перезапуска для применения. diff --git a/lang/base/strings/translations_tr.properties b/lang/base/strings/translations_tr.properties index fac021639..1fbb46403 100644 --- a/lang/base/strings/translations_tr.properties +++ b/lang/base/strings/translations_tr.properties @@ -5,6 +5,7 @@ launch=Fırlatma start=Başlangıç stop=Dur pause=Duraklat +restart=Yeniden Başlat refresh=Yenile options=Seçenekler newFile=Yeni dosya @@ -70,7 +71,7 @@ shouldElevate=Yükseltmeli shouldElevateDescription=Bu betiğin yükseltilmiş izinlerle çalıştırılıp çalıştırılmayacağı script.displayName=Senaryo script.displayDescription=Yeniden kullanılabilir bir komut dosyası oluşturma -scriptGroup.displayName=Senaryo Grubu +scriptGroup.displayName=Senaryo grubu scriptGroup.displayDescription=Komut dosyaları için bir grup oluşturma scriptGroup=Grup scriptGroupDescription=Bu komut dosyasının atanacağı grup @@ -174,3 +175,4 @@ untarHere=Untar burada untarDirectory=Untar'a $DIR$ unzipDirectory=Açmak için $DIR$ unzipHere=Buradan açın +requiresRestart=Uygulamak için yeniden başlatma gerekir. diff --git a/lang/base/strings/translations_zh.properties b/lang/base/strings/translations_zh.properties index 407289b05..28909226a 100644 --- a/lang/base/strings/translations_zh.properties +++ b/lang/base/strings/translations_zh.properties @@ -5,6 +5,7 @@ launch=启动 start=开始 stop=停止 pause=暂停 +restart=重新启动 refresh=刷新 options=选项 newFile=新文件 @@ -174,3 +175,4 @@ untarHere=点击此处 untarDirectory=到$DIR$ unzipDirectory=解压缩为$DIR$ unzipHere=在此解压缩 +requiresRestart=需要重新启动才能应用。 diff --git a/lang/proc/strings/translations_da.properties b/lang/proc/strings/translations_da.properties index 94323d370..cf17f90d2 100644 --- a/lang/proc/strings/translations_da.properties +++ b/lang/proc/strings/translations_da.properties @@ -79,8 +79,8 @@ sshDynamicTunnel.displayName=Dynamisk SSH-tunnel sshDynamicTunnel.displayDescription=Etablere en SOCKS-proxy via en SSH-forbindelse shellEnvironmentGroup.displayName=Shell-miljøer shellEnvironmentGroup.displayDescription=Shell-miljøer -shellEnvironment.displayName=Brugerdefineret shell-miljø -shellEnvironment.displayDescription=Opret et tilpasset shell init-miljø +shellEnvironment.displayName=Shell-miljø +shellEnvironment.displayDescription=Opret et tilpasset shell-startmiljø shellEnvironment.informationFormat=$TYPE$ miljø shellEnvironment.elevatedInformationFormat=$ELEVATION$ $TYPE$ miljø environmentConnectionDescription=Basisforbindelsen til at skabe et miljø for @@ -117,7 +117,7 @@ sshLocalTunnel.hostDescription=Systemet til at åbne tunnelen til sshLocalTunnel.bindingDescription=Hvilke adresser tunnelen skal bindes til sshLocalTunnel.localAddressDescription=Den lokale adresse, der skal bindes sshLocalTunnel.remoteAddressDescription=Fjernadressen, der skal bindes -cmd.displayName=Brugerdefineret terminalkommando +cmd.displayName=Terminal-kommando cmd.displayDescription=Kør en brugerdefineret kommando på et system i din terminal k8sPod.displayName=Kubernetes Pod k8sPod.displayDescription=Opret forbindelse til en pod og dens containere via kubectl @@ -187,13 +187,13 @@ podDescription=Den pod, som containeren er placeret på k8sClusterHostDescription=Den vært, hvorigennem klyngen skal tilgås. Skal have kubectl installeret og konfigureret for at kunne få adgang til klyngen. script=Init-script connection=Forbindelse -shellCommand.displayName=Brugerdefineret kommando til åbning af shell +shellCommand.displayName=Brugerdefineret shell-kommando shellCommand.displayDescription=Åbn en standard shell via en brugerdefineret kommando -ssh.displayName=Simpel SSH-forbindelse +ssh.displayName=Enkel SSH-forbindelse ssh.displayDescription=Opret forbindelse via en SSH-kommandolinjeklient sshConfig.displayName=SSH-konfigurationsfil sshConfig.displayDescription=Opret forbindelse til værter defineret i en SSH-konfigurationsfil -sshConfigHost.displayName=SSH Config File Host +sshConfigHost.displayName=SSH-konfigurationsfil host sshConfigHost.displayDescription=Opret forbindelse til en vært, der er defineret i en SSH-konfigurationsfil sshConfigHost.password=Adgangskode #custom @@ -214,7 +214,7 @@ commandShellTypeDescription=Den shell, der skal bruges til denne kommando ssh.passwordDescription=Adgangskoden, der skal bruges ved autentificering keyAuthentication=Nøglebaseret autentificering keyAuthenticationDescription=Den autentificeringsmetode, der skal bruges, hvis nøglebaseret autentificering er påkrævet. -dontInteractWithSystem=Må ikke interagere med systemet (Pro) +dontInteractWithSystem=Interagerer ikke med systemet dontInteractWithSystemDescription=Forsøg ikke at identificere shell-typen, hvilket er nødvendigt for begrænsede indlejrede systemer eller IOT-enheder sshForwardX11=Fremad X11 sshForwardX11Description=Aktiverer X11-videresendelse for forbindelsen @@ -308,7 +308,7 @@ vncUsernameDescription=VNC-brugernavnet vncPassword=Adgangskode vncPasswordDescription=VNC-adgangskoden x11WslInstance=X11 Fremadrettet WSL-instans -x11WslInstanceDescription=Den lokale Windows Subsystem for Linux-distribution, der skal bruges som X11-server, når du bruger X11-videresendelse i en SSH-forbindelse. Denne distribution skal være en WSL2-distribution.\n\nKræver en genstart for at blive anvendt. +x11WslInstanceDescription=Den lokale Windows Subsystem for Linux-distribution, der skal bruges som X11-server ved brug af X11-forwarding i en SSH-forbindelse. Denne distribution skal være en WSL2-distribution. openAsRoot=Åbn som rod openInVsCodeRemote=Åbn i VSCode remote openInWSL=Åbn i WSL @@ -413,3 +413,18 @@ vmIdentity=Gæsteidentitet vmIdentityDescription=Den SSH-identitetsgodkendelsesmetode, der skal bruges til at oprette forbindelse, hvis det er nødvendigt vmPort=Port vmPortDescription=Den port, der skal oprettes forbindelse til via SSH +forwardAgent=Fremadrettet agent +forwardAgentDescription=Gør SSH-agent-identiteter tilgængelige på fjernsystemet +virshUri=URI +virshUriDescription=Hypervisor-URI'en, aliaser understøttes også +virshDomain.displayName=libvirt-domæne +virshDomain.displayDescription=Opret forbindelse til et libvirt-domæne +virshHypervisor.displayName=libvirt-hypervisor +virshHypervisor.displayDescription=Opret forbindelse til en libvirt-understøttet hypervisor-driver +virshInstall.displayName=libvirt-kommandolinjeklient +virshInstall.displayDescription=Opret forbindelse til alle tilgængelige libvirt-hypervisorer via virsh +addHypervisor=Tilføj hypervisor +serialConsole=Seriel konsol +interactiveTerminal=Interaktiv terminal +editDomain=Rediger domæne +libvirt=libvirt-domæner diff --git a/lang/proc/strings/translations_de.properties b/lang/proc/strings/translations_de.properties index 11453e080..57dd3c8fa 100644 --- a/lang/proc/strings/translations_de.properties +++ b/lang/proc/strings/translations_de.properties @@ -75,8 +75,8 @@ sshDynamicTunnel.displayName=Dynamischer SSH-Tunnel sshDynamicTunnel.displayDescription=Einen SOCKS-Proxy über eine SSH-Verbindung einrichten shellEnvironmentGroup.displayName=Shell-Umgebungen shellEnvironmentGroup.displayDescription=Shell-Umgebungen -shellEnvironment.displayName=Benutzerdefinierte Shell-Umgebung -shellEnvironment.displayDescription=Eine angepasste Shell-Init-Umgebung erstellen +shellEnvironment.displayName=Shell-Umgebung +shellEnvironment.displayDescription=Eine angepasste Shell-Startumgebung erstellen shellEnvironment.informationFormat=$TYPE$ umgebung shellEnvironment.elevatedInformationFormat=$ELEVATION$ $TYPE$ umgebung environmentConnectionDescription=Die Basisverbindung, um eine Umgebung zu schaffen für @@ -111,7 +111,7 @@ sshLocalTunnel.hostDescription=Das System, zu dem der Tunnel geöffnet werden so sshLocalTunnel.bindingDescription=An welche Adressen der Tunnel gebunden werden soll sshLocalTunnel.localAddressDescription=Die lokale Adresse zum Binden sshLocalTunnel.remoteAddressDescription=Die zu bindende Remote-Adresse -cmd.displayName=Benutzerdefinierter Terminal-Befehl +cmd.displayName=Terminal-Befehl cmd.displayDescription=Einen benutzerdefinierten Befehl auf einem System in deinem Terminal ausführen k8sPod.displayName=Kubernetes Pod k8sPod.displayDescription=Verbinden mit einem Pod und seinen Containern über kubectl @@ -174,7 +174,7 @@ podDescription=Der Pod, auf dem sich der Container befindet k8sClusterHostDescription=Der Host, über den auf den Cluster zugegriffen werden soll. Muss kubectl installiert und konfiguriert haben, um auf den Cluster zugreifen zu können. script=Init-Skript connection=Verbindung -shellCommand.displayName=Benutzerdefinierter Shell-Öffner-Befehl +shellCommand.displayName=Benutzerdefinierter Shell-Befehl shellCommand.displayDescription=Eine Standard-Shell über einen benutzerdefinierten Befehl öffnen ssh.displayName=Einfache SSH-Verbindung ssh.displayDescription=Verbindung über einen SSH-Befehlszeilen-Client @@ -198,7 +198,7 @@ commandShellTypeDescription=Die Shell, die für diesen Befehl verwendet werden s ssh.passwordDescription=Das optionale Passwort, das bei der Authentifizierung verwendet wird keyAuthentication=Schlüsselbasierte Authentifizierung keyAuthenticationDescription=Die zu verwendende Authentifizierungsmethode, wenn eine schlüsselbasierte Authentifizierung erforderlich ist. -dontInteractWithSystem=Nicht mit dem System interagieren (Pro) +dontInteractWithSystem=Nicht mit dem System interagieren dontInteractWithSystemDescription=Versuche nicht, den Shell-Typ zu identifizieren, was für begrenzte eingebettete Systeme oder IOT-Geräte notwendig ist sshForwardX11=X11 weiterleiten sshForwardX11Description=Aktiviert die X11-Weiterleitung für die Verbindung @@ -287,7 +287,7 @@ vncUsernameDescription=Der optionale VNC-Benutzername vncPassword=Passwort vncPasswordDescription=Das VNC-Passwort x11WslInstance=X11 Forward WSL-Instanz -x11WslInstanceDescription=Die lokale Windows Subsystem für Linux-Distribution, die als X11-Server verwendet werden soll, wenn die X11-Weiterleitung in einer SSH-Verbindung genutzt wird. Diese Distribution muss eine WSL2-Distribution sein.\n\nErfordert einen Neustart zur Anwendung. +x11WslInstanceDescription=Die lokale Windows Subsystem für Linux-Distribution, die als X11-Server verwendet werden soll, wenn die X11-Weiterleitung in einer SSH-Verbindung genutzt wird. Diese Distribution muss eine WSL2-Distribution sein. openAsRoot=Als Root öffnen openInVsCodeRemote=Öffnen in VSCode remote openInWSL=In WSL öffnen @@ -391,3 +391,18 @@ vmIdentity=Gast-Identität vmIdentityDescription=Die SSH-Identitätsauthentifizierungsmethode, die bei Bedarf für die Verbindung verwendet wird vmPort=Port vmPortDescription=Der Port, mit dem du dich über SSH verbinden kannst +forwardAgent=Weiterleitungsagent +forwardAgentDescription=SSH-Agenten-Identitäten auf dem entfernten System verfügbar machen +virshUri=URI +virshUriDescription=Der Hypervisor-URI, Aliasnamen werden ebenfalls unterstützt +virshDomain.displayName=libvirt-Domäne +virshDomain.displayDescription=Mit einer libvirt-Domäne verbinden +virshHypervisor.displayName=libvirt Hypervisor +virshHypervisor.displayDescription=Verbindung zu einem von libvirt unterstützten Hypervisor-Treiber +virshInstall.displayName=libvirt Kommandozeilen-Client +virshInstall.displayDescription=Verbindung zu allen verfügbaren libvirt-Hypervisoren über virsh +addHypervisor=Hypervisor hinzufügen +serialConsole=Serielle Konsole +interactiveTerminal=Interaktives Terminal +editDomain=Domäne bearbeiten +libvirt=libvirt-Domänen diff --git a/lang/proc/strings/translations_en.properties b/lang/proc/strings/translations_en.properties index 018a80b10..a16b7e275 100644 --- a/lang/proc/strings/translations_en.properties +++ b/lang/proc/strings/translations_en.properties @@ -72,10 +72,10 @@ sshRemoteTunnel.displayName=Remote SSH tunnel sshRemoteTunnel.displayDescription=Establish a reverse SSH tunnel from a remote host sshDynamicTunnel.displayName=Dynamic SSH tunnel sshDynamicTunnel.displayDescription=Establish a SOCKS proxy through an SSH connection -shellEnvironmentGroup.displayName=Shell Environments -shellEnvironmentGroup.displayDescription=Shell Environments -shellEnvironment.displayName=Custom Shell Environment -shellEnvironment.displayDescription=Create a customized shell init environment +shellEnvironmentGroup.displayName=Shell environments +shellEnvironmentGroup.displayDescription=Shell environments +shellEnvironment.displayName=Shell environment +shellEnvironment.displayDescription=Create a customized shell startup environment shellEnvironment.informationFormat=$TYPE$ environment shellEnvironment.elevatedInformationFormat=$ELEVATION$ $TYPE$ environment environmentConnectionDescription=The base connection to create an environment for @@ -109,7 +109,7 @@ sshLocalTunnel.hostDescription=The system to open the tunnel to sshLocalTunnel.bindingDescription=What addresses to bind the tunnel to sshLocalTunnel.localAddressDescription=The local address to bind sshLocalTunnel.remoteAddressDescription=The remote address to bind -cmd.displayName=Custom Terminal Command +cmd.displayName=Terminal command cmd.displayDescription=Run a custom command on a system in your terminal k8sPod.displayName=Kubernetes Pod k8sPod.displayDescription=Connect to a pod and its containers via kubectl @@ -171,13 +171,13 @@ podDescription=The pod on which the container is located k8sClusterHostDescription=The host through which the cluster should be accessed. Must have kubectl installed and configured to be able to access the cluster. script=Init Script connection=Connection -shellCommand.displayName=Custom Shell Opener Command +shellCommand.displayName=Custom shell command shellCommand.displayDescription=Open a standard shell through a custom command -ssh.displayName=Simple SSH Connection +ssh.displayName=Simple SSH connection ssh.displayDescription=Connect via an SSH command-line client -sshConfig.displayName=SSH Config File +sshConfig.displayName=SSH config file sshConfig.displayDescription=Connect to hosts defined in an SSH config file -sshConfigHost.displayName=SSH Config File Host +sshConfigHost.displayName=SSH config file host sshConfigHost.displayDescription=Connect to a host defined in an SSH config file sshConfigHost.password=Password sshConfigHost.passwordDescription=Provide the optional password for the user login. @@ -196,7 +196,7 @@ commandShellTypeDescription=The shell to use for this command ssh.passwordDescription=The optional password to use when authenticating keyAuthentication=Key-based authentication keyAuthenticationDescription=The authentication method to use if key-based authentication is required. -dontInteractWithSystem=Don't interact with system (Pro) +dontInteractWithSystem=Don't interact with system dontInteractWithSystemDescription=Don't try to identify shell type, necessary for limited embedded systems or IOT devices sshForwardX11=Forward X11 sshForwardX11Description=Enables X11 forwarding for the connection @@ -272,7 +272,7 @@ connectionInformation=Connection information connectionInformationDescription=Which system to connect to passwordAuthentication=Password authentication passwordDescription=The optional password to use to authenticate. -sshConfigString.displayName=Customized SSH Connection +sshConfigString.displayName=Customized SSH connection sshConfigString.displayDescription=Create a fully customized SSH connection sshConfigStringContent=Configuration sshConfigStringContentDescription=SSH options for the connection in OpenSSH config format @@ -285,7 +285,7 @@ vncUsernameDescription=The optional VNC username vncPassword=Password vncPasswordDescription=The VNC password x11WslInstance=X11 Forward WSL instance -x11WslInstanceDescription=The local Windows Subsystem for Linux distribution to use as an X11 server when using X11 forwarding in an SSH connection. This distribution must be a WSL2 distribution.\n\nRequires a restart to apply. +x11WslInstanceDescription=The local Windows Subsystem for Linux distribution to use as an X11 server when using X11 forwarding in an SSH connection. This distribution must be a WSL2 distribution. openAsRoot=Open as root openInVsCodeRemote=Open in VSCode remote openInWSL=Open in WSL @@ -389,3 +389,18 @@ vmIdentity=Guest identity vmIdentityDescription=The SSH identity authentication method to use for connecting if needed vmPort=Port vmPortDescription=The port to connect to via SSH +forwardAgent=Forward agent +forwardAgentDescription=Make SSH agent identities available on the remote system +virshUri=URI +virshUriDescription=The hypervisor URI, aliases are also supported +virshDomain.displayName=libvirt domain +virshDomain.displayDescription=Connect to a libvirt domain +virshHypervisor.displayName=libvirt hypervisor +virshHypervisor.displayDescription=Connect to a libvirt supported hypervisor driver +virshInstall.displayName=libvirt command-line client +virshInstall.displayDescription=Connect to all available libvirt hypervisors via virsh +addHypervisor=Add hypervisor +serialConsole=Serial console +interactiveTerminal=Interactive terminal +editDomain=Edit domain +libvirt=libvirt domains diff --git a/lang/proc/strings/translations_es.properties b/lang/proc/strings/translations_es.properties index 356486d0d..ea5691ddd 100644 --- a/lang/proc/strings/translations_es.properties +++ b/lang/proc/strings/translations_es.properties @@ -74,8 +74,8 @@ sshDynamicTunnel.displayName=Túnel SSH dinámico sshDynamicTunnel.displayDescription=Establecer un proxy SOCKS a través de una conexión SSH shellEnvironmentGroup.displayName=Entornos Shell shellEnvironmentGroup.displayDescription=Entornos Shell -shellEnvironment.displayName=Entorno Shell personalizado -shellEnvironment.displayDescription=Crear un entorno shell init personalizado +shellEnvironment.displayName=Entorno Shell +shellEnvironment.displayDescription=Crea un entorno de inicio shell personalizado shellEnvironment.informationFormat=$TYPE$ entorno shellEnvironment.elevatedInformationFormat=$ELEVATION$ $TYPE$ entorno environmentConnectionDescription=La conexión base para crear un entorno para @@ -109,7 +109,7 @@ sshLocalTunnel.hostDescription=El sistema para abrir el túnel hacia sshLocalTunnel.bindingDescription=A qué direcciones enlazar el túnel sshLocalTunnel.localAddressDescription=La dirección local a enlazar sshLocalTunnel.remoteAddressDescription=La dirección remota a enlazar -cmd.displayName=Comando de terminal personalizado +cmd.displayName=Comando de terminal cmd.displayDescription=Ejecuta un comando personalizado en un sistema en tu terminal k8sPod.displayName=Pod Kubernetes k8sPod.displayDescription=Conectarse a un pod y sus contenedores mediante kubectl @@ -171,13 +171,13 @@ podDescription=La vaina en la que se encuentra el contenedor k8sClusterHostDescription=El host a través del cual se debe acceder al clúster. Debe tener kubectl instalado y configurado para poder acceder al clúster. script=Guión de inicio connection=Conexión -shellCommand.displayName=Comando de apertura de shell personalizado +shellCommand.displayName=Comando shell personalizado shellCommand.displayDescription=Abrir un shell estándar mediante un comando personalizado ssh.displayName=Conexión SSH simple ssh.displayDescription=Conectarse mediante un cliente de línea de comandos SSH sshConfig.displayName=Archivo de configuración SSH sshConfig.displayDescription=Conectarse a hosts definidos en un archivo de configuración SSH -sshConfigHost.displayName=Archivo SSH Config Anfitrión +sshConfigHost.displayName=Archivo de configuración SSH host sshConfigHost.displayDescription=Conectarse a un host definido en un archivo de configuración SSH sshConfigHost.password=Contraseña sshConfigHost.passwordDescription=Proporciona la contraseña opcional para el inicio de sesión del usuario. @@ -195,7 +195,7 @@ commandShellTypeDescription=El shell a utilizar para este comando ssh.passwordDescription=La contraseña opcional que se utilizará al autenticarse keyAuthentication=Autenticación basada en claves keyAuthenticationDescription=El método de autenticación a utilizar si se requiere una autenticación basada en claves. -dontInteractWithSystem=No interactuar con el sistema (Pro) +dontInteractWithSystem=No interactúes con el sistema dontInteractWithSystemDescription=No intentes identificar el tipo de shell, necesario para sistemas integrados limitados o dispositivos IOT sshForwardX11=Adelante X11 sshForwardX11Description=Activa el reenvío X11 para la conexión @@ -283,7 +283,7 @@ vncUsernameDescription=El nombre de usuario VNC opcional vncPassword=Contraseña vncPasswordDescription=La contraseña VNC x11WslInstance=Instancia X11 Forward WSL -x11WslInstanceDescription=La distribución local del Subsistema Windows para Linux que se utilizará como servidor X11 cuando se utilice el reenvío X11 en una conexión SSH. Esta distribución debe ser una distribución WSL2.\n\nRequiere un reinicio para aplicarse. +x11WslInstanceDescription=La distribución local del Subsistema Windows para Linux que se utilizará como servidor X11 cuando se utilice el reenvío X11 en una conexión SSH. Esta distribución debe ser una distribución WSL2. openAsRoot=Abrir como raíz openInVsCodeRemote=Abrir en VSCode remoto openInWSL=Abrir en WSL @@ -387,3 +387,18 @@ vmIdentity=Identidad de invitado vmIdentityDescription=El método de autenticación de identidad SSH a utilizar para conectarse si es necesario vmPort=Puerto vmPortDescription=El puerto al que conectarse mediante SSH +forwardAgent=Agente de reenvío +forwardAgentDescription=Hacer que las identidades del agente SSH estén disponibles en el sistema remoto +virshUri=URI +virshUriDescription=La URI del hipervisor, también se admiten alias +virshDomain.displayName=dominio libvirt +virshDomain.displayDescription=Conectarse a un dominio libvirt +virshHypervisor.displayName=hipervisor libvirt +virshHypervisor.displayDescription=Conectarse a un controlador de hipervisor compatible con libvirt +virshInstall.displayName=cliente de línea de comandos libvirt +virshInstall.displayDescription=Conéctate a todos los hipervisores libvirt disponibles mediante virsh +addHypervisor=Añadir hipervisor +serialConsole=Consola serie +interactiveTerminal=Terminal interactivo +editDomain=Editar dominio +libvirt=dominios libvirt diff --git a/lang/proc/strings/translations_fr.properties b/lang/proc/strings/translations_fr.properties index 52afcb217..06f3a6512 100644 --- a/lang/proc/strings/translations_fr.properties +++ b/lang/proc/strings/translations_fr.properties @@ -74,8 +74,8 @@ sshDynamicTunnel.displayName=Tunnel SSH dynamique sshDynamicTunnel.displayDescription=Établir un proxy SOCKS par le biais d'une connexion SSH shellEnvironmentGroup.displayName=Environnements Shell shellEnvironmentGroup.displayDescription=Environnements Shell -shellEnvironment.displayName=Environnement Shell personnalisé -shellEnvironment.displayDescription=Créer un environnement d'initialisation de l'interpréteur de commandes personnalisé +shellEnvironment.displayName=Environnement shell +shellEnvironment.displayDescription=Créer un environnement de démarrage personnalisé pour l'interpréteur de commandes shellEnvironment.informationFormat=$TYPE$ l'environnement shellEnvironment.elevatedInformationFormat=$ELEVATION$ $TYPE$ l'environnement environmentConnectionDescription=La connexion de base pour créer un environnement pour @@ -109,7 +109,7 @@ sshLocalTunnel.hostDescription=Le système pour ouvrir le tunnel vers sshLocalTunnel.bindingDescription=A quelles adresses lier le tunnel sshLocalTunnel.localAddressDescription=L'adresse locale à lier sshLocalTunnel.remoteAddressDescription=L'adresse distante à lier -cmd.displayName=Commande personnalisée du terminal +cmd.displayName=Commande de terminal cmd.displayDescription=Exécute une commande personnalisée sur un système dans ton terminal k8sPod.displayName=Pod Kubernetes k8sPod.displayDescription=Se connecter à un pod et à ses conteneurs via kubectl @@ -171,13 +171,13 @@ podDescription=Le pod sur lequel se trouve le conteneur k8sClusterHostDescription=L'hôte par lequel il faut accéder au cluster. Doit avoir kubectl installé et configuré pour pouvoir accéder au cluster. script=Script d'initialisation connection=Connexion -shellCommand.displayName=Commande d'ouverture de shell personnalisée +shellCommand.displayName=Commande shell personnalisée shellCommand.displayDescription=Ouvrir un shell standard par le biais d'une commande personnalisée ssh.displayName=Connexion SSH simple ssh.displayDescription=Se connecter via un client de ligne de commande SSH sshConfig.displayName=Fichier de configuration SSH sshConfig.displayDescription=Se connecter aux hôtes définis dans un fichier de configuration SSH -sshConfigHost.displayName=Fichier de configuration SSH Hôte +sshConfigHost.displayName=Fichier de configuration SSH hôte sshConfigHost.displayDescription=Se connecter à un hôte défini dans un fichier de configuration SSH sshConfigHost.password=Mot de passe sshConfigHost.passwordDescription=Fournir le mot de passe facultatif pour la connexion de l'utilisateur. @@ -195,7 +195,7 @@ commandShellTypeDescription=L'interpréteur de commandes à utiliser pour cette ssh.passwordDescription=Le mot de passe facultatif à utiliser lors de l'authentification keyAuthentication=Authentification par clé keyAuthenticationDescription=La méthode d'authentification à utiliser si l'authentification par clé est requise. -dontInteractWithSystem=Ne pas interagir avec le système (Pro) +dontInteractWithSystem=N'interagis pas avec le système dontInteractWithSystemDescription=N'essaie pas d'identifier le type de coquille, nécessaire pour les systèmes embarqués limités ou les appareils IOT sshForwardX11=Faire suivre X11 sshForwardX11Description=Active le transfert X11 pour la connexion @@ -283,7 +283,7 @@ vncUsernameDescription=Le nom d'utilisateur optionnel de VNC vncPassword=Mot de passe vncPasswordDescription=Le mot de passe VNC x11WslInstance=Instance X11 Forward WSL -x11WslInstanceDescription=La distribution locale du sous-système Windows pour Linux à utiliser comme serveur X11 lors de l'utilisation du transfert X11 dans une connexion SSH. Cette distribution doit être une distribution WSL2.\n\nUn redémarrage est nécessaire pour l'appliquer. +x11WslInstanceDescription=La distribution locale de Windows Subsystem for Linux à utiliser comme serveur X11 lors de l'utilisation du transfert X11 dans une connexion SSH. Cette distribution doit être une distribution WSL2. openAsRoot=Ouvrir en tant que racine openInVsCodeRemote=Ouvrir en VSCode à distance openInWSL=Ouvrir en WSL @@ -387,3 +387,18 @@ vmIdentity=Identité de l'invité vmIdentityDescription=La méthode d'authentification de l'identité SSH à utiliser pour se connecter si nécessaire vmPort=Port vmPortDescription=Le port auquel se connecter via SSH +forwardAgent=Agent de transfert +forwardAgentDescription=Rendre les identités des agents SSH disponibles sur le système distant +virshUri=URI +virshUriDescription=L'URI de l'hyperviseur, les alias sont également pris en charge +virshDomain.displayName=domaine libvirt +virshDomain.displayDescription=Se connecter à un domaine libvirt +virshHypervisor.displayName=hyperviseur libvirt +virshHypervisor.displayDescription=Se connecter à un pilote d'hyperviseur pris en charge par libvirt +virshInstall.displayName=client de ligne de commande libvirt +virshInstall.displayDescription=Se connecter à tous les hyperviseurs libvirt disponibles via virsh +addHypervisor=Ajouter un hyperviseur +serialConsole=Console de série +interactiveTerminal=Terminal interactif +editDomain=Éditer le domaine +libvirt=domaines libvirt diff --git a/lang/proc/strings/translations_it.properties b/lang/proc/strings/translations_it.properties index 048972b44..f8f5665b6 100644 --- a/lang/proc/strings/translations_it.properties +++ b/lang/proc/strings/translations_it.properties @@ -72,10 +72,10 @@ sshRemoteTunnel.displayName=Tunnel SSH remoto sshRemoteTunnel.displayDescription=Stabilire un tunnel SSH inverso da un host remoto sshDynamicTunnel.displayName=Tunnel SSH dinamico sshDynamicTunnel.displayDescription=Stabilire un proxy SOCKS attraverso una connessione SSH -shellEnvironmentGroup.displayName=Ambienti shell -shellEnvironmentGroup.displayDescription=Ambienti shell -shellEnvironment.displayName=Ambiente Shell personalizzato -shellEnvironment.displayDescription=Creare un ambiente di init della shell personalizzato +shellEnvironmentGroup.displayName=Ambienti di shell +shellEnvironmentGroup.displayDescription=Ambienti di shell +shellEnvironment.displayName=Ambiente di shell +shellEnvironment.displayDescription=Creare un ambiente di avvio della shell personalizzato shellEnvironment.informationFormat=$TYPE$ ambiente shellEnvironment.elevatedInformationFormat=$ELEVATION$ $TYPE$ ambiente environmentConnectionDescription=La connessione di base per creare un ambiente per @@ -109,7 +109,7 @@ sshLocalTunnel.hostDescription=Il sistema per aprire il tunnel a sshLocalTunnel.bindingDescription=Quali sono gli indirizzi a cui associare il tunnel sshLocalTunnel.localAddressDescription=L'indirizzo locale a cui fare il bind sshLocalTunnel.remoteAddressDescription=L'indirizzo remoto a cui fare il bind -cmd.displayName=Comando terminale personalizzato +cmd.displayName=Comando del terminale cmd.displayDescription=Esegui un comando personalizzato su un sistema nel tuo terminale k8sPod.displayName=Pod Kubernetes k8sPod.displayDescription=Connettersi a un pod e ai suoi contenitori tramite kubectl @@ -171,13 +171,13 @@ podDescription=Il pod su cui si trova il contenitore k8sClusterHostDescription=L'host attraverso il quale si deve accedere al cluster. Deve avere kubectl installato e configurato per poter accedere al cluster. script=Script Init connection=Connessione -shellCommand.displayName=Comando personalizzato di apertura della shell +shellCommand.displayName=Comando shell personalizzato shellCommand.displayDescription=Aprire una shell standard attraverso un comando personalizzato -ssh.displayName=Connessione SSH semplice +ssh.displayName=Semplice connessione SSH ssh.displayDescription=Connettersi tramite un client a riga di comando SSH sshConfig.displayName=File di configurazione SSH sshConfig.displayDescription=Connettersi agli host definiti in un file di configurazione SSH -sshConfigHost.displayName=File di configurazione SSH Host +sshConfigHost.displayName=File di configurazione SSH host sshConfigHost.displayDescription=Connettersi a un host definito in un file di configurazione SSH sshConfigHost.password=Password sshConfigHost.passwordDescription=Fornisce la password opzionale per il login dell'utente. @@ -195,7 +195,7 @@ commandShellTypeDescription=La shell da utilizzare per questo comando ssh.passwordDescription=La password opzionale da utilizzare per l'autenticazione keyAuthentication=Autenticazione basata su chiavi keyAuthenticationDescription=Il metodo di autenticazione da utilizzare se è richiesta un'autenticazione basata su chiavi. -dontInteractWithSystem=Non interagire con il sistema (Pro) +dontInteractWithSystem=Non interagire con il sistema dontInteractWithSystemDescription=Non cercare di identificare il tipo di shell, necessario per i sistemi embedded limitati o per i dispositivi IOT sshForwardX11=Avanti X11 sshForwardX11Description=Abilita l'inoltro X11 per la connessione @@ -283,7 +283,7 @@ vncUsernameDescription=Il nome utente VNC opzionale vncPassword=Password vncPasswordDescription=La password di VNC x11WslInstance=Istanza X11 Forward WSL -x11WslInstanceDescription=La distribuzione locale di Windows Subsystem for Linux da utilizzare come server X11 quando si utilizza l'inoltro X11 in una connessione SSH. Questa distribuzione deve essere una distribuzione WSL2.\n\nRichiede un riavvio per essere applicata. +x11WslInstanceDescription=La distribuzione locale di Windows Subsystem for Linux da utilizzare come server X11 quando si utilizza l'inoltro X11 in una connessione SSH. Questa distribuzione deve essere una distribuzione WSL2. openAsRoot=Apri come root openInVsCodeRemote=Aprire in VSCode remoto openInWSL=Aprire in WSL @@ -387,3 +387,18 @@ vmIdentity=Identità dell'ospite vmIdentityDescription=Il metodo di autenticazione dell'identità SSH da utilizzare per la connessione, se necessario vmPort=Porta vmPortDescription=La porta a cui connettersi tramite SSH +forwardAgent=Agente di inoltro +forwardAgentDescription=Rendere disponibili le identità dell'agente SSH sul sistema remoto +virshUri=URI +virshUriDescription=L'URI dell'hypervisor, sono supportati anche gli alias +virshDomain.displayName=dominio libvirt +virshDomain.displayDescription=Connettersi a un dominio libvirt +virshHypervisor.displayName=hypervisor libvirt +virshHypervisor.displayDescription=Connettersi a un driver hypervisor supportato da libvirt +virshInstall.displayName=client a riga di comando libvirt +virshInstall.displayDescription=Connettersi a tutti gli hypervisor libvirt disponibili tramite virsh +addHypervisor=Aggiungi un hypervisor +serialConsole=Console seriale +interactiveTerminal=Terminale interattivo +editDomain=Modifica dominio +libvirt=domini libvirt diff --git a/lang/proc/strings/translations_ja.properties b/lang/proc/strings/translations_ja.properties index 48cf088e4..6a81a88e1 100644 --- a/lang/proc/strings/translations_ja.properties +++ b/lang/proc/strings/translations_ja.properties @@ -74,8 +74,8 @@ sshDynamicTunnel.displayName=動的SSHトンネル sshDynamicTunnel.displayDescription=SSH接続でSOCKSプロキシを確立する shellEnvironmentGroup.displayName=シェル環境 shellEnvironmentGroup.displayDescription=シェル環境 -shellEnvironment.displayName=カスタムシェル環境 -shellEnvironment.displayDescription=カスタマイズされたシェルinit環境を作成する +shellEnvironment.displayName=シェル環境 +shellEnvironment.displayDescription=カスタマイズされたシェル起動環境を作成する shellEnvironment.informationFormat=$TYPE$ 環境 shellEnvironment.elevatedInformationFormat=$ELEVATION$ $TYPE$ 環境 environmentConnectionDescription=の環境を作るためのベースとなる接続 @@ -109,7 +109,7 @@ sshLocalTunnel.hostDescription=トンネルを開くシステム sshLocalTunnel.bindingDescription=トンネルをどのアドレスにバインドするか sshLocalTunnel.localAddressDescription=バインドするローカルアドレス sshLocalTunnel.remoteAddressDescription=バインドするリモートアドレス -cmd.displayName=カスタムターミナルコマンド +cmd.displayName=ターミナルコマンド cmd.displayDescription=ターミナルでカスタムコマンドを実行する k8sPod.displayName=Kubernetesポッド k8sPod.displayDescription=kubectlでポッドとそのコンテナに接続する @@ -171,9 +171,9 @@ podDescription=コンテナが置かれているポッド k8sClusterHostDescription=クラスタにアクセスするホスト。クラスタにアクセスするにはkubectlがインストールされ、設定されている必要がある。 script=初期スクリプト connection=接続 -shellCommand.displayName=カスタムシェルオープナーコマンド +shellCommand.displayName=カスタムシェルコマンド shellCommand.displayDescription=カスタムコマンドで標準シェルを開く -ssh.displayName=シンプルなSSH接続 +ssh.displayName=簡単なSSH接続 ssh.displayDescription=SSHコマンドラインクライアントで接続する sshConfig.displayName=SSH設定ファイル sshConfig.displayDescription=SSH設定ファイルで定義されたホストに接続する @@ -195,7 +195,7 @@ commandShellTypeDescription=このコマンドに使用するシェル ssh.passwordDescription=認証時に使用する任意のパスワード keyAuthentication=鍵ベースの認証 keyAuthenticationDescription=鍵ベースの認証が必要な場合に使用する認証方法。 -dontInteractWithSystem=システムと対話しない(プロ) +dontInteractWithSystem=システムと対話しない dontInteractWithSystemDescription=シェルの種類を特定しようとしないこと。限られた組み込みシステムやIoTデバイスに必要である。 sshForwardX11=フォワードX11 sshForwardX11Description=接続のX11転送を有効にする @@ -283,7 +283,7 @@ vncUsernameDescription=オプションのVNCユーザー名 vncPassword=パスワード vncPasswordDescription=VNCパスワード x11WslInstance=X11フォワードWSLインスタンス -x11WslInstanceDescription=SSH接続でX11転送を使用する際に、X11サーバーとして使用するローカルのWindows Subsystem for Linuxディストリビューション。このディストリビューションはWSL2ディストリビューションでなければならない。\n\n適用には再起動が必要である。 +x11WslInstanceDescription=SSH接続でX11フォワーディングを使うときに、X11サーバーとして使うローカルのWindows Subsystem for Linuxディストリビューション。このディストリビューションはWSL2ディストリビューションでなければならない。 openAsRoot=ルートとして開く openInVsCodeRemote=VSCodeリモートで開く openInWSL=WSLで開く @@ -387,3 +387,18 @@ vmIdentity=ゲストID vmIdentityDescription=必要に応じて接続に使用するSSH ID認証方法 vmPort=ポート vmPortDescription=SSHで接続するポート +forwardAgent=フォワードエージェント +forwardAgentDescription=SSHエージェントのIDをリモートシステムで利用可能にする +virshUri=URI +virshUriDescription=ハイパーバイザーのURI。エイリアスもサポートされている。 +virshDomain.displayName=libvirt ドメイン +virshDomain.displayDescription=libvirt ドメインに接続する +virshHypervisor.displayName=libvirt ハイパーバイザー +virshHypervisor.displayDescription=libvirt がサポートするハイパーバイザドライバに接続する +virshInstall.displayName=libvirt コマンドラインクライアント +virshInstall.displayDescription=virsh 経由で利用可能なすべての libvirt ハイパーバイザーに接続する +addHypervisor=ハイパーバイザーを追加する +serialConsole=シリアルコンソール +interactiveTerminal=インタラクティブ端末 +editDomain=ドメインを編集する +libvirt=libvirt ドメイン diff --git a/lang/proc/strings/translations_nl.properties b/lang/proc/strings/translations_nl.properties index b2d18b6ab..49e0e411b 100644 --- a/lang/proc/strings/translations_nl.properties +++ b/lang/proc/strings/translations_nl.properties @@ -74,8 +74,8 @@ sshDynamicTunnel.displayName=Dynamische SSH-tunnel sshDynamicTunnel.displayDescription=Een SOCKS proxy opzetten via een SSH verbinding shellEnvironmentGroup.displayName=Shell-omgevingen shellEnvironmentGroup.displayDescription=Shell-omgevingen -shellEnvironment.displayName=Aangepaste Shell-omgeving -shellEnvironment.displayDescription=Een aangepaste shell init-omgeving maken +shellEnvironment.displayName=Shell-omgeving +shellEnvironment.displayDescription=Een aangepaste shell opstartomgeving maken shellEnvironment.informationFormat=$TYPE$ omgeving shellEnvironment.elevatedInformationFormat=$ELEVATION$ $TYPE$ omgeving environmentConnectionDescription=De basisverbinding om een omgeving te creëren voor @@ -109,7 +109,7 @@ sshLocalTunnel.hostDescription=Het systeem om de tunnel naar te openen sshLocalTunnel.bindingDescription=Aan welke adressen de tunnel moet worden gebonden sshLocalTunnel.localAddressDescription=Het lokale adres om te binden sshLocalTunnel.remoteAddressDescription=Het externe adres om te binden -cmd.displayName=Aangepast Terminal Commando +cmd.displayName=Terminal commando cmd.displayDescription=Een aangepast commando uitvoeren op een systeem in je terminal k8sPod.displayName=Kubernetes Pod k8sPod.displayDescription=Verbinding maken met een pod en zijn containers via kubectl @@ -171,13 +171,13 @@ podDescription=De pod waarop de container zich bevindt k8sClusterHostDescription=De host via welke het cluster benaderd moet worden. Kubectl moet geïnstalleerd en geconfigureerd zijn om toegang te krijgen tot het cluster. script=Init script connection=Verbinding -shellCommand.displayName=Aangepast commando Shell-opener +shellCommand.displayName=Aangepast shell commando shellCommand.displayDescription=Een standaard shell openen via een aangepast commando ssh.displayName=Eenvoudige SSH-verbinding ssh.displayDescription=Verbinding maken via een SSH-opdrachtregelclient -sshConfig.displayName=SSH-configuratiebestand +sshConfig.displayName=SSH config bestand sshConfig.displayDescription=Verbinding maken met hosts gedefinieerd in een SSH config bestand -sshConfigHost.displayName=SSH configuratiebestand host +sshConfigHost.displayName=SSH config bestand host sshConfigHost.displayDescription=Verbinding maken met een host gedefinieerd in een SSH config bestand sshConfigHost.password=Wachtwoord sshConfigHost.passwordDescription=Geef het optionele wachtwoord voor het inloggen van de gebruiker. @@ -195,7 +195,7 @@ commandShellTypeDescription=De shell die gebruikt moet worden voor dit commando ssh.passwordDescription=Het optionele wachtwoord om te gebruiken bij verificatie keyAuthentication=Verificatie op basis van sleutels keyAuthenticationDescription=De te gebruiken verificatiemethode als verificatie op basis van sleutels vereist is. -dontInteractWithSystem=Geen interactie met systeem (Pro) +dontInteractWithSystem=Geen interactie met systeem dontInteractWithSystemDescription=Probeer niet het type shell te identificeren, noodzakelijk voor beperkte ingebedde systemen of IOT-apparaten sshForwardX11=Vooruit X11 sshForwardX11Description=Schakelt X11-forwarding in voor de verbinding @@ -283,7 +283,7 @@ vncUsernameDescription=De optionele VNC-gebruikersnaam vncPassword=Wachtwoord vncPasswordDescription=Het VNC-wachtwoord x11WslInstance=X11 Voorwaartse WSL-instantie -x11WslInstanceDescription=De lokale Windows Subsystem for Linux distributie om te gebruiken als X11 server bij het gebruik van X11 forwarding in een SSH verbinding. Deze distributie moet een WSL2 distributie zijn.\n\nVereist een herstart om toe te passen. +x11WslInstanceDescription=De lokale Windows Subsystem for Linux distributie om te gebruiken als X11 server bij het gebruik van X11 forwarding in een SSH verbinding. Deze distributie moet een WSL2 distributie zijn. openAsRoot=Openen als root openInVsCodeRemote=Openen in VSCode op afstand openInWSL=Openen in WSL @@ -387,3 +387,18 @@ vmIdentity=Identiteit van de gast vmIdentityDescription=De SSH-identiteitsverificatiemethode om eventueel te gebruiken om verbinding te maken vmPort=Poort vmPortDescription=De poort om verbinding mee te maken via SSH +forwardAgent=Doorstuuragent +forwardAgentDescription=SSH-agent identiteiten beschikbaar maken op het externe systeem +virshUri=URI +virshUriDescription=De hypervisor URI, aliassen worden ook ondersteund +virshDomain.displayName=libvirt domein +virshDomain.displayDescription=Verbinding maken met een libvirt-domein +virshHypervisor.displayName=libvirt hypervisor +virshHypervisor.displayDescription=Verbinding maken met een door libvirt ondersteund hypervisor-stuurprogramma +virshInstall.displayName=libvirt opdrachtregelclient +virshInstall.displayDescription=Verbinding maken met alle beschikbare libvirt hypervisors via virsh +addHypervisor=Hypervisor toevoegen +serialConsole=Seriële console +interactiveTerminal=Interactieve terminal +editDomain=Domein bewerken +libvirt=libvirt domeinen diff --git a/lang/proc/strings/translations_pt.properties b/lang/proc/strings/translations_pt.properties index d2aee9f5f..c36f822a8 100644 --- a/lang/proc/strings/translations_pt.properties +++ b/lang/proc/strings/translations_pt.properties @@ -72,10 +72,10 @@ sshRemoteTunnel.displayName=Túnel SSH remoto sshRemoteTunnel.displayDescription=Estabelece um túnel SSH reverso a partir de um host remoto sshDynamicTunnel.displayName=Túnel SSH dinâmico sshDynamicTunnel.displayDescription=Estabelece um proxy SOCKS através de uma ligação SSH -shellEnvironmentGroup.displayName=Ambientes Shell -shellEnvironmentGroup.displayDescription=Ambientes Shell -shellEnvironment.displayName=Ambiente de shell personalizado -shellEnvironment.displayDescription=Cria um ambiente shell init personalizado +shellEnvironmentGroup.displayName=Ambientes de shell +shellEnvironmentGroup.displayDescription=Ambientes de shell +shellEnvironment.displayName=Ambiente de shell +shellEnvironment.displayDescription=Cria um ambiente de arranque de shell personalizado shellEnvironment.informationFormat=$TYPE$ ambiente shellEnvironment.elevatedInformationFormat=$ELEVATION$ $TYPE$ ambiente environmentConnectionDescription=A ligação de base para criar um ambiente para @@ -109,7 +109,7 @@ sshLocalTunnel.hostDescription=O sistema para abrir o túnel para sshLocalTunnel.bindingDescription=A que endereços ligar o túnel sshLocalTunnel.localAddressDescription=O endereço local a associar sshLocalTunnel.remoteAddressDescription=O endereço remoto a associar -cmd.displayName=Comando de terminal personalizado +cmd.displayName=Comando de terminal cmd.displayDescription=Executa um comando personalizado num sistema no teu terminal k8sPod.displayName=Pod de Kubernetes k8sPod.displayDescription=Liga-te a um pod e aos seus contentores através do kubectl @@ -171,13 +171,13 @@ podDescription=O pod no qual o contentor está localizado k8sClusterHostDescription=O host através do qual o cluster deve ser acessado. Deve ter o kubectl instalado e configurado para poder aceder ao cluster. script=Script de inicialização connection=Ligação -shellCommand.displayName=Comando de abertura de shell personalizado +shellCommand.displayName=Comando shell personalizado shellCommand.displayDescription=Abre uma shell padrão através de um comando personalizado ssh.displayName=Ligação SSH simples ssh.displayDescription=Liga-te através de um cliente de linha de comandos SSH sshConfig.displayName=Ficheiro de configuração SSH sshConfig.displayDescription=Liga-te a anfitriões definidos num ficheiro de configuração SSH -sshConfigHost.displayName=SSH Config File Host +sshConfigHost.displayName=Anfitrião do ficheiro de configuração SSH sshConfigHost.displayDescription=Liga-te a um anfitrião definido num ficheiro de configuração SSH sshConfigHost.password=Palavra-passe sshConfigHost.passwordDescription=Fornece a palavra-passe opcional para o início de sessão do utilizador. @@ -195,7 +195,7 @@ commandShellTypeDescription=A shell a utilizar para este comando ssh.passwordDescription=A palavra-passe opcional a utilizar na autenticação keyAuthentication=Autenticação baseada em chaves keyAuthenticationDescription=O método de autenticação a utilizar se for necessária uma autenticação baseada em chaves. -dontInteractWithSystem=Não interajas com o sistema (Pro) +dontInteractWithSystem=Não interajas com o sistema dontInteractWithSystemDescription=Não tentes identificar o tipo de shell, necessário para sistemas incorporados limitados ou dispositivos IOT sshForwardX11=Avança X11 sshForwardX11Description=Ativa o reencaminhamento X11 para a ligação @@ -283,7 +283,7 @@ vncUsernameDescription=O nome de utilizador opcional do VNC vncPassword=Palavra-passe vncPasswordDescription=A palavra-passe VNC x11WslInstance=Instância X11 Forward WSL -x11WslInstanceDescription=A distribuição local do Subsistema Windows para Linux a utilizar como um servidor X11 quando utiliza o reencaminhamento X11 numa ligação SSH. Esta distribuição deve ser uma distribuição WSL2.\n\nRequer uma reinicialização para ser aplicada. +x11WslInstanceDescription=A distribuição local do Subsistema Windows para Linux a utilizar como um servidor X11 quando utiliza o reencaminhamento X11 numa ligação SSH. Esta distribuição deve ser uma distribuição WSL2. openAsRoot=Abre como raiz openInVsCodeRemote=Abre no VSCode remoto openInWSL=Abre em WSL @@ -387,3 +387,18 @@ vmIdentity=Identidade do convidado vmIdentityDescription=O método de autenticação de identidade SSH a utilizar para estabelecer ligação, se necessário vmPort=Porta vmPortDescription=A porta a que te deves ligar via SSH +forwardAgent=Agente de encaminhamento +forwardAgentDescription=Torna as identidades do agente SSH disponíveis no sistema remoto +virshUri=URI +virshUriDescription=O URI do hipervisor, também são suportados aliases +virshDomain.displayName=domínio libvirt +virshDomain.displayDescription=Liga-te a um domínio libvirt +virshHypervisor.displayName=hipervisor libvirt +virshHypervisor.displayDescription=Liga-te a um controlador de hipervisor suportado pela libvirt +virshInstall.displayName=cliente de linha de comando libvirt +virshInstall.displayDescription=Conecta-se a todos os hipervisores libvirt disponíveis via virsh +addHypervisor=Adiciona um hipervisor +serialConsole=Consola de série +interactiveTerminal=Terminal interativo +editDomain=Editar domínio +libvirt=domínios libvirt diff --git a/lang/proc/strings/translations_ru.properties b/lang/proc/strings/translations_ru.properties index 465e5908d..70401f913 100644 --- a/lang/proc/strings/translations_ru.properties +++ b/lang/proc/strings/translations_ru.properties @@ -74,8 +74,8 @@ sshDynamicTunnel.displayName=Динамический SSH-туннель sshDynamicTunnel.displayDescription=Установите SOCKS-прокси через SSH-соединение shellEnvironmentGroup.displayName=Среды оболочки shellEnvironmentGroup.displayDescription=Среды оболочки -shellEnvironment.displayName=Пользовательская среда оболочки -shellEnvironment.displayDescription=Создайте настраиваемое окружение shell init +shellEnvironment.displayName=Среда оболочки +shellEnvironment.displayDescription=Создайте настраиваемую среду запуска оболочки shellEnvironment.informationFormat=$TYPE$ среда shellEnvironment.elevatedInformationFormat=$ELEVATION$ $TYPE$ среда environmentConnectionDescription=Базовое соединение для создания среды для @@ -109,7 +109,7 @@ sshLocalTunnel.hostDescription=Система, к которой нужно от sshLocalTunnel.bindingDescription=К каким адресам привязать туннель sshLocalTunnel.localAddressDescription=Локальный адрес для привязки sshLocalTunnel.remoteAddressDescription=Удаленный адрес для привязки -cmd.displayName=Пользовательская команда терминала +cmd.displayName=Команда терминала cmd.displayDescription=Запустить пользовательскую команду в системе в терминале k8sPod.displayName=Kubernetes Pod k8sPod.displayDescription=Подключись к капсуле и ее контейнерам с помощью kubectl @@ -171,13 +171,13 @@ podDescription=Капсула, на которой находится конте k8sClusterHostDescription=Хост, через который должен осуществляться доступ к кластеру. Должен быть установлен и настроен kubectl, чтобы иметь возможность получить доступ к кластеру. script=Init Script connection=Соединение -shellCommand.displayName=Пользовательская команда открытия оболочки +shellCommand.displayName=Пользовательская команда оболочки shellCommand.displayDescription=Открыть стандартную оболочку через пользовательскую команду ssh.displayName=Простое SSH-соединение ssh.displayDescription=Подключение через клиент командной строки SSH -sshConfig.displayName=Конфигурационный файл SSH +sshConfig.displayName=Файл конфигурации SSH sshConfig.displayDescription=Подключение к хостам, заданным в конфигурационном файле SSH -sshConfigHost.displayName=SSH Config File Host +sshConfigHost.displayName=SSH файл конфигурации хоста sshConfigHost.displayDescription=Подключиться к хосту, определенному в конфигурационном файле SSH sshConfigHost.password=Пароль sshConfigHost.passwordDescription=Укажи необязательный пароль для входа пользователя в систему. @@ -195,7 +195,7 @@ commandShellTypeDescription=Оболочка, которую нужно испо ssh.passwordDescription=Необязательный пароль, который нужно использовать при аутентификации keyAuthentication=Аутентификация на основе ключа keyAuthenticationDescription=Метод аутентификации, который нужно использовать, если требуется аутентификация на основе ключа. -dontInteractWithSystem=Не взаимодействуй с системой (Pro) +dontInteractWithSystem=Не взаимодействуй с системой dontInteractWithSystemDescription=Не пытайся определить тип оболочки, это необходимо для ограниченных встраиваемых систем или IOT-устройств sshForwardX11=Форвард X11 sshForwardX11Description=Включает переадресацию X11 для соединения @@ -283,7 +283,7 @@ vncUsernameDescription=Дополнительное имя пользовате vncPassword=Пароль vncPasswordDescription=Пароль VNC x11WslInstance=Экземпляр X11 Forward WSL -x11WslInstanceDescription=Локальный дистрибутив Windows Subsystem for Linux для использования в качестве X11-сервера при использовании X11-переадресации в SSH-соединении. Этот дистрибутив должен быть WSL2.\n\nДля применения требуется перезагрузка. +x11WslInstanceDescription=Локальный дистрибутив Windows Subsystem for Linux для использования в качестве X11-сервера при использовании X11-переадресации в SSH-соединении. Этот дистрибутив должен быть WSL2. openAsRoot=Открыть как корень openInVsCodeRemote=Открыть в VSCode remote openInWSL=Открыть в WSL @@ -387,3 +387,18 @@ vmIdentity=Идентификация гостя vmIdentityDescription=Метод аутентификации SSH, который нужно использовать для подключения при необходимости vmPort=Порт vmPortDescription=Порт, к которому нужно подключиться через SSH +forwardAgent=Форвард-агент +forwardAgentDescription=Сделать идентификаторы SSH-агентов доступными на удаленной системе +virshUri=URI +virshUriDescription=URI гипервизора, также поддерживаются псевдонимы +virshDomain.displayName=домен libvirt +virshDomain.displayDescription=Подключение к домену libvirt +virshHypervisor.displayName=гипервизор libvirt +virshHypervisor.displayDescription=Подключение к драйверу гипервизора, поддерживаемого libvirt +virshInstall.displayName=клиент командной строки libvirt +virshInstall.displayDescription=Подключись ко всем доступным гипервизорам libvirt через virsh +addHypervisor=Добавьте гипервизор +serialConsole=Последовательная консоль +interactiveTerminal=Интерактивный терминал +editDomain=Редактировать домен +libvirt=домены libvirt diff --git a/lang/proc/strings/translations_tr.properties b/lang/proc/strings/translations_tr.properties index 5c3064621..a66be532b 100644 --- a/lang/proc/strings/translations_tr.properties +++ b/lang/proc/strings/translations_tr.properties @@ -72,9 +72,9 @@ sshRemoteTunnel.displayName=Uzak SSH tüneli sshRemoteTunnel.displayDescription=Uzak bir ana bilgisayardan ters SSH tüneli oluşturma sshDynamicTunnel.displayName=Dinamik SSH tüneli sshDynamicTunnel.displayDescription=SSH bağlantısı aracılığıyla bir SOCKS proxy oluşturma -shellEnvironmentGroup.displayName=Kabuk Ortamları -shellEnvironmentGroup.displayDescription=Kabuk Ortamları -shellEnvironment.displayName=Özel Kabuk Ortamı +shellEnvironmentGroup.displayName=Kabuk ortamları +shellEnvironmentGroup.displayDescription=Kabuk ortamları +shellEnvironment.displayName=Kabuk ortamı shellEnvironment.displayDescription=Özelleştirilmiş bir kabuk başlangıç ortamı oluşturma shellEnvironment.informationFormat=$TYPE$ çevre shellEnvironment.elevatedInformationFormat=$ELEVATION$ $TYPE$ çevre @@ -109,7 +109,7 @@ sshLocalTunnel.hostDescription=Tüneli açmak için sistem sshLocalTunnel.bindingDescription=Tünelin hangi adreslere bağlanacağı sshLocalTunnel.localAddressDescription=Bağlanacak yerel adres sshLocalTunnel.remoteAddressDescription=Bağlanacak uzak adres -cmd.displayName=Özel Terminal Komutu +cmd.displayName=Terminal komutu cmd.displayDescription=Terminalinizde bir sistem üzerinde özel bir komut çalıştırın k8sPod.displayName=Kubernetes Pod k8sPod.displayDescription=Kubectl aracılığıyla bir pod'a ve kapsayıcılarına bağlanma @@ -171,13 +171,13 @@ podDescription=Konteynerin üzerinde bulunduğu bölme k8sClusterHostDescription=Kümeye erişilmesi gereken ana bilgisayar. Kümeye erişebilmek için kubectl yüklü ve yapılandırılmış olmalıdır. script=Başlangıç Komut Dosyası connection=Bağlantı -shellCommand.displayName=Özel Kabuk Açıcı Komutu +shellCommand.displayName=Özel kabuk komutu shellCommand.displayDescription=Özel bir komut aracılığıyla standart bir kabuk açma -ssh.displayName=Basit SSH Bağlantısı +ssh.displayName=Basit SSH bağlantısı ssh.displayDescription=Bir SSH komut satırı istemcisi aracılığıyla bağlanma -sshConfig.displayName=SSH Yapılandırma Dosyası +sshConfig.displayName=SSH yapılandırma dosyası sshConfig.displayDescription=SSH yapılandırma dosyasında tanımlanan ana bilgisayarlara bağlanma -sshConfigHost.displayName=SSH Yapılandırma Dosyası Ana Bilgisayar +sshConfigHost.displayName=SSH yapılandırma dosyası ana bilgisayarı sshConfigHost.displayDescription=SSH yapılandırma dosyasında tanımlanan bir ana bilgisayara bağlanma sshConfigHost.password=Şifre sshConfigHost.passwordDescription=Kullanıcı girişi için isteğe bağlı parolayı girin. @@ -195,7 +195,7 @@ commandShellTypeDescription=Bu komut için kullanılacak kabuk ssh.passwordDescription=Kimlik doğrulama sırasında kullanılacak isteğe bağlı parola keyAuthentication=Anahtar tabanlı kimlik doğrulama keyAuthenticationDescription=Anahtar tabanlı kimlik doğrulama gerekiyorsa kullanılacak kimlik doğrulama yöntemi. -dontInteractWithSystem=Sistemle etkileşime girme (Pro) +dontInteractWithSystem=Sistemle etkileşime girmeyin dontInteractWithSystemDescription=Sınırlı gömülü sistemler veya IOT cihazları için gerekli olan kabuk türünü belirlemeye çalışmayın sshForwardX11=İleri X11 sshForwardX11Description=Bağlantı için X11 yönlendirmesini etkinleştirir @@ -270,7 +270,7 @@ connectionInformation=Bağlantı bilgileri connectionInformationDescription=Hangi sisteme bağlanılacağı passwordAuthentication=Şifre doğrulama passwordDescription=Kimlik doğrulamak için kullanılacak isteğe bağlı parola. -sshConfigString.displayName=Özelleştirilmiş SSH Bağlantısı +sshConfigString.displayName=Özelleştirilmiş SSH bağlantısı sshConfigString.displayDescription=Tamamen özelleştirilmiş bir SSH bağlantısı oluşturma sshConfigStringContent=Konfigürasyon sshConfigStringContentDescription=OpenSSH yapılandırma biçiminde bağlantı için SSH seçenekleri @@ -283,7 +283,7 @@ vncUsernameDescription=İsteğe bağlı VNC kullanıcı adı vncPassword=Şifre vncPasswordDescription=VNC şifresi x11WslInstance=X11 İleri WSL örneği -x11WslInstanceDescription=Bir SSH bağlantısında X11 iletimi kullanılırken X11 sunucusu olarak kullanılacak yerel Linux için Windows Alt Sistemi dağıtımı. Bu dağıtım bir WSL2 dağıtımı olmalıdır.\n\nUygulamak için yeniden başlatma gerekir. +x11WslInstanceDescription=Bir SSH bağlantısında X11 iletimi kullanılırken X11 sunucusu olarak kullanılacak yerel Linux için Windows Alt Sistemi dağıtımı. Bu dağıtım bir WSL2 dağıtımı olmalıdır. openAsRoot=Kök olarak aç openInVsCodeRemote=VSCode remote'da açın openInWSL=WSL'de Açık @@ -387,3 +387,18 @@ vmIdentity=Misafir kimliği vmIdentityDescription=Gerekirse bağlanmak için kullanılacak SSH kimlik doğrulama yöntemi vmPort=Liman vmPortDescription=SSH aracılığıyla bağlanılacak bağlantı noktası +forwardAgent=İleri temsilci +forwardAgentDescription=SSH aracı kimliklerini uzak sistemde kullanılabilir hale getirin +virshUri=URI +virshUriDescription=Hipervizör URI'si, takma adlar da desteklenir +virshDomain.displayName=libvirt etki alanı +virshDomain.displayDescription=Bir libvirt etki alanına bağlanma +virshHypervisor.displayName=libvirt hipervizörü +virshHypervisor.displayDescription=Libvirt destekli bir hipervizör sürücüsüne bağlanma +virshInstall.displayName=libvirt komut satırı istemcisi +virshInstall.displayDescription=Virsh aracılığıyla mevcut tüm libvirt hipervizörlerine bağlanın +addHypervisor=Hipervizör ekleme +serialConsole=Seri konsol +interactiveTerminal=İnteraktif terminal +editDomain=Etki alanını düzenle +libvirt=libvirt etki alanları diff --git a/lang/proc/strings/translations_zh.properties b/lang/proc/strings/translations_zh.properties index d1f4ec1e2..a840ea13e 100644 --- a/lang/proc/strings/translations_zh.properties +++ b/lang/proc/strings/translations_zh.properties @@ -74,8 +74,8 @@ sshDynamicTunnel.displayName=动态 SSH 通道 sshDynamicTunnel.displayDescription=通过 SSH 连接建立 SOCKS 代理 shellEnvironmentGroup.displayName=外壳环境 shellEnvironmentGroup.displayDescription=外壳环境 -shellEnvironment.displayName=自定义外壳环境 -shellEnvironment.displayDescription=创建自定义的 shell 启动环境 +shellEnvironment.displayName=外壳环境 +shellEnvironment.displayDescription=创建自定义 shell 启动环境 shellEnvironment.informationFormat=$TYPE$ 环境 shellEnvironment.elevatedInformationFormat=$ELEVATION$ $TYPE$ 环境 environmentConnectionDescription=创建环境的基础连接 @@ -109,7 +109,7 @@ sshLocalTunnel.hostDescription=打开隧道的系统 sshLocalTunnel.bindingDescription=将隧道绑定到哪些地址 sshLocalTunnel.localAddressDescription=绑定的本地地址 sshLocalTunnel.remoteAddressDescription=要绑定的远程地址 -cmd.displayName=自定义终端命令 +cmd.displayName=终端命令 cmd.displayDescription=在终端上运行系统自定义命令 k8sPod.displayName=Kubernetes Pod k8sPod.displayDescription=通过 kubectl 连接 pod 及其容器 @@ -171,9 +171,9 @@ podDescription=容器所在的 pod k8sClusterHostDescription=访问群集的主机。必须安装并配置 kubectl 才能访问群集。 script=初始脚本 connection=连接 -shellCommand.displayName=自定义外壳打开器命令 +shellCommand.displayName=自定义 shell 命令 shellCommand.displayDescription=通过自定义命令打开标准 shell -ssh.displayName=简单 SSH 连接 +ssh.displayName=简单的 SSH 连接 ssh.displayDescription=通过 SSH 命令行客户端连接 sshConfig.displayName=SSH 配置文件 sshConfig.displayDescription=连接 SSH 配置文件中定义的主机 @@ -195,7 +195,7 @@ commandShellTypeDescription=该命令使用的 shell ssh.passwordDescription=验证时使用的可选密码 keyAuthentication=基于密钥的身份验证 keyAuthenticationDescription=如果需要基于密钥的身份验证,应使用的身份验证方法。 -dontInteractWithSystem=不与系统交互(专业版) +dontInteractWithSystem=不与系统交互 dontInteractWithSystemDescription=不要试图识别外壳类型,这对于有限的嵌入式系统或物联网设备是必要的 sshForwardX11=转发 X11 sshForwardX11Description=为连接启用 X11 转发 @@ -270,7 +270,7 @@ connectionInformation=连接信息 connectionInformationDescription=连接哪个系统 passwordAuthentication=密码验证 passwordDescription=用于验证的可选密码。 -sshConfigString.displayName=定制 SSH 连接 +sshConfigString.displayName=自定义 SSH 连接 sshConfigString.displayDescription=创建完全自定义的 SSH 连接 sshConfigStringContent=配置 sshConfigStringContentDescription=OpenSSH 配置格式的 SSH 连接选项 @@ -283,7 +283,7 @@ vncUsernameDescription=可选的 VNC 用户名 vncPassword=密码 vncPasswordDescription=VNC 密码 x11WslInstance=X11 Forward WSL 实例 -x11WslInstanceDescription=在 SSH 连接中使用 X11 转发时,用作 X11 服务器的本地 Windows Subsystem for Linux 发行版。该发行版必须是 WSL2 发行版。\n\n需要重新启动才能应用。 +x11WslInstanceDescription=在 SSH 连接中使用 X11 转发时,用作 X11 服务器的本地 Windows Subsystem for Linux 发行版。该发行版必须是 WSL2 发行版。 openAsRoot=以根用户身份打开 openInVsCodeRemote=在 VSCode 远程中打开 openInWSL=在 WSL 中打开 @@ -387,3 +387,18 @@ vmIdentity=访客身份 vmIdentityDescription=必要时用于连接的 SSH 身份验证方法 vmPort=端口 vmPortDescription=通过 SSH 连接的端口 +forwardAgent=前向代理 +forwardAgentDescription=在远程系统上提供 SSH 代理身份 +virshUri=通用资源识别号 +virshUriDescription=管理程序 URI,也支持别名 +virshDomain.displayName=libvirt 域 +virshDomain.displayDescription=连接到 libvirt 域 +virshHypervisor.displayName=libvirt 虚拟机管理程序 +virshHypervisor.displayDescription=连接到支持 libvirt 的管理程序驱动程序 +virshInstall.displayName=libvirt 命令行客户端 +virshInstall.displayDescription=通过 virsh 连接到所有可用的 libvirt 虚拟机管理程序 +addHypervisor=添加管理程序 +serialConsole=串行控制台 +interactiveTerminal=互动终端 +editDomain=编辑域 +libvirt=libvirt 域 diff --git a/lang/proc/texts/sshKeyVm_da.md b/lang/proc/texts/sshKeyVm_da.md deleted file mode 100644 index 891805244..000000000 --- a/lang/proc/texts/sshKeyVm_da.md +++ /dev/null @@ -1,63 +0,0 @@ -# VM SSH-identiteter - -Hvis din VM-gæstebruger kræver nøglebaseret godkendelse til SSH, kan du aktivere det her. - -Bemærk, at det antages, at din VM ikke er eksponeret for offentligheden, så VM-værtssystemet bruges som en SSH-gateway. -Som følge heraf angives enhver identitetsindstilling i forhold til VM-værtssystemet og ikke din lokale maskine. -Enhver nøgle, du angiver her, fortolkes som en fil på VM-værten. -Hvis du bruger en agent, forventes det, at agenten kører på VM-værtssystemet og ikke på din lokale maskine. - -### Ingen - -Hvis dette er valgt, vil XPipe ikke levere nogen identiteter. Dette deaktiverer også alle eksterne kilder som f.eks. agenter. - -### Identitetsfil - -Du kan også angive en identitetsfil med en valgfri passphrase. -Denne mulighed svarer til `ssh -i `. - -Bemærk, at dette skal være den *private* nøgle, ikke den offentlige. -Hvis du blander det sammen, vil ssh kun give dig kryptiske fejlmeddelelser. - -### SSH-agent - -Hvis dine identiteter er gemt i SSH-agenten, kan den eksekverbare ssh bruge dem, hvis agenten startes. -XPipe starter automatisk agentprocessen, hvis den ikke kører endnu. - -Hvis du ikke har sat agenten op på VM-værtssystemet, anbefales det, at du aktiverer SSH-agentforwarding for den oprindelige SSH-forbindelse til VM-værten. -Det kan du gøre ved at oprette en brugerdefineret SSH-forbindelse med indstillingen `ForwardAgent` aktiveret. - -### GPG-agent - -Hvis dine identiteter f.eks. er gemt på et smartcard, kan du vælge at give dem til SSH-klienten via `gpg-agent`. -Denne indstilling vil automatisk aktivere SSH-understøttelse af agenten, hvis den ikke er aktiveret endnu, og genstarte GPG-agentdæmonen med de korrekte indstillinger. - -### Yubikey PIV - -Hvis dine identiteter er gemt med Yubikeys PIV-chipkortfunktion, kan du hente dem med Yubicos -dem med Yubicos YKCS11-bibliotek, som følger med Yubico PIV Tool. - -Bemærk, at du skal have en opdateret version af OpenSSH for at kunne bruge denne funktion. - -### Brugerdefineret PKCS#11-bibliotek - -Dette vil instruere OpenSSH-klienten om at indlæse den angivne delte biblioteksfil, som vil håndtere godkendelsen. - -Bemærk, at du skal have en opdateret version af OpenSSH for at kunne bruge denne funktion. - -### Pageant (Windows) - -Hvis du bruger pageant på Windows, vil XPipe først kontrollere, om pageant kører. -På grund af pageants natur er det dit ansvar at have den kørende, da du -køre, da du manuelt skal angive alle de nøgler, du gerne vil tilføje, hver gang. -Hvis den kører, sender XPipe den rigtige navngivne pipe via -`-oIdentityAgent=...` til ssh, og du behøver ikke at inkludere nogen brugerdefinerede konfigurationsfiler. - -### Pageant (Linux & macOS) - -Hvis dine identiteter er gemt i pageant-agenten, kan den eksekverbare ssh-fil bruge dem, hvis agenten startes. -XPipe starter automatisk agentprocessen, hvis den ikke kører endnu. - -### Andre eksterne kilder - -Denne indstilling tillader enhver ekstern kørende identitetsudbyder at levere sine nøgler til SSH-klienten. Du bør bruge denne indstilling, hvis du bruger en anden agent eller adgangskodeadministrator til at administrere dine SSH-nøgler. diff --git a/lang/proc/texts/sshKeyVm_de.md b/lang/proc/texts/sshKeyVm_de.md deleted file mode 100644 index 9d508c8a2..000000000 --- a/lang/proc/texts/sshKeyVm_de.md +++ /dev/null @@ -1,63 +0,0 @@ -# VM SSH-Identitäten - -Wenn dein VM-Gastbenutzer eine schlüsselbasierte Authentifizierung für SSH benötigt, kannst du dies hier aktivieren. - -Beachte, dass davon ausgegangen wird, dass deine VM nicht öffentlich zugänglich ist und das VM-Hostsystem als SSH-Gateway verwendet wird. -Daher bezieht sich jede Identitätsoption auf das VM-Hostsystem und nicht auf deinen lokalen Rechner. -Jeder Schlüssel, den du hier angibst, wird als eine Datei auf dem VM-Host interpretiert. -Wenn du einen Agenten verwendest, wird erwartet, dass der Agent auf dem VM-Host-System und nicht auf deinem lokalen Rechner läuft. - -### Keine - -Wenn du diese Option auswählst, stellt XPipe keine Identitäten bereit. Damit werden auch alle externen Quellen wie Agenten deaktiviert. - -### Identitätsdatei - -Du kannst auch eine Identitätsdatei mit einer optionalen Passphrase angeben. -Diese Option ist das Äquivalent zu `ssh -i `. - -Beachte, dass dies der *private* Schlüssel sein sollte, nicht der öffentliche. -Wenn du das verwechselst, wird dir ssh nur kryptische Fehlermeldungen geben. - -### SSH-Agent - -Wenn deine Identitäten im SSH-Agenten gespeichert sind, kann das ssh-Programm sie verwenden, wenn der Agent gestartet wird. -XPipe startet den Agentenprozess automatisch, wenn er noch nicht läuft. - -Wenn du den Agenten nicht auf dem VM-Host-System eingerichtet hast, wird empfohlen, dass du die Weiterleitung des SSH-Agenten für die ursprüngliche SSH-Verbindung zum VM-Host aktivierst. -Das kannst du tun, indem du eine benutzerdefinierte SSH-Verbindung erstellst und die Option `ForwardAgent` aktivierst. - -### GPG Agent - -Wenn deine Identitäten zum Beispiel auf einer Smartcard gespeichert sind, kannst du sie dem SSH-Client über den `gpg-agent` zur Verfügung stellen. -Diese Option aktiviert automatisch die SSH-Unterstützung des Agenten, falls sie noch nicht aktiviert ist, und startet den GPG-Agent-Daemon mit den richtigen Einstellungen neu. - -### Yubikey PIV - -Wenn deine Identitäten mit der PIV-Chipkartenfunktion des Yubikey gespeichert sind, kannst du sie mit -kannst du sie mit der YKCS11-Bibliothek von Yubico abrufen, die im Lieferumfang des Yubico PIV Tools enthalten ist. - -Beachte, dass du eine aktuelle Version von OpenSSH benötigst, um diese Funktion nutzen zu können. - -### Benutzerdefinierte PKCS#11-Bibliothek - -Hiermit wird der OpenSSH-Client angewiesen, die angegebene Shared-Library-Datei zu laden, die die Authentifizierung übernimmt. - -Beachte, dass du einen aktuellen Build von OpenSSH brauchst, um diese Funktion zu nutzen. - -### Pageant (Windows) - -Wenn du Pageant unter Windows verwendest, prüft XPipe zuerst, ob Pageant läuft. -Aufgrund der Natur von Pageant liegt es in deiner Verantwortung, dass es -da du jedes Mal alle Schlüssel, die du hinzufügen möchtest, manuell eingeben musst. -Wenn es läuft, übergibt XPipe die richtig benannte Pipe über -`-oIdentityAgent=...` an ssh weiter, du musst keine benutzerdefinierten Konfigurationsdateien einfügen. - -### Pageant (Linux & macOS) - -Wenn deine Identitäten im Pageant-Agent gespeichert sind, kann das ssh-Programm sie verwenden, wenn der Agent gestartet wird. -XPipe startet den Agentenprozess automatisch, wenn er noch nicht läuft. - -### Andere externe Quelle - -Diese Option erlaubt es jedem externen Identitätsanbieter, seine Schlüssel an den SSH-Client zu liefern. Du solltest diese Option nutzen, wenn du einen anderen Agenten oder Passwortmanager zur Verwaltung deiner SSH-Schlüssel verwendest. diff --git a/lang/proc/texts/sshKeyVm_en.md b/lang/proc/texts/sshKeyVm_en.md deleted file mode 100644 index 5afd7d28e..000000000 --- a/lang/proc/texts/sshKeyVm_en.md +++ /dev/null @@ -1,63 +0,0 @@ -# VM SSH identities - -If your VM guest user requires key-based authentication for SSH, you can enable this here. - -Note that it is assumed that your VM is not exposed to the public, so the VM host system is used as an SSH gateway. -As a result, any identity option is specified relative to the VM host system and not your local machine. -Any key you specify here is interpreted as a file on the VM host. -If you are using any agent, is expected that the agent is running on the VM host system not on your local machine. - -### None - -If selected, XPipe will not supply any identities. This also disables any external sources like agents. - -### Identity file - -You can also specify an identity file with an optional passphrase. -This option is the equivalent of `ssh -i `. - -Note that this should be the *private* key, not the public one. -If you mix that up, ssh will only give you cryptic error messages. - -### SSH-Agent - -In case your identities are stored in the SSH-Agent, the ssh executable can use them if the agent is started. -XPipe will automatically start the agent process if it is not running yet. - -If you don't have the agent set up on the VM host system, is recommended that you enable SSH agent forwarding for the original SSH connection to the VM host. -You can do that by creating a custom SSH connection with the `ForwardAgent` option enabled. - -### GPG Agent - -If your identities are stored for example on a smartcard, you can choose to provide them to the SSH client via the `gpg-agent`. -This option will automatically enable SSH support of the agent if not enabled yet and restart the GPG agent daemon with the correct settings. - -### Yubikey PIV - -If your identities are stored with the PIV smart card function of the Yubikey, you can retreive -them with Yubico's YKCS11 library, which comes bundled with Yubico PIV Tool. - -Note that you need an up-to-date build of OpenSSH in order to use this feature. - -### Custom PKCS#11 library - -This will instruct the OpenSSH client to load the specified shared library file, which will handle the authentication. - -Note that you need an up-to-date build of OpenSSH in order to use this feature. - -### Pageant (Windows) - -In case you are using pageant on Windows, XPipe will check whether pageant is running first. -Due to the nature of pageant, it is your responsibility to have it -running as you manually have to specify all keys you would like to add every time. -If it is running, XPipe will pass the proper named pipe via -`-oIdentityAgent=...` to ssh, you don't have to include any custom config files. - -### Pageant (Linux & macOS) - -In case your identities are stored in the pageant agent, the ssh executable can use them if the agent is started. -XPipe will automatically start the agent process if it is not running yet. - -### Other external source - -This option will permit any external running identity provider to supply its keys to the SSH client. You should use this option if you are using any other agent or password manager to manage your SSH keys. diff --git a/lang/proc/texts/sshKeyVm_es.md b/lang/proc/texts/sshKeyVm_es.md deleted file mode 100644 index f2deb32c9..000000000 --- a/lang/proc/texts/sshKeyVm_es.md +++ /dev/null @@ -1,63 +0,0 @@ -# Identidades VM SSH - -Si el usuario invitado de tu VM requiere autenticación basada en clave para SSH, puedes activarla aquí. - -Ten en cuenta que se supone que tu VM no está expuesta al público, por lo que el sistema anfitrión de la VM se utiliza como pasarela SSH. -Como resultado, cualquier opción de identidad se especifica en relación con el sistema anfitrión de la VM y no con tu máquina local. -Cualquier clave que especifiques aquí se interpreta como un archivo en el host de la VM. -Si estás utilizando algún agente, se espera que el agente se esté ejecutando en el sistema anfitrión de la VM y no en tu máquina local. - -### Ninguno - -Si se selecciona, XPipe no proporcionará ninguna identidad. Esto también desactiva cualquier fuente externa como los agentes. - -### Archivo de identidad - -También puedes especificar un archivo de identidad con una frase de contraseña opcional. -Esta opción equivale a `ssh -i `. - -Ten en cuenta que ésta debe ser la clave *privada*, no la pública. -Si te confundes, ssh sólo te dará crípticos mensajes de error. - -### Agente SSH - -En caso de que tus identidades estén almacenadas en el SSH-Agent, el ejecutable ssh podrá utilizarlas si se inicia el agente. -XPipe iniciará automáticamente el proceso del agente si aún no se está ejecutando. - -Si no tienes configurado el agente en el sistema anfitrión de la máquina virtual, se recomienda que habilites el reenvío del agente SSH para la conexión SSH original al anfitrión de la máquina virtual. -Puedes hacerlo creando una conexión SSH personalizada con la opción `ReenviarAgente` activada. - -### Agente GPG - -Si tus identidades están almacenadas, por ejemplo, en una tarjeta inteligente, puedes optar por proporcionarlas al cliente SSH mediante el `agente GPG`. -Esta opción habilitará automáticamente el soporte SSH del agente si aún no está habilitado y reiniciará el demonio del agente GPG con la configuración correcta. - -### Yubikey PIV - -Si tus identidades están almacenadas con la función de tarjeta inteligente PIV del Yubikey, puedes recuperarlas -con la biblioteca YKCS11 de Yubico, que viene incluida con Yubico PIV Tool. - -Ten en cuenta que necesitas una versión actualizada de OpenSSH para utilizar esta función. - -### Biblioteca PKCS#11 personalizada - -Esto indicará al cliente OpenSSH que cargue el archivo de biblioteca compartida especificado, que se encargará de la autenticación. - -Ten en cuenta que necesitas una versión actualizada de OpenSSH para utilizar esta función. - -### Pageant (Windows) - -Si utilizas pageant en Windows, XPipe comprobará primero si pageant se está ejecutando. -Debido a la naturaleza de pageant, es tu responsabilidad tenerlo -ya que tienes que especificar manualmente todas las claves que quieras añadir cada vez. -Si se está ejecutando, XPipe pasará la tubería con el nombre adecuado a través de -`-oIdentityAgent=...` a ssh, no tienes que incluir ningún archivo de configuración personalizado. - -### Pageant (Linux y macOS) - -En caso de que tus identidades estén almacenadas en el agente pageant, el ejecutable ssh puede utilizarlas si se inicia el agente. -XPipe iniciará automáticamente el proceso del agente si aún no se está ejecutando. - -### Otra fuente externa - -Esta opción permitirá que cualquier proveedor de identidad externo en ejecución suministre sus claves al cliente SSH. Debes utilizar esta opción si utilizas cualquier otro agente o gestor de contraseñas para gestionar tus claves SSH. diff --git a/lang/proc/texts/sshKeyVm_fr.md b/lang/proc/texts/sshKeyVm_fr.md deleted file mode 100644 index b352aa2c0..000000000 --- a/lang/proc/texts/sshKeyVm_fr.md +++ /dev/null @@ -1,63 +0,0 @@ -# Identités VM SSH - -Si l'utilisateur invité de la VM a besoin d'une authentification par clé pour SSH, tu peux l'activer ici. - -Note qu'il est supposé que ta VM n'est pas exposée au public, et que le système hôte de la VM est donc utilisé comme passerelle SSH. -Par conséquent, toute option d'identité est spécifiée par rapport au système hôte de la VM et non par rapport à ta machine locale. -Toute clé spécifiée ici est interprétée comme un fichier sur l'hôte de la VM. -Si tu utilises un agent, celui-ci doit être exécuté sur le système hôte de la VM et non sur ta machine locale. - -### Aucun - -Si cette option est sélectionnée, XPipe ne fournira aucune identité. Cela désactive également toutes les sources externes telles que les agents. - -### Fichier d'identité - -Tu peux également spécifier un fichier d'identité avec une phrase de passe facultative. -Cette option est l'équivalent de `ssh -i `. - -Note qu'il doit s'agir de la clé *privée*, et non de la clé publique. -Si tu confonds les deux, ssh ne te donnera que des messages d'erreur énigmatiques. - -### SSH-Agent - -Si tes identités sont stockées dans l'agent SSH, l'exécutable ssh peut les utiliser si l'agent est démarré. -XPipe démarrera automatiquement le processus de l'agent s'il n'est pas encore en cours d'exécution. - -Si l'agent n'est pas installé sur le système hôte de la VM, il est recommandé d'activer le transfert de l'agent SSH pour la connexion SSH d'origine à l'hôte de la VM. -Tu peux le faire en créant une connexion SSH personnalisée avec l'option `ForwardAgent` activée. - -### Agent GPG - -Si tes identités sont stockées par exemple sur une carte à puce, tu peux choisir de les fournir au client SSH via l'option `gpg-agent`. -Cette option activera automatiquement la prise en charge SSH de l'agent si elle n'est pas encore activée et redémarrera le démon de l'agent GPG avec les bons paramètres. - -### Yubikey PIV - -Si tes identités sont stockées avec la fonction de carte à puce PIV du Yubikey, tu peux les récupérer à l'aide du logiciel Yubico -les récupérer avec la bibliothèque YKCS11 de Yubico, qui est fournie avec Yubico PIV Tool. - -Note que tu as besoin d'une version à jour d'OpenSSH pour utiliser cette fonction. - -### Bibliothèque PKCS#11 personnalisée - -Ceci demandera au client OpenSSH de charger le fichier de bibliothèque partagée spécifié, qui gérera l'authentification. - -Note que tu as besoin d'une version à jour d'OpenSSH pour utiliser cette fonction. - -### Pageant (Windows) - -Si tu utilises pageant sous Windows, XPipe vérifiera d'abord si pageant est en cours d'exécution. -En raison de la nature de pageant, il est de ta responsabilité de le faire fonctionner -tu dois en effet spécifier manuellement toutes les clés que tu souhaites ajouter à chaque fois. -Si c'est le cas, XPipe passera le bon tuyau nommé via -`-oIdentityAgent=...` à ssh, tu n'as pas besoin d'inclure de fichiers de configuration personnalisés. - -### Pageant (Linux & macOS) - -Dans le cas où tes identités sont stockées dans l'agent pageant, l'exécutable ssh peut les utiliser si l'agent est démarré. -XPipe démarrera automatiquement le processus de l'agent s'il n'est pas encore en cours d'exécution. - -### Autre source externe - -Cette option permet à tout fournisseur d'identité externe en cours d'exécution de fournir ses clés au client SSH. Tu devrais utiliser cette option si tu utilises un autre agent ou un gestionnaire de mots de passe pour gérer tes clés SSH. diff --git a/lang/proc/texts/sshKeyVm_it.md b/lang/proc/texts/sshKeyVm_it.md deleted file mode 100644 index 58822a19a..000000000 --- a/lang/proc/texts/sshKeyVm_it.md +++ /dev/null @@ -1,63 +0,0 @@ -# Identità VM SSH - -Se l'utente guest della VM richiede un'autenticazione basata su chiavi per SSH, puoi attivarla qui. - -Si presuppone che la VM non sia esposta al pubblico e che il sistema host della VM sia utilizzato come gateway SSH. -Di conseguenza, qualsiasi opzione di identità è specificata relativamente al sistema host della VM e non al tuo computer locale. -Qualsiasi chiave specificata qui viene interpretata come un file sull'host della macchina virtuale. -Se stai usando un agente, è previsto che l'agente sia in esecuzione sul sistema host della VM e non sul tuo computer locale. - -### Nessuno - -Se selezionato, XPipe non fornirà alcuna identità. Questo disabilita anche qualsiasi fonte esterna come gli agenti. - -### File di identità - -Puoi anche specificare un file di identità con una passphrase opzionale. -Questa opzione è l'equivalente di `ssh -i `. - -Nota che questa deve essere la chiave *privata*, non quella pubblica. -Se fai confusione, ssh ti darà solo messaggi di errore criptici. - -### Agente SSH - -Se le tue identità sono memorizzate nell'agente SSH, l'eseguibile ssh può utilizzarle se l'agente viene avviato. -XPipe avvierà automaticamente il processo dell'agente se non è ancora in esecuzione. - -Se non hai impostato l'agente sul sistema host della macchina virtuale, ti consigliamo di attivare l'inoltro dell'agente SSH per la connessione SSH originale all'host della macchina virtuale. -Puoi farlo creando una connessione SSH personalizzata con l'opzione `ForwardAgent` abilitata. - -### Agente GPG - -Se le tue identità sono memorizzate, ad esempio, su una smartcard, puoi scegliere di fornirle al client SSH tramite l'opzione `gpg-agent`. -Questa opzione abiliterà automaticamente il supporto SSH dell'agente se non ancora abilitato e riavvierà il demone dell'agente GPG con le impostazioni corrette. - -### Yubikey PIV - -Se le tue identità sono memorizzate con la funzione smart card PIV di Yubikey, puoi recuperarle con Yubico -con la libreria YKCS11 di Yubico, fornita con Yubico PIV Tool. - -Per utilizzare questa funzione è necessario disporre di una versione aggiornata di OpenSSH. - -### Libreria PKCS#11 personalizzata - -Indica al client OpenSSH di caricare il file di libreria condiviso specificato, che gestirà l'autenticazione. - -Si noti che per utilizzare questa funzione è necessaria una versione aggiornata di OpenSSH. - -### Pageant (Windows) - -Se utilizzi pageant su Windows, XPipe verificherà innanzitutto che pageant sia in esecuzione. -A causa della natura di pageant, è tua responsabilità averlo in esecuzione -è tua responsabilità che sia in funzione, in quanto dovrai specificare manualmente tutte le chiavi che desideri aggiungere ogni volta. -Se è in funzione, XPipe passerà la pipe con il nome appropriato tramite -`-oIdentityAgent=...` a ssh, non è necessario includere alcun file di configurazione personalizzato. - -### Pageant (Linux e macOS) - -Se le tue identità sono memorizzate nell'agente pageant, l'eseguibile ssh può utilizzarle se l'agente viene avviato. -XPipe avvierà automaticamente il processo dell'agente se non è ancora in esecuzione. - -### Altre fonti esterne - -Questa opzione consente a qualsiasi provider di identità esterno in esecuzione di fornire le proprie chiavi al client SSH. Dovresti utilizzare questa opzione se stai usando un altro agente o un gestore di password per gestire le chiavi SSH. diff --git a/lang/proc/texts/sshKeyVm_ja.md b/lang/proc/texts/sshKeyVm_ja.md deleted file mode 100644 index 1aaf96643..000000000 --- a/lang/proc/texts/sshKeyVm_ja.md +++ /dev/null @@ -1,63 +0,0 @@ -# VM SSH ID - -VMのゲスト・ユーザーがSSHに鍵ベースの認証を必要とする場合、ここでこれを有効にすることができる。 - -VMは公衆に公開されておらず、VMホストシステムがSSHゲートウェイとして使用されている。 -その結果、IDオプションはローカル・マシンではなくVMホスト・システムに対して指定される。 -ここで指定した鍵は、VMホスト上のファイルとして解釈される。 -何らかのエージェントを使用している場合、そのエージェントはローカル・マシン上ではなく、VMホスト・システム上で動作していることが期待される。 - -### なし - -このオプションを選択すると、XPipe は ID を提供しない。エージェントのような外部ソースも無効になる。 - -### アイデンティティファイル - -オプションのパスフレーズとともに ID ファイルを指定することもできる。 -このオプションは、`ssh -i ` と同等である。 - -これは公開鍵ではなく、*秘密*鍵であることに注意すること。 -これを間違えると、sshは不可解なエラーメッセージを出すだけである。 - -### SSHエージェント - -あなたのIDがSSH-Agentに保存されている場合、エージェントが起動すればssh実行ファイルはそれを使用することができる。 -XPipeはエージェントプロセスがまだ起動していない場合、自動的に起動する。 - -VMホスト・システムにエージェントがセットアップされていない場合は、VMホストへのオリジナルのSSH接続に対してSSHエージェントのフォワーディングを有効にすることを推奨する。 -`ForwardAgent` オプションを有効にしてカスタムSSH接続を作成することでそれができる。 - -### GPG エージェント - -IDが例えばスマートカードに保存されている場合、`gpg-agent`を介してSSHクライアントにIDを提供することができる。 -このオプションは、まだ有効になっていない場合、エージェントのSSHサポートを自動的に有効にし、正しい設定でGPGエージェントデーモンを再起動する。 - -### Yubikey PIV - -IDがYubikeyのPIVスマートカード機能で保存されている場合、YubicoのYubikey PIVを使用してIDを取得できる。 -Yubico PIV ToolにバンドルされているYubicoのYKCS11ライブラリを使用する。 - -この機能を使うには、OpenSSHの最新ビルドが必要であることに注意。 - -### カスタム PKCS#11 ライブラリ - -これは OpenSSH クライアントに、指定した共有ライブラリファイルを読み込むように指示する。 - -この機能を使うには、最新の OpenSSH が必要であることに注意。 - -### ページェント(Windows) - -Windows で pageant を使用する場合、XPipe はまず pageant が起動しているかどうかを確認する。 -ページャントの性質上、ページャントが実行されているかどうかはユーザーの責任である。 -ページェントが実行されている場合、XPipeは最初にページェントが実行されているかどうかを確認する。 -ページェントが実行されていれば、XPipeは適切な名前のパイプを -`-oIdentityAgent=...`経由で適切な名前のパイプをsshに渡す。 - -### Pageant (Linux & macOS) - -IDがページェントエージェントに保存されている場合、エージェントが起動すればssh実行ファイルはIDを使用できる。 -XPipeは、エージェントプロセスがまだ実行されていない場合、自動的に開始する。 - -### その他の外部ソース - -このオプションは、外部で実行中の ID プロバイダが SSH クライアントに鍵を提供することを許可する。SSH鍵の管理に他のエージェントやパスワードマネージャを使用している場合は、このオプションを使用する必要がある。 diff --git a/lang/proc/texts/sshKeyVm_nl.md b/lang/proc/texts/sshKeyVm_nl.md deleted file mode 100644 index 82ecf1112..000000000 --- a/lang/proc/texts/sshKeyVm_nl.md +++ /dev/null @@ -1,63 +0,0 @@ -# VM SSH-identiteiten - -Als je VM gastgebruiker sleutelgebaseerde authenticatie vereist voor SSH, dan kun je dat hier inschakelen. - -Merk op dat er wordt aangenomen dat je VM niet openbaar is, dus het VM hostsysteem wordt gebruikt als een SSH gateway. -Als gevolg hiervan wordt elke identiteitsoptie gespecificeerd met betrekking tot het VM hostsysteem en niet je lokale machine. -Elke sleutel die je hier opgeeft, wordt geïnterpreteerd als een bestand op de VM-host. -Als je een agent gebruikt, wordt verwacht dat de agent draait op het VM host systeem en niet op je lokale machine. - -### Geen - -Als deze optie is geselecteerd, levert XPipe geen identiteiten. Hiermee worden ook externe bronnen zoals agents uitgeschakeld. - -### Identiteitsbestand - -Je kunt ook een identiteitsbestand opgeven met een optionele wachtwoordzin. -Deze optie is het equivalent van `ssh -i `. - -Merk op dat dit de *private* sleutel moet zijn, niet de publieke. -Als je dat verwisselt, zal ssh je alleen maar cryptische foutmeldingen geven. - -### SSH-agent - -Als je identiteiten zijn opgeslagen in de SSH-Agent, kan de ssh executable deze gebruiken als de agent wordt gestart. -XPipe zal automatisch het agent proces starten als het nog niet draait. - -Als je de agent niet hebt ingesteld op het VM-hostsysteem, wordt aanbevolen om SSH-agent doorsturen in te schakelen voor de oorspronkelijke SSH-verbinding naar de VM-host. -Je kunt dat doen door een aangepaste SSH-verbinding te maken met de optie `ForwardAgent` ingeschakeld. - -### GPG-agent - -Als je identiteiten bijvoorbeeld zijn opgeslagen op een smartcard, kun je ervoor kiezen om deze aan de SSH-client te verstrekken via de `gpg-agent`. -Deze optie zal automatisch SSH-ondersteuning van de agent inschakelen als deze nog niet is ingeschakeld en de GPG-agent daemon herstarten met de juiste instellingen. - -### Yubikey PIV - -Als je identiteiten zijn opgeslagen met de PIV smartcardfunctie van de Yubikey, dan kun je ze ophalen -ophalen met Yubico's YKCS11 bibliotheek, die wordt meegeleverd met Yubico PIV Tool. - -Merk op dat je een up-to-date build van OpenSSH nodig hebt om deze functie te kunnen gebruiken. - -### Aangepaste PKCS#11 bibliotheek - -Dit zal de OpenSSH client instrueren om het gespecificeerde shared library bestand te laden, dat de authenticatie zal afhandelen. - -Merk op dat je een actuele build van OpenSSH nodig hebt om deze functie te gebruiken. - -### Pageant (Windows) - -Als je pageant op Windows gebruikt, zal XPipe eerst controleren of pageant draait. -Vanwege de aard van pageant, is het jouw verantwoordelijkheid om het -actief is, omdat je elke keer handmatig alle sleutels moet opgeven die je wilt toevoegen. -Als het draait, geeft XPipe de juiste pipe door via -`-oIdentityAgent=...` naar ssh, je hoeft geen aangepaste configuratiebestanden op te nemen. - -### Pageant (Linux & macOS) - -Als je identiteiten zijn opgeslagen in de pageant agent, kan de ssh executable ze gebruiken als de agent wordt gestart. -XPipe zal automatisch het agent proces starten als het nog niet draait. - -### Andere externe bron - -Met deze optie kan elke externe identiteitsaanbieder zijn sleutels aan de SSH-client leveren. Je moet deze optie gebruiken als je een andere agent of wachtwoordmanager gebruikt om je SSH-sleutels te beheren. diff --git a/lang/proc/texts/sshKeyVm_pt.md b/lang/proc/texts/sshKeyVm_pt.md deleted file mode 100644 index da6c0c226..000000000 --- a/lang/proc/texts/sshKeyVm_pt.md +++ /dev/null @@ -1,63 +0,0 @@ -# Identidades VM SSH - -Se o usuário convidado da VM exigir autenticação baseada em chave para SSH, você pode ativar isso aqui. - -Observe que é assumido que sua VM não está exposta ao público, portanto, o sistema host da VM é usado como um gateway SSH. -Como resultado, qualquer opção de identidade é especificada em relação ao sistema host da VM e não à sua máquina local. -Qualquer chave que especifiques aqui é interpretada como um ficheiro no anfitrião da VM. -Se estiveres a utilizar qualquer agente, espera-se que o agente esteja a ser executado no sistema anfitrião da VM e não na tua máquina local. - -### Não tens nada - -Se selecionado, o XPipe não fornecerá quaisquer identidades. Isto também desactiva quaisquer fontes externas como agentes. - -### Ficheiro de identidade - -Podes também especificar um ficheiro de identidade com uma frase-chave opcional. -Esta opção é o equivalente a `ssh -i `. - -Nota que esta deve ser a chave *privada*, não a pública. -Se misturares isso, o ssh apenas te dará mensagens de erro crípticas. - -### Agente SSH - -Caso as tuas identidades estejam armazenadas no SSH-Agent, o executável ssh pode usá-las se o agente for iniciado. -O XPipe iniciará automaticamente o processo do agente se ele ainda não estiver em execução. - -Se não tiveres o agente configurado no sistema anfitrião da VM, recomenda-se que actives o encaminhamento do agente SSH para a ligação SSH original ao anfitrião da VM. -Podes fazer isso criando uma conexão SSH personalizada com a opção `ForwardAgent` ativada. - -### Agente GPG - -Se as tuas identidades estão armazenadas, por exemplo, num smartcard, podes optar por fornecê-las ao cliente SSH através do `gpg-agent`. -Esta opção habilitará automaticamente o suporte SSH do agente se ainda não estiver habilitado e reiniciará o daemon do agente GPG com as configurações corretas. - -### Yubikey PIV - -Se as tuas identidades estão armazenadas com a função de cartão inteligente PIV do Yubikey, podes recuperá-las -podes recuperá-las com a biblioteca YKCS11 do Yubico, que vem junto com a ferramenta Yubico PIV. - -Nota que necessita de uma versão actualizada do OpenSSH para poder utilizar esta função. - -### Biblioteca PKCS#11 personalizada - -Isso instruirá o cliente OpenSSH a carregar o arquivo de biblioteca compartilhada especificado, que lidará com a autenticação. - -Nota que precisas de uma versão actualizada do OpenSSH para usar esta funcionalidade. - -### Pageant (Windows) - -Caso estejas a usar o pageant no Windows, o XPipe irá verificar se o pageant está a ser executado primeiro. -Devido à natureza do pageant, é da tua responsabilidade tê-lo -a responsabilidade de o ter em execução, uma vez que tens de especificar manualmente todas as chaves que gostarias de adicionar de cada vez. -Se estiver em execução, o XPipe passará o pipe nomeado apropriado via -`-oIdentityAgent=...` para o ssh, não tens de incluir quaisquer ficheiros de configuração personalizados. - -### Pageant (Linux & macOS) - -Caso as tuas identidades estejam armazenadas no agente pageant, o executável ssh pode usá-las se o agente for iniciado. -O XPipe iniciará automaticamente o processo do agente se ele ainda não estiver em execução. - -### Outra fonte externa - -Esta opção permitirá que qualquer provedor de identidade externo em execução forneça suas chaves para o cliente SSH. Deves utilizar esta opção se estiveres a utilizar qualquer outro agente ou gestor de palavras-passe para gerir as tuas chaves SSH. diff --git a/lang/proc/texts/sshKeyVm_ru.md b/lang/proc/texts/sshKeyVm_ru.md deleted file mode 100644 index 0704badd4..000000000 --- a/lang/proc/texts/sshKeyVm_ru.md +++ /dev/null @@ -1,63 +0,0 @@ -# VM SSH identities - -Если гостевой пользователь твоей VM требует аутентификации на основе ключей для SSH, ты можешь включить эту опцию здесь. - -Обрати внимание, что предполагается, что твоя ВМ не открыта для публичного доступа, поэтому хост-система ВМ используется в качестве SSH-шлюза. -В результате любая опция идентификации указывается относительно хост-системы ВМ, а не твоей локальной машины. -Любой ключ, который ты указываешь здесь, интерпретируется как файл на хосте ВМ. -Если ты используешь какой-либо агент, предполагается, что он запущен на хост-системе ВМ, а не на твоей локальной машине. - -### None - -Если выбрано это значение, XPipe не будет предоставлять никаких идентификаторов. Это также отключает любые внешние источники, такие как агенты. - -### Файл идентификации - -Ты также можешь указать файл идентификации с необязательной парольной фразой. -Эта опция эквивалентна `ssh -i `. - -Обрати внимание, что это должен быть *приватный* ключ, а не открытый. -Если ты перепутаешь их, ssh будет выдавать тебе только загадочные сообщения об ошибках. - -### SSH-Agent - -В случае если твои идентификаторы хранятся в SSH-агенте, исполняемый файл ssh сможет использовать их, если агент будет запущен. -XPipe автоматически запустит процесс агента, если он еще не запущен. - -Если у тебя не установлен агент на хост-системе ВМ, рекомендуется включить переадресацию SSH-агента для исходного SSH-соединения с хостом ВМ. -Это можно сделать, создав пользовательское SSH-соединение с включенной опцией `ForwardAgent`. - -### GPG Agent - -Если твои идентификационные данные хранятся, например, на смарт-карте, ты можешь предоставить их SSH-клиенту через `gpg-agent`. -Эта опция автоматически включит поддержку SSH агентом, если она еще не включена, и перезапустит демон GPG-агента с правильными настройками. - -### Yubikey PIV - -Если твои личные данные хранятся в смарт-карте PIV, встроенной в Yubikey, ты можешь получить их -их с помощью библиотеки YKCS11 от Yubico, которая поставляется в комплекте с Yubico PIV Tool. - -Обрати внимание, что для использования этой функции тебе нужна актуальная сборка OpenSSH. - -### Пользовательская библиотека PKCS#11 - -Это даст указание клиенту OpenSSH загрузить указанный файл общей библиотеки, который будет обрабатывать аутентификацию. - -Обрати внимание, что для использования этой функции тебе нужна актуальная сборка OpenSSH. - -### Pageant (Windows) - -Если ты используешь pageant под Windows, XPipe сначала проверит, запущен ли pageant. -Из-за особенностей работы pageant ты должен убедиться в том, что она запущена -так как тебе придется каждый раз вручную указывать все ключи, которые ты хочешь добавить. -Если он запущен, XPipe передаст соответствующую именованную трубу через -`-oIdentityAgent=...` к ssh, тебе не придется включать какие-либо пользовательские файлы конфигурации. - -### Pageant (Linux & macOS) - -Если твои идентификаторы хранятся в агенте Pageant, то исполняемый файл ssh сможет их использовать, если агент будет запущен. -XPipe автоматически запустит процесс агента, если он еще не запущен. - -### Другой внешний источник - -Эта опция позволит любому внешнему провайдеру идентификации предоставлять свои ключи SSH-клиенту. Тебе следует использовать эту опцию, если ты используешь любой другой агент или менеджер паролей для управления ключами SSH. diff --git a/lang/proc/texts/sshKeyVm_tr.md b/lang/proc/texts/sshKeyVm_tr.md deleted file mode 100644 index 7a33f9148..000000000 --- a/lang/proc/texts/sshKeyVm_tr.md +++ /dev/null @@ -1,63 +0,0 @@ -# VM SSH kimlikleri - -VM konuk kullanıcınız SSH için anahtar tabanlı kimlik doğrulama gerektiriyorsa, bunu buradan etkinleştirebilirsiniz. - -Sanal makinenizin herkese açık olmadığının varsayıldığını, bu nedenle sanal makine ana sisteminin bir SSH ağ geçidi olarak kullanıldığını unutmayın. -Sonuç olarak, herhangi bir kimlik seçeneği yerel makinenize göre değil, VM ana bilgisayar sistemine göre belirtilir. -Burada belirttiğiniz herhangi bir anahtar, VM ana bilgisayarında bir dosya olarak yorumlanır. -Herhangi bir aracı kullanıyorsanız, aracının yerel makinenizde değil VM ana bilgisayar sisteminde çalışıyor olması beklenir. - -### Yok - -Eğer seçilirse, XPipe herhangi bir kimlik sağlamayacaktır. Bu aynı zamanda aracılar gibi harici kaynakları da devre dışı bırakır. - -### Kimlik dosyası - -İsteğe bağlı bir parola ile bir kimlik dosyası da belirtebilirsiniz. -Bu seçenek `ssh -i ` seçeneğine eşdeğerdir. - -Bunun genel değil *özel* anahtar olması gerektiğini unutmayın. -Eğer bunu karıştırırsanız, ssh size sadece şifreli hata mesajları verecektir. - -### SSH-Agent - -Kimliklerinizin SSH-Agent'ta depolanması durumunda, ssh yürütülebilir dosyası, agent başlatıldığında bunları kullanabilir. -XPipe, henüz çalışmıyorsa aracı sürecini otomatik olarak başlatacaktır. - -Sanal makine ana bilgisayar sisteminde aracı kurulu değilse, sanal makine ana bilgisayarına orijinal SSH bağlantısı için SSH aracısı iletmeyi etkinleştirmeniz önerilir. -Bunu, `ForwardAgent` seçeneği etkinleştirilmiş özel bir SSH bağlantısı oluşturarak yapabilirsiniz. - -### GPG Agent - -Kimlikleriniz örneğin bir akıllı kartta saklanıyorsa, bunları SSH istemcisine `gpg-agent` aracılığıyla sağlamayı seçebilirsiniz. -Bu seçenek, henüz etkinleştirilmemişse aracının SSH desteğini otomatik olarak etkinleştirecek ve GPG aracı arka plan programını doğru ayarlarla yeniden başlatacaktır. - -### Yubikey PIV - -Kimlikleriniz Yubikey'in PIV akıllı kart işlevi ile saklanıyorsa, şunları geri alabilirsiniz -yubico PIV Aracı ile birlikte gelen Yubico'nun YKCS11 kütüphanesi ile. - -Bu özelliği kullanabilmek için güncel bir OpenSSH yapısına ihtiyacınız olduğunu unutmayın. - -### Özel PKCS#11 kütüphanesi - -Bu, OpenSSH istemcisine kimlik doğrulamasını gerçekleştirecek olan belirtilen paylaşılan kütüphane dosyasını yüklemesi talimatını verecektir. - -Bu özelliği kullanabilmek için güncel bir OpenSSH yapısına ihtiyacınız olduğunu unutmayın. - -### Pageant (Windows) - -Windows üzerinde pageant kullanıyorsanız, XPipe önce pageant'ın çalışıp çalışmadığını kontrol edecektir. -Pageant'ın doğası gereği, pageant'a sahip olmak sizin sorumluluğunuzdadır -her seferinde eklemek istediğiniz tüm anahtarları manuel olarak belirtmeniz gerektiğinden çalışıyor. -Eğer çalışıyorsa, XPipe uygun adlandırılmış boruyu -`-oIdentityAgent=...` ssh için, herhangi bir özel yapılandırma dosyası eklemeniz gerekmez. - -### Pageant (Linux ve macOS) - -Kimliklerinizin pageant aracısında saklanması durumunda, aracı başlatılırsa ssh yürütülebilir dosyası bunları kullanabilir. -XPipe, henüz çalışmıyorsa aracı sürecini otomatik olarak başlatacaktır. - -### Diğer dış kaynak - -Bu seçenek, çalışan herhangi bir harici kimlik sağlayıcısının anahtarlarını SSH istemcisine sağlamasına izin verecektir. SSH anahtarlarınızı yönetmek için başka bir aracı veya parola yöneticisi kullanıyorsanız bu seçeneği kullanmalısınız. diff --git a/lang/proc/texts/sshKeyVm_zh.md b/lang/proc/texts/sshKeyVm_zh.md deleted file mode 100644 index 90b540746..000000000 --- a/lang/proc/texts/sshKeyVm_zh.md +++ /dev/null @@ -1,63 +0,0 @@ -# 虚拟机 SSH 身份 - -如果虚拟机访客用户需要基于密钥的 SSH 身份验证,可以在此处启用。 - -请注意,假定虚拟机不对外开放,因此虚拟机主机系统被用作 SSH 网关。 -因此,任何身份选项都是相对于虚拟机主机系统而非本地机器指定的。 -在此指定的任何密钥都会被解释为虚拟机主机上的文件。 -如果使用任何代理,则该代理应运行在虚拟机主机系统上,而不是本地计算机上。 - -### 无 - -如果选择该选项,XPipe 将不提供任何身份信息。这也会禁用代理等任何外部来源。 - -### 身份文件 - -您还可以指定一个带有可选口令的身份文件。 -该选项等同于 `ssh -i `. - -请注意,这应该是 *private* 密钥,而不是公钥。 -如果弄混了,ssh 只会给出令人费解的错误信息。 - -### SSH 代理 - -如果您的身份信息存储在 SSH-Agent 中,则 ssh 可执行文件可以在代理启动时使用这些身份信息。 -如果代理进程尚未运行,XPipe 会自动启动它。 - -如果您没有在虚拟机主机系统上设置代理,建议您为虚拟机主机的原始 SSH 连接启用 SSH 代理转发。 -为此,您可以创建一个自定义 SSH 连接,并启用 `ForwardAgent` 选项。 - -### GPG 代理 - -如果你的身份信息存储在智能卡等设备上,你可以选择通过 `gpg-agent` 将其提供给 SSH 客户端。 -如果尚未启用,该选项将自动启用代理的 SSH 支持,并以正确的设置重启 GPG 代理守护进程。 - -### Yubikey PIV - -如果你的身份信息存储在 Yubikey 的 PIV 智能卡功能中,你可以用 Yubico 的 Yubikey PIV 功能来恢复它们。 -Yubico PIV 工具捆绑的 YKCS11 库。 - -请注意,要使用这一功能,你需要最新的 OpenSSH 版本。 - -### 自定义 PKCS#11 库 - -这将指示 OpenSSH 客户端加载指定的共享库文件,以处理身份验证。 - -请注意,您需要最新版本的 OpenSSH 才能使用此功能。 - -### Pageant(Windows) - -如果您在 Windows 上使用 Pageant,XPipe 会首先检查 Pageant 是否正在运行。 -由于 Pageant 的性质,您有责任使其运行。 -因为您每次都必须手动指定要添加的所有密钥。 -如果正在运行,XPipe 将通过 -`-oIdentityAgent=...`传递给 ssh,您不必包含任何自定义配置文件。 - -### Pageant(Linux 和 macOS) - -如果您的身份信息存储在 pageant 代理中,则 ssh 可执行文件可以在代理启动时使用这些身份信息。 -如果代理进程尚未运行,XPipe 将自动启动该进程。 - -### 其他外部资源 - -该选项允许任何外部运行的身份供应商向 SSH 客户端提供密钥。如果使用其他代理或密码管理器管理 SSH 密钥,则应使用该选项。 diff --git a/version b/version index a1e7534db..7281c85cd 100644 --- a/version +++ b/version @@ -1 +1 @@ -12.3.5 +13.0-6