mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-07-01 04:21:11 +12:00
Add ssh config support plus polishing
This commit is contained in:
parent
c70d6da314
commit
5be0748c9f
|
@ -7,6 +7,7 @@ import io.xpipe.app.fxcomps.impl.TextAreaComp;
|
|||
import io.xpipe.app.util.FileOpener;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.StackPane;
|
||||
|
@ -18,9 +19,10 @@ public class IntegratedTextAreaComp extends SimpleComp {
|
|||
private final Property<String> value;
|
||||
private final boolean lazy;
|
||||
private final String identifier;
|
||||
private final String fileType;
|
||||
private final ObservableValue<String> fileType;
|
||||
|
||||
public IntegratedTextAreaComp(Property<String> value, boolean lazy, String identifier, String fileType) {
|
||||
public IntegratedTextAreaComp(
|
||||
Property<String> value, boolean lazy, String identifier, ObservableValue<String> fileType) {
|
||||
this.value = value;
|
||||
this.lazy = lazy;
|
||||
this.identifier = identifier;
|
||||
|
@ -47,10 +49,13 @@ public class IntegratedTextAreaComp extends SimpleComp {
|
|||
}
|
||||
|
||||
private Region createOpenButton(Region container) {
|
||||
var name = identifier + (fileType != null ? "." + fileType : "");
|
||||
var button = new IconButtonComp(
|
||||
"mdal-edit",
|
||||
() -> FileOpener.openString(name, this, value.getValue(), (s) -> {
|
||||
() -> FileOpener.openString(
|
||||
identifier + (fileType.getValue() != null ? "." + fileType.getValue() : ""),
|
||||
this,
|
||||
value.getValue(),
|
||||
(s) -> {
|
||||
Platform.runLater(() -> value.setValue(s));
|
||||
}))
|
||||
.createRegion();
|
||||
|
|
|
@ -23,8 +23,8 @@ public class DenseStoreEntryComp extends StoreEntryComp {
|
|||
grid.setHgap(8);
|
||||
|
||||
if (showIcon) {
|
||||
var storeIcon = createIcon(30, 25);
|
||||
grid.getColumnConstraints().add(new ColumnConstraints(30));
|
||||
var storeIcon = createIcon(26, 21);
|
||||
grid.getColumnConstraints().add(new ColumnConstraints(26));
|
||||
grid.add(storeIcon, 0, 0);
|
||||
GridPane.setHalignment(storeIcon, HPos.CENTER);
|
||||
} else {
|
||||
|
|
|
@ -17,10 +17,10 @@ public class StandardStoreEntryComp extends StoreEntryComp {
|
|||
var name = createName().createRegion();
|
||||
|
||||
var grid = new GridPane();
|
||||
grid.setHgap(10);
|
||||
grid.setHgap(7);
|
||||
grid.setVgap(0);
|
||||
|
||||
var storeIcon = createIcon(45, 35);
|
||||
var storeIcon = createIcon(50, 39);
|
||||
grid.add(storeIcon, 0, 0, 1, 2);
|
||||
grid.getColumnConstraints().add(new ColumnConstraints(50));
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package io.xpipe.app.fxcomps.impl;
|
||||
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.fxcomps.Comp;
|
||||
import io.xpipe.app.fxcomps.CompStructure;
|
||||
import io.xpipe.app.fxcomps.SimpleCompStructure;
|
||||
|
@ -37,8 +36,8 @@ public class ChoicePaneComp extends Comp<CompStructure<VBox>> {
|
|||
cb.setConverter(new StringConverter<>() {
|
||||
@Override
|
||||
public String toString(Entry object) {
|
||||
if (object == null) {
|
||||
return AppI18n.get("app.none");
|
||||
if (object == null || object.name() == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return object.name().getValue();
|
||||
|
@ -53,9 +52,11 @@ public class ChoicePaneComp extends Comp<CompStructure<VBox>> {
|
|||
var vbox = new VBox(transformer.apply(cb));
|
||||
vbox.setFillWidth(true);
|
||||
cb.prefWidthProperty().bind(vbox.widthProperty());
|
||||
SimpleChangeListener.apply(cb.valueProperty(), n-> {
|
||||
SimpleChangeListener.apply(cb.valueProperty(), n -> {
|
||||
if (n == null) {
|
||||
if (vbox.getChildren().size() > 1) {
|
||||
vbox.getChildren().remove(1);
|
||||
}
|
||||
} else {
|
||||
var region = n.comp().createRegion();
|
||||
region.setPadding(new Insets(0, 0, 0, 10));
|
||||
|
|
|
@ -93,7 +93,7 @@ public class SvgView {
|
|||
|
||||
private WebView createWebView() {
|
||||
var wv = new WebView();
|
||||
// Sometimes a web view might not render when the background is said to transparent, at least according to stack
|
||||
// Sometimes a web view might not render when the background is set to transparent, at least according to stack
|
||||
// overflow
|
||||
wv.setPageFill(Color.valueOf("#00000001"));
|
||||
// wv.setPageFill(Color.BLACK);
|
||||
|
|
|
@ -69,12 +69,12 @@ public class JfxHelper {
|
|||
return text;
|
||||
}
|
||||
|
||||
var size = AppFont.getPixelSize(1) + AppFont.getPixelSize(-2) + 2;
|
||||
var size = AppFont.getPixelSize(1) + AppFont.getPixelSize(-2) + 8;
|
||||
var graphic = new PrettyImageComp(new SimpleStringProperty(image), size, size).createRegion();
|
||||
|
||||
var hbox = new HBox(graphic, text);
|
||||
hbox.setAlignment(Pos.CENTER_LEFT);
|
||||
hbox.setSpacing(8);
|
||||
hbox.setSpacing(10);
|
||||
|
||||
// graphic.fitWidthProperty().bind(Bindings.createDoubleBinding(() -> header.getHeight() +
|
||||
// desc.getHeight() + 2,
|
||||
|
|
|
@ -48,11 +48,11 @@ public class OptionsBuilder {
|
|||
public OptionsBuilder choice(IntegerProperty selectedIndex, Map<String, OptionsBuilder> options) {
|
||||
var list = options.entrySet().stream()
|
||||
.map(e -> new ChoicePaneComp.Entry(
|
||||
AppI18n.observable(e.getKey()), e.getValue().buildComp()))
|
||||
AppI18n.observable(e.getKey()), e.getValue() != null ? e.getValue().buildComp() : Comp.empty()))
|
||||
.toList();
|
||||
var validatorList =
|
||||
options.values().stream().map(builder -> builder.buildEffectiveValidator()).toList();
|
||||
var selected = new SimpleObjectProperty<>(list.get(selectedIndex.getValue()));
|
||||
options.values().stream().map(builder -> builder != null ? builder.buildEffectiveValidator() : new SimpleValidator()).toList();
|
||||
var selected = new SimpleObjectProperty<>(selectedIndex.getValue() != -1 ? list.get(selectedIndex.getValue()) : null);
|
||||
selected.addListener((observable, oldValue, newValue) -> {
|
||||
selectedIndex.setValue(newValue != null ? list.indexOf(newValue) : null);
|
||||
});
|
||||
|
@ -65,7 +65,11 @@ public class OptionsBuilder {
|
|||
validatorMap.put(null, new SimpleValidator());
|
||||
var orVal = new ExclusiveValidator<>(validatorMap, selected);
|
||||
|
||||
options.values().forEach(builder -> props.addAll(builder.props));
|
||||
options.values().forEach(builder -> {
|
||||
if (builder != null) {
|
||||
props.addAll(builder.props);
|
||||
}
|
||||
});
|
||||
props.add(selectedIndex);
|
||||
allValidators.add(orVal);
|
||||
pushComp(pane);
|
||||
|
|
|
@ -86,7 +86,7 @@ public class SecretRetrievalStrategyHelper {
|
|||
? 1
|
||||
: strat instanceof SecretRetrievalStrategy.PasswordManager
|
||||
? 2
|
||||
: strat instanceof SecretRetrievalStrategy.CustomCommand ? 3 : strat instanceof SecretRetrievalStrategy.Prompt ? 4 : 0);
|
||||
: strat instanceof SecretRetrievalStrategy.CustomCommand ? 3 : strat instanceof SecretRetrievalStrategy.Prompt ? 4 : strat == null ? -1 : 0);
|
||||
return new OptionsBuilder()
|
||||
.choice(selected, map)
|
||||
.bindChoice(
|
||||
|
@ -97,6 +97,7 @@ public class SecretRetrievalStrategyHelper {
|
|||
case 2 -> passwordManager;
|
||||
case 3 -> customCommand;
|
||||
case 4 -> new SimpleObjectProperty<>(new SecretRetrievalStrategy.Prompt());
|
||||
case 5 -> new SimpleObjectProperty<>();
|
||||
default -> new SimpleObjectProperty<>();
|
||||
};
|
||||
},
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package io.xpipe.core.dialog;
|
||||
|
||||
import io.xpipe.core.charsetter.Charsetter;
|
||||
import io.xpipe.core.util.FailableSupplier;
|
||||
import io.xpipe.core.util.SecretValue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -457,11 +458,6 @@ public abstract class Dialog {
|
|||
|
||||
protected abstract DialogElement next(String answer) throws Exception;
|
||||
|
||||
public interface FailableSupplier<T> {
|
||||
|
||||
T get() throws Exception;
|
||||
}
|
||||
|
||||
public static class Choice extends Dialog {
|
||||
|
||||
private final ChoiceElement element;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package io.xpipe.core.process;
|
||||
|
||||
import io.xpipe.core.dialog.Dialog;
|
||||
import io.xpipe.core.util.FailableFunction;
|
||||
import io.xpipe.core.util.FailableSupplier;
|
||||
import io.xpipe.core.util.SecretValue;
|
||||
import io.xpipe.core.util.XPipeSystemId;
|
||||
import lombok.NonNull;
|
||||
|
@ -99,7 +99,7 @@ public interface ShellControl extends ProcessControl {
|
|||
default ShellControl elevationPassword(SecretValue value) {
|
||||
return elevationPassword(() -> value);
|
||||
}
|
||||
ShellControl elevationPassword(Dialog.FailableSupplier<SecretValue> value);
|
||||
ShellControl elevationPassword(FailableSupplier<SecretValue> value);
|
||||
|
||||
ShellControl initWith(String cmds);
|
||||
|
||||
|
@ -107,7 +107,7 @@ public interface ShellControl extends ProcessControl {
|
|||
|
||||
ShellControl startTimeout(int ms);
|
||||
|
||||
Dialog.FailableSupplier<SecretValue> getElevationPassword();
|
||||
FailableSupplier<SecretValue> getElevationPassword();
|
||||
|
||||
default ShellControl subShell(@NonNull ShellDialect type) {
|
||||
return subShell(p -> type.getOpenCommand(), new TerminalOpenFunction() {
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
package io.xpipe.core.util;
|
||||
|
||||
public interface FailableSupplier<T> {
|
||||
|
||||
T get() throws Exception;
|
||||
}
|
|
@ -1,7 +1,5 @@
|
|||
package io.xpipe.core.util;
|
||||
|
||||
import io.xpipe.core.dialog.Dialog;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
|
@ -15,7 +13,7 @@ public class UuidHelper {
|
|||
}
|
||||
}
|
||||
|
||||
public static Optional<UUID> parse(Dialog.FailableSupplier<String> supplier) {
|
||||
public static Optional<UUID> parse(FailableSupplier<String> supplier) {
|
||||
try {
|
||||
var s = supplier.get();
|
||||
return Optional.of(UUID.fromString(s));
|
||||
|
|
8
dist/changelogs/1.5.0.md
vendored
8
dist/changelogs/1.5.0.md
vendored
|
@ -29,9 +29,10 @@ To start off, it comes with a few new commands to read and write files on remote
|
|||
|
||||
The workflow is designed as follows:
|
||||
|
||||
1. You can list all available connections and their ids to use with `xpipe list`
|
||||
2. Using the command `xpipe drain <id> <remote file path>`, you are able to forward the file contents to the stdout
|
||||
3. Using the command `xpipe sink <id> <remote file path>`, you are able to forward content from your stdin to the remote file
|
||||
- You can list all available connections and their ids to use with `xpipe list`
|
||||
- Using the command `xpipe launch <id>`, you are able to log into a remote shell connection in your existing terminal session
|
||||
- Using the command `xpipe drain <id> <remote file path>`, you are able to forward the file contents to the stdout
|
||||
- Using the command `xpipe sink <id> <remote file path>`, you are able to forward content from your stdin to the remote file
|
||||
|
||||
The id system is flexible, allowing you to only specify as much of the id as is necessary.
|
||||
|
||||
|
@ -64,6 +65,7 @@ This also comes with full support of the feature set for these environments
|
|||
- Fix desktop directory not being determined correctly on Windows when it was moved from the default location
|
||||
- Rework threading in navigation bar in browser to improve responsiveness
|
||||
- Recheck if prepared update is still the latest one prior to installing it
|
||||
- Properly use shell script file extension for external editor when creating shell environments
|
||||
- Built-in documentation popups now honour the dark mode setting
|
||||
- Properly detect applications such as editors and terminals when they are present in the path on Windows
|
||||
- Rework operation mode handling to properly honor the startup mode setting
|
||||
|
|
Loading…
Reference in a new issue