Merge branch 'spice' into pve-improvements

This commit is contained in:
crschnick
2026-01-14 19:39:33 +00:00
parent 40f89e9be8
commit f38cf43ef4
43 changed files with 517 additions and 70 deletions
@@ -3,6 +3,7 @@ package io.xpipe.app.comp;
import io.xpipe.app.comp.base.TooltipHelper;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.platform.PlatformThread;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.property.ReadOnlyObjectWrapper;
@@ -69,15 +70,15 @@ public class CompDescriptor {
getName() != null ? getName() : new ReadOnlyObjectWrapper<>(),
getDescription() != null ? getDescription() : new ReadOnlyObjectWrapper<>());
var tt = TooltipHelper.create(tooltipText);
var tt = TooltipHelper.create(PlatformThread.sync(tooltipText));
Tooltip.install(r, tt);
}
if (accessibleText != null) {
r.accessibleTextProperty().bind(getName());
r.accessibleTextProperty().bind(PlatformThread.sync(getName()));
}
if (getDescription() != null) {
r.accessibleHelpProperty().bind(getDescription());
r.accessibleHelpProperty().bind(PlatformThread.sync(getDescription()));
}
if (getFocusTraversal() != null) {
switch (getFocusTraversal()) {
@@ -96,7 +96,7 @@ public class OptionsComp extends Comp<CompStructure<VBox>> {
if (entry.description() != null) {
var description = new Label();
description.wrapTextProperty().bind(pane.visibleProperty());
description.setWrapText(true);
description.getStyleClass().add("description");
description.textProperty().bind(entry.description());
description.setAlignment(Pos.CENTER_LEFT);
@@ -4,6 +4,8 @@ import io.xpipe.app.beacon.AppBeaconServer;
import io.xpipe.app.core.*;
import io.xpipe.app.core.check.AppDebugModeCheck;
import io.xpipe.app.core.window.AppMainWindow;
import io.xpipe.app.core.window.AppSideWindow;
import io.xpipe.app.core.window.AppWindowStyle;
import io.xpipe.app.issue.*;
import io.xpipe.app.platform.PlatformInit;
import io.xpipe.app.platform.PlatformState;
@@ -177,6 +179,11 @@ public abstract class AppOperationMode {
ThreadHelper.runAsync(() -> {
DataStorage.get().generateCaches();
});
// Ugly solution to only start tracking kb input after we are finished starting up
// Otherwise, any typed vault password will always make think that kb input is active
Platform.runLater(() -> {
AppWindowStyle.addNavigationPseudoClasses(AppMainWindow.get().getStage().getScene());
});
} catch (Throwable ex) {
ErrorEventFactory.fromThrowable(ex).term().handle();
}
@@ -105,7 +105,6 @@ public class AppMainWindow {
}
AppWindowStyle.addIcons(stage);
AppWindowStyle.addStylesheets(stage.getScene());
AppWindowStyle.addNavigationPseudoClasses(stage.getScene());
AppWindowStyle.addClickShield(stage);
AppWindowStyle.addMaximizedPseudoClass(stage);
AppWindowStyle.addFontSize(stage);
@@ -150,6 +150,7 @@ public enum PlatformState {
// Platform initialization has failed in this case
var msg = getErrorMessage(t.getMessage());
var ex = new UnsupportedOperationException(msg, t);
ErrorEventFactory.expected(ex);
PlatformState.setCurrent(PlatformState.EXITED);
lastError = ex;
return;
@@ -8,6 +8,7 @@ import javafx.beans.value.ObservableValue;
import javafx.collections.ListChangeListener;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.control.Labeled;
import javafx.stage.Window;
import java.util.HashSet;
@@ -96,6 +97,11 @@ public class PlatformThreadWatcher {
c.opacityProperty().addListener(listener);
c.accessibleHelpProperty().addListener(listener);
c.accessibleTextProperty().addListener(listener);
if (c instanceof Labeled l) {
l.textProperty().addListener(listener);
l.graphicProperty().addListener(listener);
}
} else {
c.visibleProperty().removeListener(listener);
c.boundsInParentProperty().removeListener(listener);
@@ -103,6 +109,11 @@ public class PlatformThreadWatcher {
c.opacityProperty().removeListener(listener);
c.accessibleHelpProperty().removeListener(listener);
c.accessibleTextProperty().removeListener(listener);
if (c instanceof Labeled l) {
l.textProperty().removeListener(listener);
l.graphicProperty().removeListener(listener);
}
}
});
});
@@ -13,6 +13,7 @@ import io.xpipe.app.process.ShellDialect;
import io.xpipe.app.process.ShellScript;
import io.xpipe.app.pwman.PasswordManager;
import io.xpipe.app.rdp.ExternalRdpClient;
import io.xpipe.app.spice.ExternalSpiceClient;
import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.storage.DataStorageUserHandler;
import io.xpipe.app.terminal.ExternalTerminalType;
@@ -243,6 +244,11 @@ public final class AppPrefs {
.valueClass(ExternalVncClient.class)
.documentationLink(DocumentationLink.VNC)
.build());
public final Property<ExternalSpiceClient> spiceClient = map(Mapping.builder()
.property(new GlobalObjectProperty<>())
.key("spiceClient")
.valueClass(ExternalSpiceClient.class)
.build());
final Property<PasswordManager> passwordManager = map(Mapping.builder()
.property(new GlobalObjectProperty<>())
.key("passwordManager")
@@ -801,6 +807,7 @@ public final class AppPrefs {
externalEditor.setValue(ExternalEditorType.determineDefault(externalEditor.get()));
terminalType.set(ExternalTerminalType.determineDefault(terminalType.get()));
rdpClientType.setValue(ExternalRdpClient.determineDefault(rdpClientType.get()));
spiceClient.setValue(ExternalSpiceClient.determineDefault(spiceClient.getValue()));
PrefsProvider.getAll().forEach(prov -> prov.initDefaultValues());
}
@@ -22,11 +22,13 @@ import org.kordamp.ikonli.javafx.FontIcon;
import java.time.Duration;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
public class PasswordManagerTestComp extends SimpleComp {
private final StringProperty value;
private final boolean handleEnter;
private final AtomicInteger counter = new AtomicInteger(0);
public PasswordManagerTestComp(StringProperty value, boolean handleEnter) {
this.value = value;
@@ -85,6 +87,7 @@ public class PasswordManagerTestComp extends SimpleComp {
}
private void testPasswordManager(String key, StringProperty testPasswordManagerResult) {
var currentIndex = counter.incrementAndGet();
var prefs = AppPrefs.get();
ThreadHelper.runFailableAsync(() -> {
if (prefs.passwordManager.getValue() == null || key == null) {
@@ -111,7 +114,9 @@ public class PasswordManagerTestComp extends SimpleComp {
GlobalTimer.delay(
() -> {
Platform.runLater(() -> {
testPasswordManagerResult.set(null);
if (counter.get() == currentIndex) {
testPasswordManagerResult.set(null);
}
});
},
Duration.ofSeconds(5));
@@ -1,26 +1,50 @@
package io.xpipe.app.pwman;
import io.xpipe.app.comp.base.ButtonComp;
import io.xpipe.app.comp.base.ListBoxViewComp;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.ext.ProcessControlProvider;
import io.xpipe.app.issue.ErrorEventFactory;
import io.xpipe.app.platform.DerivedObservableList;
import io.xpipe.app.platform.OptionsBuilder;
import io.xpipe.app.process.*;
import io.xpipe.app.secret.SecretManager;
import io.xpipe.app.secret.SecretPromptStrategy;
import io.xpipe.app.secret.SecretQueryState;
import io.xpipe.app.terminal.TerminalLaunch;
import io.xpipe.core.InPlaceSecretValue;
import io.xpipe.core.JacksonMapper;
import io.xpipe.core.OsType;
import io.xpipe.app.util.AskpassAlert;
import io.xpipe.app.util.ThreadHelper;
import io.xpipe.core.*;
import com.fasterxml.jackson.annotation.JsonTypeName;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import lombok.Builder;
import lombok.Getter;
import lombok.ToString;
import lombok.extern.jackson.Jacksonized;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.List;
import java.util.UUID;
@JsonTypeName("keeper")
@Getter
@Builder(toBuilder = true)
@ToString
@Jacksonized
public class KeeperPasswordManager implements PasswordManager {
private static final UUID KEEPER_PASSWORD_ID = UUID.randomUUID();
private static ShellControl SHELL;
private final Boolean mfa;
private static synchronized ShellControl getOrStartShell() throws Exception {
if (SHELL == null) {
@@ -31,18 +55,29 @@ public class KeeperPasswordManager implements PasswordManager {
}
private String getExecutable(ShellControl sc) {
return sc.getShellDialect() == ShellDialects.CMD
? "@keeper"
: (OsType.ofLocal() == OsType.WINDOWS ? "keeper-commander" : "keeper");
return OsType.ofLocal() == OsType.WINDOWS ? "keeper-commander" : "keeper";
}
@SuppressWarnings("unused")
public static OptionsBuilder createOptions(Property<KeeperPasswordManager> p) {
var mfa = new SimpleObjectProperty<>(p.getValue().getMfa());
return new OptionsBuilder()
.nameAndDescription("keeperUseMfa")
.addToggle(mfa)
.bind(
() -> {
return KeeperPasswordManager.builder().mfa(mfa.get()).build();
},
p);
}
@Override
public synchronized CredentialResult retrieveCredentials(String key) {
// The copy UID button copies the whole URL in the Keeper UI. Why? ...
key = key.replaceFirst("https://keepersecurity\\.\\w+/vault/#detail/", "");
key = key.replaceFirst("https://\\w+\\.\\w+/vault/#detail/", "");
try {
CommandSupport.isInLocalPathOrThrow("Keeper Commander CLI", "keeper");
CommandSupport.isInLocalPathOrThrow("Keeper Commander CLI", "keeper-commander");
} catch (Exception e) {
ErrorEventFactory.fromThrowable(e)
.link("https://docs.keeper.io/en/keeperpam/commander-cli/commander-installation-setup")
@@ -52,8 +87,8 @@ public class KeeperPasswordManager implements PasswordManager {
try {
var sc = getOrStartShell();
var file = sc.view().userHome().join(".keeper", "config.json");
if (!sc.view().fileExists(file)) {
var config = sc.view().userHome().join(".keeper", "config.json");
if (!sc.view().fileExists(config)) {
var script = ShellScript.lines(
sc.getShellDialect().getEchoCommand("Log in into your Keeper account from the CLI:", false),
getExecutable(sc) + " login");
@@ -76,19 +111,97 @@ public class KeeperPasswordManager implements PasswordManager {
return null;
}
var out = sc.command(CommandBuilder.of()
.add(getExecutable(sc), "get")
.addLiteral(key)
.add("--format", "json", "--unmask")
.add("--password")
.addLiteral(r.getSecretValue()))
.sensitive()
.readStdoutOrThrow();
if (r.getSecretValue().contains("\"")) {
SecretManager.clearAll(KEEPER_PASSWORD_ID);
throw ErrorEventFactory.expected(new IllegalArgumentException("Keeper password contains double quote \" character, which is not supported by the Keeper Commander application"));
}
var b = CommandBuilder.of()
.add(getExecutable(sc), "get")
.addLiteral(key)
.add("--format", "json", "--unmask")
.add("--password")
.addLiteral(r.getSecretValue());
FilePath file = null;
CommandBuilder fullB;
if (mfa != null && mfa) {
var totp = AskpassAlert.queryRaw("Enter Keeper 2FA Code", null, true);
if (totp.getState() != SecretQueryState.NORMAL) {
return null;
}
var input = """
1
%s
""".formatted(totp.getSecret().getSecretValue());
file = sc.getSystemTemporaryDirectory().join("keeper.txt");
sc.view().writeTextFile(file, input);
fullB = CommandBuilder.of().add(sc.getShellDialect() == ShellDialects.CMD ? "type" : "cat").addFile(file).add("|").add(b);
} else {
fullB = b;
}
var queryCommand = sc.command(fullB);
queryCommand.sensitive();
queryCommand.killOnTimeout(CountDown.of().start(15_000));
var result = queryCommand.readStdoutAndStderr();
var exitCode = queryCommand.getExitCode();
if (file != null) {
sc.view().deleteFileIfPossible(file);
}
var out = result[0].replace("\r\n", "\n").replace("""
Selection: Invalid entry, additional factors of authentication shown may be configured if not currently enabled.
Selection:\s
2FA Code Duration: Require Every Login.
To change duration: 2fa_duration=login|12_hours|24_hours|30_days|forever
""", "")
.replace("""
This account requires 2FA Authentication
1. TOTP (Google and Microsoft Authenticator) \s
q. Quit login attempt and return to Commander prompt
""", "")
.replace("Selection:", "")
.strip();
var err = result[1].replace("\r\n", "\n")
.replace("""
EOF when reading a line
""", "")
.strip();
var jsonStart = out.indexOf("{\n");
var jsonEnd = out.indexOf("\n}");
if (jsonEnd != -1) {
jsonEnd += 2;
}
var outPrefix = jsonStart <= 0 ? out : out.substring(0, jsonStart + 1);
var outJson = jsonStart <= 0 ? (jsonEnd != -1 ? out.substring(0, jsonEnd) : out) :
(jsonEnd != -1 ? out.substring(jsonStart, jsonEnd) : out.substring(jsonStart));
if (exitCode != 0) {
var wrongPw = outPrefix.contains("Enter password for");
if (wrongPw) {
SecretManager.clearAll(KEEPER_PASSWORD_ID);
ErrorEventFactory.fromMessage("Master password was not accepted by Keeper. Is it correct?").expected().handle();
return null;
}
var message = !err.isEmpty() ? outPrefix + "\n" + err : outPrefix;
ErrorEventFactory.fromMessage(message).expected().handle();
return null;
}
JsonNode tree;
try {
tree = JacksonMapper.getDefault().readTree(out);
tree = JacksonMapper.getDefault().readTree(outJson);
} catch (JsonProcessingException e) {
ErrorEventFactory.fromMessage(out).expected().handle();
var message = !err.isEmpty() ? outPrefix + "\n" + err : outPrefix;
ErrorEventFactory.fromMessage(message).expected().handle();
return null;
}
@@ -105,7 +105,7 @@ public class SecretPasswordManagerStrategy implements SecretRetrievalStrategy {
@Override
public Duration cacheDuration() {
// To reduce password manager access, cache it for a few seconds
return Duration.ofSeconds(10);
return Duration.ofSeconds(15);
}
@Override
@@ -0,0 +1,54 @@
package io.xpipe.app.spice;
import com.fasterxml.jackson.annotation.JsonTypeName;
import io.xpipe.app.comp.base.TextFieldComp;
import io.xpipe.app.platform.OptionsBuilder;
import io.xpipe.app.prefs.ExternalApplicationHelper;
import io.xpipe.app.process.CommandBuilder;
import io.xpipe.app.vnc.ExternalVncClient;
import io.xpipe.app.vnc.VncLaunchConfig;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleObjectProperty;
import lombok.Builder;
import lombok.Value;
import lombok.extern.jackson.Jacksonized;
import java.util.Locale;
@JsonTypeName("custom")
@Value
@Jacksonized
@Builder
public class CustomSpiceClient implements ExternalSpiceClient {
String command;
@SuppressWarnings("unused")
static OptionsBuilder createOptions(Property<CustomSpiceClient> property) {
var command = new SimpleObjectProperty<>(property.getValue().getCommand());
return new OptionsBuilder()
.nameAndDescription("customSpiceCommand")
.addComp(
new TextFieldComp(command, false)
.apply(struc -> struc.get().setPromptText("myspiceClient $FILE"))
.maxWidth(600),
command)
.bind(() -> CustomSpiceClient.builder().command(command.get()).build(), property);
}
@Override
public void launch(SpiceLaunchConfig configuration) throws Exception {
if (command == null) {
return;
}
var format = command.toLowerCase(Locale.ROOT).contains("$file") ? command : command + " $FILE";
var toExecute = ExternalApplicationHelper.replaceVariableArgument(format, "ADDRESS", configuration.getFile().toString());
ExternalApplicationHelper.startAsync(CommandBuilder.of().add(toExecute));
}
@Override
public String getWebsite() {
return null;
}
}
@@ -0,0 +1,65 @@
package io.xpipe.app.spice;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import io.xpipe.app.ext.PrefsValue;
import io.xpipe.app.platform.ClipboardHelper;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.rdp.*;
import io.xpipe.app.vnc.*;
import io.xpipe.core.OsType;
import java.util.ArrayList;
import java.util.List;
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
public interface ExternalSpiceClient extends PrefsValue {
static ExternalSpiceClient determineDefault(ExternalSpiceClient existing) {
// Verify that our selection is still valid
if (existing != null && existing.isAvailable()) {
return existing;
}
return switch (OsType.ofLocal()) {
case OsType.Linux ignored -> {
yield new VirtViewerSpiceClient.Linux();
}
case OsType.MacOs ignored -> {
yield new VirtViewerSpiceClient.MacOs();
}
case OsType.Windows ignored -> {
yield new VirtViewerSpiceClient.Windows();
}
};
}
static void launchClient(SpiceLaunchConfig configuration) throws Exception {
var client = AppPrefs.get().spiceClient.getValue();
if (client == null) {
return;
}
client.launch(configuration);
}
static List<Class<?>> getClasses() {
var l = new ArrayList<Class<?>>();
switch (OsType.ofLocal()) {
case OsType.Linux ignored -> {
l.add(VirtViewerSpiceClient.Linux.class);
}
case OsType.MacOs ignored -> {
l.add(VirtViewerSpiceClient.MacOs.class);
}
case OsType.Windows ignored -> {
l.add(VirtViewerSpiceClient.Windows.class);
}
}
l.add(CustomSpiceClient.class);
return l;
}
void launch(SpiceLaunchConfig configuration) throws Exception;
String getWebsite();
}
@@ -0,0 +1,18 @@
package io.xpipe.app.spice;
import io.xpipe.app.process.ShellControl;
import io.xpipe.app.secret.SecretManager;
import io.xpipe.app.storage.DataStoreEntryRef;
import io.xpipe.app.vnc.VncBaseStore;
import io.xpipe.core.SecretValue;
import lombok.Value;
import java.nio.file.Path;
import java.util.Optional;
@Value
public class SpiceLaunchConfig {
DataStoreEntryRef entry;
Path file;
}
@@ -0,0 +1,117 @@
package io.xpipe.app.spice;
import com.fasterxml.jackson.annotation.JsonTypeName;
import io.xpipe.app.core.AppSystemInfo;
import io.xpipe.app.issue.ErrorEventFactory;
import io.xpipe.app.prefs.ExternalApplicationType;
import io.xpipe.app.process.CommandBuilder;
import io.xpipe.app.process.LocalShell;
import io.xpipe.app.vnc.ExternalVncClient;
import io.xpipe.app.vnc.VncLaunchConfig;
import lombok.Builder;
import lombok.extern.jackson.Jacksonized;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Optional;
public abstract class VirtViewerSpiceClient implements ExternalSpiceClient {
protected CommandBuilder createBuilder(SpiceLaunchConfig configuration) {
var builder = CommandBuilder.of().addFile(configuration.getFile());
return builder;
}
@Override
public String getWebsite() {
return "https://virt-manager.org";
}
@Builder
@Jacksonized
@JsonTypeName("virtViewer")
public static class Windows extends VirtViewerSpiceClient implements ExternalApplicationType.WindowsType {
@Override
public boolean detach() {
return false;
}
@Override
public String getExecutable() {
return "virt-viewer.exe";
}
@Override
public Optional<Path> determineInstallation() {
try (var stream = Files.list(AppSystemInfo.ofWindows().getProgramFiles())) {
var l = stream.toList();
var found = l.stream().filter(path -> path.toString().contains("VirtViewer")).findFirst();
if (found.isEmpty()) {
return Optional.empty();
}
return Optional.ofNullable(found.get().resolve("bin", "virt-viewer.exe"));
} catch (IOException e) {
ErrorEventFactory.fromThrowable(e).handle();
return Optional.empty();
}
}
@Override
public void launch(SpiceLaunchConfig configuration) throws Exception {
var builder = createBuilder(configuration);
launch(builder);
}
}
@Builder
@Jacksonized
@JsonTypeName("virtViewer")
public static class Linux extends VirtViewerSpiceClient implements ExternalApplicationType.LinuxApplication {
@Override
public void launch(SpiceLaunchConfig configuration) throws Exception {
var builder = createBuilder(configuration);
launch(builder);
}
@Override
public String getExecutable() {
return "remote-viewer";
}
@Override
public boolean detach() {
return true;
}
@Override
public String getFlatpakId() {
return "org.virt_manager.virt-viewer";
}
}
@Builder
@Jacksonized
@JsonTypeName("virtViewer")
public static class MacOs extends VirtViewerSpiceClient implements ExternalApplicationType.PathApplication {
@Override
public void launch(SpiceLaunchConfig configuration) throws Exception {
var builder = createBuilder(configuration);
launch(builder);
}
@Override
public String getExecutable() {
return "remote-viewer";
}
@Override
public boolean detach() {
return true;
}
}
}
@@ -9,6 +9,7 @@ import io.xpipe.app.pwman.KeePassXcPasswordManager;
import io.xpipe.app.pwman.PasswordManager;
import io.xpipe.app.rdp.ExternalRdpClient;
import io.xpipe.app.secret.*;
import io.xpipe.app.spice.ExternalSpiceClient;
import io.xpipe.app.storage.*;
import io.xpipe.app.terminal.ExternalTerminalType;
import io.xpipe.app.terminal.TerminalMultiplexer;
@@ -83,6 +84,7 @@ public class AppJacksonModule extends SimpleModule {
context.registerSubtypes(TerminalPrompt.getClasses());
context.registerSubtypes(ExternalVncClient.getClasses());
context.registerSubtypes(ExternalRdpClient.getClasses());
context.registerSubtypes(ExternalSpiceClient.getClasses());
context.registerSubtypes(SecretRetrievalStrategy.getClasses());
context.registerSubtypes(DataStorageGroupStrategy.getClasses());
@@ -29,6 +29,8 @@ public enum DocumentationLink {
KUBERNETES("guide/kubernetes"),
DOCKER("guide/docker"),
PROXMOX("guide/proxmox"),
PROXMOX_GUEST_AGENT("guide/proxmox#guest-agent"),
PROXMOX_NETWORKING("guide/proxmox#networking"),
TAILSCALE("guide/tailscale"),
TAILSCALE_AUTH("guide/tailscale#tailscale-authentication"),
IDENTITY_APPLY("guide/ssh#applying-identities"),
@@ -40,8 +42,11 @@ public enum DocumentationLink {
PODMAN("guide/podman"),
KVM("guide/kvm"),
KVM_VNC("guide/kvm#vnc-access"),
KVM_GUEST_AGENT("guide/kvm#guest-agent"),
KVM_NETWORKING("guide/kvm#networking"),
HCLOUD("guide/hcloud"),
VMWARE("guide/vmware"),
VMWARE_NETWORKING("guide/vmware#networking"),
AWS("guide/aws"),
AWS_PROFILES("guide/aws#profiles"),
AWS_EC2("guide/aws#ec2-instances"),
@@ -78,6 +83,7 @@ public enum DocumentationLink {
TUNNELS_REMOTE("guide/ssh#remote-tunnels"),
TUNNELS_DYNAMIC("guide/ssh#dynamic-tunnels"),
HYPERV("guide/hyperv"),
HYPERV_NETWORKING("guide/hyperv#custom-networking"),
SSH_MACS("troubleshoot/ssh#no-matching-mac-found"),
SSH_FEATURE_NOT_SUPPORTED("troubleshoot/ssh#requested-feature-not-supported"),
SSH_JUMP_SERVERS("guide/ssh#gateways-and-jump-servers"),
+1
View File
@@ -0,0 +1 @@
- Fix powershell runnable scripts with named parameters failing to execute
@@ -24,7 +24,7 @@ public class RunBackgroundScriptActionProvider implements ActionProvider {
@Override
public void executeImpl() throws Exception {
var sc = ref.getStore().getOrStartSession();
var script = scriptStore.getStore().assembleScriptChain(sc);
var script = scriptStore.getStore().assembleScriptChain(sc, false);
if (script != null) {
sc.command(script).execute();
}
@@ -139,7 +139,7 @@ public class RunFileScriptMenuProvider implements BrowserMenuBranchProvider {
@Override
protected List<CommandBuilder> createCommand(BrowserFileSystemTabModel model, List<BrowserEntry> entries) {
var sc = model.getFileSystem().getShell().orElseThrow();
var content = ref.getStore().assembleScriptChain(sc);
var content = ref.getStore().assembleScriptChain(sc, true);
var script = ScriptHelper.createExecScript(sc, content);
var builder = CommandBuilder.of().add(sc.getShellDialect().runScriptCommand(sc, script.toString()));
for (BrowserEntry entry : entries) {
@@ -30,7 +30,7 @@ public class RunHubBatchScriptActionProvider implements ActionProvider {
var map = new LinkedHashMap<String, CommandControl>();
for (DataStoreEntryRef<ShellStore> ref : refs) {
var sc = ref.getStore().getOrStartSession();
var script = scriptStore.getStore().assembleScriptChain(sc);
var script = scriptStore.getStore().assembleScriptChain(sc, false);
var cmd = sc.command(script);
map.put(ref.get().getName(), cmd);
}
@@ -25,7 +25,7 @@ public class RunHubScriptActionProvider implements ActionProvider {
@Override
public void executeImpl() throws Exception {
var sc = ref.getStore().getOrStartSession();
var script = scriptStore.getStore().assembleScriptChain(sc);
var script = scriptStore.getStore().assembleScriptChain(sc, false);
var cmd = sc.command(script);
CommandDialog.runAndShow(cmd);
}
@@ -25,7 +25,7 @@ public class RunTerminalScriptActionProvider implements ActionProvider {
@Override
public void executeImpl() throws Exception {
var sc = ref.getStore().getOrStartSession();
var script = scriptStore.getStore().assembleScriptChain(sc);
var script = scriptStore.getStore().assembleScriptChain(sc, false);
TerminalLaunch.builder()
.entry(ref.get())
.title(scriptStore.get().getName())
@@ -56,7 +56,7 @@ public class ScriptStoreSetup {
new ShellTerminalInitCommand() {
@Override
public Optional<String> terminalContent(ShellControl shellControl) {
return Optional.ofNullable(s.getStore().assembleScriptChain(shellControl));
return Optional.ofNullable(s.getStore().assembleScriptChain(shellControl, false));
}
@Override
@@ -49,7 +49,7 @@ public class SimpleScriptStore extends ScriptStore implements SelfReferentialSto
return minimumDialect == null || minimumDialect.isCompatibleTo(dialect);
}
private String assembleScript(ShellControl shellControl) {
private String assembleScript(ShellControl shellControl, boolean args) {
if (isCompatible(shellControl)) {
var shebang = getCommands().startsWith("#");
// Fix new lines and shebang
@@ -60,18 +60,18 @@ public class SimpleScriptStore extends ScriptStore implements SelfReferentialSto
shellControl.getShellDialect().getNewLine().getNewLineString()));
var targetType = shellControl.getOriginalShellDialect();
var script = ScriptHelper.createExecScript(targetType, shellControl, fixedCommands);
return targetType.sourceScriptCommand(shellControl, script.toString()) + " "
+ targetType.getCatchAllVariable();
return targetType.sourceScriptCommand(shellControl, script.toString()) + (args ? " "
+ targetType.getCatchAllVariable() : "");
}
return null;
}
public String assembleScriptChain(ShellControl shellControl) {
public String assembleScriptChain(ShellControl shellControl, boolean args) {
var nl = shellControl.getShellDialect().getNewLine().getNewLineString();
var all = queryFlattenedScripts();
var r = all.stream()
.map(ref -> ref.getStore().assembleScript(shellControl))
.map(ref -> ref.getStore().assembleScript(shellControl, args))
.filter(s -> s != null)
.toList();
if (r.isEmpty()) {
+3 -1
View File
@@ -1129,7 +1129,7 @@ gitVaultOverwriteLocalContent=Vil du tilsidesætte dine lokale vault-ændringer?
rdpSimple.displayName=Direkte RDP-forbindelse
rdpSimple.displayDescription=Opret forbindelse til en vært via RDP
rdpUsername=Brugernavn
rdpUsernameDescription=Til brugeren for at logge ind som
rdpUsernameDescription=Den bruger, der skal logges ind som. Kan indeholde et domænepræfiks
addressDescription=Hvor skal man oprette forbindelse til
rdpAdditionalOptions=Yderligere RDP-muligheder
rdpAdditionalOptionsDescription=Rå RDP-muligheder, der skal inkluderes, formateret på samme måde som i .rdp-filer
@@ -1858,3 +1858,5 @@ syncBackgroundCommand=Blokering af baggrundskommando
terminalBackgroundCommand=Terminal-kommando
testingConnection=Test af forbindelse ...
openManagementConsole=Åben administrationskonsol
keeperUseMfa=Brug 2FA-godkendelsesapp
keeperUseMfaDescription=Aktivér dette, hvis din Keeper-konto kræver en 2FA TOTP for at få adgang til adgangskoder.
+5 -3
View File
@@ -1121,7 +1121,7 @@ gitVaultOverwriteLocalContent=Willst du die Änderungen in deinem lokalen Tresor
rdpSimple.displayName=Direkte RDP-Verbindung
rdpSimple.displayDescription=Verbindung zu einem Host über RDP
rdpUsername=Benutzername
rdpUsernameDescription=An Benutzer, der sich anmelden soll als
rdpUsernameDescription=Der Benutzer, mit dem du dich anmeldest. Kann ein Domänenpräfix enthalten
addressDescription=Wohin soll die Verbindung gehen?
rdpAdditionalOptions=Zusätzliche RDP-Optionen
rdpAdditionalOptionsDescription=Rohe RDP-Optionen, die genauso formatiert sind wie in .rdp-Dateien
@@ -1275,7 +1275,7 @@ activate=Aktivieren
validUntil=Gültig bis
licenseActivated=Lizenz aktiviert
restart=Neustart
lockVault=Schlosstresor
lockVault=Tresor schließen
restartApp=XPipe neu starten
free=Kostenlos
upgradeInfo=Informationen zum Upgrade auf eine Lizenz findest du weiter unten.
@@ -1849,7 +1849,9 @@ commandTypeAsyncBackground=Losgelöst im Hintergrund laufen lassen
commandTypeSyncBackground=Im Hintergrund laufen und auf das Ende warten
commandTypeTerminalBackground=Im Terminal öffnen
asyncBackgroundCommand=Hintergrund-Befehl
syncBackgroundCommand=Hintergrundbefehl blockieren
syncBackgroundCommand=Blockierender Hintergrundbefehl
terminalBackgroundCommand=Terminal-Befehl
testingConnection=Verbindung testen ...
openManagementConsole=Verwaltungskonsole öffnen
keeperUseMfa=2FA-Authentifikator-App verwenden
keeperUseMfaDescription=Aktiviere dies, wenn dein Keeper-Konto ein 2FA TOTP erfordert, um auf Passwörter zuzugreifen.
+8 -2
View File
@@ -1137,7 +1137,7 @@ gitVaultOverwriteLocalContent=Do you want to override your local vault changes?
rdpSimple.displayName=Direct RDP connection
rdpSimple.displayDescription=Connect to a host via RDP
rdpUsername=Username
rdpUsernameDescription=To user to log in as
rdpUsernameDescription=The user to log in as. Can include a domain prefix
addressDescription=Where to connect to
rdpAdditionalOptions=Additional RDP options
rdpAdditionalOptionsDescription=Raw RDP options to include, formatted the same as in .rdp files
@@ -1296,6 +1296,7 @@ activate=Activate
validUntil=Valid until
licenseActivated=License activated
restart=Restart
#context: verb, to close
lockVault=Lock vault
restartApp=Restart XPipe
#context: No payment required
@@ -1511,6 +1512,8 @@ updateFailActionDescription=Check out the latest releases at GitHub
onePasswordPlaceholder=Item name
computeDirectorySizes=Compute directory sizes
computeSize=Compute size
customSpiceCommand=Custom command
customSpiceCommandDescription=The custom command to execute to launch SPICE sessions. The placeholder string $FILE will be replaced by the quoted file path to the .vv file when called.
vncClient=VNC client
vncClientDescription=The VNC client to launch when opening VNC connections in XPipe.\n\nYou have the option to either use the integrated VNC client within XPipe or alternatively launch an external locally installed VNC client if you are looking for more customization.
integratedXPipeVncClient=Integrated XPipe VNC client
@@ -1883,9 +1886,12 @@ commandTypeAsyncBackground=Run detached in background
commandTypeSyncBackground=Run in background and wait for finish
commandTypeTerminalBackground=Open in terminal
asyncBackgroundCommand=Background command
#context: A command that does not return until finished
syncBackgroundCommand=Blocking background command
terminalBackgroundCommand=Terminal command
testingConnection=Testing connection ...
openManagementConsole=Open management console
openLxcTerminal=Open LXC terminal
openContainerConsole=Open serial console
openContainerConsole=Open serial console
keeperUseMfa=Use 2FA authenticator app
keeperUseMfaDescription=Enable this if your Keeper account requires an 2FA TOTP to access passwords.
+3 -1
View File
@@ -1090,7 +1090,7 @@ gitVaultOverwriteLocalContent=¿Quieres anular los cambios de tu repositorio loc
rdpSimple.displayName=Conexión directa RDP
rdpSimple.displayDescription=Conectarse a un host mediante RDP
rdpUsername=Nombre de usuario
rdpUsernameDescription=Para que el usuario inicie sesión como
rdpUsernameDescription=El usuario con el que iniciar sesión. Puede incluir un prefijo de dominio
addressDescription=Dónde conectarse
rdpAdditionalOptions=Opciones RDP adicionales
rdpAdditionalOptionsDescription=Opciones RDP en bruto a incluir, con el mismo formato que en los archivos .rdp
@@ -1817,3 +1817,5 @@ syncBackgroundCommand=Comando de fondo de bloqueo
terminalBackgroundCommand=Comando de terminal
testingConnection=Probar la conexión ...
openManagementConsole=Consola de gestión abierta
keeperUseMfa=Utilizar la aplicación de autenticación 2FA
keeperUseMfaDescription=Actívala si tu cuenta de Keeper requiere un TOTP 2FA para acceder a las contraseñas.
+3 -1
View File
@@ -1121,7 +1121,7 @@ gitVaultOverwriteLocalContent=Veux-tu remplacer les modifications de ton coffre-
rdpSimple.displayName=Connexion directe RDP
rdpSimple.displayDescription=Se connecter à un hôte via RDP
rdpUsername=Nom d'utilisateur
rdpUsernameDescription=A l'utilisateur de se connecter en tant que
rdpUsernameDescription=L'utilisateur sous lequel se connecter. Peut inclure un préfixe de domaine
addressDescription=Où se connecter
rdpAdditionalOptions=Options RDP supplémentaires
rdpAdditionalOptionsDescription=Options RDP brutes à inclure, formatées de la même manière que dans les fichiers .rdp
@@ -1857,3 +1857,5 @@ syncBackgroundCommand=Commande de blocage de l'arrière-plan
terminalBackgroundCommand=Commande de terminal
testingConnection=Test de connexion ...
openManagementConsole=Console de gestion ouverte
keeperUseMfa=Utilise l'application 2FA authenticator
keeperUseMfaDescription=Active cette option si ton compte Keeper nécessite un TOTP 2FA pour accéder aux mots de passe.
+3 -1
View File
@@ -1090,7 +1090,7 @@ gitVaultOverwriteLocalContent=Apakah Anda ingin menimpa perubahan brankas lokal
rdpSimple.displayName=Koneksi RDP langsung
rdpSimple.displayDescription=Menyambung ke host melalui RDP
rdpUsername=Nama pengguna
rdpUsernameDescription=Kepada pengguna untuk masuk sebagai
rdpUsernameDescription=Pengguna yang akan masuk sebagai. Dapat menyertakan awalan domain
addressDescription=Tempat untuk menyambung ke
rdpAdditionalOptions=Opsi RDP tambahan
rdpAdditionalOptionsDescription=Opsi RDP mentah untuk disertakan, diformat sama seperti pada file .rdp
@@ -1817,3 +1817,5 @@ syncBackgroundCommand=Memblokir perintah latar belakang
terminalBackgroundCommand=Perintah terminal
testingConnection=Menguji koneksi ...
openManagementConsole=Konsol manajemen terbuka
keeperUseMfa=Menggunakan aplikasi pengautentikasi 2FA
keeperUseMfaDescription=Aktifkan ini jika akun Keeper Anda memerlukan TOTP 2FA untuk mengakses kata sandi.
+5 -3
View File
@@ -1090,7 +1090,7 @@ gitVaultOverwriteLocalContent=Vuoi sovrascrivere le modifiche del tuo vault loca
rdpSimple.displayName=Connessione diretta RDP
rdpSimple.displayDescription=Connettersi a un host tramite RDP
rdpUsername=Nome utente
rdpUsernameDescription=All'utente di accedere come
rdpUsernameDescription=L'utente con cui accedere. Può includere un prefisso di dominio
addressDescription=Dove connettersi
rdpAdditionalOptions=Opzioni RDP aggiuntive
rdpAdditionalOptionsDescription=Opzioni RDP grezze da includere, formattate come nei file .rdp
@@ -1243,7 +1243,7 @@ activate=Attivare
validUntil=Valido fino a
licenseActivated=Licenza attivata
restart=Riavvio
lockVault=Una cassaforte con serratura
lockVault=Cassaforte con serratura
restartApp=Riavviare XPipe
free=Gratuito
upgradeInfo=Qui di seguito puoi trovare informazioni sull'aggiornamento della licenza.
@@ -1813,7 +1813,9 @@ commandTypeAsyncBackground=Eseguire in background
commandTypeSyncBackground=Eseguire in background e attendere il completamento
commandTypeTerminalBackground=Aprire nel terminale
asyncBackgroundCommand=Comando di sfondo
syncBackgroundCommand=Comando di blocco dello sfondo
syncBackgroundCommand=Comando di blocco in background
terminalBackgroundCommand=Comando del terminale
testingConnection=Verifica della connessione ...
openManagementConsole=Console di gestione aperta
keeperUseMfa=Usa l'applicazione autenticatore 2FA
keeperUseMfaDescription=Abilita questa opzione se il tuo account Keeper richiede un 2FA TOTP per accedere alle password.
+3 -1
View File
@@ -1090,7 +1090,7 @@ gitVaultOverwriteLocalContent=ローカルの保管庫の変更を上書きす
rdpSimple.displayName=直接RDP接続
rdpSimple.displayDescription=RDPでホストに接続する
rdpUsername=ユーザー名
rdpUsernameDescription=としてログインする
rdpUsernameDescription=ログインするユーザー。ドメインプレフィックスを含むことができる。
addressDescription=接続先
rdpAdditionalOptions=RDPの追加オプション
rdpAdditionalOptionsDescription=.rdpファイルと同じ書式で、RDPの生オプションを含める。
@@ -1817,3 +1817,5 @@ syncBackgroundCommand=バックグラウンドコマンドをブロックする
terminalBackgroundCommand=ターミナルコマンド
testingConnection=接続をテストする
openManagementConsole=オープン管理コンソール
keeperUseMfa=2FA認証アプリを使用する
keeperUseMfaDescription=Keeperアカウントがパスワードにアクセスするために2FA TOTPを必要とする場合、これを有効にする。
+3 -1
View File
@@ -1119,7 +1119,7 @@ gitVaultOverwriteLocalContent=로컬 볼트 변경 내용을 덮어쓰시겠습
rdpSimple.displayName=직접 RDP 연결
rdpSimple.displayDescription=RDP를 통해 호스트에 연결
rdpUsername=사용자 이름
rdpUsernameDescription=로그인할 사용자
rdpUsernameDescription=로그인할 사용자입니다. 도메인 접두사를 포함할 수 있습니다
addressDescription=연결할 위치
rdpAdditionalOptions=추가 RDP 옵션
rdpAdditionalOptionsDescription=포함할 원시 RDP 옵션(.rdp 파일과 동일한 형식)
@@ -1870,3 +1870,5 @@ syncBackgroundCommand=백그라운드 명령 차단
terminalBackgroundCommand=터미널 명령
testingConnection=연결 테스트 중 ...
openManagementConsole=관리 콘솔 열기
keeperUseMfa=2FA 인증 앱 사용
keeperUseMfaDescription=Keeper 계정에서 비밀번호에 액세스하기 위해 2FA TOTP가 필요한 경우 이 옵션을 사용 설정합니다.
+4 -2
View File
@@ -1090,7 +1090,7 @@ gitVaultOverwriteLocalContent=Wil je je lokale kluiswijzigingen overschrijven? D
rdpSimple.displayName=Directe RDP-verbinding
rdpSimple.displayDescription=Verbinding maken met een host via RDP
rdpUsername=Gebruikersnaam
rdpUsernameDescription=Naar gebruiker om in te loggen als
rdpUsernameDescription=De gebruiker om als in te loggen. Kan een domeinvoorvoegsel bevatten
addressDescription=Waar je verbinding mee moet maken
rdpAdditionalOptions=Extra RDP opties
rdpAdditionalOptionsDescription=Rauwe RDP-opties om op te nemen, in dezelfde opmaak als in .rdp-bestanden
@@ -1813,7 +1813,9 @@ commandTypeAsyncBackground=Vrijstaand op de achtergrond uitvoeren
commandTypeSyncBackground=Op de achtergrond draaien en wachten tot het klaar is
commandTypeTerminalBackground=Openen in terminal
asyncBackgroundCommand=Opdracht op de achtergrond
syncBackgroundCommand=Opdracht voor achtergrond blokkeren
syncBackgroundCommand=Achtergrondcommando blokkeren
terminalBackgroundCommand=Terminal commando
testingConnection=Verbinding testen ...
openManagementConsole=Open beheerconsole
keeperUseMfa=Gebruik 2FA authenticator app
keeperUseMfaDescription=Schakel dit in als je Keeper-account een 2FA TOTP vereist om toegang te krijgen tot wachtwoorden.
+5 -3
View File
@@ -1090,7 +1090,7 @@ gitVaultOverwriteLocalContent=Czy chcesz zastąpić zmiany w lokalnym sejfie? Sp
rdpSimple.displayName=Bezpośrednie połączenie RDP
rdpSimple.displayDescription=Połącz się z hostem przez RDP
rdpUsername=Nazwa użytkownika
rdpUsernameDescription=Aby użytkownik zalogował się jako
rdpUsernameDescription=Użytkownik, jako który chcesz się zalogować. Może zawierać prefiks domeny
addressDescription=Gdzie się połączyć
rdpAdditionalOptions=Dodatkowe opcje RDP
rdpAdditionalOptionsDescription=Surowe opcje RDP do uwzględnienia, sformatowane tak samo jak w plikach .rdp
@@ -1244,7 +1244,7 @@ activate=Aktywuj
validUntil=Ważny do
licenseActivated=Aktywowana licencja
restart=Restart
lockVault=Skarbiec z zamkiem
lockVault=Zamknięty skarbiec
restartApp=Uruchom ponownie XPipe
free=Darmowy
upgradeInfo=Poniżej znajdziesz informacje na temat aktualizacji do licencji.
@@ -1814,7 +1814,9 @@ commandTypeAsyncBackground=Uruchom odłączony w tle
commandTypeSyncBackground=Uruchom w tle i czekaj na zakończenie
commandTypeTerminalBackground=Otwórz w terminalu
asyncBackgroundCommand=Polecenie tła
syncBackgroundCommand=Polecenie blokowania w tle
syncBackgroundCommand=Polecenie blokujące w tle
terminalBackgroundCommand=Polecenie terminala
testingConnection=Testowanie połączenia ...
openManagementConsole=Otwarta konsola zarządzania
keeperUseMfa=Użyj aplikacji uwierzytelniającej 2FA
keeperUseMfaDescription=Włącz tę opcję, jeśli Twoje konto Keeper wymaga TOTP 2FA, aby uzyskać dostęp do haseł.
+5 -3
View File
@@ -1090,7 +1090,7 @@ gitVaultOverwriteLocalContent=Queres substituir as alterações do teu cofre loc
rdpSimple.displayName=Ligação direta RDP
rdpSimple.displayDescription=Liga-te a um anfitrião através de RDP
rdpUsername=Nome de utilizador
rdpUsernameDescription=Para que o utilizador inicie sessão como
rdpUsernameDescription=O utilizador com o qual deves iniciar sessão. Pode incluir um prefixo de domínio
addressDescription=Onde te deves ligar
rdpAdditionalOptions=Opções adicionais de RDP
rdpAdditionalOptionsDescription=Opções RDP brutas a incluir, formatadas da mesma forma que nos ficheiros .rdp
@@ -1243,7 +1243,7 @@ activate=Ativar
validUntil=Válido até
licenseActivated=Licença activada
restart=Reinicia
lockVault=Cofre com fechadura
lockVault=Fecha o cofre
restartApp=Reinicia o XPipe
free=Gratuito
upgradeInfo=Podes encontrar informações sobre a atualização para uma licença abaixo.
@@ -1813,7 +1813,9 @@ commandTypeAsyncBackground=Executa a desanexação em segundo plano
commandTypeSyncBackground=Corre em segundo plano e espera pela conclusão
commandTypeTerminalBackground=Abre no terminal
asyncBackgroundCommand=Comando de fundo
syncBackgroundCommand=Bloqueio do comando de fundo
syncBackgroundCommand=Bloqueia o comando de fundo
terminalBackgroundCommand=Comando de terminal
testingConnection=Testar a ligação ...
openManagementConsole=Abre a consola de gestão
keeperUseMfa=Utiliza a aplicação de autenticação 2FA
keeperUseMfaDescription=Ative essa opção se a sua conta do Keeper exigir um TOTP 2FA para acessar senhas.
+4 -2
View File
@@ -1181,7 +1181,7 @@ gitVaultOverwriteLocalContent=Хочешь отменить изменения
rdpSimple.displayName=Прямое RDP-соединение
rdpSimple.displayDescription=Подключение к хосту через RDP
rdpUsername=Имя пользователя
rdpUsernameDescription=Чтобы пользователь вошел в систему как
rdpUsernameDescription=Пользователь, под которым нужно войти в систему. Может включать префикс домена
addressDescription=К чему подключиться
rdpAdditionalOptions=Дополнительные опции RDP
rdpAdditionalOptionsDescription=Необработанные опции RDP, которые нужно включить, в том же формате, что и в файлах .rdp
@@ -1925,7 +1925,9 @@ commandTypeAsyncBackground=Запускать detached в фоновом реж
commandTypeSyncBackground=Запустить в фоновом режиме и дождаться завершения
commandTypeTerminalBackground=Открыть в терминале
asyncBackgroundCommand=Фоновая команда
syncBackgroundCommand=Блокировка фоновой команды
syncBackgroundCommand=Блокирующая фоновая команда
terminalBackgroundCommand=Команда терминала
testingConnection=Тестирование соединения ...
openManagementConsole=Открытая консоль управления
keeperUseMfa=Используйте приложение аутентификатора 2FA
keeperUseMfaDescription=Включи эту опцию, если твой аккаунт Keeper требует 2FA TOTP для доступа к паролям.
+3 -1
View File
@@ -1090,7 +1090,7 @@ gitVaultOverwriteLocalContent=Vill du åsidosätta dina lokala valvändringar? D
rdpSimple.displayName=Direkt RDP-anslutning
rdpSimple.displayDescription=Ansluta till en värd via RDP
rdpUsername=Användarnamn
rdpUsernameDescription=Till användare att logga in som
rdpUsernameDescription=Användaren att logga in som. Kan innehålla ett domänprefix
addressDescription=Var ska man ansluta till
rdpAdditionalOptions=Ytterligare RDP-alternativ
rdpAdditionalOptionsDescription=Raw RDP-alternativ att inkludera, formaterade på samma sätt som i .rdp-filer
@@ -1817,3 +1817,5 @@ syncBackgroundCommand=Blockering av bakgrundskommando
terminalBackgroundCommand=Kommando för terminal
testingConnection=Testning av anslutning ...
openManagementConsole=Öppen hanteringskonsol
keeperUseMfa=Använd 2FA-autentiseringsapp
keeperUseMfaDescription=Aktivera detta om ditt Keeper-konto kräver en 2FA TOTP för att komma åt lösenord.
+3 -1
View File
@@ -1090,7 +1090,7 @@ gitVaultOverwriteLocalContent=Yerel kasa değişikliklerinizi geçersiz kılmak
rdpSimple.displayName=Doğrudan RDP bağlantısı
rdpSimple.displayDescription=RDP aracılığıyla bir ana bilgisayara bağlanma
rdpUsername=Kullanıcı Adı
rdpUsernameDescription=Kullanıcı olarak oturum açmak için
rdpUsernameDescription=Oturum açılacak kullanıcı. Bir alan adı öneki içerebilir
addressDescription=Nereye bağlanmalı
rdpAdditionalOptions=Ek RDP seçenekleri
rdpAdditionalOptionsDescription=Dahil edilecek ham RDP seçenekleri, .rdp dosyalarında olduğu gibi biçimlendirilir
@@ -1817,3 +1817,5 @@ syncBackgroundCommand=Arka plan komutunu engelleme
terminalBackgroundCommand=Terminal komutu
testingConnection=Test bağlantısı ...
openManagementConsole=Açık yönetim konsolu
keeperUseMfa=2FA kimlik doğrulayıcı uygulamasını kullanın
keeperUseMfaDescription=Keeper hesabınız parolalara erişmek için bir 2FA TOTP gerektiriyorsa bunu etkinleştirin.
+5 -3
View File
@@ -1090,7 +1090,7 @@ gitVaultOverwriteLocalContent=Bạn có muốn ghi đè các thay đổi trong k
rdpSimple.displayName=Kết nối RDP trực tiếp
rdpSimple.displayDescription=Kết nối với máy chủ qua RDP
rdpUsername=Tên người dùng
rdpUsernameDescription=Để người dùng đăng nhập với tư cách là
rdpUsernameDescription=Tên người dùng để đăng nhập. Có thể bao gồm tiền tố miền
addressDescription=Nơi kết nối đến
rdpAdditionalOptions=Các tùy chọn RDP bổ sung
rdpAdditionalOptionsDescription=Các tùy chọn RDP thô cần bao gồm, định dạng giống như trong các tệp .rdp
@@ -1243,7 +1243,7 @@ activate=Kích hoạt
validUntil=Hiệu lực đến
licenseActivated=Giấy phép đã được kích hoạt
restart=Khởi động lại
lockVault=Kho lưu trữ an toàn
lockVault=Khoá két sắt
restartApp=Khởi động lại XPipe
free=Miễn phí
upgradeInfo=Cậu có thể tìm thấy thông tin về việc nâng cấp lên giấy phép ở phần dưới đây.
@@ -1813,7 +1813,9 @@ commandTypeAsyncBackground=Chạy độc lập trong nền
commandTypeSyncBackground=Chạy ngầm và chờ hoàn tất
commandTypeTerminalBackground=Mở trong terminal
asyncBackgroundCommand=Lệnh nền
syncBackgroundCommand=Chặn lệnh nền
syncBackgroundCommand=Lệnh nền chặn
terminalBackgroundCommand=Lệnh terminal
testingConnection=Kiểm tra kết nối ...
openManagementConsole=Mở bảng điều khiển quản lý
keeperUseMfa=Sử dụng ứng dụng xác thực hai yếu tố (2FA)
keeperUseMfaDescription=Bật tùy chọn này nếu tài khoản Keeper của cậu yêu cầu xác thực hai yếu tố (2FA) bằng mã TOTP để truy cập mật khẩu.
+2
View File
@@ -2444,3 +2444,5 @@ syncBackgroundCommand=阻止后台命令
terminalBackgroundCommand=终端命令
testingConnection=测试连接...
openManagementConsole=开放式管理控制台
keeperUseMfa=使用 2FA 验证器应用程序
keeperUseMfaDescription=如果 Keeper 帐户要求使用 2FA TOTP 访问密码,请启用此选项。
+4 -2
View File
@@ -1090,7 +1090,7 @@ gitVaultOverwriteLocalContent=要覆蓋您本地儲存庫的變更?這會將
rdpSimple.displayName=直接 RDP 連線
rdpSimple.displayDescription=透過 RDP 連接到主機
rdpUsername=使用者名稱
rdpUsernameDescription=使用者以
rdpUsernameDescription=登入的使用者。可包含網域前綴
addressDescription=連接至何處
rdpAdditionalOptions=其他 RDP 選項
rdpAdditionalOptionsDescription=要包含的原始 RDP 選項,格式與 .rdp 檔案相同
@@ -1243,7 +1243,7 @@ activate=啟動
validUntil=有效期至
licenseActivated=已啟用的授權
restart=重新啟動
lockVault=鎖庫
lockVault=
restartApp=重新啟動 XPipe
free=免費
upgradeInfo=您可以在下方找到升級為授權的相關資訊。
@@ -1817,3 +1817,5 @@ syncBackgroundCommand=封鎖背景指令
terminalBackgroundCommand=終端命令
testingConnection=測試連接 ...
openManagementConsole=開放式管理主控台
keeperUseMfa=使用 2FA 認證器應用程式
keeperUseMfaDescription=如果您的 Keeper 帳戶需要 2FA TOTP 才能存取密碼,請啟用此項。
+1 -1
View File
@@ -1 +1 @@
20.3-8
20.4-1