This commit is contained in:
crschnick 2024-09-20 16:17:50 +00:00
parent c718f8d3f6
commit 51196f15bb
95 changed files with 414 additions and 286 deletions

View file

@ -1,8 +1,8 @@
package io.xpipe.app.beacon;
import io.xpipe.app.resources.AppResources;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.issue.TrackEvent;
import io.xpipe.app.resources.AppResources;
import io.xpipe.app.util.MarkdownHelper;
import io.xpipe.beacon.BeaconConfig;
import io.xpipe.beacon.BeaconInterface;

View file

@ -39,7 +39,8 @@ public class BeaconRequestHandler<T> implements HttpHandler {
}
}
if (beaconInterface.requiresEnabledApi() && !AppPrefs.get().enableHttpApi().get()) {
if (beaconInterface.requiresEnabledApi()
&& !AppPrefs.get().enableHttpApi().get()) {
var ex = new BeaconServerException("HTTP API is not enabled in the settings menu");
writeError(exchange, ex, 403);
return;

View file

@ -43,7 +43,6 @@ public class FsReadExchangeImpl extends FsReadExchange {
var out = exchange.getResponseBody()) {
fileIn.transferTo(out);
}
return Response.builder().build();
} else {
byte[] bytes;
try (var in = fs.openInput(msg.getPath().toString())) {
@ -55,7 +54,7 @@ public class FsReadExchangeImpl extends FsReadExchange {
try (var out = exchange.getResponseBody()) {
out.write(bytes);
}
return Response.builder().build();
}
return Response.builder().build();
}
}

View file

@ -1,12 +1,13 @@
package io.xpipe.app.beacon.impl;
import com.sun.net.httpserver.HttpExchange;
import io.xpipe.app.beacon.AppBeaconServer;
import io.xpipe.app.beacon.BeaconShellSession;
import io.xpipe.app.storage.DataStorage;
import io.xpipe.beacon.BeaconClientException;
import io.xpipe.beacon.api.ShellStartExchange;
import io.xpipe.core.store.ShellStore;
import com.sun.net.httpserver.HttpExchange;
import lombok.SneakyThrows;
public class ShellStartExchangeImpl extends ShellStartExchange {

View file

@ -1,11 +1,12 @@
package io.xpipe.app.beacon.impl;
import com.sun.net.httpserver.HttpExchange;
import io.xpipe.app.ext.ProcessControlProvider;
import io.xpipe.app.util.TerminalLauncherManager;
import io.xpipe.beacon.api.SshLaunchExchange;
import io.xpipe.app.ext.ProcessControlProvider;
import io.xpipe.core.process.ShellDialects;
import com.sun.net.httpserver.HttpExchange;
import java.util.List;
public class SshLaunchExchangeImpl extends SshLaunchExchange {

View file

@ -3,9 +3,9 @@ package io.xpipe.app.browser;
import io.xpipe.app.browser.file.BrowserEntry;
import io.xpipe.app.browser.file.BrowserFileTransferMode;
import io.xpipe.app.browser.file.LocalFileSystem;
import io.xpipe.app.ext.ProcessControlProvider;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.util.ThreadHelper;
import io.xpipe.app.ext.ProcessControlProvider;
import io.xpipe.core.store.FileEntry;
import io.xpipe.core.util.FailableRunnable;

View file

@ -10,12 +10,14 @@ import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.util.DesktopHelper;
import io.xpipe.app.util.ShellTemp;
import io.xpipe.app.util.ThreadHelper;
import javafx.beans.binding.Bindings;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableBooleanValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import lombok.Value;
import org.apache.commons.io.FileUtils;

View file

@ -63,7 +63,8 @@ public class BrowserAlerts {
}
public static boolean showDeleteAlert(List<FileEntry> source) {
if (!AppPrefs.get().confirmDeletions().get() && source.stream().noneMatch(entry -> entry.getKind() == FileKind.DIRECTORY)) {
if (!AppPrefs.get().confirmDeletions().get()
&& source.stream().noneMatch(entry -> entry.getKind() == FileKind.DIRECTORY)) {
return true;
}

View file

@ -194,9 +194,9 @@ public final class BrowserFileListComp extends SimpleComp {
? unix.getGroup()
: m.getCache().getGroups().getOrDefault(unix.getGid(), "?");
var uid = String.valueOf(
unix.getUid() != null ? unix.getUid() : m.getCache().getUidForUser(user));
unix.getUid() != null ? unix.getUid() : m.getCache().getUidForUser(user));
var gid = String.valueOf(
unix.getGid() != null ? unix.getGid() : m.getCache().getGidForGroup(group));
unix.getGid() != null ? unix.getGid() : m.getCache().getGidForGroup(group));
if (uid.equals(gid) && user.equals(group)) {
return user + " [" + uid + "]";
}
@ -248,7 +248,6 @@ public final class BrowserFileListComp extends SimpleComp {
if (inCooldown) {
lastType.set(Instant.now());
event.consume();
return;
} else {
lastType.set(null);
typedSelection.set("");
@ -256,8 +255,8 @@ public final class BrowserFileListComp extends SimpleComp {
if (!recursive) {
updateTypedSelection(table, lastType, event, true);
}
return;
}
return;
}
lastType.set(Instant.now());

View file

@ -1,9 +1,9 @@
package io.xpipe.app.browser.file;
import io.xpipe.app.ext.LocalStore;
import io.xpipe.core.store.FileEntry;
import io.xpipe.core.store.FileKind;
import io.xpipe.core.store.FileSystem;
import io.xpipe.app.ext.LocalStore;
import java.nio.file.Files;
import java.nio.file.Path;

View file

@ -60,7 +60,8 @@ public class OpenFileSystemCache extends ShellControlCache {
var split = s.split(":");
try {
users.putIfAbsent(Integer.parseInt(split[2]), split[0]);
} catch (Exception ignored) {}
} catch (Exception ignored) {
}
});
if (users.isEmpty()) {
@ -81,7 +82,8 @@ public class OpenFileSystemCache extends ShellControlCache {
var split = s.split(":");
try {
groups.putIfAbsent(Integer.parseInt(split[2]), split[0]);
} catch (Exception ignored) {}
} catch (Exception ignored) {
}
});
if (groups.isEmpty()) {

View file

@ -11,6 +11,7 @@ import io.xpipe.app.browser.file.FileSystemHelper;
import io.xpipe.app.browser.session.BrowserAbstractSessionModel;
import io.xpipe.app.browser.session.BrowserSessionTab;
import io.xpipe.app.comp.base.ModalOverlayComp;
import io.xpipe.app.ext.ProcessControlProvider;
import io.xpipe.app.fxcomps.Comp;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.storage.DataStorage;
@ -18,7 +19,6 @@ import io.xpipe.app.storage.DataStoreEntryRef;
import io.xpipe.app.util.BooleanScope;
import io.xpipe.app.util.TerminalLauncher;
import io.xpipe.app.util.ThreadHelper;
import io.xpipe.app.ext.ProcessControlProvider;
import io.xpipe.core.process.ShellControl;
import io.xpipe.core.process.ShellDialects;
import io.xpipe.core.process.ShellOpenFunction;
@ -453,7 +453,7 @@ public final class OpenFileSystemModel extends BrowserSessionTab<FileSystemStore
return fileSystem == null;
}
public void initWithGivenDirectory(String dir) throws Exception {
public void initWithGivenDirectory(String dir) {
cdSync(dir);
}

View file

@ -96,7 +96,7 @@ public class BrowserChooserComp extends SimpleComp {
return;
}
if (entry.getStore() instanceof ShellStore fileSystem) {
if (entry.getStore() instanceof ShellStore) {
model.openFileSystemAsync(entry.ref(), null, busy);
}
});

View file

@ -238,7 +238,6 @@ public class BrowserSessionTabsComp extends SimpleComp {
% tabs.getTabs().size();
tabs.getSelectionModel().select(previous);
keyEvent.consume();
return;
}
});

View file

@ -64,7 +64,6 @@ public class AppLayoutComp extends Comp<CompStructure<Pane>> {
if (shortcut != null && shortcut.match(event)) {
((ButtonBase) ((Parent) node).getChildrenUnmodifiable().get(1)).fire();
event.consume();
return;
}
});
});

View file

@ -1,13 +1,13 @@
package io.xpipe.app.comp.base;
import io.xpipe.app.core.AppProperties;
import io.xpipe.app.resources.AppResources;
import io.xpipe.app.fxcomps.Comp;
import io.xpipe.app.fxcomps.CompStructure;
import io.xpipe.app.fxcomps.SimpleCompStructure;
import io.xpipe.app.fxcomps.util.PlatformThread;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.resources.AppResources;
import io.xpipe.app.util.Hyperlinks;
import io.xpipe.app.util.MarkdownHelper;
import io.xpipe.app.util.ShellTemp;

View file

@ -1,11 +1,11 @@
package io.xpipe.app.comp.base;
import io.xpipe.app.comp.store.StoreEntryWrapper;
import io.xpipe.app.resources.AppResources;
import io.xpipe.app.fxcomps.SimpleComp;
import io.xpipe.app.fxcomps.impl.PrettyImageComp;
import io.xpipe.app.fxcomps.impl.StackComp;
import io.xpipe.app.fxcomps.util.BindingsHelper;
import io.xpipe.app.resources.AppResources;
import io.xpipe.core.process.OsNameState;
import io.xpipe.core.store.FileNames;

View file

@ -1,6 +1,5 @@
package io.xpipe.app.comp.store;
import atlantafx.base.controls.Spacer;
import io.xpipe.app.comp.base.ButtonComp;
import io.xpipe.app.comp.base.DialogComp;
import io.xpipe.app.comp.base.ErrorOverlayComp;
@ -23,6 +22,7 @@ import io.xpipe.app.util.*;
import io.xpipe.core.store.DataStore;
import io.xpipe.core.store.ValidationContext;
import io.xpipe.core.util.ValidationException;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.property.*;
@ -34,6 +34,8 @@ import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import atlantafx.base.controls.Spacer;
import lombok.AccessLevel;
import lombok.experimental.FieldDefaults;
import net.synedra.validatorfx.GraphicDecorationStackPane;
@ -209,7 +211,7 @@ public class StoreCreationComp extends DialogComp {
null);
}
private static interface CreationConsumer {
public interface CreationConsumer {
void consume(DataStoreEntry entry, ValidationContext<?> validationContext, boolean validated);
}
@ -318,7 +320,7 @@ public class StoreCreationComp extends DialogComp {
return;
}
try (var b = new BooleanScope(busy).start()) {
try (var ignored = new BooleanScope(busy).start()) {
DataStorage.get().addStoreEntryInProgress(entry.getValue());
var context = entry.getValue().validateOrThrow(false);
commit(context, true);

View file

@ -32,17 +32,21 @@ public class StoreCreationMenu {
menu.getItems().add(category("addDesktop", "mdi2c-camera-plus", DataStoreCreationCategory.DESKTOP, null));
menu.getItems().add(category("addShell", "mdi2t-text-box-multiple", DataStoreCreationCategory.SHELL, "shellEnvironment"));
menu.getItems()
.add(category(
"addShell", "mdi2t-text-box-multiple", DataStoreCreationCategory.SHELL, "shellEnvironment"));
menu.getItems()
.add(category("addScript", "mdi2s-script-text-outline", DataStoreCreationCategory.SCRIPT, "script"));
menu.getItems()
.add(category("addTunnel", "mdi2v-vector-polyline-plus", DataStoreCreationCategory.TUNNEL, "customService"));
.add(category(
"addTunnel", "mdi2v-vector-polyline-plus", DataStoreCreationCategory.TUNNEL, "customService"));
menu.getItems().add(category("addSerial", "mdi2s-serial-port", DataStoreCreationCategory.SERIAL, "serial"));
// menu.getItems().add(category("addDatabase", "mdi2d-database-plus", DataStoreCreationCategory.DATABASE, null));
// menu.getItems().add(category("addDatabase", "mdi2d-database-plus", DataStoreCreationCategory.DATABASE,
// null));
}
private static MenuItem category(
@ -85,8 +89,7 @@ public class StoreCreationMenu {
.sorted(Comparator.comparingInt(dataStoreProvider -> dataStoreProvider.getOrderPriority()))
.toList();
int lastOrder = providers.getFirst().getOrderPriority();
for (int i = 0; i < providers.size(); i++) {
var dataStoreProvider = providers.get(i);
for (io.xpipe.app.ext.DataStoreProvider dataStoreProvider : providers) {
if (dataStoreProvider.getOrderPriority() != lastOrder) {
menu.getItems().add(new SeparatorMenuItem());
lastOrder = dataStoreProvider.getOrderPriority();
@ -94,8 +97,7 @@ public class StoreCreationMenu {
var item = new MenuItem();
item.textProperty().bind(dataStoreProvider.displayName());
item.setGraphic(PrettyImageHelper.ofFixedSizeSquare(dataStoreProvider.getDisplayIconFileName(null), 16)
.createRegion());
item.setGraphic(PrettyImageHelper.ofFixedSizeSquare(dataStoreProvider.getDisplayIconFileName(null), 16).createRegion());
item.setOnAction(event -> {
StoreCreationComp.showCreation(dataStoreProvider, category);
event.consume();

View file

@ -1,7 +1,5 @@
package io.xpipe.app.comp.store;
import atlantafx.base.layout.InputGroup;
import atlantafx.base.theme.Styles;
import io.xpipe.app.comp.base.LoadingOverlayComp;
import io.xpipe.app.core.*;
import io.xpipe.app.ext.ActionProvider;
@ -23,6 +21,7 @@ import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.storage.DataStoreEntry;
import io.xpipe.app.update.XPipeDistributionType;
import io.xpipe.app.util.*;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableDoubleValue;
@ -34,6 +33,9 @@ import javafx.scene.control.*;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Region;
import atlantafx.base.layout.InputGroup;
import atlantafx.base.theme.Styles;
import org.kordamp.ikonli.javafx.FontIcon;
import java.nio.file.Files;

View file

@ -51,7 +51,8 @@ public class StoreEntryListComp extends SimpleComp {
() -> {
var allCat = StoreViewState.get().getAllConnectionsCategory();
var connections = StoreViewState.get().getAllEntries().getList().stream()
.filter(wrapper -> allCat.equals(wrapper.getCategory().getValue().getRoot()))
.filter(wrapper -> allCat.equals(
wrapper.getCategory().getValue().getRoot()))
.toList();
return initialCount == connections.size()
&& StoreViewState.get()

View file

@ -72,8 +72,13 @@ public class StoreEntryListOverviewComp extends SimpleComp {
// But it is good enough.
var showProvider = true;
try {
showProvider = storeEntryWrapper.getEntry().getProvider() == null || storeEntryWrapper.getEntry().getProvider().shouldShow(storeEntryWrapper);
} catch (Exception ignored) {}
showProvider = storeEntryWrapper.getEntry().getProvider() == null
|| storeEntryWrapper
.getEntry()
.getProvider()
.shouldShow(storeEntryWrapper);
} catch (Exception ignored) {
}
return inRootCategory && showProvider;
},
StoreViewState.get().getActiveCategory());

View file

@ -1,9 +1,9 @@
package io.xpipe.app.comp.store;
import atlantafx.base.theme.Tweaks;
import io.xpipe.app.fxcomps.SimpleComp;
import io.xpipe.app.fxcomps.impl.PrettyImageHelper;
import io.xpipe.app.resources.SystemIcon;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
@ -12,6 +12,8 @@ import javafx.scene.control.*;
import javafx.scene.input.MouseButton;
import javafx.scene.layout.Region;
import atlantafx.base.theme.Tweaks;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@ -27,7 +29,12 @@ public class StoreIconChoiceComp extends SimpleComp {
private final SimpleStringProperty filter;
private final Runnable doubleClick;
public StoreIconChoiceComp(Property<SystemIcon> selected, List<SystemIcon> icons, int columns, SimpleStringProperty filter, Runnable doubleClick) {
public StoreIconChoiceComp(
Property<SystemIcon> selected,
List<SystemIcon> icons,
int columns,
SimpleStringProperty filter,
Runnable doubleClick) {
this.selected = selected;
this.icons = icons;
this.columns = columns;
@ -44,7 +51,6 @@ public class StoreIconChoiceComp extends SimpleComp {
return table;
}
private void initTable(TableView<List<SystemIcon>> table) {
for (int i = 0; i < columns; i++) {
var col = new TableColumn<List<SystemIcon>, SystemIcon>("col" + i);
@ -65,8 +71,11 @@ public class StoreIconChoiceComp extends SimpleComp {
}
private void updateData(TableView<List<SystemIcon>> table, String filterString) {
var displayedIcons = filterString == null || filterString.isBlank() || filterString.length() < 2 ? icons : icons.stream().filter(
icon -> containsString(icon.getDisplayName(), filterString)).toList();
var displayedIcons = filterString == null || filterString.isBlank() || filterString.length() < 2
? icons
: icons.stream()
.filter(icon -> containsString(icon.getDisplayName(), filterString))
.toList();
var data = partitionList(displayedIcons, columns);
table.getItems().setAll(data);
@ -97,12 +106,12 @@ public class StoreIconChoiceComp extends SimpleComp {
private final Label root = new Label();
private final StringProperty image = new SimpleStringProperty();
private final Region imageView = PrettyImageHelper.ofFixedSize(image, 40, 40).createRegion();
public IconCell() {
super();
root.setContentDisplay(ContentDisplay.TOP);
Region imageView = PrettyImageHelper.ofFixedSize(image, 40, 40).createRegion();
root.setGraphic(imageView);
root.setGraphicTextGap(10);
root.getStyleClass().addAll("icon-label", TEXT_SMALL);

View file

@ -12,12 +12,14 @@ import io.xpipe.app.resources.SystemIcon;
import io.xpipe.app.resources.SystemIcons;
import io.xpipe.app.storage.DataStoreEntry;
import io.xpipe.app.util.Hyperlinks;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.scene.layout.Region;
import javafx.stage.Modality;
import javafx.stage.Stage;
import org.kordamp.ikonli.javafx.FontIcon;
import java.util.List;
@ -26,7 +28,8 @@ public class StoreIconChoiceDialogComp extends SimpleComp {
public static void show(DataStoreEntry entry) {
SystemIcons.load();
var window = AppWindowHelper.sideWindow(AppI18n.get("chooseCustomIcon"), stage -> new StoreIconChoiceDialogComp(entry,stage),false,null);
var window = AppWindowHelper.sideWindow(
AppI18n.get("chooseCustomIcon"), stage -> new StoreIconChoiceDialogComp(entry, stage), false, null);
window.initModality(Modality.APPLICATION_MODAL);
window.show();
}
@ -50,8 +53,9 @@ public class StoreIconChoiceDialogComp extends SimpleComp {
});
});
var github = new ButtonComp(null, new FontIcon("mdi2g-github"), () -> {
Hyperlinks.open(Hyperlinks.SELFHST_ICONS);
}).grow(false, true);
Hyperlinks.open(Hyperlinks.SELFHST_ICONS);
})
.grow(false, true);
var dialog = new DialogComp() {
@Override
protected void finish() {
@ -68,10 +72,11 @@ public class StoreIconChoiceDialogComp extends SimpleComp {
@Override
public Comp<?> bottom() {
var clear = new ButtonComp(AppI18n.observable("clear"),() -> {
selected.setValue(null);
finish();
}).grow(false, true);
var clear = new ButtonComp(AppI18n.observable("clear"), () -> {
selected.setValue(null);
finish();
})
.grow(false, true);
return new HorizontalComp(List.of(github, filter.hgrow(), clear)).spacing(10);
}

View file

@ -4,27 +4,31 @@ import io.xpipe.app.fxcomps.SimpleComp;
import io.xpipe.app.fxcomps.impl.PrettyImageHelper;
import io.xpipe.app.fxcomps.impl.TooltipAugment;
import io.xpipe.app.resources.SystemIcons;
import javafx.beans.binding.Bindings;
import javafx.geometry.Pos;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import lombok.AllArgsConstructor;
import org.kordamp.ikonli.javafx.FontIcon;
@AllArgsConstructor
public class StoreIconComp extends SimpleComp {
private final StoreEntryWrapper wrapper;
private final int w;
private final int h;
@Override
protected Region createSimple() {
var icon = Bindings.createStringBinding(() -> {
return getImage();
}, wrapper.getIcon());
var icon = Bindings.createStringBinding(
() -> {
return getImage();
},
wrapper.getIcon());
var imageComp = PrettyImageHelper.ofFixedSize(icon, w, h);
var storeIcon = imageComp.createRegion();
if (wrapper.getValidity().getValue().isUsable()) {
@ -43,17 +47,21 @@ public class StoreIconComp extends SimpleComp {
stack.setAlignment(Pos.CENTER);
dots.visibleProperty().bind(stack.hoverProperty());
storeIcon.opacityProperty().bind(Bindings.createDoubleBinding(() -> {
return stack.isHover() ? 0.5 : 1.0;
}, stack.hoverProperty()));
storeIcon
.opacityProperty()
.bind(Bindings.createDoubleBinding(
() -> {
return stack.isHover() ? 0.5 : 1.0;
},
stack.hoverProperty()));
stack.addEventFilter(MouseEvent.MOUSE_PRESSED,event -> {
stack.addEventFilter(MouseEvent.MOUSE_PRESSED, event -> {
if (event.getButton() == MouseButton.PRIMARY) {
StoreIconChoiceDialogComp.show(wrapper.getEntry());
event.consume();
}
});
return stack;
}
@ -63,8 +71,7 @@ public class StoreIconComp extends SimpleComp {
}
if (wrapper.getIcon().getValue() == null) {
return wrapper
.getEntry()
return wrapper.getEntry()
.getProvider()
.getDisplayIconFileName(wrapper.getEntry().getStore());
}

View file

@ -176,7 +176,8 @@ public class StoreSection {
var showProvider = true;
try {
showProvider = other.getEntry().getProvider().shouldShow(other);
} catch (Exception ignored) {}
} catch (Exception ignored) {
}
return showProvider;
},
e.getPersistentState(),

View file

@ -98,10 +98,11 @@ public class StoreViewState {
private void initFilterJump() {
var all = getAllConnectionsCategory();
filter.addListener((observable, oldValue, newValue) -> {
var matchingCats = categories.getList().stream().filter(storeCategoryWrapper -> storeCategoryWrapper.getRoot().equals(all))
.filter(storeCategoryWrapper -> storeCategoryWrapper.getDirectContainedEntries()
.stream()
.anyMatch(wrapper -> wrapper.matchesFilter(newValue)))
var matchingCats = categories.getList().stream()
.filter(storeCategoryWrapper ->
storeCategoryWrapper.getRoot().equals(all))
.filter(storeCategoryWrapper -> storeCategoryWrapper.getDirectContainedEntries().stream()
.anyMatch(wrapper -> wrapper.matchesFilter(newValue)))
.toList();
if (matchingCats.size() == 1) {
activeCategory.setValue(matchingCats.getFirst());

View file

@ -9,10 +9,10 @@ import io.xpipe.app.util.PlatformState;
import io.xpipe.app.util.ThreadHelper;
import io.xpipe.core.process.OsType;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.desktop.*;
import java.util.List;
import javax.imageio.ImageIO;
public class AppDesktopIntegration {
@ -36,7 +36,8 @@ public class AppDesktopIntegration {
ThreadHelper.sleep(1000);
OperationMode.close();
});
}}
}
}
});
}

View file

@ -1,11 +1,11 @@
package io.xpipe.app.core;
import io.xpipe.app.ext.ExtensionException;
import io.xpipe.app.ext.ProcessControlProvider;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.issue.TrackEvent;
import io.xpipe.app.resources.AppResources;
import io.xpipe.core.process.OsType;
import io.xpipe.app.ext.ProcessControlProvider;
import io.xpipe.core.util.ModuleHelper;
import io.xpipe.core.util.ModuleLayerLoader;
import io.xpipe.core.util.XPipeInstallation;

View file

@ -4,8 +4,8 @@ import io.xpipe.app.comp.base.MarkdownComp;
import io.xpipe.app.core.mode.OperationMode;
import io.xpipe.app.core.window.AppWindowHelper;
import io.xpipe.app.fxcomps.Comp;
import io.xpipe.app.resources.AppResources;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.geometry.Insets;
import javafx.geometry.Pos;

View file

@ -3,8 +3,8 @@ package io.xpipe.app.core;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.issue.TrackEvent;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.resources.AppResources;
import javafx.scene.Scene;
import java.io.IOException;

View file

@ -8,7 +8,9 @@ import java.util.concurrent.TimeUnit;
public class AppBundledToolsCheck {
private static boolean getResult() {
var fc = new ProcessBuilder("where", "ssh").redirectErrorStream(true).redirectOutput(ProcessBuilder.Redirect.DISCARD);
var fc = new ProcessBuilder("where", "ssh")
.redirectErrorStream(true)
.redirectOutput(ProcessBuilder.Redirect.DISCARD);
try {
var proc = fc.start();
proc.waitFor(2, TimeUnit.SECONDS);

View file

@ -4,14 +4,17 @@ import io.xpipe.app.issue.ErrorEvent;
public class AppJavaOptionsCheck {
public static void check() throws Exception {
public static void check() {
var env = System.getenv("_JAVA_OPTIONS");
if (env == null) {
return;
}
ErrorEvent.fromMessage("You have configured the environment variable _JAVA_OPTIONS=%s on your system.".formatted(env) +
" This will forcefully apply all custom JVM options to XPipe as well and can cause a variety of different issues." +
" Please remove this global environment variable and use local configuration instead for your other JVM programs.").expected().handle();
ErrorEvent.fromMessage(
"You have configured the environment variable _JAVA_OPTIONS=%s on your system.".formatted(env)
+ " This will forcefully apply all custom JVM options to XPipe as well and can cause a variety of different issues."
+ " Please remove this global environment variable and use local configuration instead for your other JVM programs.")
.expected()
.handle();
}
}

View file

@ -25,8 +25,10 @@ public class AppRosettaCheck {
if (ret.get().equals("1")) {
ErrorEvent.fromMessage("You are running the Intel version of XPipe on an Apple Silicon system."
+ " There is a native build available that comes with much better performance."
+ " Please install that one instead.").expected().handle();
+ " There is a native build available that comes with much better performance."
+ " Please install that one instead.")
.expected()
.handle();
}
}
}

View file

@ -1,9 +1,9 @@
package io.xpipe.app.core.check;
import io.xpipe.app.ext.ProcessControlProvider;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.util.LocalShell;
import io.xpipe.core.process.OsType;
import io.xpipe.app.ext.ProcessControlProvider;
import io.xpipe.core.process.ProcessOutputException;
import lombok.Value;

View file

@ -9,6 +9,7 @@ import io.xpipe.app.resources.AppImages;
import io.xpipe.app.update.UpdateAvailableAlert;
import io.xpipe.app.util.PlatformState;
import io.xpipe.app.util.ThreadHelper;
import javafx.application.Application;
public abstract class PlatformMode extends OperationMode {

View file

@ -1,7 +1,6 @@
package io.xpipe.app.core.window;
import io.xpipe.app.core.AppCache;
import io.xpipe.app.resources.AppImages;
import io.xpipe.app.core.AppProperties;
import io.xpipe.app.core.AppTheme;
import io.xpipe.app.core.mode.OperationMode;
@ -10,8 +9,10 @@ import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.issue.TrackEvent;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.prefs.CloseBehaviourAlert;
import io.xpipe.app.resources.AppImages;
import io.xpipe.app.util.ThreadHelper;
import io.xpipe.core.process.OsType;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.geometry.Rectangle2D;
@ -24,17 +25,18 @@ import javafx.scene.layout.Region;
import javafx.scene.paint.Color;
import javafx.stage.Screen;
import javafx.stage.Stage;
import lombok.Builder;
import lombok.Getter;
import lombok.Value;
import lombok.extern.jackson.Jacksonized;
import javax.imageio.ImageIO;
import java.io.IOException;
import java.nio.file.Path;
import java.time.Duration;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import javax.imageio.ImageIO;
public class AppMainWindow {

View file

@ -1,11 +1,13 @@
package io.xpipe.app.core.window;
import com.sun.jna.NativeLong;
import io.xpipe.app.core.AppProperties;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.util.NativeBridge;
import io.xpipe.core.util.ModuleHelper;
import javafx.stage.Window;
import com.sun.jna.NativeLong;
import lombok.Getter;
import lombok.SneakyThrows;

View file

@ -7,9 +7,9 @@ import io.xpipe.app.comp.store.StoreEntryWrapper;
import io.xpipe.app.comp.store.StoreSection;
import io.xpipe.app.comp.store.StoreSectionComp;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.resources.AppImages;
import io.xpipe.app.fxcomps.Comp;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.resources.AppImages;
import io.xpipe.app.storage.DataStoreEntry;
import io.xpipe.core.store.DataStore;
import io.xpipe.core.util.JacksonizedValue;

View file

@ -3,6 +3,7 @@ package io.xpipe.app.ext;
import io.xpipe.app.storage.DataStoreEntryRef;
import io.xpipe.core.process.*;
import io.xpipe.core.store.DataStore;
import lombok.NonNull;
import java.util.ServiceLoader;

View file

@ -4,6 +4,7 @@ import io.xpipe.app.comp.base.ButtonComp;
import io.xpipe.app.comp.store.*;
import io.xpipe.app.core.AppFont;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.ext.LocalStore;
import io.xpipe.app.fxcomps.Comp;
import io.xpipe.app.fxcomps.SimpleComp;
import io.xpipe.app.resources.SystemIcons;
@ -12,7 +13,6 @@ import io.xpipe.app.storage.DataStoreEntry;
import io.xpipe.app.storage.DataStoreEntryRef;
import io.xpipe.app.util.DataStoreCategoryChoiceComp;
import io.xpipe.core.store.DataStore;
import io.xpipe.app.ext.LocalStore;
import io.xpipe.core.store.ShellStore;
import javafx.beans.binding.Bindings;
@ -217,7 +217,8 @@ public class DataStoreChoiceComp<T extends DataStore> extends SimpleComp {
}
SystemIcons.load();
return "app:system/" + selected.getValue().get().getIcon() + ".svg";
return "app:system/"
+ selected.getValue().get().getIcon() + ".svg";
},
selected),
16,

View file

@ -1,10 +1,10 @@
package io.xpipe.app.fxcomps.impl;
import io.xpipe.app.resources.AppImages;
import io.xpipe.app.fxcomps.SimpleComp;
import io.xpipe.app.fxcomps.util.PlatformThread;
import io.xpipe.app.issue.TrackEvent;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.resources.AppImages;
import io.xpipe.core.store.FileNames;
import javafx.beans.binding.Bindings;

View file

@ -1,9 +1,9 @@
package io.xpipe.app.fxcomps.impl;
import io.xpipe.app.core.App;
import io.xpipe.app.resources.AppImages;
import io.xpipe.app.fxcomps.Comp;
import io.xpipe.app.fxcomps.util.BindingsHelper;
import io.xpipe.app.resources.AppImages;
import io.xpipe.core.store.FileNames;
import javafx.beans.binding.Bindings;
@ -34,27 +34,29 @@ public class PrettyImageHelper {
}
private static ObservableValue<String> rasterizedImageIfExistsScaled(String img, int height) {
return Bindings.createStringBinding(() -> {
if (img == null) {
return null;
}
return Bindings.createStringBinding(
() -> {
if (img == null) {
return null;
}
if (!img.endsWith(".svg")) {
return rasterizedImageIfExists(img, height).orElse(null);
}
if (!img.endsWith(".svg")) {
return rasterizedImageIfExists(img, height).orElse(null);
}
var sizes = List.of(16, 24, 40, 80);
var mult = Math.round(App.getApp().displayScale().get() * height);
var base = FileNames.getBaseName(img);
var available = sizes.stream()
.filter(integer -> AppImages.hasNormalImage(base + "-" + integer + ".png"))
.toList();
var closest = available.stream()
.filter(integer -> integer >= mult)
.findFirst()
.orElse(available.size() > 0 ? available.getLast() : 0);
return rasterizedImageIfExists(img, closest).orElse(null);
}, App.getApp().displayScale());
var sizes = List.of(16, 24, 40, 80);
var mult = Math.round(App.getApp().displayScale().get() * height);
var base = FileNames.getBaseName(img);
var available = sizes.stream()
.filter(integer -> AppImages.hasNormalImage(base + "-" + integer + ".png"))
.toList();
var closest = available.stream()
.filter(integer -> integer >= mult)
.findFirst()
.orElse(available.size() > 0 ? available.getLast() : 0);
return rasterizedImageIfExists(img, closest).orElse(null);
},
App.getApp().displayScale());
}
public static Comp<?> ofFixedSizeSquare(String img, int size) {
@ -62,7 +64,7 @@ public class PrettyImageHelper {
}
public static Comp<?> ofFixedSize(String img, int w, int h) {
return ofFixedSize(new SimpleStringProperty(img), w,h);
return ofFixedSize(new SimpleStringProperty(img), w, h);
}
public static Comp<?> ofFixedSize(ObservableValue<String> img, int w, int h) {

View file

@ -1,9 +1,9 @@
package io.xpipe.app.fxcomps.impl;
import io.xpipe.app.resources.AppImages;
import io.xpipe.app.fxcomps.SimpleComp;
import io.xpipe.app.fxcomps.util.PlatformThread;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.resources.AppImages;
import io.xpipe.core.store.FileNames;
import javafx.beans.binding.Bindings;

View file

@ -8,8 +8,8 @@ import io.xpipe.app.core.*;
import io.xpipe.app.core.window.AppWindowHelper;
import io.xpipe.app.fxcomps.Comp;
import io.xpipe.app.fxcomps.SimpleComp;
import io.xpipe.app.resources.AppResources;
import javafx.beans.property.ListProperty;
import javafx.beans.property.SimpleListProperty;
import javafx.beans.property.SimpleStringProperty;

View file

@ -112,17 +112,21 @@ public class LauncherCommand implements Callable<Integer> {
}
try {
client.get().performRequest(DaemonFocusExchange.Request.builder()
.mode(getEffectiveMode())
.build());
client.get()
.performRequest(DaemonFocusExchange.Request.builder()
.mode(getEffectiveMode())
.build());
if (!inputs.isEmpty()) {
client.get().performRequest(DaemonOpenExchange.Request.builder()
.arguments(inputs)
.build());
client.get()
.performRequest(DaemonOpenExchange.Request.builder()
.arguments(inputs)
.build());
}
} catch (Exception ex) {
// Wait until shutdown has completed
if (ex.getMessage() != null && ex.getMessage().contains("Daemon is currently in shutdown") && attemptCounter < 10) {
if (ex.getMessage() != null
&& ex.getMessage().contains("Daemon is currently in shutdown")
&& attemptCounter < 10) {
ThreadHelper.sleep(1000);
checkStart(++attemptCounter);
return;

View file

@ -45,8 +45,12 @@ public class AppPrefs {
mapVaultSpecific(new SimpleBooleanProperty(false), "dontAutomaticallyStartVmSshServer", Boolean.class);
final BooleanProperty dontAcceptNewHostKeys =
mapVaultSpecific(new SimpleBooleanProperty(false), "dontAcceptNewHostKeys", Boolean.class);
final BooleanProperty performanceMode = map(new SimpleBooleanProperty(XPipeDistributionType.get() == XPipeDistributionType.WEBTOP), "performanceMode", Boolean.class);
public final BooleanProperty useBundledTools = map(new SimpleBooleanProperty(false), "useBundledTools", Boolean.class);
final BooleanProperty performanceMode = map(
new SimpleBooleanProperty(XPipeDistributionType.get() == XPipeDistributionType.WEBTOP),
"performanceMode",
Boolean.class);
public final BooleanProperty useBundledTools =
map(new SimpleBooleanProperty(false), "useBundledTools", Boolean.class);
public final ObjectProperty<AppTheme.Theme> theme =
map(new SimpleObjectProperty<>(), "theme", AppTheme.Theme.class);
final BooleanProperty useSystemFont = map(new SimpleBooleanProperty(true), "useSystemFont", Boolean.class);
@ -76,7 +80,8 @@ public class AppPrefs {
mapVaultSpecific(new SimpleBooleanProperty(false), "dontCachePasswords", Boolean.class);
public final BooleanProperty denyTempScriptCreation =
mapVaultSpecific(new SimpleBooleanProperty(false), "denyTempScriptCreation", Boolean.class);
final Property<ExternalPasswordManager> passwordManager = mapVaultSpecific(new SimpleObjectProperty<>(), "passwordManager", ExternalPasswordManager.class);
final Property<ExternalPasswordManager> passwordManager =
mapVaultSpecific(new SimpleObjectProperty<>(), "passwordManager", ExternalPasswordManager.class);
final StringProperty passwordManagerCommand =
map(new SimpleStringProperty(""), "passwordManagerCommand", String.class);
final ObjectProperty<StartupBehaviour> startupBehaviour =

View file

@ -79,7 +79,10 @@ public interface ExternalEditorType extends PrefsChoiceValue {
LinuxPathType VSCODE_LINUX = new LinuxPathType("app.vscode", "code") {
@Override
public void launch(Path file) throws Exception {
var builder = CommandBuilder.of().fixedEnvrironment("DONT_PROMPT_WSL_INSTALL", "No_Prompt_please").addFile(executable).addFile(file.toString());
var builder = CommandBuilder.of()
.fixedEnvrironment("DONT_PROMPT_WSL_INSTALL", "No_Prompt_please")
.addFile(executable)
.addFile(file.toString());
ExternalApplicationHelper.startAsync(builder);
}
};

View file

@ -45,14 +45,15 @@ public interface ExternalPasswordManager extends PrefsChoiceValue {
@Override
public synchronized String retrievePassword(String key) {
try {
if (!loaded) {
loaded = true;
var cmd = """
if (!loaded) {
loaded = true;
var cmd =
"""
$code = @"
using System.Text;
using System;
using System.Runtime.InteropServices;
namespace CredManager {
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct CredentialMem
@ -70,16 +71,16 @@ public interface ExternalPasswordManager extends PrefsChoiceValue {
public string targetAlias;
public string userName;
}
public class Credential {
[DllImport("advapi32.dll", EntryPoint = "CredReadW", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern bool CredRead(string target, int type, int reservedFlag, out IntPtr credentialPtr);
public static string GetUserPassword(string target)
{
CredentialMem credMem;
IntPtr credPtr;
if (CredRead(target, 1, 0, out credPtr))
{
credMem = Marshal.PtrToStructure<CredentialMem>(credPtr);
@ -95,14 +96,14 @@ public interface ExternalPasswordManager extends PrefsChoiceValue {
"@
Add-Type -TypeDefinition $code -Language CSharp
""";
LocalShell.getLocalPowershell().command(cmd).execute();
}
LocalShell.getLocalPowershell().command(cmd).execute();
}
return LocalShell.getLocalPowershell().command("[CredManager.Credential]::GetUserPassword(\"" + key.replaceAll("\"", "`\"") + "\")").readStdoutOrThrow();
return LocalShell.getLocalPowershell()
.command("[CredManager.Credential]::GetUserPassword(\"" + key.replaceAll("\"", "`\"") + "\")")
.readStdoutOrThrow();
} catch (Exception ex) {
ErrorEvent.fromThrowable(ex)
.expected()
.handle();
ErrorEvent.fromThrowable(ex).expected().handle();
return null;
}
}

View file

@ -1,6 +1,5 @@
package io.xpipe.app.prefs;
import atlantafx.base.theme.Styles;
import io.xpipe.app.comp.base.ButtonComp;
import io.xpipe.app.comp.base.IntegratedTextAreaComp;
import io.xpipe.app.core.AppI18n;
@ -13,6 +12,7 @@ import io.xpipe.app.fxcomps.impl.VerticalComp;
import io.xpipe.app.fxcomps.util.BindingsHelper;
import io.xpipe.app.util.OptionsBuilder;
import io.xpipe.app.util.ThreadHelper;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.geometry.Insets;
@ -21,6 +21,8 @@ import javafx.scene.control.MenuButton;
import javafx.scene.control.MenuItem;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.Region;
import atlantafx.base.theme.Styles;
import lombok.Value;
import org.kordamp.ikonli.javafx.FontIcon;
@ -45,11 +47,16 @@ public class PasswordManagerCategory extends AppPrefsCategory {
protected Comp<?> create() {
var choices = new ArrayList<Choice>();
ExternalPasswordManagerTemplate.ALL.forEach(externalPasswordManagerTemplate -> {
choices.add(new Choice(externalPasswordManagerTemplate.getId(), externalPasswordManagerTemplate.getTemplate(), ExternalPasswordManager.COMMAND));
});
ExternalPasswordManager.ALL.stream().filter(externalPasswordManager -> externalPasswordManager != ExternalPasswordManager.COMMAND).forEach(externalPasswordManager -> {
choices.add(new Choice(externalPasswordManager.getId(), null, externalPasswordManager));
choices.add(new Choice(
externalPasswordManagerTemplate.getId(),
externalPasswordManagerTemplate.getTemplate(),
ExternalPasswordManager.COMMAND));
});
ExternalPasswordManager.ALL.stream()
.filter(externalPasswordManager -> externalPasswordManager != ExternalPasswordManager.COMMAND)
.forEach(externalPasswordManager -> {
choices.add(new Choice(externalPasswordManager.getId(), null, externalPasswordManager));
});
var prefs = AppPrefs.get();
var testPasswordManagerValue = new SimpleStringProperty();
@ -89,8 +96,10 @@ public class PasswordManagerCategory extends AppPrefsCategory {
.minHeight(120);
var templates = Comp.of(() -> {
var cb = new MenuButton();
cb.textProperty().bind(BindingsHelper.flatMap(prefs.passwordManager,externalPasswordManager -> {
return externalPasswordManager != null ? AppI18n.observable(externalPasswordManager.getId()) : AppI18n.observable("selectType");
cb.textProperty().bind(BindingsHelper.flatMap(prefs.passwordManager, externalPasswordManager -> {
return externalPasswordManager != null
? AppI18n.observable(externalPasswordManager.getId())
: AppI18n.observable("selectType");
}));
choices.forEach(e -> {
var m = new MenuItem();
@ -119,17 +128,16 @@ public class PasswordManagerCategory extends AppPrefsCategory {
event.consume();
}
})),
new ButtonComp(null, new FontIcon("mdi2p-play"), test)
.styleClass(Styles.RIGHT_PILL)));
new ButtonComp(null, new FontIcon("mdi2p-play"), test).styleClass(Styles.RIGHT_PILL)));
testInput.apply(struc -> {
var first = ((Region) struc.get().getChildren().get(0));
var second = ((Region) struc.get().getChildren().get(1));
second.prefHeightProperty().bind(first.heightProperty());
});
var testPasswordManager = new HorizontalComp(List.of(testInput,
Comp.hspacer(25),
new LabelComp(testPasswordManagerResult).apply(struc -> struc.get().setOpacity(0.5))))
var testPasswordManager = new HorizontalComp(List.of(
testInput, Comp.hspacer(25), new LabelComp(testPasswordManagerResult).apply(struc -> struc.get()
.setOpacity(0.5))))
.padding(new Insets(10, 0, 0, 0))
.apply(struc -> struc.get().setAlignment(Pos.CENTER_LEFT))
.apply(struc -> struc.get().setFillHeight(true));

View file

@ -1,6 +1,5 @@
package io.xpipe.app.prefs;
import atlantafx.base.theme.Styles;
import io.xpipe.app.comp.base.ButtonComp;
import io.xpipe.app.comp.base.MarkdownComp;
import io.xpipe.app.core.AppI18n;
@ -14,6 +13,7 @@ import io.xpipe.app.storage.DataStorageSyncHandler;
import io.xpipe.app.util.DesktopHelper;
import io.xpipe.app.util.OptionsBuilder;
import io.xpipe.app.util.ThreadHelper;
import javafx.application.Platform;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.geometry.Insets;
@ -21,6 +21,8 @@ import javafx.geometry.Pos;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.layout.Region;
import atlantafx.base.theme.Styles;
import org.kordamp.ikonli.javafx.FontIcon;
import java.util.List;
@ -33,7 +35,6 @@ public class SyncCategory extends AppPrefsCategory {
return "sync";
}
private static void showHelpAlert() {
AppWindowHelper.showAlert(
alert -> {
@ -76,8 +77,7 @@ public class SyncCategory extends AppPrefsCategory {
restartButton.visible(canRestart);
restartButton.padding(new Insets(6, 10, 6, 6));
var testRow = new HorizontalComp(
List.of(testButton, restartButton))
var testRow = new HorizontalComp(List.of(testButton, restartButton))
.spacing(10)
.padding(new Insets(10, 0, 0, 0))
.apply(struc -> struc.get().setAlignment(Pos.CENTER_LEFT));

View file

@ -2,6 +2,7 @@ package io.xpipe.app.prefs;
import io.xpipe.app.comp.base.ButtonComp;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.ext.LocalStore;
import io.xpipe.app.ext.PrefsChoiceValue;
import io.xpipe.app.fxcomps.Comp;
import io.xpipe.app.fxcomps.impl.ChoiceComp;
@ -13,7 +14,6 @@ import io.xpipe.app.util.Hyperlinks;
import io.xpipe.app.util.OptionsBuilder;
import io.xpipe.app.util.TerminalLauncher;
import io.xpipe.app.util.ThreadHelper;
import io.xpipe.app.ext.LocalStore;
import javafx.beans.binding.Bindings;
import javafx.geometry.Insets;

View file

@ -47,9 +47,12 @@ public class TroubleshootCategory extends AppPrefsCategory {
.toString(),
XPipeInstallation.getDaemonDebugScriptPath(OsType.getLocal()));
// We can't use the SSH bridge
var type = ExternalTerminalType.determineNonSshBridgeFallback(AppPrefs.get().terminalType().getValue());
TerminalLauncher.openDirect("XPipe Debug", sc -> sc.getShellDialect()
.runScriptCommand(sc, script), type);
var type = ExternalTerminalType.determineNonSshBridgeFallback(
AppPrefs.get().terminalType().getValue());
TerminalLauncher.openDirect(
"XPipe Debug",
sc -> sc.getShellDialect().runScriptCommand(sc, script),
type);
});
e.consume();
})

View file

@ -10,8 +10,8 @@ import io.xpipe.core.util.XPipeInstallation;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleBooleanProperty;
import lombok.SneakyThrows;
public class VaultCategory extends AppPrefsCategory {
@ -39,8 +39,11 @@ public class VaultCategory extends AppPrefsCategory {
var encryptVault = new SimpleBooleanProperty(prefs.encryptAllVaultData().get());
encryptVault.addListener((observable, oldValue, newValue) -> {
if (!newValue && !AppWindowHelper.showConfirmationAlert(
"confirmVaultUnencryptTitle", "confirmVaultUnencryptHeader", "confirmVaultUnencryptContent")) {
if (!newValue
&& !AppWindowHelper.showConfirmationAlert(
"confirmVaultUnencryptTitle",
"confirmVaultUnencryptHeader",
"confirmVaultUnencryptContent")) {
Platform.runLater(() -> {
encryptVault.set(true);
});

View file

@ -8,6 +8,7 @@ import io.xpipe.app.core.window.AppWindowHelper;
import io.xpipe.app.util.*;
import io.xpipe.core.process.OsType;
import io.xpipe.core.util.XPipeInstallation;
import javafx.beans.property.SimpleObjectProperty;
import javafx.geometry.Insets;
import javafx.scene.control.ButtonType;

View file

@ -3,13 +3,14 @@ package io.xpipe.app.resources;
import io.xpipe.app.ext.ContainerImageStore;
import io.xpipe.core.process.ShellControl;
import io.xpipe.core.store.DataStore;
import lombok.EqualsAndHashCode;
import lombok.Value;
import java.util.function.Predicate;
@Value
@EqualsAndHashCode(callSuper=true)
@EqualsAndHashCode(callSuper = true)
public class ContainerAutoSystemIcon extends SystemIcon {
Predicate<String> imageCheck;
@ -20,7 +21,7 @@ public class ContainerAutoSystemIcon extends SystemIcon {
}
@Override
public boolean isApplicable(ShellControl sc) throws Exception {
public boolean isApplicable(ShellControl sc) {
var source = sc.getSourceStore();
if (source.isEmpty()) {
return false;

View file

@ -2,11 +2,12 @@ package io.xpipe.app.resources;
import io.xpipe.core.process.OsType;
import io.xpipe.core.process.ShellControl;
import lombok.EqualsAndHashCode;
import lombok.Value;
@Value
@EqualsAndHashCode(callSuper=true)
@EqualsAndHashCode(callSuper = true)
public class FileAutoSystemIcon extends SystemIcon {
OsType.Any osType;
@ -29,7 +30,7 @@ public class FileAutoSystemIcon extends SystemIcon {
return false;
}
return sc.getShellDialect().createFileExistsCommand(sc, abs.get()).executeAndCheck() ||
sc.getShellDialect().directoryExists(sc, abs.get()).executeAndCheck();
return sc.getShellDialect().createFileExistsCommand(sc, abs.get()).executeAndCheck()
|| sc.getShellDialect().directoryExists(sc, abs.get()).executeAndCheck();
}
}

View file

@ -2,16 +2,18 @@ package io.xpipe.app.resources;
import io.xpipe.core.process.ShellControl;
import io.xpipe.core.util.FailableFunction;
import lombok.EqualsAndHashCode;
import lombok.Value;
@Value
@EqualsAndHashCode(callSuper=true)
@EqualsAndHashCode(callSuper = true)
public class ShellAutoSystemIcon extends SystemIcon {
FailableFunction<ShellControl, Boolean, Exception> applicable;
public ShellAutoSystemIcon(String iconName, String displayName, FailableFunction<ShellControl, Boolean, Exception> applicable) {
public ShellAutoSystemIcon(
String iconName, String displayName, FailableFunction<ShellControl, Boolean, Exception> applicable) {
super(iconName, displayName);
this.applicable = applicable;
}

View file

@ -2,6 +2,7 @@ package io.xpipe.app.resources;
import io.xpipe.core.process.ShellControl;
import io.xpipe.core.store.DataStore;
import lombok.Value;
import lombok.experimental.NonFinal;

View file

@ -6,6 +6,7 @@ import io.xpipe.core.process.ShellDialects;
import io.xpipe.core.process.ShellStoreState;
import io.xpipe.core.store.DataStore;
import io.xpipe.core.store.StatefulDataStore;
import org.apache.commons.io.FilenameUtils;
import java.nio.file.Files;
@ -21,22 +22,21 @@ public class SystemIcons {
new SystemIcon("opnsense", "opnsense") {
@Override
public boolean isApplicable(DataStore store) {
return store instanceof StatefulDataStore<?> statefulDataStore &&
statefulDataStore.getState() instanceof ShellStoreState shellStoreState &&
shellStoreState.getShellDialect() == ShellDialects.OPNSENSE;
return store instanceof StatefulDataStore<?> statefulDataStore
&& statefulDataStore.getState() instanceof ShellStoreState shellStoreState
&& shellStoreState.getShellDialect() == ShellDialects.OPNSENSE;
}
},
new SystemIcon("pfsense", "pfsense") {
new SystemIcon("pfsense", "pfsense") {
@Override
public boolean isApplicable(DataStore store) {
return store instanceof StatefulDataStore<?> statefulDataStore &&
statefulDataStore.getState() instanceof ShellStoreState shellStoreState &&
shellStoreState.getShellDialect() == ShellDialects.PFSENSE;
return store instanceof StatefulDataStore<?> statefulDataStore
&& statefulDataStore.getState() instanceof ShellStoreState shellStoreState
&& shellStoreState.getShellDialect() == ShellDialects.PFSENSE;
}
},
new ContainerAutoSystemIcon("file-browser", "file browser", name -> name.contains("filebrowser")),
new FileAutoSystemIcon("syncthing", "syncthing", OsType.LINUX, "~/.local/state/syncthing")
);
new FileAutoSystemIcon("syncthing", "syncthing", OsType.LINUX, "~/.local/state/syncthing"));
private static final List<SystemIcon> SYSTEM_ICONS = new ArrayList<>();
private static boolean loaded = false;
@ -56,7 +56,9 @@ public class SystemIcons {
continue;
}
var base = name.replaceAll("-40", "");
if (AUTO_SYSTEM_ICONS.stream().anyMatch(autoSystemIcon -> autoSystemIcon.getIconName().equals(base))) {
if (AUTO_SYSTEM_ICONS.stream()
.anyMatch(autoSystemIcon ->
autoSystemIcon.getIconName().equals(base))) {
continue;
}
var displayName = base.replaceAll("-", " ");
@ -64,7 +66,7 @@ public class SystemIcons {
}
}
});
SYSTEM_ICONS.sort(Comparator.<SystemIcon, String>comparing(systemIcon -> systemIcon.getIconName()));
SYSTEM_ICONS.sort(Comparator.comparing(systemIcon -> systemIcon.getIconName()));
}
public static synchronized void load() {
@ -72,7 +74,7 @@ public class SystemIcons {
return;
}
AppImages.loadDirectory(AppResources.XPIPE_MODULE,"img/system", true, false);
AppImages.loadDirectory(AppResources.XPIPE_MODULE, "img/system", true, false);
loaded = true;
}

View file

@ -1,6 +1,7 @@
package io.xpipe.app.storage;
import io.xpipe.app.comp.store.StoreSortMode;
import io.xpipe.app.ext.LocalStore;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.issue.TrackEvent;
import io.xpipe.app.prefs.AppPrefs;
@ -8,7 +9,6 @@ import io.xpipe.app.util.FixedHierarchyStore;
import io.xpipe.app.util.ThreadHelper;
import io.xpipe.core.store.DataStore;
import io.xpipe.core.store.FixedChildStore;
import io.xpipe.app.ext.LocalStore;
import io.xpipe.core.store.StorePath;
import io.xpipe.core.util.UuidHelper;

View file

@ -1,11 +1,5 @@
package io.xpipe.app.storage;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.xpipe.app.ext.DataStoreProvider;
import io.xpipe.app.ext.DataStoreProviders;
import io.xpipe.app.issue.ErrorEvent;
@ -13,6 +7,13 @@ import io.xpipe.app.resources.SystemIcons;
import io.xpipe.app.util.FixedHierarchyStore;
import io.xpipe.core.store.*;
import io.xpipe.core.util.JacksonMapper;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.*;
import lombok.experimental.NonFinal;
import org.apache.commons.io.FileUtils;
@ -89,8 +90,7 @@ public class DataStoreEntry extends StorageElement {
DataColor color,
String notes,
Order explicitOrder,
String icon
) {
String icon) {
super(directory, uuid, name, lastUsed, lastModified, color, expanded, dirty);
this.categoryUuid = categoryUuid;
this.store = store;
@ -113,8 +113,7 @@ public class DataStoreEntry extends StorageElement {
Instant lastModified,
DataStore store,
Order explicitOrder,
String icon
) {
String icon) {
super(directory, uuid, name, lastUsed, lastModified, null, false, false);
this.categoryUuid = categoryUuid;
this.store = store;

View file

@ -1,11 +1,11 @@
package io.xpipe.app.storage;
import io.xpipe.app.ext.DataStorageExtensionProvider;
import io.xpipe.app.ext.LocalStore;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.issue.TrackEvent;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.core.process.OsType;
import io.xpipe.app.ext.LocalStore;
import io.xpipe.core.util.JacksonMapper;
import com.fasterxml.jackson.core.JacksonException;
@ -176,13 +176,11 @@ public class StandardStorage extends DataStorage {
storeEntriesSet.forEach(e -> {
if (e.getCategoryUuid() == null
|| getStoreCategoryIfPresent(e.getCategoryUuid())
.isEmpty()) {
|| getStoreCategoryIfPresent(e.getCategoryUuid()).isEmpty()) {
e.setCategoryUuid(DEFAULT_CATEGORY_UUID);
}
if (e.getCategoryUuid() != null
&& e.getCategoryUuid().equals(ALL_CONNECTIONS_CATEGORY_UUID)) {
if (e.getCategoryUuid() != null && e.getCategoryUuid().equals(ALL_CONNECTIONS_CATEGORY_UUID)) {
e.setCategoryUuid(DEFAULT_CATEGORY_UUID);
}

View file

@ -130,7 +130,6 @@ public abstract class StorageElement {
notifyUpdate(false, false);
}
public void setLastUsed(Instant lastUsed) {
if (lastUsed.equals(this.lastUsed)) {
return;

View file

@ -13,9 +13,11 @@ import io.xpipe.app.util.*;
import io.xpipe.core.process.*;
import io.xpipe.core.store.FilePath;
import io.xpipe.core.util.FailableFunction;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonBar;
import javafx.scene.control.ButtonType;
import lombok.Getter;
import lombok.Value;
import lombok.With;
@ -275,10 +277,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
var rawCommand = command.buildSimple();
var script = ScriptHelper.getExecScriptFile(sc, "sh");
Files.writeString(Path.of(script.toString()), rawCommand);
var fixedFile = script
.toString()
.replaceAll("\\\\", "/")
.replaceAll("\\s", "\\$0");
var fixedFile = script.toString().replaceAll("\\\\", "/").replaceAll("\\s", "\\$0");
sc.command(CommandBuilder.of()
.addFile(file.toString())
.add("-newtab")
@ -1032,8 +1031,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
DEEPIN_TERMINAL,
FOOT,
Q_TERMINAL,
TERMIUS
);
TERMIUS);
List<ExternalTerminalType> MACOS_TERMINALS = List.of(
WARP,
ITERM2,

View file

@ -124,12 +124,13 @@ public interface WezTerminalType extends ExternalTerminalType {
@Override
public void launch(LaunchConfiguration configuration) throws Exception {
try (var sc = LocalShell.getShell()) {
var path = sc.command(String.format(
var pathOut = sc.command(String.format(
"mdfind -name '%s' -onlyin /Applications -onlyin ~/Applications -onlyin /System/Applications 2>/dev/null",
applicationName))
.readStdoutOrThrow();
var path = Path.of(pathOut);
var spawn = sc.command(CommandBuilder.of()
.addFile(Path.of(path)
.addFile(path
.resolve("Contents")
.resolve("MacOS")
.resolve("wezterm")
@ -139,7 +140,7 @@ public interface WezTerminalType extends ExternalTerminalType {
.executeAndCheck();
if (!spawn) {
ExternalApplicationHelper.startAsync(CommandBuilder.of()
.addFile(Path.of(path)
.addFile(path
.resolve("Contents")
.resolve("MacOS")
.resolve("wezterm-gui")

View file

@ -3,6 +3,7 @@ package io.xpipe.app.update;
import io.xpipe.app.core.AppLogs;
import io.xpipe.app.core.AppProperties;
import io.xpipe.app.core.mode.OperationMode;
import io.xpipe.app.ext.LocalStore;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.terminal.ExternalTerminalType;
import io.xpipe.app.util.LocalShell;
@ -12,7 +13,6 @@ import io.xpipe.app.util.ThreadHelper;
import io.xpipe.core.process.OsType;
import io.xpipe.core.process.ShellDialects;
import io.xpipe.core.store.FileNames;
import io.xpipe.app.ext.LocalStore;
import io.xpipe.core.util.FailableRunnable;
import io.xpipe.core.util.XPipeInstallation;
@ -165,7 +165,8 @@ public class AppInstaller {
runAndClose(() -> {
// We can't use the SSH bridge
var type = ExternalTerminalType.determineNonSshBridgeFallback(AppPrefs.get().terminalType().getValue());
var type = ExternalTerminalType.determineNonSshBridgeFallback(
AppPrefs.get().terminalType().getValue());
TerminalLauncher.openDirect("XPipe Updater", sc -> command, type);
});
}
@ -205,7 +206,8 @@ public class AppInstaller {
runAndClose(() -> {
// We can't use the SSH bridge
var type = ExternalTerminalType.determineNonSshBridgeFallback(AppPrefs.get().terminalType().getValue());
var type = ExternalTerminalType.determineNonSshBridgeFallback(
AppPrefs.get().terminalType().getValue());
TerminalLauncher.openDirect("XPipe Updater", sc -> command, type);
});
}
@ -245,7 +247,8 @@ public class AppInstaller {
runAndClose(() -> {
// We can't use the SSH bridge
var type = ExternalTerminalType.determineNonSshBridgeFallback(AppPrefs.get().terminalType().getValue());
var type = ExternalTerminalType.determineNonSshBridgeFallback(
AppPrefs.get().terminalType().getValue());
TerminalLauncher.openDirect("XPipe Updater", sc -> command, type);
});
}

View file

@ -1,9 +1,9 @@
package io.xpipe.app.update;
import io.xpipe.app.core.AppProperties;
import io.xpipe.app.ext.LocalStore;
import io.xpipe.app.fxcomps.impl.CodeSnippet;
import io.xpipe.app.fxcomps.impl.CodeSnippetComp;
import io.xpipe.app.ext.LocalStore;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.layout.Region;

View file

@ -98,7 +98,9 @@ public enum XPipeDistributionType {
return UNKNOWN;
}
if (OsType.getLocal() == OsType.LINUX && "/config".equals(System.getProperty("user.home")) && Files.isDirectory(Path.of("/kclient"))) {
if (OsType.getLocal() == OsType.LINUX
&& "/config".equals(System.getProperty("user.home"))
&& Files.isDirectory(Path.of("/kclient"))) {
return WEBTOP;
}

View file

@ -1,8 +1,8 @@
package io.xpipe.app.util;
import io.xpipe.app.ext.LocalStore;
import io.xpipe.app.storage.*;
import io.xpipe.app.terminal.ExternalTerminalType;
import io.xpipe.app.ext.LocalStore;
import io.xpipe.core.util.EncryptedSecretValue;
import io.xpipe.core.util.JacksonMapper;
import io.xpipe.core.util.SecretValue;

View file

@ -72,7 +72,10 @@ public class DesktopHelper {
}
var file = new FilePath(path);
sc.command(CommandBuilder.of().add("xdg-open").addFile(kind == FileKind.DIRECTORY ? file : file.getParent())).execute();
sc.command(CommandBuilder.of()
.add("xdg-open")
.addFile(kind == FileKind.DIRECTORY ? file : file.getParent()))
.execute();
}
case OsType.MacOs macOs -> {
sc.executeSimpleCommand("open " + (kind == FileKind.DIRECTORY ? "" : "-R ") + d.fileArgument(path));

View file

@ -1,9 +1,9 @@
package io.xpipe.app.util;
import io.xpipe.app.ext.LocalStore;
import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.storage.DataStoreEntryRef;
import io.xpipe.core.store.FileSystemStore;
import io.xpipe.app.ext.LocalStore;
import io.xpipe.core.util.JacksonizedValue;
import com.fasterxml.jackson.annotation.JsonTypeName;

View file

@ -58,7 +58,9 @@ public final class HumanReadableFormat {
// not this year
if (x.getYear() != now.getYear()) {
return DAY_MONTH_YEAR.withLocale(AppI18n.get().getLoaded().getLocale()).format(x);
return DAY_MONTH_YEAR
.withLocale(AppI18n.get().getLoaded().getLocale())
.format(x);
}
// not this week

View file

@ -137,26 +137,21 @@ public enum PlatformState {
try {
latch.await();
PlatformState.setCurrent(PlatformState.RUNNING);
return;
} catch (InterruptedException e) {
lastError = e;
return;
}
} catch (Throwable t) {
// Check if we already exited
if ("Platform.exit has been called".equals(t.getMessage())) {
PlatformState.setCurrent(PlatformState.EXITED);
lastError = t;
return;
} else if ("Toolkit already initialized".equals(t.getMessage())) {
PlatformState.setCurrent(PlatformState.RUNNING);
return;
} else {
// Platform initialization has failed in this case
PlatformState.setCurrent(PlatformState.EXITED);
TrackEvent.error(t.getMessage());
lastError = t;
return;
}
}
}

View file

@ -15,9 +15,9 @@ import io.xpipe.core.process.ShellControl;
import io.xpipe.core.process.ShellStoreState;
import io.xpipe.core.process.ShellTtyState;
import io.xpipe.core.store.ShellStore;
import io.xpipe.core.store.ShellValidationContext;
import io.xpipe.core.store.ValidationContext;
import javafx.application.Platform;
import javafx.beans.property.*;
import javafx.beans.value.ObservableValue;
@ -50,35 +50,38 @@ public class ScanAlert {
}
public static void showForShellStore(DataStoreEntry initial, ShellValidationContext context) {
show(initial, (DataStoreEntry entry, ShellControl sc) -> {
if (!sc.canHaveSubshells()) {
return null;
}
if (!sc.getShellDialect().getDumbMode().supportsAnyPossibleInteraction()) {
return null;
}
if (sc.getTtyState() != ShellTtyState.NONE) {
return null;
}
var providers = ScanProvider.getAll();
var applicable = new ArrayList<ScanProvider.ScanOperation>();
for (ScanProvider scanProvider : providers) {
try {
// Previous scan operation could have exited the shell
sc.start();
ScanProvider.ScanOperation operation = scanProvider.create(entry, sc);
if (operation != null) {
applicable.add(operation);
show(
initial,
(DataStoreEntry entry, ShellControl sc) -> {
if (!sc.canHaveSubshells()) {
return null;
}
} catch (Exception ex) {
ErrorEvent.fromThrowable(ex).handle();
}
}
return applicable;
}, context);
if (!sc.getShellDialect().getDumbMode().supportsAnyPossibleInteraction()) {
return null;
}
if (sc.getTtyState() != ShellTtyState.NONE) {
return null;
}
var providers = ScanProvider.getAll();
var applicable = new ArrayList<ScanProvider.ScanOperation>();
for (ScanProvider scanProvider : providers) {
try {
// Previous scan operation could have exited the shell
sc.start();
ScanProvider.ScanOperation operation = scanProvider.create(entry, sc);
if (operation != null) {
applicable.add(operation);
}
} catch (Exception ex) {
ErrorEvent.fromThrowable(ex).handle();
}
}
return applicable;
},
context);
}
private static void show(
@ -87,7 +90,8 @@ public class ScanAlert {
ShellValidationContext shellValidationContext) {
DialogComp.showWindow(
"scanAlertTitle",
stage -> new Dialog(stage, initialStore != null ? initialStore.ref() : null, applicable, shellValidationContext));
stage -> new Dialog(
stage, initialStore != null ? initialStore.ref() : null, applicable, shellValidationContext));
}
private static class Dialog extends DialogComp {
@ -104,8 +108,8 @@ public class ScanAlert {
private Dialog(
Stage window,
DataStoreEntryRef<ShellStore> entry,
BiFunction<DataStoreEntry, ShellControl, List<ScanProvider.ScanOperation>> applicable, ShellValidationContext shellValidationContext
) {
BiFunction<DataStoreEntry, ShellControl, List<ScanProvider.ScanOperation>> applicable,
ShellValidationContext shellValidationContext) {
this.window = window;
this.initialStore = entry;
this.entry = new SimpleObjectProperty<>(entry);
@ -206,7 +210,10 @@ public class ScanAlert {
shellValidationContext = null;
}
shellValidationContext = new ShellValidationContext(newValue.getStore().control().withoutLicenseCheck().start());
shellValidationContext = new ShellValidationContext(newValue.getStore()
.control()
.withoutLicenseCheck()
.start());
var a = applicable.apply(entry.get().get(), shellValidationContext.get());
Platform.runLater(() -> {

View file

@ -1,9 +1,9 @@
package io.xpipe.app.util;
import io.xpipe.app.ext.LocalStore;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.storage.DataStoreSecret;
import io.xpipe.app.ext.LocalStore;
import io.xpipe.core.util.InPlaceSecretValue;
import com.fasterxml.jackson.annotation.JsonSubTypes;

View file

@ -121,7 +121,6 @@ public class SecretRetrievalStrategyHelper {
case 2 -> passwordManager;
case 3 -> customCommand;
case 4 -> new SimpleObjectProperty<>(new SecretRetrievalStrategy.Prompt());
case 5 -> new SimpleObjectProperty<>();
default -> new SimpleObjectProperty<>();
};
},

View file

@ -63,7 +63,8 @@ public class ShellTemp {
var systemTemp = proc.getSystemTemporaryDirectory();
if (!d.directoryExists(proc, systemTemp.toString()).executeAndCheck()
|| !checkDirectoryPermissions(proc, systemTemp.toString())) {
throw ErrorEvent.expected(new IOException("No permissions to access system temporary directory %s".formatted(systemTemp)));
throw ErrorEvent.expected(
new IOException("No permissions to access system temporary directory %s".formatted(systemTemp)));
}
// We don't do this anymore, we hope that all the legacy directories have been cleared now

View file

@ -2,10 +2,10 @@ package io.xpipe.app.util;
import io.xpipe.app.beacon.AppBeaconServer;
import io.xpipe.app.core.AppProperties;
import io.xpipe.app.ext.ProcessControlProvider;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.core.process.CommandBuilder;
import io.xpipe.core.process.OsType;
import io.xpipe.app.ext.ProcessControlProvider;
import io.xpipe.core.process.ShellControl;
import io.xpipe.core.util.XPipeInstallation;
@ -180,7 +180,8 @@ public class SshLocalBridge {
} else {
var exec = sc.command(sc.getShellDialect().getWhichCommand("sshd")).readStdoutIfPossible();
if (exec.isEmpty()) {
throw ErrorEvent.expected(new IllegalStateException("No sshd executable found in PATH. The SSH terminal bridge requires a local ssh server"));
throw ErrorEvent.expected(new IllegalStateException(
"No sshd executable found in PATH. The SSH terminal bridge requires a local ssh server"));
}
return exec.get().lines().findFirst().orElseThrow();
}

View file

@ -25,7 +25,8 @@ public class TerminalLauncher {
openDirect(title, command, type);
}
public static void openDirect(String title, FailableFunction<ShellControl, String, Exception> command, ExternalTerminalType type)
public static void openDirect(
String title, FailableFunction<ShellControl, String, Exception> command, ExternalTerminalType type)
throws Exception {
try (var sc = LocalShell.getShell().start()) {
var script = ScriptHelper.constructTerminalInitFile(

View file

@ -75,7 +75,10 @@ public class TerminalLauncherManager {
public static Path waitForNextLaunch() throws BeaconClientException, BeaconServerException {
Entry first;
synchronized (entries) {
first = entries.values().stream().filter(entry -> !entry.isLaunched()).findFirst().orElse(null);
first = entries.values().stream()
.filter(entry -> !entry.isLaunched())
.findFirst()
.orElse(null);
if (first == null) {
throw new BeaconClientException("Unknown launch request");
}
@ -116,7 +119,10 @@ public class TerminalLauncherManager {
public static Path performLaunch(UUID request) throws BeaconClientException {
synchronized (entries) {
var e = entries.values().stream().filter(entry -> entry.getRequest().equals(request)).findFirst().orElse(null);
var e = entries.values().stream()
.filter(entry -> entry.getRequest().equals(request))
.findFirst()
.orElse(null);
if (e == null) {
throw new BeaconClientException("Unknown launch request " + request);
}

View file

@ -1,4 +1,3 @@
import com.fasterxml.jackson.databind.Module;
import io.xpipe.app.beacon.impl.*;
import io.xpipe.app.browser.action.BrowserAction;
import io.xpipe.app.core.AppLogs;
@ -13,6 +12,8 @@ import io.xpipe.beacon.BeaconInterface;
import io.xpipe.core.util.DataStateProvider;
import io.xpipe.core.util.ModuleLayerLoader;
import io.xpipe.core.util.ProxyFunction;
import com.fasterxml.jackson.databind.Module;
import org.slf4j.spi.SLF4JServiceProvider;
open module io.xpipe.app {

View file

@ -21,8 +21,12 @@
-fx-text-fill: #ee4829;
}
.store-entry-grid:incomplete .name {
-fx-text-fill: #ee4829;
.root:dark .store-entry-grid:incomplete .name {
-fx-text-fill: #b2271a;
}
.root:light .store-entry-grid:incomplete .name {
-fx-text-fill: #981400;
}
.store-entry-grid:incomplete .icon {

View file

@ -21,6 +21,8 @@ public class ShellEnvironmentStoreState extends ShellStoreState {
var n = (ShellEnvironmentStoreState) newer;
var b = toBuilder();
mergeBuilder(n, b);
return b.shellName(useNewer(shellName, n.shellName)).setDefault(useNewer(setDefault,n.setDefault)).build();
return b.shellName(useNewer(shellName, n.shellName))
.setDefault(useNewer(setDefault, n.setDefault))
.build();
}
}

View file

@ -56,7 +56,7 @@ public interface FileSystem extends Closeable, AutoCloseable {
try {
var list = new ArrayList<FileEntry>();
list.add(fileEntry);
list.addAll(listFilesRecursively(fileEntry.getPath().toString()));
list.addAll(listFilesRecursively(fileEntry.getPath()));
return list.stream();
} catch (Exception e) {
throw new RuntimeException(e);

View file

@ -1,6 +1,7 @@
package io.xpipe.core.store;
import io.xpipe.core.process.ShellControl;
import lombok.Value;
@Value
@ -17,6 +18,7 @@ public class ShellValidationContext implements ValidationContext<ShellControl> {
public void close() {
try {
shellControl.close();
} catch (Exception ignored) {}
} catch (Exception ignored) {
}
}
}

View file

@ -1,13 +1,5 @@
package io.xpipe.core.util;
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.jsontype.NamedType;
import com.fasterxml.jackson.databind.module.SimpleModule;
import io.xpipe.core.dialog.BaseQueryElement;
import io.xpipe.core.dialog.BusyElement;
import io.xpipe.core.dialog.ChoiceElement;
@ -18,6 +10,15 @@ import io.xpipe.core.process.ShellDialects;
import io.xpipe.core.store.FilePath;
import io.xpipe.core.store.StorePath;
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.jsontype.NamedType;
import com.fasterxml.jackson.databind.module.SimpleModule;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Path;

View file

@ -55,7 +55,8 @@ public class BrowseStoreAction implements ActionProvider {
@Override
public void execute() {
DataStoreEntryRef<FileSystemStore> replacement = ProcessControlProvider.get().replace(entry.ref());
DataStoreEntryRef<FileSystemStore> replacement =
ProcessControlProvider.get().replace(entry.ref());
BrowserSessionModel.DEFAULT.openFileSystemAsync(replacement, null, new SimpleBooleanProperty());
AppLayoutModel.get().selectBrowser();
}

View file

@ -6,8 +6,10 @@ import io.xpipe.app.ext.ActionProvider;
import io.xpipe.app.storage.DataStoreEntry;
import io.xpipe.app.storage.DataStoreEntryRef;
import io.xpipe.core.store.DataStore;
import javafx.application.Platform;
import javafx.beans.value.ObservableValue;
import lombok.Value;
public class ChangeStoreIconAction implements ActionProvider {

View file

@ -6,7 +6,9 @@ import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.storage.DataStoreEntry;
import io.xpipe.app.storage.DataStoreEntryRef;
import io.xpipe.core.store.DataStore;
import javafx.beans.value.ObservableValue;
import lombok.Value;
import java.time.Duration;

View file

@ -2,13 +2,13 @@ package io.xpipe.ext.base.action;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.ext.ActionProvider;
import io.xpipe.app.ext.LocalStore;
import io.xpipe.app.storage.DataStoreEntry;
import io.xpipe.app.storage.DataStoreEntryRef;
import io.xpipe.core.process.CommandControl;
import io.xpipe.core.process.ElevationFunction;
import io.xpipe.core.process.ShellControl;
import io.xpipe.core.process.ShellDialects;
import io.xpipe.app.ext.LocalStore;
import io.xpipe.core.store.ShellStore;
import javafx.beans.value.ObservableValue;

View file

@ -10,8 +10,8 @@ import io.xpipe.core.process.OsType;
import io.xpipe.core.process.ShellControl;
import io.xpipe.core.store.FileKind;
import io.xpipe.core.store.FileNames;
import io.xpipe.core.store.FilePath;
import javafx.beans.value.ObservableValue;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
@ -59,7 +59,13 @@ public class OpenNativeFileDetailsAction implements LeafAction {
}
var file = new FilePath(e);
sc.command(CommandBuilder.of().add("xdg-open").addFile(entry.getRawFileEntry().getKind() == FileKind.DIRECTORY ? file : file.getParent())).execute();
sc.command(CommandBuilder.of()
.add("xdg-open")
.addFile(
entry.getRawFileEntry().getKind() == FileKind.DIRECTORY
? file
: file.getParent()))
.execute();
}
case OsType.MacOs macOs -> {
sc.osascriptCommand(String.format(

View file

@ -4,6 +4,7 @@ import io.xpipe.app.ext.ActionProvider;
import io.xpipe.app.storage.DataStoreEntryRef;
import io.xpipe.app.util.FileOpener;
import io.xpipe.core.process.OsType;
import lombok.Value;
public class SimpleScriptQuickEditAction implements ActionProvider {
@ -33,13 +34,9 @@ public class SimpleScriptQuickEditAction implements ActionProvider {
var dialect = script.getMinimumDialect();
var ext = dialect.getScriptFileEnding();
var name = OsType.getLocal().makeFileSystemCompatible(ref.get().getName());
FileOpener.openString(
name + "." + ext,
this,
script.getCommands(),
(s) -> {
ref.get().setStoreInternal(script.toBuilder().commands(s).build(), true);
});
FileOpener.openString(name + "." + ext, this, script.getCommands(), (s) -> {
ref.get().setStoreInternal(script.toBuilder().commands(s).build(), true);
});
}
}
}

View file

@ -8,6 +8,7 @@ import io.xpipe.app.storage.DataStoreEntry;
import io.xpipe.app.util.OptionsBuilder;
import io.xpipe.core.store.DataStore;
import io.xpipe.core.store.NetworkTunnelStore;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleObjectProperty;

View file

@ -18,6 +18,7 @@ import io.xpipe.app.util.TerminalLauncher;
import io.xpipe.core.process.ShellStoreState;
import io.xpipe.core.store.ShellStore;
import io.xpipe.ext.base.script.ScriptStore;
import javafx.beans.property.BooleanProperty;
import javafx.beans.value.ObservableValue;
@ -32,7 +33,8 @@ public interface ShellStoreProvider extends DataStoreProvider {
ShellStore store = replacement.getStore().asNeeded();
var control = ScriptStore.controlWithDefaultScripts(store.control());
control.onInit(sc -> {
if (entry.getStorePersistentState() instanceof ShellStoreState shellStoreState && shellStoreState.getShellDialect() == null) {
if (entry.getStorePersistentState() instanceof ShellStoreState shellStoreState
&& shellStoreState.getShellDialect() == null) {
var found = SystemIcons.detectForSystem(sc);
if (found.isPresent()) {
entry.setIcon(found.get().getIconName(), false);
@ -42,7 +44,8 @@ public interface ShellStoreProvider extends DataStoreProvider {
TerminalLauncher.open(
replacement.get(),
DataStorage.get().getStoreEntryDisplayName(replacement.get()),
null, control);
null,
control);
}
};
}