mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-06-30 20:10:57 +12:00
Various fixes
This commit is contained in:
parent
7bce1e8f3b
commit
d9e23b9ebf
|
@ -16,14 +16,14 @@ public class BrowserAlerts {
|
||||||
|
|
||||||
public static FileConflictChoice showFileConflictAlert(String file, boolean multiple) {
|
public static FileConflictChoice showFileConflictAlert(String file, boolean multiple) {
|
||||||
var map = new LinkedHashMap<ButtonType, FileConflictChoice>();
|
var map = new LinkedHashMap<ButtonType, FileConflictChoice>();
|
||||||
map.put(new ButtonType("Cancel", ButtonBar.ButtonData.CANCEL_CLOSE), FileConflictChoice.CANCEL);
|
map.put(new ButtonType(AppI18n.get("cancel"), ButtonBar.ButtonData.CANCEL_CLOSE), FileConflictChoice.CANCEL);
|
||||||
if (multiple) {
|
if (multiple) {
|
||||||
map.put(new ButtonType("Skip", ButtonBar.ButtonData.OTHER), FileConflictChoice.SKIP);
|
map.put(new ButtonType(AppI18n.get("skip"), ButtonBar.ButtonData.OTHER), FileConflictChoice.SKIP);
|
||||||
map.put(new ButtonType("Skip All", ButtonBar.ButtonData.OTHER), FileConflictChoice.SKIP_ALL);
|
map.put(new ButtonType(AppI18n.get("skipAll"), ButtonBar.ButtonData.OTHER), FileConflictChoice.SKIP_ALL);
|
||||||
}
|
}
|
||||||
map.put(new ButtonType("Replace", ButtonBar.ButtonData.OTHER), FileConflictChoice.REPLACE);
|
map.put(new ButtonType(AppI18n.get("replace"), ButtonBar.ButtonData.OTHER), FileConflictChoice.REPLACE);
|
||||||
if (multiple) {
|
if (multiple) {
|
||||||
map.put(new ButtonType("Replace All", ButtonBar.ButtonData.OTHER), FileConflictChoice.REPLACE_ALL);
|
map.put(new ButtonType(AppI18n.get("replaceAll"), ButtonBar.ButtonData.OTHER), FileConflictChoice.REPLACE_ALL);
|
||||||
}
|
}
|
||||||
return AppWindowHelper.showBlockingAlert(alert -> {
|
return AppWindowHelper.showBlockingAlert(alert -> {
|
||||||
alert.setTitle(AppI18n.get("fileConflictAlertTitle"));
|
alert.setTitle(AppI18n.get("fileConflictAlertTitle"));
|
||||||
|
|
|
@ -212,8 +212,8 @@ public class StoreCreationComp extends DialogComp {
|
||||||
.setContent(AppWindowHelper.alertContentText(AppI18n.get("confirmInvalidStoreContent")));
|
.setContent(AppWindowHelper.alertContentText(AppI18n.get("confirmInvalidStoreContent")));
|
||||||
alert.setAlertType(Alert.AlertType.CONFIRMATION);
|
alert.setAlertType(Alert.AlertType.CONFIRMATION);
|
||||||
alert.getButtonTypes().clear();
|
alert.getButtonTypes().clear();
|
||||||
alert.getButtonTypes().add(new ButtonType("Retry", ButtonBar.ButtonData.CANCEL_CLOSE));
|
alert.getButtonTypes().add(new ButtonType(AppI18n.get("retry"), ButtonBar.ButtonData.CANCEL_CLOSE));
|
||||||
alert.getButtonTypes().add(new ButtonType("Skip", ButtonBar.ButtonData.OK_DONE));
|
alert.getButtonTypes().add(new ButtonType(AppI18n.get("skip"), ButtonBar.ButtonData.OK_DONE));
|
||||||
})
|
})
|
||||||
.map(b -> b.getButtonData().isDefaultButton())
|
.map(b -> b.getButtonData().isDefaultButton())
|
||||||
.orElse(false);
|
.orElse(false);
|
||||||
|
|
|
@ -65,7 +65,7 @@ public class App extends Application {
|
||||||
"XPipe %s (%s)", t.getValue(), AppProperties.get().getVersion());
|
"XPipe %s (%s)", t.getValue(), AppProperties.get().getVersion());
|
||||||
var prefix = AppProperties.get().isStaging() ? "[Public Test Build, Not a proper release] " : "";
|
var prefix = AppProperties.get().isStaging() ? "[Public Test Build, Not a proper release] " : "";
|
||||||
var suffix = u.getValue() != null
|
var suffix = u.getValue() != null
|
||||||
? AppI18n.get("updateReadyTitle", u.getValue().getVersion())
|
? " " + AppI18n.get("updateReadyTitle", u.getValue().getVersion())
|
||||||
: "";
|
: "";
|
||||||
return prefix + base + suffix;
|
return prefix + base + suffix;
|
||||||
},
|
},
|
||||||
|
|
|
@ -84,7 +84,7 @@ public class ContextualFileReferenceChoiceComp extends Comp<CompStructure<HBox>>
|
||||||
var gitShareButton = new ButtonComp(null, new FontIcon("mdi2g-git"), () -> {
|
var gitShareButton = new ButtonComp(null, new FontIcon("mdi2g-git"), () -> {
|
||||||
if (!AppPrefs.get().enableGitStorage().get()) {
|
if (!AppPrefs.get().enableGitStorage().get()) {
|
||||||
AppLayoutModel.get().selectSettings();
|
AppLayoutModel.get().selectSettings();
|
||||||
AppPrefs.get().selectCategory(3);
|
AppPrefs.get().selectCategory("synchronization");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -139,15 +139,15 @@ public class AppPrefs {
|
||||||
new AboutCategory(),
|
new AboutCategory(),
|
||||||
new SystemCategory(),
|
new SystemCategory(),
|
||||||
new AppearanceCategory(),
|
new AppearanceCategory(),
|
||||||
|
new SyncCategory(),
|
||||||
|
new VaultCategory(),
|
||||||
|
new PasswordManagerCategory(),
|
||||||
|
new SecurityCategory(),
|
||||||
new TerminalCategory(),
|
new TerminalCategory(),
|
||||||
new EditorCategory(),
|
new EditorCategory(),
|
||||||
new RdpCategory(),
|
new RdpCategory(),
|
||||||
new SyncCategory(),
|
|
||||||
new VaultCategory(),
|
|
||||||
new SshCategory(),
|
new SshCategory(),
|
||||||
new LocalShellCategory(),
|
new LocalShellCategory(),
|
||||||
new SecurityCategory(),
|
|
||||||
new PasswordManagerCategory(),
|
|
||||||
new TroubleshootCategory(),
|
new TroubleshootCategory(),
|
||||||
new DeveloperCategory());
|
new DeveloperCategory());
|
||||||
var selected = AppCache.get("selectedPrefsCategory", Integer.class, () -> 0);
|
var selected = AppCache.get("selectedPrefsCategory", Integer.class, () -> 0);
|
||||||
|
@ -505,10 +505,12 @@ public class AppPrefs {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void selectCategory(int selected) {
|
public void selectCategory(String id) {
|
||||||
AppLayoutModel.get().selectSettings();
|
AppLayoutModel.get().selectSettings();
|
||||||
var index = selected >= 0 && selected < categories.size() ? selected : 0;
|
var found = categories.stream().filter(appPrefsCategory -> appPrefsCategory.getId().equals(id)).findFirst();
|
||||||
selectedCategory.setValue(categories.get(index));
|
found.ifPresent(appPrefsCategory -> {
|
||||||
|
selectedCategory.setValue(appPrefsCategory);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public String passwordManagerString(String key) {
|
public String passwordManagerString(String key) {
|
||||||
|
|
|
@ -241,7 +241,7 @@ public interface ExternalEditorType extends PrefsChoiceValue {
|
||||||
|
|
||||||
public WindowsType(String id, String executable, boolean detach) {
|
public WindowsType(String id, String executable, boolean detach) {
|
||||||
super(id, executable);
|
super(id, executable);
|
||||||
this.detach = true;
|
this.detach = detach;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
package io.xpipe.app.prefs;
|
||||||
|
|
||||||
|
import io.xpipe.app.ext.PrefsChoiceValue;
|
||||||
|
import io.xpipe.core.process.OsType;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public interface ExternalPasswordManager extends PrefsChoiceValue {
|
||||||
|
|
||||||
|
String getTemplate();
|
||||||
|
|
||||||
|
static ExternalPasswordManager BITWARDEN = new ExternalPasswordManager() {
|
||||||
|
@Override
|
||||||
|
public String getTemplate() {
|
||||||
|
return "bw get password $KEY --nointeraction --raw";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return "bitwarden";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static ExternalPasswordManager ONEPASSWORD = new ExternalPasswordManager() {
|
||||||
|
@Override
|
||||||
|
public String getTemplate() {
|
||||||
|
return "op read $KEY --force";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return "1Password";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static ExternalPasswordManager DASHLANE = new ExternalPasswordManager() {
|
||||||
|
@Override
|
||||||
|
public String getTemplate() {
|
||||||
|
return "dcli password --output console $KEY";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return "Dashlane";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static ExternalPasswordManager LASTPASS = new ExternalPasswordManager() {
|
||||||
|
@Override
|
||||||
|
public String getTemplate() {
|
||||||
|
return "lpass show --password $KEY";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return "LastPass";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static ExternalPasswordManager MACOS_KEYCHAIN = new ExternalPasswordManager() {
|
||||||
|
@Override
|
||||||
|
public String getTemplate() {
|
||||||
|
return "security find-generic-password -w -l $KEY";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return "macOS keychain";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSelectable() {
|
||||||
|
return OsType.getLocal() == OsType.MACOS;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static List<ExternalPasswordManager> ALL = Stream.of(ONEPASSWORD, BITWARDEN, DASHLANE, LASTPASS, MACOS_KEYCHAIN).filter(externalPasswordManager -> externalPasswordManager.isSelectable()).toList();
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ package io.xpipe.app.prefs;
|
||||||
|
|
||||||
import atlantafx.base.theme.Styles;
|
import atlantafx.base.theme.Styles;
|
||||||
import io.xpipe.app.comp.base.ButtonComp;
|
import io.xpipe.app.comp.base.ButtonComp;
|
||||||
|
import io.xpipe.app.core.AppI18n;
|
||||||
import io.xpipe.app.fxcomps.Comp;
|
import io.xpipe.app.fxcomps.Comp;
|
||||||
import io.xpipe.app.fxcomps.impl.HorizontalComp;
|
import io.xpipe.app.fxcomps.impl.HorizontalComp;
|
||||||
import io.xpipe.app.fxcomps.impl.TextFieldComp;
|
import io.xpipe.app.fxcomps.impl.TextFieldComp;
|
||||||
|
@ -14,6 +15,8 @@ import io.xpipe.core.store.LocalStore;
|
||||||
import javafx.beans.property.SimpleStringProperty;
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
|
import javafx.scene.control.MenuButton;
|
||||||
|
import javafx.scene.control.MenuItem;
|
||||||
import org.kordamp.ikonli.javafx.FontIcon;
|
import org.kordamp.ikonli.javafx.FontIcon;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -25,6 +28,22 @@ public class PasswordManagerCategory extends AppPrefsCategory {
|
||||||
return "passwordManager";
|
return "passwordManager";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Comp<?> createTemplateChoice() {
|
||||||
|
return Comp.of(() -> {
|
||||||
|
var cb = new MenuButton();
|
||||||
|
cb.textProperty().bind(AppI18n.observable("templates"));
|
||||||
|
ExternalPasswordManager.ALL.forEach(externalPasswordManager -> {
|
||||||
|
var m = new MenuItem(externalPasswordManager.toTranslatedString().getValue());
|
||||||
|
m.setOnAction(event -> {
|
||||||
|
AppPrefs.get().passwordManagerCommand.set(externalPasswordManager.getTemplate());
|
||||||
|
event.consume();
|
||||||
|
});
|
||||||
|
cb.getItems().add(m);
|
||||||
|
});
|
||||||
|
return cb;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Comp<?> create() {
|
protected Comp<?> create() {
|
||||||
var prefs = AppPrefs.get();
|
var prefs = AppPrefs.get();
|
||||||
|
@ -48,6 +67,13 @@ public class PasswordManagerCategory extends AppPrefsCategory {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var c = new TextFieldComp(prefs.passwordManagerCommand, true).apply(struc -> struc.get().setPromptText("mypassmgr get $KEY")).minWidth(350);
|
||||||
|
var visit = createTemplateChoice();
|
||||||
|
var choice = new HorizontalComp(List.of(c, visit)).apply(struc -> {
|
||||||
|
struc.get().setAlignment(Pos.CENTER_LEFT);
|
||||||
|
struc.get().setSpacing(10);
|
||||||
|
});
|
||||||
|
|
||||||
var testPasswordManager = new HorizontalComp(List.of(
|
var testPasswordManager = new HorizontalComp(List.of(
|
||||||
new TextFieldComp(testPasswordManagerValue)
|
new TextFieldComp(testPasswordManagerValue)
|
||||||
.apply(struc -> struc.get().setPromptText("Enter password key"))
|
.apply(struc -> struc.get().setPromptText("Enter password key"))
|
||||||
|
@ -63,8 +89,7 @@ public class PasswordManagerCategory extends AppPrefsCategory {
|
||||||
.addTitle("passwordManager")
|
.addTitle("passwordManager")
|
||||||
.sub(new OptionsBuilder()
|
.sub(new OptionsBuilder()
|
||||||
.nameAndDescription("passwordManagerCommand")
|
.nameAndDescription("passwordManagerCommand")
|
||||||
.addComp(new TextFieldComp(prefs.passwordManagerCommand, true)
|
.addComp(choice)
|
||||||
.apply(struc -> struc.get().setPromptText("mypassmgr get $KEY")))
|
|
||||||
.nameAndDescription("passwordManagerCommandTest")
|
.nameAndDescription("passwordManagerCommandTest")
|
||||||
.addComp(testPasswordManager))
|
.addComp(testPasswordManager))
|
||||||
.buildComp();
|
.buildComp();
|
||||||
|
|
|
@ -13,6 +13,17 @@ import java.util.function.IntFunction;
|
||||||
|
|
||||||
public class DataStoreFormatter {
|
public class DataStoreFormatter {
|
||||||
|
|
||||||
|
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<String> shellInformation(StoreEntryWrapper w) {
|
public static ObservableValue<String> shellInformation(StoreEntryWrapper w) {
|
||||||
return BindingsHelper.map(w.getPersistentState(), o -> {
|
return BindingsHelper.map(w.getPersistentState(), o -> {
|
||||||
if (o instanceof ShellStoreState s) {
|
if (o instanceof ShellStoreState s) {
|
||||||
|
@ -23,11 +34,11 @@ public class DataStoreFormatter {
|
||||||
if (s.getShellDialect() != null
|
if (s.getShellDialect() != null
|
||||||
&& !s.getShellDialect().getDumbMode().supportsAnyPossibleInteraction()) {
|
&& !s.getShellDialect().getDumbMode().supportsAnyPossibleInteraction()) {
|
||||||
return s.getOsName() != null
|
return s.getOsName() != null
|
||||||
? s.getOsName()
|
? formattedOsName(s.getOsName())
|
||||||
: s.getShellDialect().getDisplayName();
|
: s.getShellDialect().getDisplayName();
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.isRunning() ? s.getOsName() : "Connection failed";
|
return s.isRunning() ? formattedOsName(s.getOsName()) : "Connection failed";
|
||||||
}
|
}
|
||||||
|
|
||||||
return "?";
|
return "?";
|
||||||
|
|
|
@ -21,7 +21,9 @@ public abstract class LicenseProvider {
|
||||||
|
|
||||||
public abstract LicensedFeature getFeature(String id);
|
public abstract LicensedFeature getFeature(String id);
|
||||||
|
|
||||||
public abstract void checkShellControl(String s);
|
public abstract boolean checkOsName(String name);
|
||||||
|
|
||||||
|
public abstract void checkOsNameOrThrow(String s);
|
||||||
|
|
||||||
public abstract void showLicenseAlert(LicenseRequiredException ex);
|
public abstract void showLicenseAlert(LicenseRequiredException ex);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package io.xpipe.app.util;
|
package io.xpipe.app.util;
|
||||||
|
|
||||||
import io.xpipe.app.core.check.AppSystemFontCheck;
|
import io.xpipe.app.core.check.AppSystemFontCheck;
|
||||||
|
import io.xpipe.app.issue.ErrorEvent;
|
||||||
import io.xpipe.app.issue.TrackEvent;
|
import io.xpipe.app.issue.TrackEvent;
|
||||||
import io.xpipe.app.prefs.AppPrefs;
|
import io.xpipe.app.prefs.AppPrefs;
|
||||||
import io.xpipe.core.process.OsType;
|
import io.xpipe.core.process.OsType;
|
||||||
|
@ -83,7 +84,7 @@ public enum PlatformState {
|
||||||
: h.getMessage();
|
: h.getMessage();
|
||||||
TrackEvent.warn(h.getMessage());
|
TrackEvent.warn(h.getMessage());
|
||||||
PlatformState.setCurrent(PlatformState.EXITED);
|
PlatformState.setCurrent(PlatformState.EXITED);
|
||||||
return Optional.of(new HeadlessException(msg));
|
return Optional.of(ErrorEvent.expected(new HeadlessException(msg)));
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
TrackEvent.warn(t.getMessage());
|
TrackEvent.warn(t.getMessage());
|
||||||
PlatformState.setCurrent(PlatformState.EXITED);
|
PlatformState.setCurrent(PlatformState.EXITED);
|
||||||
|
|
|
@ -62,5 +62,9 @@ public class RdpConfig {
|
||||||
public static class TypedValue {
|
public static class TypedValue {
|
||||||
String type;
|
String type;
|
||||||
String value;
|
String value;
|
||||||
|
|
||||||
|
public static TypedValue string(String value) {
|
||||||
|
return new TypedValue("s", value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -183,6 +183,7 @@ public class ScanAlert {
|
||||||
}
|
}
|
||||||
|
|
||||||
shellControl = newValue.getStore().control();
|
shellControl = newValue.getStore().control();
|
||||||
|
shellControl.withoutLicenseCheck();
|
||||||
shellControl.start();
|
shellControl.start();
|
||||||
var a = applicable.apply(entry.get().get(), shellControl);
|
var a = applicable.apply(entry.get().get(), shellControl);
|
||||||
|
|
||||||
|
|
|
@ -127,13 +127,23 @@ public interface SecretRetrievalStrategy {
|
||||||
return new SecretQueryResult(null, true);
|
return new SecretQueryResult(null, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String r;
|
||||||
try (var cc = new LocalStore().control().command(cmd).start()) {
|
try (var cc = new LocalStore().control().command(cmd).start()) {
|
||||||
return new SecretQueryResult(InPlaceSecretValue.of(cc.readStdoutOrThrow()), false);
|
r = cc.readStdoutOrThrow();
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
ErrorEvent.fromThrowable("Unable to retrieve password with command " + cmd, ex)
|
ErrorEvent.fromThrowable("Unable to retrieve password with command " + cmd, ex)
|
||||||
.handle();
|
.handle();
|
||||||
return new SecretQueryResult(null, true);
|
return new SecretQueryResult(null, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (r.lines().count() > 1 || r.isBlank()) {
|
||||||
|
throw ErrorEvent.expected(new IllegalArgumentException("Received not exactly one output line:\n" + r + "\n\n" +
|
||||||
|
"XPipe requires your password manager command to output only the raw password." +
|
||||||
|
" If the output includes any formatting, messages, or your password key either matched multiple entries or none," +
|
||||||
|
" you will have to change the command and/or password key."));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new SecretQueryResult(InPlaceSecretValue.of(r), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -46,7 +46,7 @@ public class SecretRetrievalStrategyHelper {
|
||||||
.apply(struc -> struc.get().setPromptText("Password key"))
|
.apply(struc -> struc.get().setPromptText("Password key"))
|
||||||
.hgrow(),
|
.hgrow(),
|
||||||
new ButtonComp(null, new FontIcon("mdomz-settings"), () -> {
|
new ButtonComp(null, new FontIcon("mdomz-settings"), () -> {
|
||||||
AppPrefs.get().selectCategory(9);
|
AppPrefs.get().selectCategory("passwordManager");
|
||||||
App.getApp().getStage().requestFocus();
|
App.getApp().getStage().requestFocus();
|
||||||
})
|
})
|
||||||
.grow(false, true)))
|
.grow(false, true)))
|
||||||
|
@ -54,6 +54,7 @@ public class SecretRetrievalStrategyHelper {
|
||||||
return new OptionsBuilder()
|
return new OptionsBuilder()
|
||||||
.name("passwordKey")
|
.name("passwordKey")
|
||||||
.addComp(content, keyProperty)
|
.addComp(content, keyProperty)
|
||||||
|
.nonNull()
|
||||||
.bind(
|
.bind(
|
||||||
() -> {
|
() -> {
|
||||||
return new SecretRetrievalStrategy.PasswordManager(keyProperty.getValue());
|
return new SecretRetrievalStrategy.PasswordManager(keyProperty.getValue());
|
||||||
|
|
|
@ -74,21 +74,6 @@
|
||||||
-fx-border-width: 4;
|
-fx-border-width: 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
.store-header-bar .menu-button .context-menu > * > * {
|
|
||||||
-fx-padding: 5px 10px 5px 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.store-header-bar .menu-button .context-menu > * {
|
|
||||||
-fx-padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.store-header-bar .menu-button .context-menu {
|
|
||||||
-fx-padding: 3px;
|
|
||||||
-fx-background-radius: 4px;
|
|
||||||
-fx-border-radius: 4px;
|
|
||||||
-fx-border-color: -color-neutral-muted;
|
|
||||||
}
|
|
||||||
|
|
||||||
.store-creation-bar, .store-sort-bar, .store-category-bar {
|
.store-creation-bar, .store-sort-bar, .store-category-bar {
|
||||||
-fx-background-radius: 0 4px 4px 0;
|
-fx-background-radius: 0 4px 4px 0;
|
||||||
-fx-border-radius: 0 4px 4px 0;
|
-fx-border-radius: 0 4px 4px 0;
|
||||||
|
|
|
@ -1,3 +1,18 @@
|
||||||
|
.menu-button .context-menu > * > * {
|
||||||
|
-fx-padding: 5px 10px 5px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-button .context-menu > * {
|
||||||
|
-fx-padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-button .context-menu {
|
||||||
|
-fx-padding: 3px;
|
||||||
|
-fx-background-radius: 4px;
|
||||||
|
-fx-border-radius: 4px;
|
||||||
|
-fx-border-color: -color-neutral-muted;
|
||||||
|
}
|
||||||
|
|
||||||
.context-menu > * > * {
|
.context-menu > * > * {
|
||||||
-fx-padding: 3px 10px 3px 10px;
|
-fx-padding: 3px 10px 3px 10px;
|
||||||
-fx-background-radius: 1px;
|
-fx-background-radius: 1px;
|
||||||
|
|
|
@ -67,7 +67,12 @@ public interface ShellControl extends ProcessControl {
|
||||||
}
|
}
|
||||||
|
|
||||||
default <T extends ShellStoreState> ShellControl withShellStateFail(StatefulDataStore<T> store) {
|
default <T extends ShellStoreState> ShellControl withShellStateFail(StatefulDataStore<T> store) {
|
||||||
return onStartupFail(shellControl -> {
|
return onStartupFail(t -> {
|
||||||
|
// Ugly
|
||||||
|
if (t.getClass().getSimpleName().equals("LicenseRequiredException")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var s = store.getState();
|
var s = store.getState();
|
||||||
s.setRunning(false);
|
s.setRunning(false);
|
||||||
store.setState(s);
|
store.setState(s);
|
||||||
|
|
|
@ -57,3 +57,4 @@ github=GitHub
|
||||||
mstsc=Microsoft Terminal Services Client (MSTSC)
|
mstsc=Microsoft Terminal Services Client (MSTSC)
|
||||||
remmina=Remmina
|
remmina=Remmina
|
||||||
microsoftRemoteDesktopApp=Microsoft Remote Desktop.app
|
microsoftRemoteDesktopApp=Microsoft Remote Desktop.app
|
||||||
|
bitwarden=Bitwarden
|
||||||
|
|
|
@ -326,7 +326,7 @@ system=System
|
||||||
application=Anwendung
|
application=Anwendung
|
||||||
storage=Speicherung
|
storage=Speicherung
|
||||||
runOnStartup=Beim Starten ausführen
|
runOnStartup=Beim Starten ausführen
|
||||||
closeBehaviour=Verhalten schließen
|
closeBehaviour=Exit-Verhalten
|
||||||
closeBehaviourDescription=Legt fest, wie XPipe beim Schließen des Hauptfensters vorgehen soll.
|
closeBehaviourDescription=Legt fest, wie XPipe beim Schließen des Hauptfensters vorgehen soll.
|
||||||
language=Sprache
|
language=Sprache
|
||||||
languageDescription=Die zu verwendende Anzeigesprache.\n\nBeachte, dass die automatischen Übersetzungen als Grundlage dienen und von den Mitwirkenden manuell korrigiert und verbessert werden. Du kannst die Übersetzungsarbeit auch unterstützen, indem du Übersetzungsverbesserungen auf GitHub einreichst.
|
languageDescription=Die zu verwendende Anzeigesprache.\n\nBeachte, dass die automatischen Übersetzungen als Grundlage dienen und von den Mitwirkenden manuell korrigiert und verbessert werden. Du kannst die Übersetzungsarbeit auch unterstützen, indem du Übersetzungsverbesserungen auf GitHub einreichst.
|
||||||
|
@ -366,7 +366,8 @@ developerModeDescription=Wenn diese Option aktiviert ist, hast du Zugriff auf ei
|
||||||
editor=Editor
|
editor=Editor
|
||||||
custom=Benutzerdefiniert
|
custom=Benutzerdefiniert
|
||||||
passwordManagerCommand=Passwortmanager-Befehl
|
passwordManagerCommand=Passwortmanager-Befehl
|
||||||
passwordManagerCommandDescription=Der Befehl, der ausgeführt werden soll, um Passwörter abzurufen. Der Platzhalterstring $KEY wird beim Aufruf durch den zitierten Passwortschlüssel ersetzt. Dies sollte deinen Passwortmanager CLI aufrufen, um das Passwort auf stdout auszugeben, z. B. mypassmgr get $KEY.\n\nDu kannst den Schlüssel dann so einstellen, dass er immer dann abgefragt wird, wenn du eine Verbindung aufbaust, die ein Passwort erfordert.
|
#custom
|
||||||
|
passwordManagerCommandDescription=Der Befehl, der ausgeführt werden soll, um Passwörter abzurufen. Der Platzhalterstring $KEY wird beim Aufruf durch den Passwortschlüssel mit Anführungszeichen ersetzt. Dies sollte deinen Passwortmanager CLI aufrufen, um das Passwort auf stdout auszugeben, z. B. mypassmgr get $KEY.\n\nDu kannst den Schlüssel dann so einstellen, dass er immer dann abgefragt wird, wenn du eine Verbindung aufbaust, die ein Passwort erfordert.
|
||||||
passwordManagerCommandTest=Passwort-Manager testen
|
passwordManagerCommandTest=Passwort-Manager testen
|
||||||
passwordManagerCommandTestDescription=Du kannst hier testen, ob die Ausgabe korrekt aussieht, wenn du einen Passwortmanager-Befehl eingerichtet hast. Der Befehl sollte nur das Passwort selbst auf stdout ausgeben, keine andere Formatierung sollte in der Ausgabe enthalten sein.
|
passwordManagerCommandTestDescription=Du kannst hier testen, ob die Ausgabe korrekt aussieht, wenn du einen Passwortmanager-Befehl eingerichtet hast. Der Befehl sollte nur das Passwort selbst auf stdout ausgeben, keine andere Formatierung sollte in der Ausgabe enthalten sein.
|
||||||
preferEditorTabs=Lieber neue Tabs öffnen
|
preferEditorTabs=Lieber neue Tabs öffnen
|
||||||
|
@ -434,3 +435,9 @@ modified=Geändert
|
||||||
isOnlySupported=wird nur mit einer professionellen Lizenz unterstützt
|
isOnlySupported=wird nur mit einer professionellen Lizenz unterstützt
|
||||||
areOnlySupported=werden nur mit einer professionellen Lizenz unterstützt
|
areOnlySupported=werden nur mit einer professionellen Lizenz unterstützt
|
||||||
updateReadyTitle=Update auf $VERSION$ bereit
|
updateReadyTitle=Update auf $VERSION$ bereit
|
||||||
|
#custom
|
||||||
|
templates=Vorlagen
|
||||||
|
retry=Wiederholen
|
||||||
|
retryAll=Alle Versuche wiederholen
|
||||||
|
replace=Ersetzen
|
||||||
|
replaceAll=Ersetze alles
|
||||||
|
|
|
@ -328,8 +328,8 @@ system=System
|
||||||
application=Application
|
application=Application
|
||||||
storage=Storage
|
storage=Storage
|
||||||
runOnStartup=Run on startup
|
runOnStartup=Run on startup
|
||||||
#context: setting
|
#context: title
|
||||||
closeBehaviour=Close behaviour
|
closeBehaviour=Exit behaviour
|
||||||
closeBehaviourDescription=Controls how XPipe should proceed upon closing its main window.
|
closeBehaviourDescription=Controls how XPipe should proceed upon closing its main window.
|
||||||
language=Language
|
language=Language
|
||||||
languageDescription=The display language to use.\n\nNote that the translations use automatically generated translations as a base and are manually fixed and improved by contributors. You can also help the translation effort by submitting translation fixes on GitHub.
|
languageDescription=The display language to use.\n\nNote that the translations use automatically generated translations as a base and are manually fixed and improved by contributors. You can also help the translation effort by submitting translation fixes on GitHub.
|
||||||
|
@ -439,3 +439,9 @@ modified=Modified
|
||||||
isOnlySupported=is only supported with a professional license
|
isOnlySupported=is only supported with a professional license
|
||||||
areOnlySupported=are only supported with a professional license
|
areOnlySupported=are only supported with a professional license
|
||||||
updateReadyTitle=Update to $VERSION$ ready
|
updateReadyTitle=Update to $VERSION$ ready
|
||||||
|
#context: digital template
|
||||||
|
templates=Templates
|
||||||
|
retry=Retry
|
||||||
|
retryAll=Retry all
|
||||||
|
replace=Replace
|
||||||
|
replaceAll=Replace all
|
||||||
|
|
|
@ -424,3 +424,8 @@ modified=Modificado
|
||||||
isOnlySupported=sólo es compatible con una licencia profesional
|
isOnlySupported=sólo es compatible con una licencia profesional
|
||||||
areOnlySupported=sólo son compatibles con una licencia profesional
|
areOnlySupported=sólo son compatibles con una licencia profesional
|
||||||
updateReadyTitle=Actualiza a $VERSION$ ready
|
updateReadyTitle=Actualiza a $VERSION$ ready
|
||||||
|
templates=Plantillas
|
||||||
|
retry=Reintentar
|
||||||
|
retryAll=Reintentar todo
|
||||||
|
replace=Sustituye
|
||||||
|
replaceAll=Sustituir todo
|
||||||
|
|
|
@ -424,3 +424,8 @@ modified=Modifié
|
||||||
isOnlySupported=n'est pris en charge qu'avec une licence professionnelle
|
isOnlySupported=n'est pris en charge qu'avec une licence professionnelle
|
||||||
areOnlySupported=ne sont pris en charge qu'avec une licence professionnelle
|
areOnlySupported=ne sont pris en charge qu'avec une licence professionnelle
|
||||||
updateReadyTitle=Mise à jour de $VERSION$ ready
|
updateReadyTitle=Mise à jour de $VERSION$ ready
|
||||||
|
templates=Modèles
|
||||||
|
retry=Réessayer
|
||||||
|
retryAll=Réessayer tout
|
||||||
|
replace=Remplacer
|
||||||
|
replaceAll=Remplacer tout
|
||||||
|
|
|
@ -424,3 +424,8 @@ modified=Modificato
|
||||||
isOnlySupported=è supportato solo con una licenza professionale
|
isOnlySupported=è supportato solo con una licenza professionale
|
||||||
areOnlySupported=sono supportati solo con una licenza professionale
|
areOnlySupported=sono supportati solo con una licenza professionale
|
||||||
updateReadyTitle=Aggiornamento a $VERSION$ ready
|
updateReadyTitle=Aggiornamento a $VERSION$ ready
|
||||||
|
templates=Modelli
|
||||||
|
retry=Riprova
|
||||||
|
retryAll=Riprova tutti
|
||||||
|
replace=Sostituire
|
||||||
|
replaceAll=Sostituisci tutto
|
||||||
|
|
|
@ -424,3 +424,8 @@ modified=変更された
|
||||||
isOnlySupported=プロフェッショナルライセンスでのみサポートされる
|
isOnlySupported=プロフェッショナルライセンスでのみサポートされる
|
||||||
areOnlySupported=プロフェッショナルライセンスでのみサポートされる
|
areOnlySupported=プロフェッショナルライセンスでのみサポートされる
|
||||||
updateReadyTitle=$VERSION$ に更新
|
updateReadyTitle=$VERSION$ に更新
|
||||||
|
templates=テンプレート
|
||||||
|
retry=リトライ
|
||||||
|
retryAll=すべて再試行する
|
||||||
|
replace=置き換える
|
||||||
|
replaceAll=すべて置き換える
|
||||||
|
|
|
@ -424,3 +424,8 @@ modified=Gewijzigd
|
||||||
isOnlySupported=wordt alleen ondersteund met een professionele licentie
|
isOnlySupported=wordt alleen ondersteund met een professionele licentie
|
||||||
areOnlySupported=worden alleen ondersteund met een professionele licentie
|
areOnlySupported=worden alleen ondersteund met een professionele licentie
|
||||||
updateReadyTitle=Bijwerken naar $VERSION$ klaar
|
updateReadyTitle=Bijwerken naar $VERSION$ klaar
|
||||||
|
templates=Sjablonen
|
||||||
|
retry=Opnieuw proberen
|
||||||
|
retryAll=Alles opnieuw proberen
|
||||||
|
replace=Vervangen
|
||||||
|
replaceAll=Alles vervangen
|
||||||
|
|
|
@ -424,3 +424,8 @@ modified=Modificado
|
||||||
isOnlySupported=só é suportado com uma licença profissional
|
isOnlySupported=só é suportado com uma licença profissional
|
||||||
areOnlySupported=só são suportados com uma licença profissional
|
areOnlySupported=só são suportados com uma licença profissional
|
||||||
updateReadyTitle=Actualiza para $VERSION$ ready
|
updateReadyTitle=Actualiza para $VERSION$ ready
|
||||||
|
templates=Modelos
|
||||||
|
retry=Repetir
|
||||||
|
retryAll=Repetir tudo
|
||||||
|
replace=Substitui
|
||||||
|
replaceAll=Substitui tudo
|
||||||
|
|
|
@ -424,3 +424,8 @@ modified=Изменено
|
||||||
isOnlySupported=поддерживается только при наличии профессиональной лицензии
|
isOnlySupported=поддерживается только при наличии профессиональной лицензии
|
||||||
areOnlySupported=поддерживаются только с профессиональной лицензией
|
areOnlySupported=поддерживаются только с профессиональной лицензией
|
||||||
updateReadyTitle=Обновление на $VERSION$ готово
|
updateReadyTitle=Обновление на $VERSION$ готово
|
||||||
|
templates=Шаблоны
|
||||||
|
retry=Retry
|
||||||
|
retryAll=Повторите все попытки
|
||||||
|
replace=Замените
|
||||||
|
replaceAll=Заменить все
|
||||||
|
|
|
@ -424,3 +424,8 @@ modified=Değiştirilmiş
|
||||||
isOnlySupported=yalnızca profesyonel lisans ile desteklenir
|
isOnlySupported=yalnızca profesyonel lisans ile desteklenir
|
||||||
areOnlySupported=yalnızca profesyonel lisans ile desteklenir
|
areOnlySupported=yalnızca profesyonel lisans ile desteklenir
|
||||||
updateReadyTitle=$VERSION$ için güncelleme hazır
|
updateReadyTitle=$VERSION$ için güncelleme hazır
|
||||||
|
templates=Şablonlar
|
||||||
|
retry=Yeniden Dene
|
||||||
|
retryAll=Tümünü yeniden dene
|
||||||
|
replace=Değiştirin
|
||||||
|
replaceAll=Tümünü değiştirin
|
||||||
|
|
|
@ -424,3 +424,8 @@ modified=已修改
|
||||||
isOnlySupported=只有专业许可证才支持
|
isOnlySupported=只有专业许可证才支持
|
||||||
areOnlySupported=只有专业许可证才支持
|
areOnlySupported=只有专业许可证才支持
|
||||||
updateReadyTitle=更新至$VERSION$ ready
|
updateReadyTitle=更新至$VERSION$ ready
|
||||||
|
templates=模板
|
||||||
|
retry=重试
|
||||||
|
retryAll=全部重试
|
||||||
|
replace=替换
|
||||||
|
replaceAll=全部替换
|
||||||
|
|
Loading…
Reference in a new issue