Refactor plus several fixes

This commit is contained in:
crschnick 2023-08-01 19:34:08 +00:00
parent 5be0748c9f
commit 1f2919278f
34 changed files with 351 additions and 97 deletions

View file

@ -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;

View file

@ -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);

View file

@ -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());
}
}
}

View file

@ -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);

View file

@ -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());

View file

@ -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");

View file

@ -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));
}

View file

@ -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");

View file

@ -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));
}

View file

@ -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();
}
}

View file

@ -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;
}

View file

@ -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();

View file

@ -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) {

View file

@ -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();

View file

@ -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);
},

View 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;
}
}
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;

View file

@ -0,0 +1,9 @@
package io.xpipe.core.process;
import lombok.Value;
@Value
public class ElevationResult {
String value;
boolean promptsUserInput;
}

View file

@ -88,6 +88,8 @@ public interface ShellControl extends ProcessControl {
}
}
ElevationResult elevateCommand(String input) throws Exception;
void restart() throws Exception;
OsType getOsType();

View file

@ -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;
}

View file

@ -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));

View file

@ -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();
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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