mirror of
https://github.com/xpipe-io/xpipe.git
synced 2026-04-23 16:09:20 -04:00
Rework
This commit is contained in:
@@ -92,11 +92,6 @@ public interface BrowserAction {
|
||||
.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requiresFullDaemon() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean prioritizeLoading() {
|
||||
return false;
|
||||
|
||||
@@ -95,7 +95,7 @@ public abstract class StoreEntryComp extends SimpleComp {
|
||||
wrapper.executeDefaultAction();
|
||||
});
|
||||
});
|
||||
new ContextMenuAugment<>(mouseEvent -> mouseEvent.isSecondaryButtonDown(), null, () -> this.createContextMenu()).augment(new SimpleCompStructure<>(button));
|
||||
new ContextMenuAugment<>(mouseEvent -> mouseEvent.getButton() == MouseButton.SECONDARY, null, () -> this.createContextMenu()).augment(button);
|
||||
|
||||
var loading = LoadingOverlayComp.noProgress(
|
||||
Comp.of(() -> button),
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
package io.xpipe.app.core;
|
||||
|
||||
import com.fasterxml.jackson.databind.jsontype.NamedType;
|
||||
import io.xpipe.app.exchange.MessageExchangeImpls;
|
||||
import io.xpipe.app.ext.DataStoreProvider;
|
||||
import io.xpipe.app.ext.DataStoreProviders;
|
||||
import io.xpipe.app.ext.ExtensionException;
|
||||
import io.xpipe.app.ext.XPipeServiceProviders;
|
||||
import io.xpipe.app.issue.ErrorEvent;
|
||||
import io.xpipe.app.issue.TrackEvent;
|
||||
import io.xpipe.core.process.ProcessControlProvider;
|
||||
import io.xpipe.core.util.JacksonMapper;
|
||||
import io.xpipe.core.util.ModuleHelper;
|
||||
import io.xpipe.core.util.ModuleLayerLoader;
|
||||
import io.xpipe.core.util.XPipeInstallation;
|
||||
import lombok.Getter;
|
||||
import lombok.Value;
|
||||
@@ -47,9 +52,24 @@ public class AppExtensionManager {
|
||||
}
|
||||
|
||||
if (load) {
|
||||
// INSTANCE.addNativeLibrariesToPath();
|
||||
try {
|
||||
XPipeServiceProviders.load(INSTANCE.extendedLayer);
|
||||
ModuleLayerLoader.loadAll(INSTANCE.extendedLayer, true, t -> {
|
||||
ErrorEvent.fromThrowable(t).handle();
|
||||
});
|
||||
ProcessControlProvider.init(INSTANCE.extendedLayer);
|
||||
TrackEvent.info("Loading extension providers ...");
|
||||
DataStoreProviders.init(INSTANCE.extendedLayer);
|
||||
for (DataStoreProvider p : DataStoreProviders.getAll()) {
|
||||
TrackEvent.trace("Loaded data store provider " + p.getId());
|
||||
JacksonMapper.configure(objectMapper -> {
|
||||
for (Class<?> storeClass : p.getStoreClasses()) {
|
||||
objectMapper.registerSubtypes(new NamedType(storeClass));
|
||||
}
|
||||
});
|
||||
}
|
||||
ModuleLayerLoader.loadAll(INSTANCE.extendedLayer, false, t -> {
|
||||
ErrorEvent.fromThrowable(t).handle();
|
||||
});
|
||||
MessageExchangeImpls.loadAll();
|
||||
} catch (Throwable t) {
|
||||
throw new ExtensionException(
|
||||
|
||||
@@ -144,11 +144,6 @@ public interface ActionProvider {
|
||||
.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requiresFullDaemon() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean prioritizeLoading() {
|
||||
return false;
|
||||
|
||||
@@ -30,20 +30,15 @@ public interface PrefsChoiceValue extends Translatable {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static <T> List<T> getSupported(Class<T> type) {
|
||||
try {
|
||||
return (List<T>) type.getDeclaredField("SUPPORTED").get(null);
|
||||
} catch (IllegalAccessException | NoSuchFieldException e) {
|
||||
var all = getAll(type);
|
||||
if (all == null) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
return all.stream()
|
||||
.filter(t -> ((PrefsChoiceValue) t).isSelectable())
|
||||
.toList();
|
||||
var all = getAll(type);
|
||||
if (all == null) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
return all.stream()
|
||||
.filter(t -> ((PrefsChoiceValue) t).isSelectable())
|
||||
.toList();
|
||||
}
|
||||
|
||||
default boolean isAvailable() {
|
||||
|
||||
@@ -35,11 +35,6 @@ public abstract class PrefsProvider {
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requiresFullDaemon() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean prioritizeLoading() {
|
||||
return false;
|
||||
|
||||
@@ -63,11 +63,6 @@ public abstract class ScanProvider {
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requiresFullDaemon() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean prioritizeLoading() {
|
||||
return false;
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
package io.xpipe.app.ext;
|
||||
|
||||
import com.fasterxml.jackson.databind.jsontype.NamedType;
|
||||
import io.xpipe.app.issue.ErrorEvent;
|
||||
import io.xpipe.app.issue.TrackEvent;
|
||||
import io.xpipe.core.process.ProcessControlProvider;
|
||||
import io.xpipe.core.util.JacksonMapper;
|
||||
import io.xpipe.core.util.ModuleLayerLoader;
|
||||
|
||||
public class XPipeServiceProviders {
|
||||
|
||||
public static void load(ModuleLayer layer) {
|
||||
var hasDaemon = true;
|
||||
ModuleLayerLoader.loadAll(layer, hasDaemon, true, t -> {
|
||||
ErrorEvent.fromThrowable(t).handle();
|
||||
});
|
||||
ProcessControlProvider.init(layer);
|
||||
|
||||
TrackEvent.info("Loading extension providers ...");
|
||||
DataStoreProviders.init(layer);
|
||||
for (DataStoreProvider p : DataStoreProviders.getAll()) {
|
||||
TrackEvent.trace("Loaded data store provider " + p.getId());
|
||||
JacksonMapper.configure(objectMapper -> {
|
||||
for (Class<?> storeClass : p.getStoreClasses()) {
|
||||
objectMapper.registerSubtypes(new NamedType(storeClass));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ModuleLayerLoader.loadAll(layer, hasDaemon, false, t -> {
|
||||
ErrorEvent.fromThrowable(t).handle();
|
||||
});
|
||||
|
||||
TrackEvent.info("Finished loading extension providers");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package io.xpipe.app.fxcomps.impl;
|
||||
|
||||
import io.xpipe.app.fxcomps.SimpleComp;
|
||||
import io.xpipe.app.storage.DataStoreEntryRef;
|
||||
import io.xpipe.app.util.StringSource;
|
||||
import io.xpipe.core.store.ShellStore;
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TabPane;
|
||||
import javafx.scene.layout.Region;
|
||||
|
||||
public class StringSourceComp extends SimpleComp {
|
||||
|
||||
private final Property<DataStoreEntryRef<? extends ShellStore>> fileSystem;
|
||||
private final Property<StringSource> stringSource;
|
||||
|
||||
public <T extends ShellStore> StringSourceComp(ObservableValue<DataStoreEntryRef<T>> fileSystem, Property<StringSource> stringSource) {
|
||||
this.stringSource = stringSource;
|
||||
this.fileSystem = new SimpleObjectProperty<>();
|
||||
fileSystem.subscribe(val -> {
|
||||
this.fileSystem.setValue(val);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Region createSimple() {
|
||||
var tab = new TabPane();
|
||||
|
||||
var inPlace = new SimpleObjectProperty<>(stringSource.getValue() instanceof StringSource.InPlace i ? i.get() : null);
|
||||
var stringField = new TextAreaComp(inPlace);
|
||||
tab.getTabs().add(new Tab());
|
||||
|
||||
var fs = stringSource.getValue() instanceof StringSource.File f ? f.getFile() : null;
|
||||
var file = new SimpleObjectProperty<>(stringSource.getValue() instanceof StringSource.File f ? f.getFile() : null);
|
||||
// new ContextualFileReferenceChoiceComp(fileSystem, file);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,9 @@ public class TextFieldComp extends Comp<CompStructure<TextField>> {
|
||||
value.setValue(val);
|
||||
});
|
||||
}
|
||||
lastAppliedValue.addListener((c, o, n) -> {
|
||||
currentValue.setValue(n);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -39,7 +42,6 @@ public class TextFieldComp extends Comp<CompStructure<TextField>> {
|
||||
currentValue.setValue(n != null && n.length() > 0 ? n : null);
|
||||
});
|
||||
lastAppliedValue.addListener((c, o, n) -> {
|
||||
currentValue.setValue(n);
|
||||
PlatformThread.runLaterIfNeeded(() -> {
|
||||
// Check if control value is the same. Then don't set it as that might cause bugs
|
||||
if (Objects.equals(text.getText(), n)
|
||||
|
||||
@@ -144,6 +144,7 @@ public class AppPrefs {
|
||||
new RdpCategory(),
|
||||
new SyncCategory(),
|
||||
new VaultCategory(),
|
||||
new SshCategory(),
|
||||
new LocalShellCategory(),
|
||||
new SecurityCategory(),
|
||||
new PasswordManagerCategory(),
|
||||
|
||||
@@ -2,8 +2,6 @@ package io.xpipe.app.prefs;
|
||||
|
||||
import io.xpipe.app.fxcomps.Comp;
|
||||
import io.xpipe.app.util.OptionsBuilder;
|
||||
import io.xpipe.core.process.OsType;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
|
||||
public class LocalShellCategory extends AppPrefsCategory {
|
||||
|
||||
@@ -18,9 +16,6 @@ public class LocalShellCategory extends AppPrefsCategory {
|
||||
return new OptionsBuilder()
|
||||
.addTitle("localShell")
|
||||
.sub(new OptionsBuilder()
|
||||
.nameAndDescription("useBundledTools")
|
||||
.addToggle(prefs.useBundledTools)
|
||||
.hide(new SimpleBooleanProperty(!OsType.getLocal().equals(OsType.WINDOWS)))
|
||||
.nameAndDescription("useLocalFallbackShell")
|
||||
.addToggle(prefs.useLocalFallbackShell))
|
||||
.buildComp();
|
||||
|
||||
28
app/src/main/java/io/xpipe/app/prefs/SshCategory.java
Normal file
28
app/src/main/java/io/xpipe/app/prefs/SshCategory.java
Normal file
@@ -0,0 +1,28 @@
|
||||
package io.xpipe.app.prefs;
|
||||
|
||||
import io.xpipe.app.fxcomps.Comp;
|
||||
import io.xpipe.app.util.OptionsBuilder;
|
||||
import io.xpipe.core.process.OsType;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
|
||||
public class SshCategory extends AppPrefsCategory {
|
||||
|
||||
@Override
|
||||
protected String getId() {
|
||||
return "ssh";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Comp<?> create() {
|
||||
var prefs = AppPrefs.get();
|
||||
return new OptionsBuilder()
|
||||
.addTitle("sshConfiguration")
|
||||
.sub(new OptionsBuilder()
|
||||
.nameAndDescription("useBundledTools")
|
||||
.addToggle(prefs.useBundledTools)
|
||||
.hide(new SimpleBooleanProperty(!OsType.getLocal().equals(OsType.WINDOWS)))
|
||||
.addComp(prefs.getCustomComp("x11WslInstance"))
|
||||
.hide(new SimpleBooleanProperty(!OsType.getLocal().equals(OsType.WINDOWS))))
|
||||
.buildComp();
|
||||
}
|
||||
}
|
||||
@@ -42,11 +42,6 @@ public abstract class LicenseProvider {
|
||||
.orElseThrow(() -> ExtensionException.corrupt("Missing license provider"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requiresFullDaemon() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean prioritizeLoading() {
|
||||
return true;
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
package io.xpipe.app.util;
|
||||
|
||||
import io.xpipe.app.core.check.AppSystemFontCheck;
|
||||
import io.xpipe.app.fxcomps.util.PlatformThread;
|
||||
import io.xpipe.app.issue.TrackEvent;
|
||||
import io.xpipe.app.prefs.AppPrefs;
|
||||
import io.xpipe.core.process.OsType;
|
||||
import javafx.application.Platform;
|
||||
import javafx.scene.input.Clipboard;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.datatransfer.StringSelection;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
@@ -28,15 +25,16 @@ public enum PlatformState {
|
||||
private static Exception lastError;
|
||||
|
||||
public static void teardown() {
|
||||
PlatformThread.runLaterIfNeededBlocking(() -> {
|
||||
try {
|
||||
// Fix to preserve clipboard contents after shutdown
|
||||
var string = Clipboard.getSystemClipboard().getString();
|
||||
var s = new StringSelection(string);
|
||||
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(s, s);
|
||||
} catch (IllegalStateException ignored) {
|
||||
}
|
||||
});
|
||||
// This is bad and can get sometimes stuck
|
||||
// PlatformThread.runLaterIfNeededBlocking(() -> {
|
||||
// try {
|
||||
// // Fix to preserve clipboard contents after shutdown
|
||||
// var string = Clipboard.getSystemClipboard().getString();
|
||||
// var s = new StringSelection(string);
|
||||
// Toolkit.getDefaultToolkit().getSystemClipboard().setContents(s, s);
|
||||
// } catch (IllegalStateException ignored) {
|
||||
// }
|
||||
// });
|
||||
|
||||
Platform.exit();
|
||||
setCurrent(PlatformState.EXITED);
|
||||
|
||||
51
app/src/main/java/io/xpipe/app/util/StringSource.java
Normal file
51
app/src/main/java/io/xpipe/app/util/StringSource.java
Normal file
@@ -0,0 +1,51 @@
|
||||
package io.xpipe.app.util;
|
||||
|
||||
import io.xpipe.app.issue.ErrorEvent;
|
||||
import io.xpipe.app.storage.ContextualFileReference;
|
||||
import io.xpipe.core.store.ShellStore;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Value;
|
||||
|
||||
public abstract class StringSource {
|
||||
|
||||
public abstract String get() throws Exception;
|
||||
|
||||
@Value
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public static class InPlace extends StringSource {
|
||||
|
||||
String value;
|
||||
|
||||
@Override
|
||||
public String get() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
@Value
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public static class File extends StringSource {
|
||||
|
||||
ShellStore host;
|
||||
ContextualFileReference file;
|
||||
|
||||
@Override
|
||||
public String get() throws Exception {
|
||||
if (host == null || file == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
try (var sc = host.control().start()) {
|
||||
var path = file.toAbsoluteFilePath(sc);
|
||||
if (!sc.getShellDialect().createFileExistsCommand(sc, path).executeAndCheck()) {
|
||||
throw ErrorEvent.expected(
|
||||
new IllegalArgumentException("File " + path + " does not exist"));
|
||||
}
|
||||
|
||||
var abs = file.toAbsoluteFilePath(sc);
|
||||
var content = sc.getShellDialect().getFileReadCommand(sc, abs).readStdoutOrThrow();
|
||||
return content;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,11 +79,6 @@ public class ShellDialects {
|
||||
OVH_BASTION = byId("ovhBastion");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requiresFullDaemon() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean prioritizeLoading() {
|
||||
return true;
|
||||
|
||||
@@ -6,14 +6,10 @@ import java.util.function.Consumer;
|
||||
public interface ModuleLayerLoader {
|
||||
|
||||
static void loadAll(
|
||||
ModuleLayer layer, boolean hasDaemon, boolean prioritization, Consumer<Throwable> errorHandler) {
|
||||
ModuleLayer layer, boolean prioritization, Consumer<Throwable> errorHandler) {
|
||||
ServiceLoader.load(layer, ModuleLayerLoader.class).stream().forEach(moduleLayerLoaderProvider -> {
|
||||
var instance = moduleLayerLoaderProvider.get();
|
||||
try {
|
||||
if (instance.requiresFullDaemon() && !hasDaemon) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (instance.prioritizeLoading() != prioritization) {
|
||||
return;
|
||||
}
|
||||
@@ -27,7 +23,5 @@ public interface ModuleLayerLoader {
|
||||
|
||||
void init(ModuleLayer layer);
|
||||
|
||||
boolean requiresFullDaemon();
|
||||
|
||||
boolean prioritizeLoading();
|
||||
}
|
||||
|
||||
@@ -428,3 +428,5 @@ goodMorning=Good morning
|
||||
goodAfternoon=Good afternoon
|
||||
goodNight=Good night
|
||||
addVisual=Visual ...
|
||||
ssh=SSH
|
||||
sshConfiguration=SSH Configuration
|
||||
|
||||
@@ -287,3 +287,5 @@ vncUsername=Username
|
||||
vncUsernameDescription=The optional VNC username
|
||||
vncPassword=Password
|
||||
vncPasswordDescription=The VNC password
|
||||
x11WslInstance=X11 Forward WSL instance
|
||||
x11WslInstanceDescription=The local Windows Subsystem for Linux distribution to use as an X11 server when using X11 forwarding in an SSH connection. This distribution must be a WSL2 distribution.\n\nRequires a restart to apply.
|
||||
|
||||
Reference in New Issue
Block a user