Rework
@@ -0,0 +1,90 @@
|
||||
package io.xpipe.ext.base.identity;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||
import io.xpipe.app.core.AppCache;
|
||||
import io.xpipe.app.cred.SshIdentityStrategy;
|
||||
import io.xpipe.app.cred.UsernameStrategy;
|
||||
import io.xpipe.app.ext.ValidationException;
|
||||
import io.xpipe.app.issue.ErrorEventFactory;
|
||||
import io.xpipe.app.secret.EncryptedValue;
|
||||
import io.xpipe.app.secret.SecretRetrievalStrategy;
|
||||
import io.xpipe.app.storage.DataStorage;
|
||||
import io.xpipe.app.storage.DataStoreEntry;
|
||||
import io.xpipe.app.storage.DataStoreEntryRef;
|
||||
import io.xpipe.app.util.Validators;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import lombok.Value;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
import lombok.extern.jackson.Jacksonized;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
@SuperBuilder
|
||||
@JsonTypeName("multiIdentity")
|
||||
@Jacksonized
|
||||
@Value
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class MultiIdentityStore extends IdentityStore {
|
||||
|
||||
List<DataStoreEntryRef<IdentityStore>> identities;
|
||||
|
||||
public List<DataStoreEntryRef<IdentityStore>> getAvailableIdentities() {
|
||||
return identities.stream().filter(ref -> ref != null && ref.get().getValidity().isUsable()).toList();
|
||||
}
|
||||
|
||||
public Optional<DataStoreEntryRef<IdentityStore>> getSelected() {
|
||||
UUID cached = AppCache.getNonNull("id-default-" + getSelfEntry().getUuid(), UUID.class, () -> null);
|
||||
if (cached != null) {
|
||||
var entry = DataStorage.get().getStoreEntryIfPresent(cached);
|
||||
if (entry.isPresent() && entry.get().getValidity().isUsable() && getAvailableIdentities().contains(entry.get().ref())) {
|
||||
return Optional.of(entry.get().ref());
|
||||
}
|
||||
}
|
||||
|
||||
var fallback = getAvailableIdentities().stream().findFirst();
|
||||
if (fallback.isPresent()) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public void select(DataStoreEntryRef<IdentityStore> entry) {
|
||||
if (!getAvailableIdentities().contains(entry)) {
|
||||
return;
|
||||
}
|
||||
|
||||
AppCache.update("id-default-" + getSelfEntry().getUuid(), entry.get().getUuid());
|
||||
}
|
||||
|
||||
private DataStoreEntryRef<IdentityStore> getSelectedOrThrow() {
|
||||
var found = getSelected();
|
||||
if (found.isPresent()) {
|
||||
return found.get();
|
||||
}
|
||||
throw ErrorEventFactory.expected(new IllegalStateException("No available identity for multi identity " + getSelfEntry().getName()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkComplete() throws Throwable {
|
||||
getSelectedOrThrow();
|
||||
}
|
||||
|
||||
public UsernameStrategy getUsername() {
|
||||
return getSelectedOrThrow().getStore().getUsername();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecretRetrievalStrategy getPassword() {
|
||||
return getSelectedOrThrow().getStore().getPassword();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SshIdentityStrategy getSshIdentity() {
|
||||
return getSelectedOrThrow().getStore().getSshIdentity();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package io.xpipe.ext.base.identity;
|
||||
|
||||
import io.xpipe.app.cred.NoIdentityStrategy;
|
||||
import io.xpipe.app.cred.SshIdentityStrategyChoiceConfig;
|
||||
import io.xpipe.app.ext.DataStore;
|
||||
import io.xpipe.app.ext.GuiDialog;
|
||||
import io.xpipe.app.hub.comp.StoreListChoiceComp;
|
||||
import io.xpipe.app.hub.comp.StoreViewState;
|
||||
import io.xpipe.app.platform.OptionsBuilder;
|
||||
import io.xpipe.app.platform.OptionsChoiceBuilder;
|
||||
import io.xpipe.app.secret.EncryptedValue;
|
||||
import io.xpipe.app.secret.SecretNoneStrategy;
|
||||
import io.xpipe.app.secret.SecretRetrievalStrategy;
|
||||
import io.xpipe.app.secret.SecretStrategyChoiceConfig;
|
||||
import io.xpipe.app.storage.DataStorage;
|
||||
import io.xpipe.app.storage.DataStoreCategory;
|
||||
import io.xpipe.app.storage.DataStoreEntry;
|
||||
import io.xpipe.app.util.DocumentationLink;
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.beans.property.SimpleListProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.collections.FXCollections;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class MultiIdentityStoreProvider extends IdentityStoreProvider {
|
||||
|
||||
@Override
|
||||
public GuiDialog guiDialog(DataStoreEntry entry, Property<DataStore> store) {
|
||||
MultiIdentityStore st = (MultiIdentityStore) store.getValue();
|
||||
|
||||
var identities = new SimpleListProperty<>(FXCollections.observableArrayList(st.getIdentities()));
|
||||
|
||||
return new OptionsBuilder()
|
||||
.nameAndDescription("multiIdentityList")
|
||||
.addComp(new StoreListChoiceComp<>(identities, IdentityStore.class,
|
||||
ref -> !(ref.getStore() instanceof MultiIdentityStore) && !identities.contains(ref),
|
||||
StoreViewState.get().getAllIdentitiesCategory()))
|
||||
.bind(
|
||||
() -> {
|
||||
return MultiIdentityStore.builder()
|
||||
.identities(identities)
|
||||
.build();
|
||||
},
|
||||
store)
|
||||
.buildDialog();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataStore defaultStore(DataStoreCategory category) {
|
||||
return MultiIdentityStore.builder()
|
||||
.identities(new ArrayList<>())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "multiIdentity";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Class<?>> getStoreClasses() {
|
||||
return List.of(MultiIdentityStore.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package io.xpipe.ext.base.identity;
|
||||
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.hub.action.HubBranchProvider;
|
||||
import io.xpipe.app.hub.action.HubLeafProvider;
|
||||
import io.xpipe.app.hub.action.HubMenuItemProvider;
|
||||
import io.xpipe.app.hub.action.StoreActionCategory;
|
||||
import io.xpipe.app.platform.LabelGraphic;
|
||||
import io.xpipe.app.storage.DataStorage;
|
||||
import io.xpipe.app.storage.DataStoreEntryRef;
|
||||
import javafx.beans.property.ReadOnlyStringWrapper;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class MultiIdentitySwitchBranchProvider implements HubBranchProvider<MultiIdentityStore> {
|
||||
|
||||
@Override
|
||||
public boolean isMajor() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<HubMenuItemProvider<?>> getChildren(DataStoreEntryRef<MultiIdentityStore> store) {
|
||||
var selected = store.getStore().getSelected();
|
||||
return store.getStore().getAvailableIdentities().stream()
|
||||
.map(is -> {
|
||||
return new IdentityProvider(is, selected.map(ref -> ref.equals(is)).orElse(false));
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoreActionCategory getCategory() {
|
||||
return StoreActionCategory.CONFIGURATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isApplicable(DataStoreEntryRef<MultiIdentityStore> o) {
|
||||
return o.getStore().getAvailableIdentities().size() > 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObservableValue<String> getName(DataStoreEntryRef<MultiIdentityStore> store) {
|
||||
return AppI18n.observable("switchIdentity");
|
||||
}
|
||||
|
||||
@Override
|
||||
public LabelGraphic getIcon(DataStoreEntryRef<MultiIdentityStore> store) {
|
||||
return new LabelGraphic.IconGraphic("mdi2f-format-list-group");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<MultiIdentityStore> getApplicableClass() {
|
||||
return MultiIdentityStore.class;
|
||||
}
|
||||
|
||||
private static class IdentityProvider implements HubLeafProvider<MultiIdentityStore> {
|
||||
|
||||
private final DataStoreEntryRef<IdentityStore> identity;
|
||||
private final boolean active;
|
||||
|
||||
private IdentityProvider(DataStoreEntryRef<IdentityStore> identity, boolean active) {
|
||||
this.identity = identity;
|
||||
this.active = active;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(DataStoreEntryRef<MultiIdentityStore> ref) {
|
||||
ref.getStore().select(identity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObservableValue<String> getName(DataStoreEntryRef<MultiIdentityStore> store) {
|
||||
return new ReadOnlyStringWrapper((active ? "> " : "") + identity.get().getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public LabelGraphic getIcon(DataStoreEntryRef<MultiIdentityStore> store) {
|
||||
return new LabelGraphic.ImageGraphic(identity.get().getEffectiveIconFile(), 16);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<MultiIdentityStore> getApplicableClass() {
|
||||
return MultiIdentityStore.class;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,7 @@ open module io.xpipe.ext.base {
|
||||
AbstractHostCreationActionProvider,
|
||||
HostAddressSwitchBranchProvider,
|
||||
LocalIdentityConvertHubLeafProvider,
|
||||
MultiIdentitySwitchBranchProvider,
|
||||
RunBackgroundScriptActionProvider,
|
||||
RunHubBatchScriptActionProvider,
|
||||
RunHubScriptActionProvider,
|
||||
@@ -68,6 +69,7 @@ open module io.xpipe.ext.base {
|
||||
LocalIdentityStoreProvider,
|
||||
SyncedIdentityStoreProvider,
|
||||
PasswordManagerIdentityStoreProvider,
|
||||
MultiIdentityStoreProvider,
|
||||
AbstractHostStoreProvider;
|
||||
provides DataStorageExtensionProvider with
|
||||
ScriptDataStorageProvider;
|
||||
|
||||
|
After Width: | Height: | Size: 589 B |
|
After Width: | Height: | Size: 564 B |
|
After Width: | Height: | Size: 878 B |
|
After Width: | Height: | Size: 819 B |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
@@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
id="Layer_1"
|
||||
data-name="Layer 1"
|
||||
viewBox="0 0 204.59 204.59"
|
||||
version="1.1"
|
||||
sodipodi:docname="multiIdentity_icon-dark.svg"
|
||||
inkscape:version="1.4 (86a8ad7, 2024-10-11)"
|
||||
xml:space="preserve"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"><path
|
||||
style="fill:#e98325;fill-opacity:1;stroke-width:0.647549"
|
||||
d="m 137.49341,134.48676 -18.02556,-19.08771 -0.002,12.28612 h -16.44943 -0.3122 -9.677136 v 13.60523 h 9.678366 v 0 h 16.75995 l 0.002,12.28747 z"
|
||||
id="path1-4" /><sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#000000"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="2.7891646"
|
||||
inkscape:cx="127.99531"
|
||||
inkscape:cy="122.79663"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1009"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="Layer_1" /><defs
|
||||
id="defs856"><style
|
||||
id="style854">.cls-1{fill:#ac55ff;}</style><style
|
||||
id="style2411">.cls-1{fill:#606161;}</style></defs><title
|
||||
id="title858">identity</title><path
|
||||
class="cls-1"
|
||||
d="M332.32,153.7H179.68a26,26,0,0,0-26,26V332.32a26,26,0,0,0,26,26H332.32a26,26,0,0,0,26-26V179.68A26,26,0,0,0,332.32,153.7Zm14,178.62a14,14,0,0,1-14,14H179.68a14,14,0,0,1-14-14V179.68a14,14,0,0,1,14-14H332.32a14,14,0,0,1,14,14Z"
|
||||
id="path860"
|
||||
style="fill:#d9d9d9;fill-opacity:1"
|
||||
transform="translate(-153.7 -153.7)" /><metadata
|
||||
id="metadata932"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:title>identity</dc:title></cc:Work></rdf:RDF></metadata><path
|
||||
d="M 154.40997,126.10572 A 53.816715,53.816715 0 0 0 142.81203,108.91027 54.051264,54.051264 0 0 0 125.61659,97.312331 c -0.0576,-0.0288 -0.11512,-0.0432 -0.17268,-0.072 8.96466,-6.47527 14.7924,-17.02277 14.7924,-28.92289 0,-19.71361 -15.97234,-35.68595 -35.68595,-35.68595 -19.713613,0 -35.685953,15.97234 -35.685953,35.68595 0,11.90012 5.82775,22.44762 14.79241,28.93728 -0.0576,0.0288 -0.11512,0.0432 -0.17268,0.072 -6.44649,2.719609 -12.23107,6.619159 -17.19545,11.597939 a 54.051264,54.051264 0 0 0 -11.59793,17.19545 53.485756,53.485756 0 0 0 -4.2449,19.87189 1.1511597,1.1511597 0 0 0 1.15116,1.17994 h 8.6337 c 0.63313,0 1.13677,-0.50363 1.15116,-1.12238 0.28779,-11.10869 4.74853,-21.5123 12.63397,-29.39774 8.15885,-8.15884 18.99414,-12.64838 30.534513,-12.64838 11.54038,0 22.37567,4.48954 30.53451,12.64838 7.88545,7.88544 12.34619,18.28905 12.63398,29.39774 0.0144,0.63314 0.51802,1.12238 1.15116,1.12238 h 8.6337 a 1.1511597,1.1511597 0 0 0 1.15116,-1.17994 c -0.1439,-6.87818 -1.56846,-13.56929 -4.2449,-19.88628 z M 104.55036,93.067431 c -6.604773,0 -12.821043,-2.57572 -17.497623,-7.25231 -4.67659,-4.67659 -7.25231,-10.89285 -7.25231,-17.49763 0,-6.60478 2.57572,-12.82104 7.25231,-17.49762 4.67658,-4.67659 10.89285,-7.25231 17.497623,-7.25231 6.60478,0 12.82104,2.57572 17.49763,7.25231 4.67659,4.67658 7.25231,10.89284 7.25231,17.49762 0,6.60478 -2.57572,12.82104 -7.25231,17.49763 -4.67659,4.67659 -10.89285,7.25231 -17.49763,7.25231 z"
|
||||
id="path1"
|
||||
style="fill:#e98325;fill-opacity:1;stroke-width:0.143895" /><path
|
||||
style="fill:#e98325;fill-opacity:1;stroke-width:0.653351"
|
||||
d="m 66.172124,153.93532 18.350031,-19.08837 0.0012,12.28609 h 16.745855 0.31783 9.29408 v 13.60524 h -9.29529 v 0 H 84.523412 l -0.0012,12.28747 z"
|
||||
id="path2" /></svg>
|
||||
|
After Width: | Height: | Size: 3.8 KiB |
@@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
id="Layer_1"
|
||||
data-name="Layer 1"
|
||||
viewBox="0 0 204.59 204.59"
|
||||
version="1.1"
|
||||
sodipodi:docname="multiIdentity_icon.svg"
|
||||
inkscape:version="1.4 (86a8ad7, 2024-10-11)"
|
||||
xml:space="preserve"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"><path
|
||||
style="fill:#d96700;fill-opacity:1;stroke-width:0.647549"
|
||||
d="m 137.49341,134.48676 -18.02556,-19.08771 -0.002,12.28612 h -16.44943 -0.3122 -9.677136 v 13.60523 h 9.678366 v 0 h 16.75995 l 0.002,12.28747 z"
|
||||
id="path1-4" /><sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="1.9722372"
|
||||
inkscape:cx="146.5341"
|
||||
inkscape:cy="133.60462"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1009"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="Layer_1" /><defs
|
||||
id="defs856"><style
|
||||
id="style854">.cls-1{fill:#ac55ff;}</style><style
|
||||
id="style2411">.cls-1{fill:#606161;}</style></defs><title
|
||||
id="title858">identity</title><path
|
||||
class="cls-1"
|
||||
d="M332.32,153.7H179.68a26,26,0,0,0-26,26V332.32a26,26,0,0,0,26,26H332.32a26,26,0,0,0,26-26V179.68A26,26,0,0,0,332.32,153.7Zm14,178.62a14,14,0,0,1-14,14H179.68a14,14,0,0,1-14-14V179.68a14,14,0,0,1,14-14H332.32a14,14,0,0,1,14,14Z"
|
||||
id="path860"
|
||||
style="fill:#212121;fill-opacity:1"
|
||||
transform="translate(-153.7 -153.7)" /><metadata
|
||||
id="metadata932"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:title>identity</dc:title></cc:Work></rdf:RDF></metadata><path
|
||||
d="M 154.40997,126.10572 A 53.816715,53.816715 0 0 0 142.81203,108.91027 54.051264,54.051264 0 0 0 125.61659,97.312331 c -0.0576,-0.0288 -0.11512,-0.0432 -0.17268,-0.072 8.96466,-6.47527 14.7924,-17.02277 14.7924,-28.92289 0,-19.71361 -15.97234,-35.68595 -35.68595,-35.68595 -19.713613,0 -35.685953,15.97234 -35.685953,35.68595 0,11.90012 5.82775,22.44762 14.79241,28.93728 -0.0576,0.0288 -0.11512,0.0432 -0.17268,0.072 -6.44649,2.719609 -12.23107,6.619159 -17.19545,11.597939 a 54.051264,54.051264 0 0 0 -11.59793,17.19545 53.485756,53.485756 0 0 0 -4.2449,19.87189 1.1511597,1.1511597 0 0 0 1.15116,1.17994 h 8.6337 c 0.63313,0 1.13677,-0.50363 1.15116,-1.12238 0.28779,-11.10869 4.74853,-21.5123 12.63397,-29.39774 8.15885,-8.15884 18.99414,-12.64838 30.534513,-12.64838 11.54038,0 22.37567,4.48954 30.53451,12.64838 7.88545,7.88544 12.34619,18.28905 12.63398,29.39774 0.0144,0.63314 0.51802,1.12238 1.15116,1.12238 h 8.6337 a 1.1511597,1.1511597 0 0 0 1.15116,-1.17994 c -0.1439,-6.87818 -1.56846,-13.56929 -4.2449,-19.88628 z M 104.55036,93.067431 c -6.604773,0 -12.821043,-2.57572 -17.497623,-7.25231 -4.67659,-4.67659 -7.25231,-10.89285 -7.25231,-17.49763 0,-6.60478 2.57572,-12.82104 7.25231,-17.49762 4.67658,-4.67659 10.89285,-7.25231 17.497623,-7.25231 6.60478,0 12.82104,2.57572 17.49763,7.25231 4.67659,4.67658 7.25231,10.89284 7.25231,17.49762 0,6.60478 -2.57572,12.82104 -7.25231,17.49763 -4.67659,4.67659 -10.89285,7.25231 -17.49763,7.25231 z"
|
||||
id="path1"
|
||||
style="fill:#d96700;fill-opacity:1;stroke-width:0.143895" /><path
|
||||
style="fill:#d96700;fill-opacity:1;stroke-width:0.653351"
|
||||
d="m 66.172124,153.93532 18.350031,-19.08837 0.0012,12.28609 h 16.745855 0.31783 9.29408 v 13.60524 h -9.29529 v 0 H 84.523412 l -0.0012,12.28747 z"
|
||||
id="path2" /></svg>
|
||||
|
After Width: | Height: | Size: 3.8 KiB |
@@ -2016,3 +2016,8 @@ passwordManagerSshAgentSocketDescription=Override the default agent socket locat
|
||||
passwordManagerSshKeysNotSupported=The current password manager configuration does not support retrieving SSH keys
|
||||
passwordManagerIdentityAgentKey=Additional SSH key
|
||||
passwordManagerIdentityAgentKeyDescription=The SSH key to use from the password manager SSH agent
|
||||
multiIdentity.displayName=Multi identity
|
||||
multiIdentity.displayDescription=Choose from multiple different identities to connect to a system
|
||||
multiIdentityList=Identity list
|
||||
multiIdentityListDescription=The list of identities to switch between
|
||||
switchIdentity=Switch identity
|
||||