mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-21 23:20:23 +00:00
Refactor plus several fixes
This commit is contained in:
parent
5be0748c9f
commit
1f2919278f
34 changed files with 351 additions and 97 deletions
|
@ -4,7 +4,6 @@ import atlantafx.base.controls.Breadcrumbs;
|
|||
import io.xpipe.app.fxcomps.SimpleComp;
|
||||
import io.xpipe.app.fxcomps.util.PlatformThread;
|
||||
import io.xpipe.app.fxcomps.util.SimpleChangeListener;
|
||||
import io.xpipe.app.util.ThreadHelper;
|
||||
import io.xpipe.core.impl.FileNames;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Button;
|
||||
|
@ -81,9 +80,7 @@ public class BrowserBreadcrumbBar extends SimpleComp {
|
|||
}
|
||||
|
||||
breadcrumbs.selectedCrumbProperty().addListener((obs, old, val) -> {
|
||||
ThreadHelper.runFailableAsync(() -> {
|
||||
model.cdSync(val != null ? val.getValue() : null);
|
||||
});
|
||||
model.cdAsync(val != null ? val.getValue() : null);
|
||||
});
|
||||
|
||||
return breadcrumbs;
|
||||
|
|
|
@ -200,7 +200,7 @@ public class BrowserFileListCompEntry {
|
|||
return;
|
||||
}
|
||||
|
||||
model.getFileSystemModel().cdSync(item.getRawFileEntry().getPath());
|
||||
model.getFileSystemModel().cdAsync(item.getRawFileEntry().getPath());
|
||||
}
|
||||
};
|
||||
DROP_TIMER.schedule(activeTask, 1000);
|
||||
|
|
|
@ -128,7 +128,7 @@ public final class BrowserFileListModel {
|
|||
}
|
||||
|
||||
if (entry.getRawFileEntry().resolved().getKind() == FileKind.DIRECTORY) {
|
||||
fileSystemModel.cdSync(entry.getRawFileEntry().resolved().getPath());
|
||||
fileSystemModel.cdAsync(entry.getRawFileEntry().resolved().getPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ public class BrowserFileOverviewComp extends SimpleComp {
|
|||
var icon = BrowserIcons.createIcon(entry);
|
||||
var l = new Button(entry.getPath(), icon.createRegion());
|
||||
l.setOnAction(event -> {
|
||||
model.cdSync(entry.getPath());
|
||||
model.cdAsync(entry.getPath());
|
||||
event.consume();
|
||||
});
|
||||
l.setAlignment(Pos.CENTER_LEFT);
|
||||
|
|
|
@ -11,6 +11,7 @@ import io.xpipe.app.fxcomps.impl.PrettyImageComp;
|
|||
import io.xpipe.app.fxcomps.impl.StackComp;
|
||||
import io.xpipe.app.fxcomps.impl.TextFieldComp;
|
||||
import io.xpipe.app.fxcomps.util.SimpleChangeListener;
|
||||
import io.xpipe.app.util.BusyProperty;
|
||||
import io.xpipe.app.util.ThreadHelper;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.binding.Bindings;
|
||||
|
@ -45,8 +46,10 @@ public class BrowserNavBar extends SimpleComp {
|
|||
});
|
||||
path.addListener((observable, oldValue, newValue) -> {
|
||||
ThreadHelper.runFailableAsync(() -> {
|
||||
var changed = model.cdSyncOrRetry(newValue, true);
|
||||
changed.ifPresent(s -> Platform.runLater(() -> path.set(s)));
|
||||
BusyProperty.execute(model.getBusy(), () -> {
|
||||
var changed = model.cdSyncOrRetry(newValue, true);
|
||||
changed.ifPresent(s -> Platform.runLater(() -> path.set(s)));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -88,7 +91,7 @@ public class BrowserNavBar extends SimpleComp {
|
|||
() -> {
|
||||
var icon = model.getCurrentDirectory() != null
|
||||
? FileIconManager.getFileIcon(model.getCurrentDirectory(), false)
|
||||
: "home_icon.png";
|
||||
: "home_icon.svg";
|
||||
return icon;
|
||||
},
|
||||
model.getCurrentPath());
|
||||
|
|
|
@ -43,7 +43,7 @@ public class OpenFileSystemComp extends SimpleComp {
|
|||
|
||||
private Region createContent() {
|
||||
var overview = new Button(null, new FontIcon("mdi2m-monitor"));
|
||||
overview.setOnAction(e -> model.cdSync(null));
|
||||
overview.setOnAction(e -> model.cdAsync(null));
|
||||
overview.disableProperty().bind(model.getInOverview());
|
||||
overview.setAccessibleText("System overview");
|
||||
|
||||
|
|
|
@ -107,6 +107,14 @@ public final class OpenFileSystemModel {
|
|||
return new FileSystem.FileEntry(fileSystem, currentPath.get(), null, false, false, 0, null, FileKind.DIRECTORY);
|
||||
}
|
||||
|
||||
public void cdAsync(String path) {
|
||||
ThreadHelper.runFailableAsync(() -> {
|
||||
BusyProperty.execute(busy, () -> {
|
||||
cdSync(path);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public void cdSync(String path) {
|
||||
cdSyncOrRetry(path, false).ifPresent(s -> cdSyncOrRetry(s, false));
|
||||
}
|
||||
|
|
|
@ -26,10 +26,11 @@ public class DsStoreProviderChoiceComp extends Comp<CompStructure<ComboBox<Node>
|
|||
|
||||
Predicate<DataStoreProvider> filter;
|
||||
Property<DataStoreProvider> provider;
|
||||
boolean staticDisplay;
|
||||
|
||||
private Region createDefaultNode() {
|
||||
return JfxHelper.createNamedEntry(
|
||||
AppI18n.get("selectType"), AppI18n.get("selectTypeDescription"), "machine_icon.png");
|
||||
AppI18n.get("selectType"), AppI18n.get("selectTypeDescription"), "connection_icon.svg");
|
||||
}
|
||||
|
||||
private List<DataStoreProvider> getProviders() {
|
||||
|
@ -50,7 +51,7 @@ public class DsStoreProviderChoiceComp extends Comp<CompStructure<ComboBox<Node>
|
|||
var comboBox = new CustomComboBoxBuilder<>(provider, this::createGraphic, createDefaultNode(), v -> true);
|
||||
comboBox.setAccessibleNames(dataStoreProvider -> dataStoreProvider.getDisplayName());
|
||||
getProviders().stream()
|
||||
.filter(p -> AppPrefs.get().developerShowHiddenProviders().get() || p.canManuallyCreate())
|
||||
.filter(p -> AppPrefs.get().developerShowHiddenProviders().get() || p.canManuallyCreate() || staticDisplay)
|
||||
.forEach(comboBox::add);
|
||||
ComboBox<Node> cb = comboBox.build();
|
||||
cb.getStyleClass().add("data-source-type");
|
||||
|
|
|
@ -240,7 +240,7 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
|
|||
var layout = new BorderPane();
|
||||
layout.getStyleClass().add("store-creator");
|
||||
layout.setPadding(new Insets(20));
|
||||
var providerChoice = new DsStoreProviderChoiceComp(filter, provider);
|
||||
var providerChoice = new DsStoreProviderChoiceComp(filter, provider, provider.getValue() != null);
|
||||
if (provider.getValue() != null) {
|
||||
providerChoice.apply(struc -> struc.get().setDisable(true));
|
||||
}
|
||||
|
|
|
@ -1,69 +1,20 @@
|
|||
package io.xpipe.app.exchange;
|
||||
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.core.AppWindowHelper;
|
||||
import io.xpipe.app.core.mode.OperationMode;
|
||||
import io.xpipe.app.fxcomps.impl.SecretFieldComp;
|
||||
import io.xpipe.app.util.AskpassAlert;
|
||||
import io.xpipe.beacon.BeaconHandler;
|
||||
import io.xpipe.beacon.exchange.AskpassExchange;
|
||||
import io.xpipe.core.util.SecretValue;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.layout.StackPane;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class AskpassExchangeImpl extends AskpassExchange
|
||||
implements MessageExchangeImpl<AskpassExchange.Request, AskpassExchange.Response> {
|
||||
|
||||
private final Map<String, String> requestToId = new HashMap<>();
|
||||
private final Map<String, SecretValue> passwords = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public Response handleRequest(BeaconHandler handler, Request msg) {
|
||||
if (OperationMode.get().equals(OperationMode.BACKGROUND)) {
|
||||
OperationMode.switchTo(OperationMode.TRAY);
|
||||
}
|
||||
|
||||
// SecretValue set = AppCache.get(msg.getId(), SecretValue.class, () -> null);
|
||||
// if (set != null) {
|
||||
// return Response.builder().value(set).build();
|
||||
// }
|
||||
|
||||
if (requestToId.containsKey(msg.getRequest())) {
|
||||
var id = requestToId.remove(msg.getRequest());
|
||||
passwords.remove(id);
|
||||
}
|
||||
|
||||
if (passwords.containsKey(msg.getId())) {
|
||||
return Response.builder()
|
||||
.value(passwords.get(msg.getId()).getSecretValue())
|
||||
.build();
|
||||
}
|
||||
|
||||
var prop = new SimpleObjectProperty<SecretValue>();
|
||||
var r = AppWindowHelper.showBlockingAlert(alert -> {
|
||||
alert.setTitle(AppI18n.get("askpassAlertTitle"));
|
||||
alert.setHeaderText(msg.getPrompt());
|
||||
alert.setAlertType(Alert.AlertType.CONFIRMATION);
|
||||
|
||||
var text = new SecretFieldComp(prop).createRegion();
|
||||
alert.getDialogPane().setContent(new StackPane(text));
|
||||
})
|
||||
.filter(b -> b.getButtonData().isDefaultButton() && prop.getValue() != null)
|
||||
.map(t -> {
|
||||
// AppCache.update(msg.getId(), prop.getValue());
|
||||
return prop.getValue();
|
||||
})
|
||||
.orElse(null);
|
||||
|
||||
// If the result is null, assume that the operation was aborted by the user
|
||||
if (r != null) {
|
||||
passwords.put(msg.getId(), r);
|
||||
requestToId.put(msg.getRequest(), msg.getId());
|
||||
}
|
||||
|
||||
var r = AskpassAlert.query(msg.getPrompt(), msg.getRequest(), msg.getId());
|
||||
return Response.builder().value(r != null ? r.getSecretValue() : null).build();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,13 +22,16 @@ public class ErrorEvent {
|
|||
@Builder.Default
|
||||
private final boolean reportable = true;
|
||||
|
||||
private Throwable throwable;
|
||||
private final Throwable throwable;
|
||||
|
||||
@Singular
|
||||
private List<Path> attachments;
|
||||
|
||||
private String userReport;
|
||||
|
||||
@Singular
|
||||
private final List<ErrorAction> customActions;
|
||||
|
||||
public void attachUserReport(String text) {
|
||||
userReport = text;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import io.xpipe.core.process.ShellDialects;
|
|||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Comparator;
|
||||
import java.util.Optional;
|
||||
|
||||
public abstract class ExternalApplicationType implements PrefsChoiceValue {
|
||||
|
@ -55,13 +56,14 @@ public abstract class ExternalApplicationType implements PrefsChoiceValue {
|
|||
}
|
||||
|
||||
// Check if returned paths are actually valid
|
||||
// Also sort them by length to prevent finding a deeply buried app
|
||||
var valid = path.lines().filter(s -> {
|
||||
try {
|
||||
return Files.exists(Path.of(s));
|
||||
} catch (Exception ex) {
|
||||
return false;
|
||||
}
|
||||
}).toList();
|
||||
}).sorted(Comparator.comparingInt(value -> value.length())).toList();
|
||||
|
||||
// Prefer app in proper applications directory
|
||||
var app = valid.stream().filter(s -> s.startsWith("/Applications")).findFirst();
|
||||
|
|
|
@ -101,14 +101,18 @@ public abstract class DataStorage {
|
|||
}
|
||||
|
||||
public synchronized Optional<DataStoreEntry> getParent(DataStoreEntry entry, boolean display) {
|
||||
if (!entry.getState().isUsable()) {
|
||||
if (entry.getState() == DataStoreEntry.State.LOAD_FAILED) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
var provider = entry.getProvider();
|
||||
var parent =
|
||||
display ? provider.getDisplayParent(entry.getStore()) : provider.getLogicalParent(entry.getStore());
|
||||
return parent != null ? getStoreEntryIfPresent(parent) : Optional.empty();
|
||||
try {
|
||||
var provider = entry.getProvider();
|
||||
var parent =
|
||||
display ? provider.getDisplayParent(entry.getStore()) : provider.getLogicalParent(entry.getStore());
|
||||
return parent != null ? getStoreEntryIfPresent(parent) : Optional.empty();
|
||||
} catch (Exception ex) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized List<DataStoreEntry> getStoreChildren(DataStoreEntry entry, boolean display, boolean deep) {
|
||||
|
|
|
@ -3,7 +3,6 @@ package io.xpipe.app.util;
|
|||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.core.AppWindowHelper;
|
||||
import io.xpipe.app.fxcomps.impl.SecretFieldComp;
|
||||
import io.xpipe.core.store.DataStore;
|
||||
import io.xpipe.core.util.SecretValue;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.scene.control.Alert;
|
||||
|
@ -19,9 +18,9 @@ public class AskpassAlert {
|
|||
private static final Map<UUID, UUID> requestToId = new HashMap<>();
|
||||
private static final Map<UUID, SecretValue> passwords = new HashMap<>();
|
||||
|
||||
public static SecretValue query(String prompt, DataStore store) {
|
||||
public static SecretValue query(String prompt, Object key) {
|
||||
var rid = UUID.randomUUID();
|
||||
var secretId = UUID.nameUUIDFromBytes(ByteBuffer.allocate(4).putInt(store.hashCode()).array());
|
||||
var secretId = UUID.nameUUIDFromBytes(ByteBuffer.allocate(4).putInt(key.hashCode()).array());
|
||||
return query(prompt, rid, secretId);
|
||||
}
|
||||
|
||||
|
@ -39,6 +38,8 @@ public class AskpassAlert {
|
|||
var r = AppWindowHelper.showBlockingAlert(alert -> {
|
||||
alert.setTitle(AppI18n.get("askpassAlertTitle"));
|
||||
alert.setHeaderText(prompt);
|
||||
// alert.getDialogPane().setHeader(
|
||||
// AppWindowHelper.alertContentText(prompt));
|
||||
alert.setAlertType(Alert.AlertType.CONFIRMATION);
|
||||
|
||||
var text = new SecretFieldComp(prop).createRegion();
|
||||
|
|
|
@ -22,10 +22,11 @@ public class FileOpener {
|
|||
}
|
||||
|
||||
var file = entry.getPath();
|
||||
var key = entry.getPath().hashCode() + entry.getFileSystem().hashCode();
|
||||
FileBridge.get()
|
||||
.openIO(
|
||||
FileNames.getFileName(file),
|
||||
file,
|
||||
key,
|
||||
() -> {
|
||||
return entry.getFileSystem().openInput(file);
|
||||
},
|
||||
|
@ -40,10 +41,11 @@ public class FileOpener {
|
|||
}
|
||||
|
||||
var file = entry.getPath();
|
||||
var key = entry.getPath().hashCode() + entry.getFileSystem().hashCode();
|
||||
FileBridge.get()
|
||||
.openIO(
|
||||
FileNames.getFileName(file),
|
||||
file,
|
||||
key,
|
||||
() -> {
|
||||
return entry.getFileSystem().openInput(file);
|
||||
},
|
||||
|
|
|
@ -17,18 +17,19 @@ import java.util.function.Supplier;
|
|||
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
|
||||
@JsonSubTypes({
|
||||
@JsonSubTypes.Type(value = SecretRetrievalStrategy.None.class),
|
||||
@JsonSubTypes.Type(value = SecretRetrievalStrategy.Unsupported.class),
|
||||
@JsonSubTypes.Type(value = SecretRetrievalStrategy.Reference.class),
|
||||
@JsonSubTypes.Type(value = SecretRetrievalStrategy.InPlace.class),
|
||||
@JsonSubTypes.Type(value = SecretRetrievalStrategy.Prompt.class),
|
||||
@JsonSubTypes.Type(value = SecretRetrievalStrategy.CustomCommand.class),
|
||||
@JsonSubTypes.Type(value = SecretRetrievalStrategy.PasswordManager.class)
|
||||
@JsonSubTypes.Type(value = SecretRetrievalStrategy.None.class),
|
||||
@JsonSubTypes.Type(value = SecretRetrievalStrategy.Reference.class),
|
||||
@JsonSubTypes.Type(value = SecretRetrievalStrategy.InPlace.class),
|
||||
@JsonSubTypes.Type(value = SecretRetrievalStrategy.Prompt.class),
|
||||
@JsonSubTypes.Type(value = SecretRetrievalStrategy.CustomCommand.class),
|
||||
@JsonSubTypes.Type(value = SecretRetrievalStrategy.PasswordManager.class)
|
||||
})
|
||||
public interface SecretRetrievalStrategy {
|
||||
|
||||
SecretValue retrieve(String displayName, DataStore store) throws Exception;
|
||||
|
||||
boolean supportsLocalAskpass();
|
||||
|
||||
@JsonTypeName("none")
|
||||
public static class None implements SecretRetrievalStrategy {
|
||||
|
||||
|
@ -36,14 +37,10 @@ public interface SecretRetrievalStrategy {
|
|||
public SecretValue retrieve(String displayName, DataStore store) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@JsonTypeName("unsupported")
|
||||
public static class Unsupported implements SecretRetrievalStrategy {
|
||||
|
||||
@Override
|
||||
public SecretValue retrieve(String displayName, DataStore store) {
|
||||
throw new UnsupportedOperationException();
|
||||
public boolean supportsLocalAskpass() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,6 +58,11 @@ public interface SecretRetrievalStrategy {
|
|||
public SecretValue retrieve(String displayName, DataStore store) {
|
||||
return supplier.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsLocalAskpass() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@JsonTypeName("inPlace")
|
||||
|
@ -80,6 +82,11 @@ public interface SecretRetrievalStrategy {
|
|||
public SecretValue retrieve(String displayName, DataStore store) {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsLocalAskpass() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@JsonTypeName("prompt")
|
||||
|
@ -89,6 +96,11 @@ public interface SecretRetrievalStrategy {
|
|||
public SecretValue retrieve(String displayName, DataStore store) {
|
||||
return AskpassAlert.query(displayName, store);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsLocalAskpass() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@JsonTypeName("passwordManager")
|
||||
|
@ -110,6 +122,11 @@ public interface SecretRetrievalStrategy {
|
|||
return SecretHelper.encrypt(cc.readStdoutOrThrow());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsLocalAskpass() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@JsonTypeName("customCommand")
|
||||
|
@ -126,5 +143,10 @@ public interface SecretRetrievalStrategy {
|
|||
return SecretHelper.encrypt(cc.readStdoutOrThrow());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsLocalAskpass() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
id="Layer_1"
|
||||
data-name="Layer 1"
|
||||
viewBox="0 0 198.72 199.16"
|
||||
version="1.1"
|
||||
sodipodi:docname="connection_icon-dark.svg"
|
||||
inkscape:version="1.1.2 (b8e25be833, 2022-02-05)"
|
||||
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/">
|
||||
<sodipodi:namedview
|
||||
id="namedview11"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="2.1515364"
|
||||
inkscape:cx="49.034727"
|
||||
inkscape:cy="110.61863"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1017"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="Layer_1" />
|
||||
<defs
|
||||
id="defs4">
|
||||
<style
|
||||
id="style2">.cls-1{fill:#ac55ff;}</style>
|
||||
</defs>
|
||||
<title
|
||||
id="title6">connection</title>
|
||||
<path
|
||||
class="cls-1"
|
||||
d="M340.72,273H279.48a14.66,14.66,0,0,0-14.64,14.64v34.79a14.66,14.66,0,0,0,14.64,14.64h24.4v6.07H297.4a6.22,6.22,0,1,0,0,12.44h25.4a6.22,6.22,0,0,0,0-12.44h-6.48v-6.07h24.4a14.66,14.66,0,0,0,14.64-14.64V287.64A14.66,14.66,0,0,0,340.72,273Zm2.2,49.43a2.21,2.21,0,0,1-2.2,2.2H279.48a2.21,2.21,0,0,1-2.2-2.2V287.64a2.21,2.21,0,0,1,2.2-2.2h61.24a2.21,2.21,0,0,1,2.2,2.2Zm-122.1-89.65a6.22,6.22,0,0,0-6.22-6.22h-6.48v-6.07h24.4a14.66,14.66,0,0,0,14.64-14.64V171.06a14.66,14.66,0,0,0-14.64-14.64H171.28a14.66,14.66,0,0,0-14.64,14.64v34.79a14.66,14.66,0,0,0,14.64,14.64h24.4v6.07H189.2a6.22,6.22,0,1,0,0,12.44h25.4a6.22,6.22,0,0,0,6.22-6.22Zm-51.74-26.93V171.06a2.21,2.21,0,0,1,2.2-2.2h61.24a2.21,2.21,0,0,1,2.2,2.2v34.79a2.21,2.21,0,0,1-2.2,2.2H171.28A2.21,2.21,0,0,1,169.08,205.85Zm83,99.15a6.22,6.22,0,0,1-6.22,6.22h-44a6.22,6.22,0,0,1-6.22-6.22V257.27a6.22,6.22,0,0,1,12.44,0v41.5h37.77A6.22,6.22,0,0,1,252.11,305Zm13.13-111.26a6.22,6.22,0,0,1,0-12.44h44a6.22,6.22,0,0,1,6.22,6.22V252A6.22,6.22,0,1,1,303,252v-58.3Z"
|
||||
transform="translate(-156.64 -156.42)"
|
||||
id="path8"
|
||||
style="fill:#f6f6f6;fill-opacity:1" />
|
||||
<metadata
|
||||
id="metadata828">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:title>connection</dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
|
@ -0,0 +1,56 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
id="Layer_1"
|
||||
data-name="Layer 1"
|
||||
viewBox="0 0 198.72 199.16"
|
||||
version="1.1"
|
||||
sodipodi:docname="connection_icon.svg"
|
||||
inkscape:version="1.1.2 (b8e25be833, 2022-02-05)"
|
||||
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/">
|
||||
<sodipodi:namedview
|
||||
id="namedview11"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="2.1515364"
|
||||
inkscape:cx="49.034727"
|
||||
inkscape:cy="110.61863"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1017"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="Layer_1" />
|
||||
<defs
|
||||
id="defs4">
|
||||
<style
|
||||
id="style2">.cls-1{fill:#ac55ff;}</style>
|
||||
</defs>
|
||||
<title
|
||||
id="title6">connection</title>
|
||||
<path
|
||||
class="cls-1"
|
||||
d="M340.72,273H279.48a14.66,14.66,0,0,0-14.64,14.64v34.79a14.66,14.66,0,0,0,14.64,14.64h24.4v6.07H297.4a6.22,6.22,0,1,0,0,12.44h25.4a6.22,6.22,0,0,0,0-12.44h-6.48v-6.07h24.4a14.66,14.66,0,0,0,14.64-14.64V287.64A14.66,14.66,0,0,0,340.72,273Zm2.2,49.43a2.21,2.21,0,0,1-2.2,2.2H279.48a2.21,2.21,0,0,1-2.2-2.2V287.64a2.21,2.21,0,0,1,2.2-2.2h61.24a2.21,2.21,0,0,1,2.2,2.2Zm-122.1-89.65a6.22,6.22,0,0,0-6.22-6.22h-6.48v-6.07h24.4a14.66,14.66,0,0,0,14.64-14.64V171.06a14.66,14.66,0,0,0-14.64-14.64H171.28a14.66,14.66,0,0,0-14.64,14.64v34.79a14.66,14.66,0,0,0,14.64,14.64h24.4v6.07H189.2a6.22,6.22,0,1,0,0,12.44h25.4a6.22,6.22,0,0,0,6.22-6.22Zm-51.74-26.93V171.06a2.21,2.21,0,0,1,2.2-2.2h61.24a2.21,2.21,0,0,1,2.2,2.2v34.79a2.21,2.21,0,0,1-2.2,2.2H171.28A2.21,2.21,0,0,1,169.08,205.85Zm83,99.15a6.22,6.22,0,0,1-6.22,6.22h-44a6.22,6.22,0,0,1-6.22-6.22V257.27a6.22,6.22,0,0,1,12.44,0v41.5h37.77A6.22,6.22,0,0,1,252.11,305Zm13.13-111.26a6.22,6.22,0,0,1,0-12.44h44a6.22,6.22,0,0,1,6.22,6.22V252A6.22,6.22,0,1,1,303,252v-58.3Z"
|
||||
transform="translate(-156.64 -156.42)"
|
||||
id="path8"
|
||||
style="fill:#2e2e2e;fill-opacity:1" />
|
||||
<metadata
|
||||
id="metadata828">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:title>connection</dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
</svg>
|
After Width: | Height: | Size: 2.5 KiB |
|
@ -0,0 +1,56 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
id="Layer_1"
|
||||
data-name="Layer 1"
|
||||
viewBox="0 0 178.23 178.25"
|
||||
version="1.1"
|
||||
sodipodi:docname="home_icon-dark.svg"
|
||||
inkscape:version="1.1.2 (b8e25be833, 2022-02-05)"
|
||||
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/">
|
||||
<sodipodi:namedview
|
||||
id="namedview11"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="2.4039271"
|
||||
inkscape:cx="21.423279"
|
||||
inkscape:cy="89.852975"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1017"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="Layer_1" />
|
||||
<defs
|
||||
id="defs4">
|
||||
<style
|
||||
id="style2">.cls-1{fill:#ac55ff;}</style>
|
||||
</defs>
|
||||
<title
|
||||
id="title6">home</title>
|
||||
<path
|
||||
class="cls-1"
|
||||
d="M340.33,244.41v0L267.6,171.68a16.39,16.39,0,0,0-23.2,0l-72.68,72.67-.07.08a16.41,16.41,0,0,0,10.92,28l.51,0H186v53.51a19.23,19.23,0,0,0,19.21,19.21h28.45a5.23,5.23,0,0,0,5.22-5.23V298a8.77,8.77,0,0,1,8.76-8.76h16.78a8.77,8.77,0,0,1,8.76,8.76V339.9a5.23,5.23,0,0,0,5.22,5.23h28.45A19.23,19.23,0,0,0,326,325.92V272.41h2.69a16.26,16.26,0,0,0,11.6-4.81A16.43,16.43,0,0,0,340.33,244.41Zm-7.4,15.81a5.89,5.89,0,0,1-4.21,1.75h-7.91a5.23,5.23,0,0,0-5.23,5.22v58.73a8.77,8.77,0,0,1-8.76,8.76H283.6V298a19.23,19.23,0,0,0-19.21-19.2H247.61A19.23,19.23,0,0,0,228.4,298v36.73H205.18a8.77,8.77,0,0,1-8.76-8.76V267.19a5.23,5.23,0,0,0-5.23-5.22h-8a6,6,0,0,1-4.11-10.18h0l72.71-72.7a6,6,0,0,1,8.44,0l72.69,72.69,0,0A6,6,0,0,1,332.93,260.22Z"
|
||||
transform="translate(-166.88 -166.87)"
|
||||
id="path8"
|
||||
style="fill:#f6f6f6;fill-opacity:1" />
|
||||
<metadata
|
||||
id="metadata828">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:title>home</dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
Binary file not shown.
Before Width: | Height: | Size: 22 KiB |
|
@ -0,0 +1,56 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
id="Layer_1"
|
||||
data-name="Layer 1"
|
||||
viewBox="0 0 178.23 178.25"
|
||||
version="1.1"
|
||||
sodipodi:docname="home_icon.svg"
|
||||
inkscape:version="1.1.2 (b8e25be833, 2022-02-05)"
|
||||
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/">
|
||||
<sodipodi:namedview
|
||||
id="namedview11"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="2.4039271"
|
||||
inkscape:cx="21.423279"
|
||||
inkscape:cy="89.852975"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1017"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="Layer_1" />
|
||||
<defs
|
||||
id="defs4">
|
||||
<style
|
||||
id="style2">.cls-1{fill:#ac55ff;}</style>
|
||||
</defs>
|
||||
<title
|
||||
id="title6">home</title>
|
||||
<path
|
||||
class="cls-1"
|
||||
d="M340.33,244.41v0L267.6,171.68a16.39,16.39,0,0,0-23.2,0l-72.68,72.67-.07.08a16.41,16.41,0,0,0,10.92,28l.51,0H186v53.51a19.23,19.23,0,0,0,19.21,19.21h28.45a5.23,5.23,0,0,0,5.22-5.23V298a8.77,8.77,0,0,1,8.76-8.76h16.78a8.77,8.77,0,0,1,8.76,8.76V339.9a5.23,5.23,0,0,0,5.22,5.23h28.45A19.23,19.23,0,0,0,326,325.92V272.41h2.69a16.26,16.26,0,0,0,11.6-4.81A16.43,16.43,0,0,0,340.33,244.41Zm-7.4,15.81a5.89,5.89,0,0,1-4.21,1.75h-7.91a5.23,5.23,0,0,0-5.23,5.22v58.73a8.77,8.77,0,0,1-8.76,8.76H283.6V298a19.23,19.23,0,0,0-19.21-19.2H247.61A19.23,19.23,0,0,0,228.4,298v36.73H205.18a8.77,8.77,0,0,1-8.76-8.76V267.19a5.23,5.23,0,0,0-5.23-5.22h-8a6,6,0,0,1-4.11-10.18h0l72.71-72.7a6,6,0,0,1,8.44,0l72.69,72.69,0,0A6,6,0,0,1,332.93,260.22Z"
|
||||
transform="translate(-166.88 -166.87)"
|
||||
id="path8"
|
||||
style="fill:#2e2e2e;fill-opacity:1" />
|
||||
<metadata
|
||||
id="metadata828">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:title>home</dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
Binary file not shown.
Before Width: | Height: | Size: 14 KiB |
|
@ -1,11 +1,16 @@
|
|||
html {
|
||||
font-family: Roboto;
|
||||
}
|
||||
|
||||
.markdown-body {
|
||||
color-scheme: dark;
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
margin: 0;
|
||||
padding: 1em;
|
||||
color: #c9d1d9;
|
||||
font-family: -apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";
|
||||
font-size: 16px;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ import lombok.NonNull;
|
|||
import lombok.Value;
|
||||
import lombok.extern.jackson.Jacksonized;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class AskpassExchange implements MessageExchange {
|
||||
|
||||
@Override
|
||||
|
@ -19,10 +21,10 @@ public class AskpassExchange implements MessageExchange {
|
|||
@Value
|
||||
public static class Request implements RequestMessage {
|
||||
@NonNull
|
||||
String id;
|
||||
UUID id;
|
||||
|
||||
@NonNull
|
||||
String request;
|
||||
UUID request;
|
||||
|
||||
String prompt;
|
||||
}
|
||||
|
|
|
@ -45,6 +45,11 @@ public class CommandBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
public CommandBuilder remove(String s) {
|
||||
elements.removeIf(element -> element instanceof Fixed fixed && s.equals(fixed.string));
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandBuilder addQuoted(String s) {
|
||||
elements.add(new Fixed("\"" + s + "\""));
|
||||
return this;
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package io.xpipe.core.process;
|
||||
|
||||
import lombok.Value;
|
||||
|
||||
@Value
|
||||
public class ElevationResult {
|
||||
String value;
|
||||
boolean promptsUserInput;
|
||||
}
|
|
@ -88,6 +88,8 @@ public interface ShellControl extends ProcessControl {
|
|||
}
|
||||
}
|
||||
|
||||
ElevationResult elevateCommand(String input) throws Exception;
|
||||
|
||||
void restart() throws Exception;
|
||||
|
||||
OsType getOsType();
|
||||
|
|
|
@ -2,5 +2,9 @@ package io.xpipe.core.store;
|
|||
|
||||
public interface LaunchableStore extends DataStore {
|
||||
|
||||
default boolean canLaunch() {
|
||||
return true;
|
||||
}
|
||||
|
||||
String prepareLaunchCommand(String displayName) throws Exception;
|
||||
}
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
package io.xpipe.core.util;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public class UuidHelper {
|
||||
|
||||
public static UUID generateFromObject(Object o) {
|
||||
return UUID.nameUUIDFromBytes(o.toString().getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
public static Optional<UUID> parse(String s) {
|
||||
try {
|
||||
return Optional.of(UUID.fromString(s));
|
||||
|
|
|
@ -178,7 +178,9 @@ public class XPipeInstallation {
|
|||
}
|
||||
|
||||
public static String getLocalDefaultCliExecutable() {
|
||||
Path path = ModuleHelper.isImage() ? getCurrentInstallationBasePath() : Path.of(getLocalDefaultInstallationBasePath(true));
|
||||
Path path = ModuleHelper.isImage()
|
||||
? getCurrentInstallationBasePath()
|
||||
: Path.of(getLocalDefaultInstallationBasePath(true));
|
||||
return path.resolve(getRelativeCliExecutablePath(OsType.getLocal())).toString();
|
||||
}
|
||||
|
||||
|
|
1
dist/changelogs/1.5.0.md
vendored
1
dist/changelogs/1.5.0.md
vendored
|
@ -63,6 +63,7 @@ This also comes with full support of the feature set for these environments
|
|||
- Implement a new internal API to better assemble complex commands
|
||||
- Rework os detection logic for passthrough environments like Cygwin and MSYS2
|
||||
- Fix desktop directory not being determined correctly on Windows when it was moved from the default location
|
||||
- Fix various checks in file browser not being applied properly and leading to wrong error messages
|
||||
- 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
|
||||
|
|
|
@ -57,13 +57,14 @@ public class LaunchAction implements ActionProvider {
|
|||
@Override
|
||||
public DefaultDataStoreCallSite<?> getDefaultDataStoreCallSite() {
|
||||
return new DefaultDataStoreCallSite<LaunchableStore>() {
|
||||
|
||||
@Override
|
||||
public boolean isApplicable(LaunchableStore o) {
|
||||
return DataStorage.get()
|
||||
.getStoreEntryIfPresent(o)
|
||||
.orElseThrow()
|
||||
.getState()
|
||||
.isUsable();
|
||||
.isUsable() && o.canLaunch();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -20,7 +20,7 @@ public class FollowLinkAction implements LeafAction {
|
|||
@Override
|
||||
public void execute(OpenFileSystemModel model, List<BrowserEntry> entries) {
|
||||
var target = FileNames.getParent(entries.get(0).getRawFileEntry().resolved().getPath());
|
||||
model.cdSync(target);
|
||||
model.cdAsync(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -16,7 +16,7 @@ public class OpenDirectoryAction implements LeafAction {
|
|||
|
||||
@Override
|
||||
public void execute(OpenFileSystemModel model, List<BrowserEntry> entries) {
|
||||
model.cdSync(entries.get(0).getRawFileEntry().getPath());
|
||||
model.cdAsync(entries.get(0).getRawFileEntry().getPath());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in a new issue