mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-21 23:20:23 +00:00
Merge branch serial into master
This commit is contained in:
parent
a26917b500
commit
65b2be5709
122 changed files with 1353 additions and 413 deletions
|
@ -197,6 +197,7 @@ The distributed XPipe application consists out of two parts:
|
|||
- The closed-source extensions, mostly for professional edition features, which are not included in this repository
|
||||
|
||||
Additional features are available in the professional edition. For more details see https://xpipe.io/pricing.
|
||||
If your enterprise puts great emphasis on having access to the full source code, there are also full source-available enterprise options available.
|
||||
|
||||
## More links
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package io.xpipe.app.beacon;
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import com.sun.net.httpserver.HttpServer;
|
||||
import io.xpipe.app.core.AppResources;
|
||||
import io.xpipe.app.issue.ErrorEvent;
|
||||
import io.xpipe.app.issue.TrackEvent;
|
||||
|
@ -8,13 +10,10 @@ import io.xpipe.beacon.BeaconConfig;
|
|||
import io.xpipe.beacon.BeaconInterface;
|
||||
import io.xpipe.core.process.OsType;
|
||||
import io.xpipe.core.util.XPipeInstallation;
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import com.sun.net.httpserver.HttpServer;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
|
@ -127,7 +126,7 @@ public class AppBeaconServer {
|
|||
}
|
||||
|
||||
private void start() throws IOException {
|
||||
server = HttpServer.create(new InetSocketAddress(InetAddress.getLoopbackAddress(), port), 10);
|
||||
server = HttpServer.create(new InetSocketAddress(Inet4Address.getByAddress(new byte[]{ 0x7f,0x00,0x00,0x01 }), port), 10);
|
||||
BeaconInterface.getAll().forEach(beaconInterface -> {
|
||||
server.createContext(beaconInterface.getPath(), new BeaconRequestHandler<>(beaconInterface));
|
||||
});
|
||||
|
|
|
@ -28,7 +28,8 @@ public class BeaconRequestHandler<T> implements HttpHandler {
|
|||
|
||||
@Override
|
||||
public void handle(HttpExchange exchange) {
|
||||
if (OperationMode.isInShutdown()) {
|
||||
if (OperationMode.isInShutdown() && !beaconInterface.acceptInShutdown()) {
|
||||
writeError(exchange, new BeaconClientErrorResponse("Daemon is currently in shutdown"), 400);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ public class BlobManager {
|
|||
|
||||
public Path newBlobFile() throws IOException {
|
||||
var file = TEMP.resolve(UUID.randomUUID().toString());
|
||||
Files.createDirectories(file.getParent());
|
||||
FileUtils.forceMkdir(file.getParent().toFile());
|
||||
return file;
|
||||
}
|
||||
|
||||
|
|
|
@ -190,12 +190,11 @@ public class BrowserTransferModel {
|
|||
}
|
||||
|
||||
public ObservableBooleanValue downloadFinished() {
|
||||
return Bindings.createBooleanBinding(
|
||||
() -> {
|
||||
return progress.getValue() != null
|
||||
&& progress.getValue().done();
|
||||
},
|
||||
progress);
|
||||
synchronized (progress) {
|
||||
return Bindings.createBooleanBinding(() -> {
|
||||
return progress.getValue() != null && progress.getValue().done();
|
||||
}, progress);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,7 +70,9 @@ public class ListBoxViewComp<T> extends Comp<CompStructure<ScrollPane>> {
|
|||
.bind(Bindings.createDoubleBinding(
|
||||
() -> {
|
||||
var v = bar.getVisibleAmount();
|
||||
return v < 1.0 ? 1.0 : 0.0;
|
||||
// Check for rounding and accuracy issues
|
||||
// It might not be exactly equal to 1.0
|
||||
return v < 0.99 ? 1.0 : 0.0;
|
||||
},
|
||||
bar.visibleAmountProperty()));
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import javafx.scene.web.WebEngine;
|
|||
import javafx.scene.web.WebView;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
|
@ -63,7 +64,7 @@ public class MarkdownComp extends Comp<CompStructure<StackPane>> {
|
|||
var html = MarkdownHelper.toHtml(markdown, s -> s, htmlTransformation, null);
|
||||
try {
|
||||
// Workaround for https://bugs.openjdk.org/browse/JDK-8199014
|
||||
Files.createDirectories(file.getParent());
|
||||
FileUtils.forceMkdir(file.getParent().toFile());
|
||||
Files.writeString(file, html);
|
||||
return file;
|
||||
} catch (IOException e) {
|
||||
|
|
|
@ -3,7 +3,6 @@ package io.xpipe.app.comp.store;
|
|||
import io.xpipe.app.fxcomps.Comp;
|
||||
import io.xpipe.app.fxcomps.augment.GrowAugment;
|
||||
import io.xpipe.app.fxcomps.util.PlatformThread;
|
||||
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.geometry.HPos;
|
||||
|
@ -41,9 +40,11 @@ public class DenseStoreEntryComp extends StoreEntryComp {
|
|||
.bind(PlatformThread.sync(Bindings.createStringBinding(
|
||||
() -> {
|
||||
var val = summary.getValue();
|
||||
if (val != null
|
||||
&& grid.isHover()
|
||||
&& getWrapper().getEntry().getProvider().alwaysShowSummary()) {
|
||||
var p = getWrapper().getEntry().getProvider();
|
||||
if (val != null && grid.isHover()
|
||||
&& p.alwaysShowSummary()) {
|
||||
return val;
|
||||
} else if (info.getValue() == null && p.alwaysShowSummary()){
|
||||
return val;
|
||||
} else {
|
||||
return info.getValue();
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
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;
|
||||
|
@ -21,7 +22,6 @@ import io.xpipe.app.storage.DataStoreEntry;
|
|||
import io.xpipe.app.util.*;
|
||||
import io.xpipe.core.store.DataStore;
|
||||
import io.xpipe.core.util.ValidationException;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.*;
|
||||
|
@ -33,8 +33,6 @@ 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;
|
||||
|
@ -51,7 +49,7 @@ public class StoreCreationComp extends DialogComp {
|
|||
Stage window;
|
||||
BiConsumer<DataStoreEntry, Boolean> consumer;
|
||||
Property<DataStoreProvider> provider;
|
||||
Property<DataStore> store;
|
||||
ObjectProperty<DataStore> store;
|
||||
Predicate<DataStoreProvider> filter;
|
||||
BooleanProperty busy = new SimpleBooleanProperty();
|
||||
Property<Validator> validator = new SimpleObjectProperty<>(new SimpleValidator());
|
||||
|
@ -60,6 +58,7 @@ public class StoreCreationComp extends DialogComp {
|
|||
ObservableValue<DataStoreEntry> entry;
|
||||
BooleanProperty changedSinceError = new SimpleBooleanProperty();
|
||||
BooleanProperty skippable = new SimpleBooleanProperty();
|
||||
BooleanProperty connectable = new SimpleBooleanProperty();
|
||||
StringProperty name;
|
||||
DataStoreEntry existingEntry;
|
||||
boolean staticDisplay;
|
||||
|
@ -68,7 +67,7 @@ public class StoreCreationComp extends DialogComp {
|
|||
Stage window,
|
||||
BiConsumer<DataStoreEntry, Boolean> consumer,
|
||||
Property<DataStoreProvider> provider,
|
||||
Property<DataStore> store,
|
||||
ObjectProperty<DataStore> store,
|
||||
Predicate<DataStoreProvider> filter,
|
||||
String initialName,
|
||||
DataStoreEntry existingEntry,
|
||||
|
@ -96,6 +95,12 @@ public class StoreCreationComp extends DialogComp {
|
|||
}
|
||||
});
|
||||
|
||||
this.provider.subscribe((n) -> {
|
||||
if (n != null) {
|
||||
connectable.setValue(n.canConnectDuringCreation());
|
||||
}
|
||||
});
|
||||
|
||||
this.apply(r -> {
|
||||
r.get().setPrefWidth(650);
|
||||
r.get().setPrefHeight(750);
|
||||
|
@ -163,7 +168,12 @@ public class StoreCreationComp extends DialogComp {
|
|||
if (!DataStorage.get().getStoreEntries().contains(e)) {
|
||||
DataStorage.get().addStoreEntryIfNotPresent(newE);
|
||||
} else {
|
||||
DataStorage.get().updateEntry(e, newE);
|
||||
// We didn't change anything
|
||||
if (e.getStore().equals(newE.getStore())) {
|
||||
e.setName(newE.getName());
|
||||
} else {
|
||||
DataStorage.get().updateEntry(e, newE);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
@ -239,7 +249,16 @@ public class StoreCreationComp extends DialogComp {
|
|||
finish();
|
||||
}
|
||||
})
|
||||
.visible(skippable));
|
||||
.visible(skippable),
|
||||
new ButtonComp(AppI18n.observable("connect"), null, () -> {
|
||||
var temp = DataStoreEntry.createTempWrapper(store.getValue());
|
||||
var action = provider.getValue().launchAction(temp);
|
||||
ThreadHelper.runFailableAsync(() -> {
|
||||
action.execute();
|
||||
});
|
||||
}).hide(connectable.not().or(Bindings.createBooleanBinding(() -> {
|
||||
return store.getValue() == null || !store.getValue().isComplete();
|
||||
}, store))));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -393,11 +412,9 @@ public class StoreCreationComp extends DialogComp {
|
|||
private Region createLayout() {
|
||||
var layout = new BorderPane();
|
||||
layout.getStyleClass().add("store-creator");
|
||||
layout.setPadding(new Insets(20));
|
||||
var providerChoice = new StoreProviderChoiceComp(filter, provider, staticDisplay);
|
||||
if (staticDisplay) {
|
||||
providerChoice.apply(struc -> struc.get().setDisable(true));
|
||||
} else {
|
||||
var showProviders = !staticDisplay && providerChoice.getProviders().size() > 1;
|
||||
if (showProviders) {
|
||||
providerChoice.onSceneAssign(struc -> struc.get().requestFocus());
|
||||
}
|
||||
providerChoice.apply(GrowAugment.create(true, false));
|
||||
|
@ -422,9 +439,14 @@ public class StoreCreationComp extends DialogComp {
|
|||
|
||||
var sep = new Separator();
|
||||
sep.getStyleClass().add("spacer");
|
||||
var top = new VBox(providerChoice.createRegion(), new Spacer(7, Orientation.VERTICAL), sep);
|
||||
var top = new VBox(providerChoice.createRegion(), new Spacer(5, Orientation.VERTICAL), sep);
|
||||
top.getStyleClass().add("top");
|
||||
layout.setTop(top);
|
||||
if (showProviders) {
|
||||
layout.setTop(top);
|
||||
layout.setPadding(new Insets(15, 20, 20, 20));
|
||||
} else {
|
||||
layout.setPadding(new Insets(5, 20, 20, 20));
|
||||
}
|
||||
|
||||
var valSp = new GraphicDecorationStackPane();
|
||||
valSp.getChildren().add(layout);
|
||||
|
|
|
@ -42,6 +42,8 @@ public class StoreCreationMenu {
|
|||
|
||||
// menu.getItems().add(category("addCommand", "mdi2c-code-greater-than", DataStoreCreationCategory.COMMAND, "cmd"));
|
||||
|
||||
menu.getItems().add(category("addSerial", "mdi2s-serial-port", DataStoreCreationCategory.SERIAL, "serial"));
|
||||
|
||||
menu.getItems().add(category("addDatabase", "mdi2d-database-plus", DataStoreCreationCategory.DATABASE, null));
|
||||
}
|
||||
|
||||
|
|
|
@ -482,7 +482,7 @@ public abstract class StoreEntryComp extends SimpleComp {
|
|||
sc.textProperty().bind(AppI18n.observable("base.createShortcut"));
|
||||
sc.setOnAction(event -> {
|
||||
ThreadHelper.runFailableAsync(() -> {
|
||||
DesktopShortcuts.create(
|
||||
DesktopShortcuts.createCliOpen(
|
||||
url,
|
||||
DataStorage.get()
|
||||
.getStoreEntryDisplayName(
|
||||
|
|
|
@ -29,7 +29,7 @@ public class StoreProviderChoiceComp extends Comp<CompStructure<ComboBox<DataSto
|
|||
Property<DataStoreProvider> provider;
|
||||
boolean staticDisplay;
|
||||
|
||||
private List<DataStoreProvider> getProviders() {
|
||||
public List<DataStoreProvider> getProviders() {
|
||||
return DataStoreProviders.getAll().stream()
|
||||
.filter(val -> filter == null || filter.test(val))
|
||||
.toList();
|
||||
|
|
|
@ -163,10 +163,10 @@ public class StoreSection {
|
|||
var allChildren = all.filtered(
|
||||
other -> {
|
||||
// Legacy implementation that does not use children caches. Use for testing
|
||||
// if (true) return DataStorage.get()
|
||||
// .getDisplayParent(other.getEntry())
|
||||
// .map(found -> found.equals(e.getEntry()))
|
||||
// .orElse(false);
|
||||
// if (true) return DataStorage.get()
|
||||
// .getDefaultDisplayParent(other.getEntry())
|
||||
// .map(found -> found.equals(e.getEntry()))
|
||||
// .orElse(false);
|
||||
|
||||
// is children. This check is fast as the children are cached in the storage
|
||||
return DataStorage.get().getStoreChildren(e.getEntry()).contains(other.getEntry())
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package io.xpipe.app.core;
|
||||
|
||||
import io.xpipe.app.issue.ErrorEvent;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.channels.FileChannel;
|
||||
|
@ -21,7 +22,7 @@ public class AppDataLock {
|
|||
public static boolean lock() {
|
||||
try {
|
||||
var file = getLockFile().toFile();
|
||||
Files.createDirectories(file.toPath().getParent());
|
||||
FileUtils.forceMkdir(file.getParentFile());
|
||||
if (!Files.exists(file.toPath())) {
|
||||
try {
|
||||
// It is possible that another instance creates the lock at almost the same time
|
||||
|
|
|
@ -55,6 +55,12 @@ public class AppGreetings {
|
|||
if (set || AppProperties.get().isDevelopmentEnvironment()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (AppProperties.get().isAutoAcceptEula()) {
|
||||
AppCache.update("legalAccepted", true);
|
||||
return;
|
||||
}
|
||||
|
||||
var read = new SimpleBooleanProperty();
|
||||
var accepted = new SimpleBooleanProperty();
|
||||
AppWindowHelper.showBlockingAlert(alert -> {
|
||||
|
|
|
@ -138,7 +138,7 @@ public class AppLogs {
|
|||
var shouldLogToFile = shouldWriteLogs();
|
||||
if (shouldLogToFile) {
|
||||
try {
|
||||
Files.createDirectories(usedLogsDir);
|
||||
FileUtils.forceMkdir(usedLogsDir.toFile());
|
||||
var file = usedLogsDir.resolve("xpipe.log");
|
||||
var fos = new FileOutputStream(file.toFile(), true);
|
||||
var buf = new BufferedOutputStream(fos);
|
||||
|
|
|
@ -37,11 +37,13 @@ public class AppProperties {
|
|||
boolean useVirtualThreads;
|
||||
boolean debugThreads;
|
||||
Path dataDir;
|
||||
Path defaultDataDir;
|
||||
boolean showcase;
|
||||
AppVersion canonicalVersion;
|
||||
boolean locatePtb;
|
||||
boolean locatorVersionCheck;
|
||||
boolean isTest;
|
||||
boolean autoAcceptEula;
|
||||
|
||||
public AppProperties() {
|
||||
var appDir = Path.of(System.getProperty("user.dir")).resolve("app");
|
||||
|
@ -86,6 +88,7 @@ public class AppProperties {
|
|||
debugThreads = Optional.ofNullable(System.getProperty("io.xpipe.app.debugThreads"))
|
||||
.map(Boolean::parseBoolean)
|
||||
.orElse(false);
|
||||
defaultDataDir = Path.of(System.getProperty("user.home"), isStaging() ? ".xpipe-ptb" : ".xpipe");
|
||||
dataDir = Optional.ofNullable(System.getProperty("io.xpipe.app.dataDir"))
|
||||
.map(s -> {
|
||||
var p = Path.of(s);
|
||||
|
@ -94,7 +97,7 @@ public class AppProperties {
|
|||
}
|
||||
return p;
|
||||
})
|
||||
.orElse(Path.of(System.getProperty("user.home"), isStaging() ? ".xpipe-ptb" : ".xpipe"));
|
||||
.orElse(defaultDataDir);
|
||||
showcase = Optional.ofNullable(System.getProperty("io.xpipe.app.showcase"))
|
||||
.map(Boolean::parseBoolean)
|
||||
.orElse(false);
|
||||
|
@ -107,6 +110,9 @@ public class AppProperties {
|
|||
.map(s -> !Boolean.parseBoolean(s))
|
||||
.orElse(true);
|
||||
isTest = isJUnitTest();
|
||||
autoAcceptEula = Optional.ofNullable(System.getProperty("io.xpipe.app.acceptEula"))
|
||||
.map(Boolean::parseBoolean)
|
||||
.orElse(false);
|
||||
}
|
||||
|
||||
private static boolean isJUnitTest() {
|
||||
|
|
|
@ -2,6 +2,7 @@ package io.xpipe.app.core.check;
|
|||
|
||||
import io.xpipe.app.core.AppProperties;
|
||||
import io.xpipe.app.issue.ErrorEvent;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
|
@ -12,9 +13,9 @@ public class AppUserDirectoryCheck {
|
|||
var dataDirectory = AppProperties.get().getDataDir();
|
||||
|
||||
try {
|
||||
Files.createDirectories(dataDirectory);
|
||||
FileUtils.forceMkdir(dataDirectory.toFile());
|
||||
var testDirectory = dataDirectory.resolve("permissions_check");
|
||||
Files.createDirectories(testDirectory);
|
||||
FileUtils.forceMkdir(testDirectory.toFile());
|
||||
if (!Files.exists(testDirectory)) {
|
||||
throw new IOException("Directory creation in user home directory failed silently");
|
||||
}
|
||||
|
|
|
@ -9,5 +9,6 @@ public enum DataStoreCreationCategory {
|
|||
TUNNEL,
|
||||
SCRIPT,
|
||||
CLUSTER,
|
||||
DESKTOP
|
||||
DESKTOP,
|
||||
SERIAL
|
||||
}
|
||||
|
|
|
@ -100,6 +100,10 @@ public interface DataStoreProvider {
|
|||
return Comp.empty();
|
||||
}
|
||||
|
||||
default boolean canConnectDuringCreation() {
|
||||
return false;
|
||||
}
|
||||
|
||||
default Comp<?> createInsightsComp(ObservableValue<DataStore> store) {
|
||||
var content = Bindings.createStringBinding(
|
||||
() -> {
|
||||
|
@ -148,6 +152,10 @@ public interface DataStoreProvider {
|
|||
return DataStoreUsageCategory.DATABASE;
|
||||
}
|
||||
|
||||
if (cc == DataStoreCreationCategory.SERIAL) {
|
||||
return DataStoreUsageCategory.SERIAL;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,5 +16,7 @@ public enum DataStoreUsageCategory {
|
|||
@JsonProperty("desktop")
|
||||
DESKTOP,
|
||||
@JsonProperty("group")
|
||||
GROUP;
|
||||
GROUP,
|
||||
@JsonProperty("serial")
|
||||
SERIAL;
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ public interface EnabledStoreProvider extends DataStoreProvider {
|
|||
|
||||
@Override
|
||||
default StoreEntryComp customEntryComp(StoreSection sec, boolean preferLarge) {
|
||||
if (sec.getWrapper().getValidity().getValue() != DataStoreEntry.Validity.COMPLETE) {
|
||||
if (sec.getWrapper().getValidity().getValue() == DataStoreEntry.Validity.LOAD_FAILED) {
|
||||
return StoreEntryComp.create(sec, null, preferLarge);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,10 +2,8 @@ package io.xpipe.app.ext;
|
|||
|
||||
import io.xpipe.app.storage.DataStoreEntry;
|
||||
import io.xpipe.core.process.ShellControl;
|
||||
import io.xpipe.core.store.DataStore;
|
||||
import io.xpipe.core.util.FailableRunnable;
|
||||
import io.xpipe.core.util.ModuleLayerLoader;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Value;
|
||||
|
||||
|
@ -22,10 +20,6 @@ public abstract class ScanProvider {
|
|||
return ALL;
|
||||
}
|
||||
|
||||
public ScanOperation create(DataStore store) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public ScanOperation create(DataStoreEntry entry, ShellControl sc) throws Exception {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package io.xpipe.app.fxcomps.impl;
|
||||
|
||||
import atlantafx.base.theme.Styles;
|
||||
import io.xpipe.app.browser.session.BrowserChooserComp;
|
||||
import io.xpipe.app.comp.base.ButtonComp;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
|
@ -15,39 +16,29 @@ import io.xpipe.app.storage.DataStorage;
|
|||
import io.xpipe.app.storage.DataStoreEntryRef;
|
||||
import io.xpipe.core.store.FileNames;
|
||||
import io.xpipe.core.store.FileSystemStore;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Priority;
|
||||
|
||||
import atlantafx.base.theme.Styles;
|
||||
import org.kordamp.ikonli.javafx.FontIcon;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ContextualFileReferenceChoiceComp extends Comp<CompStructure<HBox>> {
|
||||
|
||||
private final Property<DataStoreEntryRef<? extends FileSystemStore>> fileSystem;
|
||||
private final Property<String> filePath;
|
||||
private final boolean allowSync;
|
||||
|
||||
public <T extends FileSystemStore> ContextualFileReferenceChoiceComp(
|
||||
ObservableValue<DataStoreEntryRef<T>> fileSystem, Property<String> filePath) {
|
||||
this.fileSystem = new SimpleObjectProperty<>();
|
||||
fileSystem.subscribe(val -> {
|
||||
this.fileSystem.setValue(val);
|
||||
});
|
||||
this.filePath = filePath;
|
||||
}
|
||||
|
||||
public <T extends FileSystemStore> ContextualFileReferenceChoiceComp(
|
||||
Property<DataStoreEntryRef<T>> fileSystem, Property<String> filePath) {
|
||||
Property<DataStoreEntryRef<T>> fileSystem, Property<String> filePath, boolean allowSync
|
||||
) {
|
||||
this.allowSync = allowSync;
|
||||
this.fileSystem = new SimpleObjectProperty<>();
|
||||
fileSystem.subscribe(val -> {
|
||||
this.fileSystem.setValue(val);
|
||||
|
@ -79,7 +70,7 @@ public class ContextualFileReferenceChoiceComp extends Comp<CompStructure<HBox>>
|
|||
},
|
||||
false);
|
||||
})
|
||||
.styleClass(Styles.CENTER_PILL)
|
||||
.styleClass(allowSync ? Styles.CENTER_PILL : Styles.RIGHT_PILL)
|
||||
.grow(false, true);
|
||||
|
||||
var gitShareButton = new ButtonComp(null, new FontIcon("mdi2g-git"), () -> {
|
||||
|
@ -126,7 +117,13 @@ public class ContextualFileReferenceChoiceComp extends Comp<CompStructure<HBox>>
|
|||
gitShareButton.tooltipKey("gitShareFileTooltip");
|
||||
gitShareButton.styleClass(Styles.RIGHT_PILL).grow(false, true);
|
||||
|
||||
var layout = new HorizontalComp(List.of(fileNameComp, fileBrowseButton, gitShareButton))
|
||||
var nodes = new ArrayList<Comp<?>>();
|
||||
nodes.add(fileNameComp);
|
||||
nodes.add(fileBrowseButton);
|
||||
if (allowSync) {
|
||||
nodes.add(gitShareButton);
|
||||
}
|
||||
var layout = new HorizontalComp(nodes)
|
||||
.apply(struc -> struc.get().setFillHeight(true));
|
||||
|
||||
layout.apply(struc -> {
|
||||
|
|
|
@ -53,7 +53,7 @@ public class DataStoreListChoiceComp<T extends DataStore> extends SimpleComp {
|
|||
});
|
||||
return new HorizontalComp(List.of(label, Comp.hspacer(), delete)).styleClass("entry");
|
||||
},
|
||||
true)
|
||||
false)
|
||||
.padding(new Insets(0))
|
||||
.apply(struc -> struc.get().setMinHeight(0))
|
||||
.apply(struc -> ((VBox) struc.get().getContent()).setSpacing(5));
|
||||
|
|
|
@ -10,6 +10,9 @@ import io.xpipe.app.fxcomps.util.PlatformThread;
|
|||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.scene.Cursor;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.input.KeyCodeCombination;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
import javafx.scene.input.MouseButton;
|
||||
|
||||
import atlantafx.base.controls.CustomTextField;
|
||||
|
@ -53,6 +56,13 @@ public class FilterComp extends Comp<CompStructure<CustomTextField>> {
|
|||
filter.focusedProperty()));
|
||||
filter.setAccessibleText("Filter");
|
||||
|
||||
filter.addEventFilter(KeyEvent.KEY_PRESSED,event -> {
|
||||
if (new KeyCodeCombination(KeyCode.ESCAPE).match(event)) {
|
||||
filter.getScene().getRoot().requestFocus();
|
||||
event.consume();
|
||||
}
|
||||
});
|
||||
|
||||
filterText.subscribe(val -> {
|
||||
PlatformThread.runLaterIfNeeded(() -> {
|
||||
clear.setVisible(val != null);
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
package io.xpipe.app.fxcomps.impl;
|
||||
|
||||
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 javafx.beans.property.Property;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.scene.control.ComboBox;
|
||||
import javafx.scene.control.skin.ComboBoxListViewSkin;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
|
||||
public class IntComboFieldComp extends Comp<CompStructure<ComboBox<String>>> {
|
||||
|
||||
Property<Integer> value;
|
||||
List<Integer> predefined;
|
||||
boolean allowNegative;
|
||||
|
||||
public IntComboFieldComp(Property<Integer> value, List<Integer> predefined, boolean allowNegative) {
|
||||
this.value = value;
|
||||
this.predefined = predefined;
|
||||
this.allowNegative = allowNegative;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompStructure<ComboBox<String>> createBase() {
|
||||
var text = new ComboBox<String>();
|
||||
text.setEditable(true);
|
||||
text.setValue(value.getValue() != null ? value.getValue().toString() : null);
|
||||
text.setItems(FXCollections.observableList(predefined.stream().map(integer -> "" + integer).toList()));
|
||||
text.setMaxWidth(2000);
|
||||
text.getStyleClass().add("int-combo-field-comp");
|
||||
text.setSkin(new ComboBoxListViewSkin<>(text));
|
||||
text.setVisibleRowCount(Math.min(10, predefined.size()));
|
||||
|
||||
value.addListener((ChangeListener<Number>) (observableValue, oldValue, newValue) -> {
|
||||
PlatformThread.runLaterIfNeeded(() -> {
|
||||
if (newValue == null) {
|
||||
text.setValue("");
|
||||
} else {
|
||||
text.setValue(newValue.toString());
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
text.addEventFilter(KeyEvent.KEY_TYPED, keyEvent -> {
|
||||
if (allowNegative) {
|
||||
if (!"-0123456789".contains(keyEvent.getCharacter())) {
|
||||
keyEvent.consume();
|
||||
}
|
||||
} else {
|
||||
if (!"0123456789".contains(keyEvent.getCharacter())) {
|
||||
keyEvent.consume();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
text.valueProperty().addListener((observableValue, oldValue, newValue) -> {
|
||||
if (newValue == null
|
||||
|| newValue.isEmpty()
|
||||
|| (allowNegative && "-".equals(newValue))
|
||||
|| !newValue.matches("-?\\d+")) {
|
||||
value.setValue(null);
|
||||
return;
|
||||
}
|
||||
|
||||
int intValue = Integer.parseInt(newValue);
|
||||
value.setValue(intValue);
|
||||
});
|
||||
|
||||
return new SimpleCompStructure<>(text);
|
||||
}
|
||||
}
|
|
@ -4,12 +4,10 @@ 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 javafx.beans.property.Property;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
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.SimpleBooleanProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.StackPane;
|
||||
|
||||
public class StringSourceComp extends SimpleComp {
|
||||
|
||||
private final Property<DataStoreEntryRef<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.get().ref());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Region createSimple() {
|
||||
var inPlace =
|
||||
new SimpleObjectProperty<>(stringSource.getValue() instanceof StringSource.InPlace i ? i.get() : null);
|
||||
var fs = stringSource.getValue() instanceof StringSource.File f ? f.getFile() : null;
|
||||
var file = new SimpleObjectProperty<>(
|
||||
stringSource.getValue() instanceof StringSource.File f
|
||||
? f.getFile().serialize()
|
||||
: null);
|
||||
var showText = new SimpleBooleanProperty(inPlace.get() != null);
|
||||
|
||||
var stringField = new TextAreaComp(inPlace);
|
||||
stringField.hide(showText.not());
|
||||
var fileComp = new ContextualFileReferenceChoiceComp(fileSystem, file);
|
||||
fileComp.hide(showText);
|
||||
|
||||
var tr = stringField.createRegion();
|
||||
var button = new IconButtonComp("mdi2c-checkbox-marked-outline", () -> {
|
||||
showText.set(!showText.getValue());
|
||||
})
|
||||
.createRegion();
|
||||
AnchorPane.setBottomAnchor(button, 10.0);
|
||||
AnchorPane.setRightAnchor(button, 10.0);
|
||||
var anchorPane = new AnchorPane(tr, button);
|
||||
AnchorPane.setBottomAnchor(tr, 0.0);
|
||||
AnchorPane.setTopAnchor(tr, 0.0);
|
||||
AnchorPane.setLeftAnchor(tr, 0.0);
|
||||
AnchorPane.setRightAnchor(tr, 0.0);
|
||||
|
||||
var fr = fileComp.createRegion();
|
||||
|
||||
return new StackPane(tr, fr);
|
||||
}
|
||||
}
|
|
@ -14,18 +14,16 @@ import io.xpipe.app.terminal.ExternalTerminalType;
|
|||
import io.xpipe.app.util.PasswordLockSecretValue;
|
||||
import io.xpipe.core.util.InPlaceSecretValue;
|
||||
import io.xpipe.core.util.ModuleHelper;
|
||||
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.*;
|
||||
import javafx.beans.value.ObservableBooleanValue;
|
||||
import javafx.beans.value.ObservableDoubleValue;
|
||||
import javafx.beans.value.ObservableStringValue;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Value;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.stream.Stream;
|
||||
|
@ -175,6 +173,7 @@ public class AppPrefs {
|
|||
new SecurityCategory(),
|
||||
new HttpApiCategory(),
|
||||
new WorkflowCategory(),
|
||||
new WorkspacesCategory(),
|
||||
new TroubleshootCategory(),
|
||||
new DeveloperCategory())
|
||||
.filter(appPrefsCategory -> appPrefsCategory.show())
|
||||
|
@ -489,7 +488,7 @@ public class AppPrefs {
|
|||
}
|
||||
|
||||
try {
|
||||
Files.createDirectories(storageDirectory.get());
|
||||
FileUtils.forceMkdir(storageDirectory.getValue().toFile());
|
||||
} catch (Exception e) {
|
||||
ErrorEvent.fromThrowable(e).expected().build().handle();
|
||||
storageDirectory.setValue(DEFAULT_STORAGE_DIR);
|
||||
|
|
|
@ -21,11 +21,7 @@ public class SyncCategory extends AppPrefsCategory {
|
|||
builder.addTitle("sync")
|
||||
.sub(new OptionsBuilder()
|
||||
.name("enableGitStorage")
|
||||
.description(
|
||||
AppProperties.get().isStaging()
|
||||
&& !prefs.developerMode().getValue()
|
||||
? "enableGitStoragePtbDisabled"
|
||||
: "enableGitStorageDescription")
|
||||
.description("enableGitStorageDescription")
|
||||
.addToggle(prefs.enableGitStorage)
|
||||
.disable(AppProperties.get().isStaging()
|
||||
&& !prefs.developerMode().getValue())
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
package io.xpipe.app.prefs;
|
||||
|
||||
import io.xpipe.app.core.AppFont;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.core.AppProperties;
|
||||
import io.xpipe.app.core.mode.OperationMode;
|
||||
import io.xpipe.app.core.window.AppWindowHelper;
|
||||
import io.xpipe.app.issue.ErrorEvent;
|
||||
import io.xpipe.app.util.DesktopHelper;
|
||||
import io.xpipe.app.util.DesktopShortcuts;
|
||||
import io.xpipe.app.util.OptionsBuilder;
|
||||
import io.xpipe.app.util.ThreadHelper;
|
||||
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;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
|
||||
import java.nio.file.Files;
|
||||
|
||||
public class WorkspaceCreationAlert {
|
||||
|
||||
public static void showAsync() {
|
||||
ThreadHelper.runFailableAsync(() -> {
|
||||
show();
|
||||
});
|
||||
}
|
||||
|
||||
private static void show() throws Exception {
|
||||
var name = new SimpleObjectProperty<>("New workspace");
|
||||
var path = new SimpleObjectProperty<>(AppProperties.get().getDataDir());
|
||||
var show = AppWindowHelper.showBlockingAlert(alert -> {
|
||||
alert.setTitle(AppI18n.get("workspaceCreationAlertTitle"));
|
||||
var content = new OptionsBuilder()
|
||||
.nameAndDescription("workspaceName")
|
||||
.addString(name)
|
||||
.nameAndDescription("workspacePath")
|
||||
.addPath(path)
|
||||
.buildComp()
|
||||
.minWidth(500)
|
||||
.padding(new Insets(5, 20, 20, 20))
|
||||
.apply(struc -> AppFont.small(struc.get()))
|
||||
.createRegion();
|
||||
alert.getButtonTypes().add(ButtonType.CANCEL);
|
||||
alert.getButtonTypes().add(ButtonType.OK);
|
||||
alert.getDialogPane().setContent(content);
|
||||
})
|
||||
.map(b -> b.getButtonData().isDefaultButton())
|
||||
.orElse(false);
|
||||
|
||||
if (!show || name.get() == null || path.get() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Files.exists(path.get()) && !FileUtils.isEmptyDirectory(path.get().toFile())) {
|
||||
ErrorEvent.fromMessage("New workspace directory is not empty").expected().handle();
|
||||
return;
|
||||
}
|
||||
|
||||
var shortcutName = (AppProperties.get().isStaging() ? "XPipe PTB" : "XPipe") + " (" + name.get() + ")";
|
||||
var file = switch (OsType.getLocal()) {
|
||||
case OsType.Windows w -> {
|
||||
var exec = XPipeInstallation.getCurrentInstallationBasePath().resolve(XPipeInstallation.getDaemonExecutablePath(w)).toString();
|
||||
yield DesktopShortcuts.create(exec, "-Dio.xpipe.app.dataDir=\"" + path.get().toString() + "\" -Dio.xpipe.app.acceptEula=true", shortcutName);
|
||||
}
|
||||
default -> {
|
||||
var exec = XPipeInstallation.getCurrentInstallationBasePath().resolve(XPipeInstallation.getRelativeCliExecutablePath(OsType.getLocal())).toString();
|
||||
yield DesktopShortcuts.create(exec, "-d \"" + path.get().toString() + "\" --accept-eula", shortcutName);
|
||||
}
|
||||
};
|
||||
DesktopHelper.browseFileInDirectory(file);
|
||||
OperationMode.close();
|
||||
}
|
||||
}
|
26
app/src/main/java/io/xpipe/app/prefs/WorkspacesCategory.java
Normal file
26
app/src/main/java/io/xpipe/app/prefs/WorkspacesCategory.java
Normal file
|
@ -0,0 +1,26 @@
|
|||
package io.xpipe.app.prefs;
|
||||
|
||||
import io.xpipe.app.comp.base.ButtonComp;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.fxcomps.Comp;
|
||||
import io.xpipe.app.util.OptionsBuilder;
|
||||
|
||||
public class WorkspacesCategory extends AppPrefsCategory {
|
||||
|
||||
@Override
|
||||
protected String getId() {
|
||||
return "workspaces";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Comp<?> create() {
|
||||
return new OptionsBuilder()
|
||||
.addTitle("manageWorkspaces")
|
||||
.sub(new OptionsBuilder()
|
||||
.nameAndDescription("workspaceAdd")
|
||||
.addComp(
|
||||
new ButtonComp(AppI18n.observable("addWorkspace"),
|
||||
WorkspaceCreationAlert::showAsync)))
|
||||
.buildComp();
|
||||
}
|
||||
}
|
|
@ -23,7 +23,7 @@ public class ContextualFileReference {
|
|||
|
||||
private static String getDataDir() {
|
||||
if (DataStorage.get() == null) {
|
||||
return lastDataDir != null ? lastDataDir : normalized(AppPrefs.DEFAULT_STORAGE_DIR);
|
||||
return lastDataDir != null ? lastDataDir : normalized(AppPrefs.DEFAULT_STORAGE_DIR.resolve("data"));
|
||||
}
|
||||
|
||||
return lastDataDir = normalized(DataStorage.get().getDataDir());
|
||||
|
|
|
@ -273,6 +273,10 @@ public abstract class DataStorage {
|
|||
}
|
||||
|
||||
public void updateEntry(DataStoreEntry entry, DataStoreEntry newEntry) {
|
||||
var state = entry.getStorePersistentState();
|
||||
var newState = state.mergeCopy(newEntry.getStorePersistentState());
|
||||
newEntry.setStorePersistentState(newState);
|
||||
|
||||
var oldParent = DataStorage.get().getDefaultDisplayParent(entry);
|
||||
var newParent = DataStorage.get().getDefaultDisplayParent(newEntry);
|
||||
var sameParent = Objects.equals(oldParent, newParent);
|
||||
|
|
|
@ -157,7 +157,7 @@ public class DataStoreEntry extends StorageElement {
|
|||
null,
|
||||
uuid,
|
||||
categoryUuid,
|
||||
name,
|
||||
name.trim(),
|
||||
Instant.now(),
|
||||
Instant.now(),
|
||||
storeFromNode,
|
||||
|
@ -194,7 +194,7 @@ public class DataStoreEntry extends StorageElement {
|
|||
var categoryUuid = Optional.ofNullable(json.get("categoryUuid"))
|
||||
.map(jsonNode -> UUID.fromString(jsonNode.textValue()))
|
||||
.orElse(DataStorage.DEFAULT_CATEGORY_UUID);
|
||||
var name = json.required("name").textValue();
|
||||
var name = json.required("name").textValue().trim();
|
||||
|
||||
var persistentState = stateJson.get("persistentState");
|
||||
var lastUsed = Optional.ofNullable(stateJson.get("lastUsed"))
|
||||
|
|
|
@ -437,7 +437,7 @@ public class StandardStorage extends DataStorage {
|
|||
var s = Files.readString(file);
|
||||
vaultKey = new String(Base64.getDecoder().decode(s), StandardCharsets.UTF_8);
|
||||
} else {
|
||||
Files.createDirectories(dir);
|
||||
FileUtils.forceMkdir(dir.toFile());
|
||||
vaultKey = UUID.randomUUID().toString();
|
||||
Files.writeString(file, Base64.getEncoder().encodeToString(vaultKey.getBytes(StandardCharsets.UTF_8)));
|
||||
}
|
||||
|
@ -458,7 +458,7 @@ public class StandardStorage extends DataStorage {
|
|||
Files.writeString(file, s);
|
||||
}
|
||||
} else {
|
||||
Files.createDirectories(dir);
|
||||
FileUtils.forceMkdir(dir.toFile());
|
||||
var s = OsType.getLocal().getName();
|
||||
Files.writeString(file, s);
|
||||
}
|
||||
|
|
|
@ -4,27 +4,31 @@ import io.xpipe.core.process.OsType;
|
|||
import io.xpipe.core.util.XPipeInstallation;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class DesktopShortcuts {
|
||||
|
||||
private static void createWindowsShortcut(String target, String name) throws Exception {
|
||||
private static Path createWindowsShortcut(String executable, String args, String name) throws Exception {
|
||||
var icon = XPipeInstallation.getLocalDefaultInstallationIcon();
|
||||
var shortcutTarget = XPipeInstallation.getLocalDefaultCliExecutable();
|
||||
var shortcutPath = DesktopHelper.getDesktopDirectory().resolve(name + ".lnk");
|
||||
var content = String.format(
|
||||
"""
|
||||
set "TARGET=%s"
|
||||
set "SHORTCUT=%s"
|
||||
set PWS=powershell.exe -ExecutionPolicy Restricted -NoLogo -NonInteractive -NoProfile
|
||||
|
||||
%%PWS%% -Command "$ws = New-Object -ComObject WScript.Shell; $s = $ws.CreateShortcut('%%SHORTCUT%%'); $S.IconLocation='%s'; $S.WindowStyle=7; $S.TargetPath = '%%TARGET%%'; $S.Arguments = 'open %s'; $S.Save()"
|
||||
$TARGET="%s"
|
||||
$SHORTCUT="%s"
|
||||
$ws = New-Object -ComObject WScript.Shell
|
||||
$s = $ws.CreateShortcut("$SHORTCUT")
|
||||
$S.IconLocation='%s'
|
||||
$S.WindowStyle=7
|
||||
$S.TargetPath = "$TARGET"
|
||||
$S.Arguments = '%s'
|
||||
$S.Save()
|
||||
""",
|
||||
shortcutTarget, shortcutPath, icon, target);
|
||||
LocalShell.getShell().executeSimpleCommand(content);
|
||||
executable, shortcutPath, icon, args);
|
||||
LocalShell.getLocalPowershell().executeSimpleCommand(content);
|
||||
return shortcutPath;
|
||||
}
|
||||
|
||||
private static void createLinuxShortcut(String target, String name) throws Exception {
|
||||
var exec = XPipeInstallation.getLocalDefaultCliExecutable();
|
||||
private static Path createLinuxShortcut(String executable, String args, String name) throws Exception {
|
||||
var icon = XPipeInstallation.getLocalDefaultInstallationIcon();
|
||||
var content = String.format(
|
||||
"""
|
||||
|
@ -32,19 +36,19 @@ public class DesktopShortcuts {
|
|||
Type=Application
|
||||
Name=%s
|
||||
Comment=Open with XPipe
|
||||
Exec="%s" open %s
|
||||
Exec="%s" %s
|
||||
Icon=%s
|
||||
Terminal=false
|
||||
Categories=Utility;Development;
|
||||
""",
|
||||
name, exec, target, icon);
|
||||
name, executable, args, icon);
|
||||
var file = DesktopHelper.getDesktopDirectory().resolve(name + ".desktop");
|
||||
Files.writeString(file, content);
|
||||
file.toFile().setExecutable(true);
|
||||
return file;
|
||||
}
|
||||
|
||||
private static void createMacOSShortcut(String target, String name) throws Exception {
|
||||
var exec = XPipeInstallation.getLocalDefaultCliExecutable();
|
||||
private static Path createMacOSShortcut(String executable, String args, String name) throws Exception {
|
||||
var icon = XPipeInstallation.getLocalDefaultInstallationIcon();
|
||||
var base = DesktopHelper.getDesktopDirectory().resolve(name + ".app");
|
||||
var content = String.format(
|
||||
|
@ -52,18 +56,18 @@ public class DesktopShortcuts {
|
|||
#!/usr/bin/env sh
|
||||
"%s" open %s
|
||||
""",
|
||||
exec, target);
|
||||
executable, args);
|
||||
|
||||
try (var pc = LocalShell.getShell()) {
|
||||
pc.getShellDialect().deleteFileOrDirectory(pc, base.toString()).executeAndCheck();
|
||||
pc.executeSimpleCommand(pc.getShellDialect().getMkdirsCommand(base + "/Contents/MacOS"));
|
||||
pc.executeSimpleCommand(pc.getShellDialect().getMkdirsCommand(base + "/Contents/Resources"));
|
||||
|
||||
var executable = base + "/Contents/MacOS/" + name;
|
||||
var macExec = base + "/Contents/MacOS/" + name;
|
||||
pc.getShellDialect()
|
||||
.createScriptTextFileWriteCommand(pc, content, executable)
|
||||
.createScriptTextFileWriteCommand(pc, content, macExec)
|
||||
.execute();
|
||||
pc.executeSimpleCommand("chmod ugo+x \"" + executable + "\"");
|
||||
pc.executeSimpleCommand("chmod ugo+x \"" + macExec + "\"");
|
||||
|
||||
pc.getShellDialect()
|
||||
.createTextFileWriteCommand(pc, "APPL????", base + "/Contents/PkgInfo")
|
||||
|
@ -85,15 +89,21 @@ public class DesktopShortcuts {
|
|||
.execute();
|
||||
pc.executeSimpleCommand("cp \"" + icon + "\" \"" + base + "/Contents/Resources/icon.icns\"");
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
public static void create(String target, String name) throws Exception {
|
||||
public static Path createCliOpen(String action, String name) throws Exception {
|
||||
var exec = XPipeInstallation.getLocalDefaultCliExecutable();
|
||||
return create(exec, "open " + action, name);
|
||||
}
|
||||
|
||||
public static Path create(String executable, String args, String name) throws Exception {
|
||||
if (OsType.getLocal().equals(OsType.WINDOWS)) {
|
||||
createWindowsShortcut(target, name);
|
||||
return createWindowsShortcut(executable, args, name);
|
||||
} else if (OsType.getLocal().equals(OsType.LINUX)) {
|
||||
createLinuxShortcut(target, name);
|
||||
return createLinuxShortcut(executable, args, name);
|
||||
} else {
|
||||
createMacOSShortcut(target, name);
|
||||
return createMacOSShortcut(executable, args, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ public class ScanAlert {
|
|||
});
|
||||
}
|
||||
|
||||
private static void showForShellStore(DataStoreEntry initial) {
|
||||
public static void showForShellStore(DataStoreEntry initial) {
|
||||
show(initial, (DataStoreEntry entry, ShellControl sc) -> {
|
||||
if (!sc.getShellDialect().getDumbMode().supportsAnyPossibleInteraction()) {
|
||||
return null;
|
||||
|
|
|
@ -26,7 +26,7 @@ public class ShellTemp {
|
|||
temp = temp.resolve(user != null ? user : "user");
|
||||
|
||||
try {
|
||||
Files.createDirectories(temp);
|
||||
FileUtils.forceMkdir(temp.toFile());
|
||||
// We did not set this in earlier versions. If we are running as a different user, it might fail
|
||||
Files.setPosixFilePermissions(temp, PosixFilePermissions.fromString("rwxrwxrwx"));
|
||||
} catch (Exception e) {
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,4 +18,4 @@
|
|||
|
||||
.options-comp .long-description {
|
||||
-fx-padding: 0 6 0 6;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,14 +25,6 @@
|
|||
-fx-text-fill: #ee4829;
|
||||
}
|
||||
|
||||
.store-entry-grid:incomplete .summary {
|
||||
-fx-text-fill: #ee4829;
|
||||
}
|
||||
|
||||
.store-entry-grid:incomplete .information {
|
||||
-fx-text-fill: #ee4829;
|
||||
}
|
||||
|
||||
.store-entry-grid:incomplete .icon {
|
||||
-fx-opacity: 0.5;
|
||||
}
|
||||
|
|
|
@ -101,7 +101,7 @@
|
|||
-fx-border-color: -color-neutral-emphasis;
|
||||
}
|
||||
|
||||
.text {
|
||||
* {
|
||||
-fx-font-smoothing-type: gray;
|
||||
}
|
||||
|
||||
|
|
|
@ -64,7 +64,8 @@ public class BeaconClient {
|
|||
var client = HttpClient.newHttpClient();
|
||||
HttpResponse<String> response;
|
||||
try {
|
||||
var uri = URI.create("http://localhost:" + port + prov.getPath());
|
||||
// Use direct IP to prevent DNS lookups and potential blocks (e.g. portmaster)
|
||||
var uri = URI.create("http://127.0.0.1:" + port + prov.getPath());
|
||||
var builder = HttpRequest.newBuilder();
|
||||
if (token != null) {
|
||||
builder.header("Authorization", "Bearer " + token);
|
||||
|
|
|
@ -62,6 +62,10 @@ public abstract class BeaconInterface<T> {
|
|||
return (Class<T>) Class.forName(name);
|
||||
}
|
||||
|
||||
public boolean acceptInShutdown() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean requiresCompletedStartup() {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import io.xpipe.core.util.XPipeInstallation;
|
|||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.util.List;
|
||||
|
@ -20,7 +20,7 @@ public class BeaconServer {
|
|||
|
||||
public static boolean isReachable(int port) {
|
||||
try (var socket = new Socket()) {
|
||||
socket.connect(new InetSocketAddress(InetAddress.getLoopbackAddress(), port), 5000);
|
||||
socket.connect(new InetSocketAddress(Inet4Address.getByAddress(new byte[]{ 0x7f,0x00,0x00,0x01 }), port), 5000);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
|
|
|
@ -12,6 +12,11 @@ import java.util.UUID;
|
|||
|
||||
public class AskpassExchange extends BeaconInterface<AskpassExchange.Request> {
|
||||
|
||||
@Override
|
||||
public boolean acceptInShutdown() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
return "/askpass";
|
||||
|
|
|
@ -11,6 +11,11 @@ import lombok.extern.jackson.Jacksonized;
|
|||
|
||||
public class HandshakeExchange extends BeaconInterface<HandshakeExchange.Request> {
|
||||
|
||||
@Override
|
||||
public boolean acceptInShutdown() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
return "/handshake";
|
||||
|
|
|
@ -255,6 +255,10 @@ public class CommandBuilder {
|
|||
}
|
||||
|
||||
public String buildFull(ShellControl sc) throws Exception {
|
||||
if (sc == null) {
|
||||
return buildSimple();
|
||||
}
|
||||
|
||||
var s = buildBase(sc);
|
||||
LinkedHashMap<String, String> map = new LinkedHashMap<>();
|
||||
for (var e : environmentVariables.entrySet()) {
|
||||
|
|
|
@ -130,7 +130,7 @@ public interface ShellDialect {
|
|||
|
||||
default void prepareCommandForShell(CommandBuilder b) {}
|
||||
|
||||
String prepareTerminalInitFileOpenCommand(ShellDialect parentDialect, ShellControl sc, String file);
|
||||
String prepareTerminalInitFileOpenCommand(ShellDialect parentDialect, ShellControl sc, String file, boolean exit);
|
||||
|
||||
String runScriptCommand(ShellControl parent, String file);
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@ public interface ShellDumbMode {
|
|||
return true;
|
||||
}
|
||||
|
||||
default void throwIfUnsupported() {}
|
||||
|
||||
default ShellDialect getSwitchDialect() {
|
||||
return null;
|
||||
}
|
||||
|
@ -25,6 +27,14 @@ public interface ShellDumbMode {
|
|||
|
||||
class Unsupported implements ShellDumbMode {
|
||||
|
||||
private final String message;
|
||||
|
||||
public Unsupported(String message) {this.message = message;}
|
||||
|
||||
public void throwIfUnsupported() {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsAnyPossibleInteraction() {
|
||||
return false;
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
package io.xpipe.core.store;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import io.xpipe.core.process.CommandBuilder;
|
||||
import io.xpipe.core.process.ShellControl;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
@ -37,9 +36,10 @@ public class ConnectionFileSystem implements FileSystem {
|
|||
@Override
|
||||
public FileSystem open() throws Exception {
|
||||
shellControl.start();
|
||||
if (!shellControl.getShellDialect().getDumbMode().supportsAnyPossibleInteraction()) {
|
||||
var d = shellControl.getShellDialect().getDumbMode();
|
||||
if (!d.supportsAnyPossibleInteraction()) {
|
||||
shellControl.close();
|
||||
throw new UnsupportedOperationException("System shell does not support file system interaction");
|
||||
d.throwIfUnsupported();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,6 @@ public class EnabledStoreState extends DataStoreState {
|
|||
@Override
|
||||
public DataStoreState mergeCopy(DataStoreState newer) {
|
||||
var n = (EnabledStoreState) newer;
|
||||
return EnabledStoreState.builder().enabled(n.enabled).build();
|
||||
return EnabledStoreState.builder().enabled(enabled || n.enabled).build();
|
||||
}
|
||||
}
|
||||
|
|
67
dist/changelogs/10.3.md
vendored
67
dist/changelogs/10.3.md
vendored
|
@ -1,67 +0,0 @@
|
|||
## A new HTTP API
|
||||
|
||||
There is now a new HTTP API for the XPipe daemon, which allows you to programmatically manage remote systems. You can find details and an OpenAPI specification at the new API button in the sidebar. The API page contains everything you need to get started, including code samples for various different programming languages.
|
||||
|
||||
To start off, you can query connections based on various filters. With the matched connections, you can start remote shell sessions for each one and run arbitrary commands in them. You get the command exit code and output as a response, allowing you to adapt your control flow based on command outputs. Any kind of passwords and other secrets are automatically provided by XPipe when establishing a shell connection. You can also access the file systems via these shell connections to read and write remote files.
|
||||
|
||||
There already exists a community made [XPipe API library for python](https://github.com/coandco/python_xpipe_client) and a [python CLI client](https://github.com/coandco/xpipe_cli). These tools allow you to interact with the API more ergonomically and can also serve as an inspiration of what you can do with the new API. If you also built a tool to interact with the XPipe API, you can let me know and I can compile a list of community development projects.
|
||||
|
||||
## Service integration
|
||||
|
||||
Many systems run a variety of different services such as web services and others. There is now support to detect, forward, and open the services. For example, if you are running a web service on a remote container, you can automatically forward the service port via SSH tunnels, allowing you to access these services from your local machine, e.g. in a web browser. These service tunnels can be toggled at any time. The port forwarding supports specifying a custom local target port and also works for connections with multiple intermediate systems through chained tunnels. For containers, services are automatically detected via their exposed mapped ports. For other systems, you can manually add services via their port.
|
||||
|
||||
You can use an unlimited amount of local services and one active tunneled service in the community edition.
|
||||
|
||||
## Script rework
|
||||
|
||||
The scripting system has been reworked. There have been several issues with it being clunky and not fun to use. The new system allows you to assign each script one of multiple execution types. Based on these execution types, you can make scripts active or inactive with a toggle. If they are active, the scripts will apply in the selected use cases. There currently are these types:
|
||||
- Init scripts: When enabled, they will automatically run on init in all compatible shells. This is useful for setting things like aliases consistently
|
||||
- Shell scripts: When enabled, they will be copied over to the target system and put into the PATH. You can then call them in a normal shell session by their name, e.g. `myscript.sh`, also with arguments.
|
||||
- File scripts: When enabled, you can call them in the file browser with the selected files as arguments. Useful to perform common actions with files
|
||||
|
||||
If you have existing scripts, they will have to be manually adjusted by setting their execution types.
|
||||
|
||||
## Docker improvements
|
||||
|
||||
The docker integration has been updated to support docker contexts. You can use the default context in the community edition, essentially being the same as before as XPipe previously only used the default context. Support for using multiple contexts is included in the professional edition.
|
||||
|
||||
There's now support for Windows docker containers running on HyperV.
|
||||
|
||||
Note that old docker container connections will be removed as they are incompatible with the new version.
|
||||
|
||||
## Proxmox improvements
|
||||
|
||||
You can now automatically open the Proxmox dashboard website through the new service integration. This will also work with the service tunneling feature for remote servers.
|
||||
|
||||
You can now open VNC sessions to Proxmox VMs.
|
||||
|
||||
The Proxmox professional license requirement has been reworked to support one non-enterprise PVE node in the community edition.
|
||||
|
||||
## Better connection organization
|
||||
|
||||
The toggle to show only running connections will now no longer actually remove the connections internally and instead just not display them. This will reduce git vault updates and is faster in general.
|
||||
|
||||
You can now order connections relative to other sibling connections. This ordering will also persist when changing the global order in the top left.
|
||||
|
||||
The UI has also been streamlined to make common actions and toggles more easily accessible.
|
||||
|
||||
## Other
|
||||
|
||||
- The title bar on Windows will now follow the appearance theme
|
||||
- Several more actions have been added for podman containers
|
||||
- Support VMs for tunneling
|
||||
- Searching for connections has been improved to show children as well
|
||||
- There is now an AppImage portable release
|
||||
- The welcome screen will now also contain the option to straight up jump to the synchronization settings
|
||||
- You can now launch xpipe in another data directory with `xpipe open -d "<dir>"`
|
||||
- Add option to use double clicks to open connections instead of single clicks
|
||||
- Add support for foot terminal
|
||||
- Fix rare null pointers and freezes in file browser
|
||||
- Fix PowerShell remote session file editing not transferring file correctly
|
||||
- Fix elementary terminal not launching correctly
|
||||
- Fix windows jumping around when created
|
||||
- Fix kubernetes not elevating correctly for non-default contexts
|
||||
- Fix ohmyzsh update notification freezing shell
|
||||
- Fix file browser icons being broken for links
|
||||
- The Linux installers now contain application icons from multiple sizes which should increase the icon display quality
|
||||
- The Linux builds now list socat as a dependency such that the kitty terminal integration will work without issues
|
|
@ -1,3 +1,13 @@
|
|||
## Profiles
|
||||
|
||||
You can now create multiple user profiles in the settings menu.
|
||||
|
||||
This will create desktop shortcuts that you can use to start XPipe with different profiles active.
|
||||
|
||||
## Serial connection support
|
||||
|
||||
There is now support to add serial connections.
|
||||
|
||||
## Scripting improvements
|
||||
|
||||
The scripting system has been reworked in order to make it more intuitive and powerful.
|
||||
|
@ -12,6 +22,13 @@ When multiple files are selected, a script is now called only once with all the
|
|||
|
||||
## Other
|
||||
|
||||
- Rework state information display for proxmox VMs
|
||||
- Fix terminal exit not working properly in fish
|
||||
- Fix renaming a connection clearing all state information
|
||||
- Fix script enabled status being wrong after editing an enabled script
|
||||
- Fix download move operation failing when moving a directory that already existed in the downloads folder
|
||||
- Fix some scrollbars are necessarily showing
|
||||
- Improve error messages when system interaction was disabled for a system
|
||||
- Don't show git all compatibility warnings on minor version updates
|
||||
- Enable ZGC on Linux and macOS
|
||||
- Some small appearance fixes
|
34
dist/changelogs/11.0_incremental.md
vendored
Normal file
34
dist/changelogs/11.0_incremental.md
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
## Profiles
|
||||
|
||||
You can now create multiple user profiles in the settings menu.
|
||||
|
||||
This will create desktop shortcuts that you can use to start XPipe with different profiles active.
|
||||
|
||||
## Serial connection support
|
||||
|
||||
There is now support to add serial connections.
|
||||
|
||||
## Scripting improvements
|
||||
|
||||
The scripting system has been reworked in order to make it more intuitive and powerful.
|
||||
|
||||
The script execution types have been renamed, the documentation has been improved, and a new execution type has been added.
|
||||
The new runnable execution type will allow you to call a script from the connection hub directly in a dropdown for each connection when the script is active.
|
||||
This will also replace the current terminal command functionality, which has been removed.
|
||||
|
||||
Any file browser scripts are now grouped by the scripts groups they are in, improving the overview when having many file browser scripts.
|
||||
Furthermore, you can now launch these scripts in the file browser either in the background if they are quiet or in a terminal if they are intended to be interactive.
|
||||
When multiple files are selected, a script is now called only once with all the selected files as arguments.
|
||||
|
||||
## Other
|
||||
|
||||
- Rework state information display for proxmox VMs
|
||||
- Fix terminal exit not working properly in fish
|
||||
- Fix renaming a connection clearing all state information
|
||||
- Fix script enabled status being wrong after editing an enabled script
|
||||
- Fix download move operation failing when moving a directory that already existed in the downloads folder
|
||||
- Fix some scrollbars are necessarily showing
|
||||
- Improve error messages when system interaction was disabled for a system
|
||||
- Don't show git all compatibility warnings on minor version updates
|
||||
- Enable ZGC on Linux and macOS
|
||||
- Some small appearance fixes
|
|
@ -3,6 +3,7 @@ package io.xpipe.ext.base.action;
|
|||
import io.xpipe.app.comp.store.StoreViewState;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.ext.ActionProvider;
|
||||
import io.xpipe.app.prefs.AppPrefs;
|
||||
import io.xpipe.app.storage.DataStoreEntryRef;
|
||||
import io.xpipe.app.util.TerminalLauncher;
|
||||
import io.xpipe.core.process.ShellStoreState;
|
||||
|
@ -17,7 +18,7 @@ import java.util.List;
|
|||
public class RunScriptActionMenu implements ActionProvider {
|
||||
|
||||
@Value
|
||||
private static class ScriptActionProvider implements ActionProvider {
|
||||
private static class TerminalRunActionProvider implements ActionProvider {
|
||||
|
||||
ScriptHierarchy hierarchy;
|
||||
|
||||
|
@ -41,10 +42,6 @@ public class RunScriptActionMenu implements ActionProvider {
|
|||
|
||||
@Override
|
||||
public LeafDataStoreCallSite<?> getLeafDataStoreCallSite() {
|
||||
if (!hierarchy.isLeaf()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new LeafDataStoreCallSite<ShellStore>() {
|
||||
@Override
|
||||
public Action createAction(DataStoreEntryRef<ShellStore> store) {
|
||||
|
@ -53,12 +50,15 @@ public class RunScriptActionMenu implements ActionProvider {
|
|||
|
||||
@Override
|
||||
public ObservableValue<String> getName(DataStoreEntryRef<ShellStore> store) {
|
||||
return new SimpleStringProperty(hierarchy.getBase().get().getName());
|
||||
var t = AppPrefs.get().terminalType().getValue();
|
||||
return AppI18n.observable(
|
||||
"executeInTerminal",
|
||||
t != null ? t.toTranslatedString().getValue() : "?");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIcon(DataStoreEntryRef<ShellStore> store) {
|
||||
return "mdi2p-play-box-multiple-outline";
|
||||
return "mdi2d-desktop-mac";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -67,10 +67,91 @@ public class RunScriptActionMenu implements ActionProvider {
|
|||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Value
|
||||
private static class BackgroundRunActionProvider implements ActionProvider {
|
||||
|
||||
ScriptHierarchy hierarchy;
|
||||
|
||||
@Value
|
||||
private class Action implements ActionProvider.Action {
|
||||
|
||||
DataStoreEntryRef<ShellStore> shellStore;
|
||||
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
try (var sc = shellStore.getStore().control().start()) {
|
||||
var script = hierarchy.getLeafBase().getStore().assembleScriptChain(sc);
|
||||
sc.command(script).execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public LeafDataStoreCallSite<?> getLeafDataStoreCallSite() {
|
||||
return new LeafDataStoreCallSite<ShellStore>() {
|
||||
@Override
|
||||
public Action createAction(DataStoreEntryRef<ShellStore> store) {
|
||||
return new Action(store);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObservableValue<String> getName(DataStoreEntryRef<ShellStore> store) {
|
||||
return AppI18n.observable("executeInBackground");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIcon(DataStoreEntryRef<ShellStore> store) {
|
||||
return "mdi2f-flip-to-back";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getApplicableClass() {
|
||||
return ShellStore.class;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Value
|
||||
private static class ScriptActionProvider implements ActionProvider {
|
||||
|
||||
ScriptHierarchy hierarchy;
|
||||
|
||||
private BranchDataStoreCallSite<?> getLeafSite() {
|
||||
return new BranchDataStoreCallSite<ShellStore>() {
|
||||
|
||||
@Override
|
||||
public Class<ShellStore> getApplicableClass() {
|
||||
return ShellStore.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObservableValue<String> getName(DataStoreEntryRef<ShellStore> store) {
|
||||
return new SimpleStringProperty(hierarchy.getBase().get().getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDynamicallyGenerated() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIcon(DataStoreEntryRef<ShellStore> store) {
|
||||
return "mdi2p-play-box-multiple-outline";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends ActionProvider> getChildren(DataStoreEntryRef<ShellStore> store) {
|
||||
return List.of(new TerminalRunActionProvider(hierarchy), new BackgroundRunActionProvider(hierarchy));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public BranchDataStoreCallSite<?> getBranchDataStoreCallSite() {
|
||||
if (hierarchy.isLeaf()) {
|
||||
return null;
|
||||
return getLeafSite();
|
||||
}
|
||||
|
||||
return new BranchDataStoreCallSite<ShellStore>() {
|
||||
|
|
|
@ -7,9 +7,7 @@ import io.xpipe.app.storage.DataStoreEntryRef;
|
|||
import io.xpipe.app.util.ScanAlert;
|
||||
import io.xpipe.core.process.ShellStoreState;
|
||||
import io.xpipe.core.store.ShellStore;
|
||||
|
||||
import javafx.beans.value.ObservableValue;
|
||||
|
||||
import lombok.Value;
|
||||
|
||||
public class ScanStoreAction implements ActionProvider {
|
||||
|
@ -67,7 +65,9 @@ public class ScanStoreAction implements ActionProvider {
|
|||
|
||||
@Override
|
||||
public void execute() {
|
||||
ScanAlert.showAsync(entry);
|
||||
if (entry == null || entry.getStore() instanceof ShellStore) {
|
||||
ScanAlert.showForShellStore(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -97,7 +97,7 @@ public class DesktopEnvironmentStore extends JacksonizedValue
|
|||
var scriptFile = base.getStore().createScript(dialect, toExecute);
|
||||
var launchScriptFile = base.getStore()
|
||||
.createScript(
|
||||
dialect, dialect.prepareTerminalInitFileOpenCommand(dialect, null, scriptFile.toString()));
|
||||
dialect, dialect.prepareTerminalInitFileOpenCommand(dialect, null, scriptFile.toString(), false));
|
||||
var launchConfig = new ExternalTerminalType.LaunchConfiguration(null, name, name, launchScriptFile, dialect);
|
||||
base.getStore().runDesktopScript(name, launchCommand.apply(launchConfig));
|
||||
}
|
||||
|
|
|
@ -488,3 +488,15 @@ closeOtherTabs=Luk andre faner
|
|||
closeAllTabs=Luk alle faner
|
||||
closeLeftTabs=Luk faner til venstre
|
||||
closeRightTabs=Luk faner til højre
|
||||
addSerial=Seriel ...
|
||||
connect=Forbind
|
||||
workspaces=Arbejdsområder
|
||||
manageWorkspaces=Administrer arbejdsområder
|
||||
addWorkspace=Tilføj arbejdsområde ...
|
||||
workspaceAdd=Tilføj et nyt arbejdsområde
|
||||
workspaceAddDescription=Arbejdsområder er forskellige konfigurationer til at køre XPipe. Hvert arbejdsområde har et datakatalog, hvor alle data gemmes lokalt. Det omfatter forbindelsesdata, indstillinger og meget mere.\n\nHvis du bruger synkroniseringsfunktionen, kan du også vælge at synkronisere hvert arbejdsområde med et forskelligt git-repository.
|
||||
workspaceName=Navn på arbejdsområde
|
||||
workspaceNameDescription=Visningsnavnet på arbejdsområdet
|
||||
workspacePath=Sti til arbejdsområde
|
||||
workspacePathDescription=Placeringen af arbejdsområdets datakatalog
|
||||
workspaceCreationAlertTitle=Oprettelse af arbejdsområde
|
||||
|
|
|
@ -482,3 +482,15 @@ closeOtherTabs=Andere Tabs schließen
|
|||
closeAllTabs=Alle Registerkarten schließen
|
||||
closeLeftTabs=Tabs nach links schließen
|
||||
closeRightTabs=Tabs nach rechts schließen
|
||||
addSerial=Serielle ...
|
||||
connect=Verbinden
|
||||
workspaces=Arbeitsbereiche
|
||||
manageWorkspaces=Arbeitsbereiche verwalten
|
||||
addWorkspace=Arbeitsbereich hinzufügen ...
|
||||
workspaceAdd=Einen neuen Arbeitsbereich hinzufügen
|
||||
workspaceAddDescription=Arbeitsbereiche sind unterschiedliche Konfigurationen für die Ausführung von XPipe. Jeder Arbeitsbereich hat ein Datenverzeichnis, in dem alle Daten lokal gespeichert werden. Dazu gehören Verbindungsdaten, Einstellungen und mehr.\n\nWenn du die Synchronisierungsfunktion verwendest, kannst du auch wählen, ob du jeden Arbeitsbereich mit einem anderen Git-Repository synchronisieren möchtest.
|
||||
workspaceName=Name des Arbeitsbereichs
|
||||
workspaceNameDescription=Der Anzeigename des Arbeitsbereichs
|
||||
workspacePath=Pfad zum Arbeitsbereich
|
||||
workspacePathDescription=Der Ort des Datenverzeichnisses des Arbeitsbereichs
|
||||
workspaceCreationAlertTitle=Arbeitsbereich erstellen
|
||||
|
|
|
@ -486,3 +486,15 @@ closeOtherTabs=Close other tabs
|
|||
closeAllTabs=Close all tabs
|
||||
closeLeftTabs=Close tabs to the left
|
||||
closeRightTabs=Close tabs to the right
|
||||
addSerial=Serial ...
|
||||
connect=Connect
|
||||
workspaces=Workspaces
|
||||
manageWorkspaces=Manage workspaces
|
||||
addWorkspace=Add workspace ...
|
||||
workspaceAdd=Add a new workspace
|
||||
workspaceAddDescription=Workspaces are distinct configurations for running XPipe. Every workspace has a data directory where all data is stored locally. This includes connection data, settings, and more.\n\nIf you use the synchronization feature, you can also choose to synchronize each workspace with a different git repository.
|
||||
workspaceName=Workspace name
|
||||
workspaceNameDescription=The display name of the workspace
|
||||
workspacePath=Workspace path
|
||||
workspacePathDescription=The location of the workspace data directory
|
||||
workspaceCreationAlertTitle=Workspace creation
|
||||
|
|
|
@ -469,3 +469,15 @@ closeOtherTabs=Cerrar otras pestañas
|
|||
closeAllTabs=Cerrar todas las pestañas
|
||||
closeLeftTabs=Cerrar pestañas a la izquierda
|
||||
closeRightTabs=Cerrar pestañas a la derecha
|
||||
addSerial=Serie ...
|
||||
connect=Conecta
|
||||
workspaces=Espacios de trabajo
|
||||
manageWorkspaces=Gestionar espacios de trabajo
|
||||
addWorkspace=Añadir espacio de trabajo ...
|
||||
workspaceAdd=Añadir un nuevo espacio de trabajo
|
||||
workspaceAddDescription=Los espacios de trabajo son configuraciones distintas para ejecutar XPipe. Cada espacio de trabajo tiene un directorio de datos donde se almacenan localmente todos los datos. Esto incluye datos de conexión, configuraciones y más.\n\nSi utilizas la función de sincronización, también puedes elegir sincronizar cada espacio de trabajo con un repositorio git diferente.
|
||||
workspaceName=Nombre del espacio de trabajo
|
||||
workspaceNameDescription=El nombre para mostrar del espacio de trabajo
|
||||
workspacePath=Ruta del espacio de trabajo
|
||||
workspacePathDescription=La ubicación del directorio de datos del espacio de trabajo
|
||||
workspaceCreationAlertTitle=Creación de espacios de trabajo
|
||||
|
|
|
@ -469,3 +469,15 @@ closeOtherTabs=Fermer d'autres onglets
|
|||
closeAllTabs=Fermer tous les onglets
|
||||
closeLeftTabs=Ferme les onglets à gauche
|
||||
closeRightTabs=Ferme les onglets à droite
|
||||
addSerial=Série ...
|
||||
connect=Connecter
|
||||
workspaces=Espaces de travail
|
||||
manageWorkspaces=Gérer les espaces de travail
|
||||
addWorkspace=Ajouter un espace de travail ...
|
||||
workspaceAdd=Ajouter un nouvel espace de travail
|
||||
workspaceAddDescription=Les espaces de travail sont des configurations distinctes pour l'exécution de XPipe. Chaque espace de travail possède un répertoire de données où toutes les données sont stockées localement. Cela comprend les données de connexion, les paramètres, et plus encore.\n\nSi tu utilises la fonctionnalité de synchronisation, tu peux aussi choisir de synchroniser chaque espace de travail avec un dépôt git différent.
|
||||
workspaceName=Nom de l'espace de travail
|
||||
workspaceNameDescription=Le nom d'affichage de l'espace de travail
|
||||
workspacePath=Chemin d'accès à l'espace de travail
|
||||
workspacePathDescription=L'emplacement du répertoire de données de l'espace de travail
|
||||
workspaceCreationAlertTitle=Création d'un espace de travail
|
||||
|
|
|
@ -469,3 +469,15 @@ closeOtherTabs=Chiudere altre schede
|
|||
closeAllTabs=Chiudi tutte le schede
|
||||
closeLeftTabs=Chiudere le schede a sinistra
|
||||
closeRightTabs=Chiudere le schede a destra
|
||||
addSerial=Seriale ...
|
||||
connect=Collegare
|
||||
workspaces=Spazi di lavoro
|
||||
manageWorkspaces=Gestire gli spazi di lavoro
|
||||
addWorkspace=Aggiungi spazio di lavoro ...
|
||||
workspaceAdd=Aggiungere un nuovo spazio di lavoro
|
||||
workspaceAddDescription=Gli spazi di lavoro sono configurazioni distinte per l'esecuzione di XPipe. Ogni workspace ha una directory di dati in cui vengono memorizzati tutti i dati a livello locale. Questi includono i dati di connessione, le impostazioni e altro ancora.\n\nSe utilizzi la funzione di sincronizzazione, puoi anche scegliere di sincronizzare ogni workspace con un repository git diverso.
|
||||
workspaceName=Nome dello spazio di lavoro
|
||||
workspaceNameDescription=Il nome di visualizzazione dell'area di lavoro
|
||||
workspacePath=Percorso dello spazio di lavoro
|
||||
workspacePathDescription=La posizione della directory dei dati dell'area di lavoro
|
||||
workspaceCreationAlertTitle=Creazione di uno spazio di lavoro
|
||||
|
|
|
@ -469,3 +469,15 @@ closeOtherTabs=他のタブを閉じる
|
|||
closeAllTabs=すべてのタブを閉じる
|
||||
closeLeftTabs=タブを左に閉じる
|
||||
closeRightTabs=タブを右に閉じる
|
||||
addSerial=シリアル ...
|
||||
connect=接続する
|
||||
workspaces=ワークスペース
|
||||
manageWorkspaces=ワークスペースを管理する
|
||||
addWorkspace=ワークスペースを追加する
|
||||
workspaceAdd=新しいワークスペースを追加する
|
||||
workspaceAddDescription=ワークスペースは、XPipeを実行するための個別の設定である。すべてのワークスペースには、すべてのデータがローカルに保存されるデータ・ディレクトリがある。これには、接続データや設定などが含まれる。\n\n同期機能を使えば、ワークスペースごとに異なるgitリポジトリと同期させることもできる。
|
||||
workspaceName=ワークスペース名
|
||||
workspaceNameDescription=ワークスペースの表示名
|
||||
workspacePath=ワークスペースのパス
|
||||
workspacePathDescription=ワークスペースのデータディレクトリの場所
|
||||
workspaceCreationAlertTitle=ワークスペースの作成
|
||||
|
|
|
@ -469,3 +469,15 @@ closeOtherTabs=Andere tabbladen sluiten
|
|||
closeAllTabs=Alle tabbladen sluiten
|
||||
closeLeftTabs=Tabbladen naar links sluiten
|
||||
closeRightTabs=Tabbladen naar rechts sluiten
|
||||
addSerial=Serieel ...
|
||||
connect=Maak verbinding met
|
||||
workspaces=Werkruimten
|
||||
manageWorkspaces=Werkruimten beheren
|
||||
addWorkspace=Werkruimte toevoegen ...
|
||||
workspaceAdd=Een nieuwe werkruimte toevoegen
|
||||
workspaceAddDescription=Workspaces zijn verschillende configuraties voor het uitvoeren van XPipe. Elke workspace heeft een datamap waar alle gegevens lokaal worden opgeslagen. Dit omvat verbindingsgegevens, instellingen en meer.\n\nAls je de synchronisatiefunctie gebruikt, kun je er ook voor kiezen om elke workspace met een andere git repository te synchroniseren.
|
||||
workspaceName=Naam werkruimte
|
||||
workspaceNameDescription=De weergavenaam van de werkruimte
|
||||
workspacePath=Werkruimte pad
|
||||
workspacePathDescription=De locatie van de gegevensmap van de werkruimte
|
||||
workspaceCreationAlertTitle=Werkruimte maken
|
||||
|
|
|
@ -469,3 +469,15 @@ closeOtherTabs=Fecha outros separadores
|
|||
closeAllTabs=Fecha todos os separadores
|
||||
closeLeftTabs=Fecha os separadores à esquerda
|
||||
closeRightTabs=Fecha os separadores à direita
|
||||
addSerial=Série ...
|
||||
connect=Liga-te
|
||||
workspaces=Espaços de trabalho
|
||||
manageWorkspaces=Gere espaços de trabalho
|
||||
addWorkspace=Adiciona um espaço de trabalho ...
|
||||
workspaceAdd=Adiciona um novo espaço de trabalho
|
||||
workspaceAddDescription=Os espaços de trabalho são configurações distintas para executar o XPipe. Cada espaço de trabalho tem um diretório de dados onde todos os dados são armazenados localmente. Isto inclui dados de ligação, definições e muito mais.\n\nSe utilizares a funcionalidade de sincronização, também podes optar por sincronizar cada espaço de trabalho com um repositório git diferente.
|
||||
workspaceName=Nome do espaço de trabalho
|
||||
workspaceNameDescription=O nome de apresentação do espaço de trabalho
|
||||
workspacePath=Caminho do espaço de trabalho
|
||||
workspacePathDescription=A localização do diretório de dados do espaço de trabalho
|
||||
workspaceCreationAlertTitle=Criação de espaço de trabalho
|
||||
|
|
|
@ -469,3 +469,15 @@ closeOtherTabs=Закрыть другие вкладки
|
|||
closeAllTabs=Закрыть все вкладки
|
||||
closeLeftTabs=Закрыть вкладки слева
|
||||
closeRightTabs=Закрывать вкладки справа
|
||||
addSerial=Серийный ...
|
||||
connect=Connect
|
||||
workspaces=Рабочие пространства
|
||||
manageWorkspaces=Управляй рабочими пространствами
|
||||
addWorkspace=Добавь рабочее пространство ...
|
||||
workspaceAdd=Добавьте новое рабочее пространство
|
||||
workspaceAddDescription=Рабочие пространства - это отдельные конфигурации для запуска XPipe. В каждом рабочем пространстве есть каталог данных, где все данные хранятся локально. Сюда входят данные о соединениях, настройки и многое другое.\n\nЕсли ты используешь функцию синхронизации, ты также можешь выбрать синхронизацию каждого рабочего пространства с отдельным git-репозиторием.
|
||||
workspaceName=Имя рабочей области
|
||||
workspaceNameDescription=Отображаемое имя рабочей области
|
||||
workspacePath=Путь к рабочему пространству
|
||||
workspacePathDescription=Расположение каталога данных рабочей области
|
||||
workspaceCreationAlertTitle=Создание рабочего пространства
|
||||
|
|
|
@ -470,3 +470,15 @@ closeOtherTabs=Diğer sekmeleri kapatın
|
|||
closeAllTabs=Tüm sekmeleri kapat
|
||||
closeLeftTabs=Sekmeleri sola doğru kapatın
|
||||
closeRightTabs=Sekmeleri sağa doğru kapatın
|
||||
addSerial=Seri ...
|
||||
connect=Bağlan
|
||||
workspaces=Çalışma Alanları
|
||||
manageWorkspaces=Çalışma alanlarını yönetme
|
||||
addWorkspace=Çalışma alanı ekle ...
|
||||
workspaceAdd=Yeni bir çalışma alanı ekleme
|
||||
workspaceAddDescription=Çalışma alanları XPipe'ı çalıştırmak için farklı konfigürasyonlardır. Her çalışma alanı, tüm verilerin yerel olarak depolandığı bir veri dizinine sahiptir. Buna bağlantı verileri, ayarlar ve daha fazlası dahildir.\n\nSenkronizasyon özelliğini kullanırsanız, her çalışma alanını farklı bir git deposu ile senkronize etmeyi de seçebilirsiniz.
|
||||
workspaceName=Çalışma alanı adı
|
||||
workspaceNameDescription=Çalışma alanının görünen adı
|
||||
workspacePath=Çalışma alanı yolu
|
||||
workspacePathDescription=Çalışma alanı veri dizininin konumu
|
||||
workspaceCreationAlertTitle=Çalışma alanı oluşturma
|
||||
|
|
|
@ -469,3 +469,15 @@ closeOtherTabs=关闭其他标签页
|
|||
closeAllTabs=关闭所有标签页
|
||||
closeLeftTabs=向左关闭标签
|
||||
closeRightTabs=向右关闭标签页
|
||||
addSerial=串行 ...
|
||||
connect=连接
|
||||
workspaces=工作空间
|
||||
manageWorkspaces=管理工作区
|
||||
addWorkspace=添加工作区 ...
|
||||
workspaceAdd=添加新工作区
|
||||
workspaceAddDescription=工作区是运行 XPipe 的独特配置。每个工作区都有一个数据目录,本地存储所有数据。其中包括连接数据、设置等。\n\n如果使用同步功能,您还可以选择将每个工作区与不同的 git 仓库同步。
|
||||
workspaceName=工作区名称
|
||||
workspaceNameDescription=工作区的显示名称
|
||||
workspacePath=工作区路径
|
||||
workspacePathDescription=工作区数据目录的位置
|
||||
workspaceCreationAlertTitle=创建工作区
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
wsl=Windows Subsystem for Linux
|
||||
docker=Docker
|
||||
proxmox=Proxmox PVE
|
||||
proxmox=Proxmox PVE
|
||||
xonXoff=XON/XOFF
|
||||
rtsCts=RTS/CTS
|
||||
dsrDtr=DSR/DTR
|
||||
putty=PuTTY
|
||||
screen=Screen
|
||||
minicom=Minicom
|
||||
odd=Odd
|
||||
even=Even
|
||||
mark=Mark
|
||||
space=Space
|
||||
|
|
|
@ -359,3 +359,20 @@ k8sPodActions=Pod-handlinger
|
|||
openVnc=Sæt VNC op
|
||||
commandGroup.displayName=Kommandogruppe
|
||||
commandGroup.displayDescription=Grupper tilgængelige kommandoer for et system
|
||||
serial.displayName=Seriel forbindelse
|
||||
serial.displayDescription=Åbn en seriel forbindelse i en terminal
|
||||
serialPort=Seriel port
|
||||
serialPortDescription=Den serielle port / enhed, der skal forbindes til
|
||||
baudRate=Baud-hastighed
|
||||
dataBits=Data-bits
|
||||
stopBits=Stop-bits
|
||||
parity=Paritet
|
||||
flowControlWindow=Flow-kontrol
|
||||
serialImplementation=Seriel implementering
|
||||
serialImplementationDescription=Det værktøj, der skal bruges til at oprette forbindelse til den serielle port
|
||||
serialHost=Vært
|
||||
serialHostDescription=Systemet til at få adgang til den serielle port på
|
||||
serialPortConfiguration=Konfiguration af seriel port
|
||||
serialPortConfigurationDescription=Konfigurationsparametre for den tilsluttede serielle enhed
|
||||
serialInformation=Seriel information
|
||||
openXShell=Åbn i XShell
|
||||
|
|
|
@ -337,3 +337,20 @@ k8sPodActions=Pod-Aktionen
|
|||
openVnc=VNC einrichten
|
||||
commandGroup.displayName=Befehlsgruppe
|
||||
commandGroup.displayDescription=Verfügbare Befehle für ein System gruppieren
|
||||
serial.displayName=Serielle Verbindung
|
||||
serial.displayDescription=Eine serielle Verbindung in einem Terminal öffnen
|
||||
serialPort=Serieller Anschluss
|
||||
serialPortDescription=Der serielle Anschluss/das Gerät, mit dem eine Verbindung hergestellt werden soll
|
||||
baudRate=Baudrate
|
||||
dataBits=Datenbits
|
||||
stopBits=Stoppbits
|
||||
parity=Parität
|
||||
flowControlWindow=Flusskontrolle
|
||||
serialImplementation=Serielle Implementierung
|
||||
serialImplementationDescription=Das Tool für die Verbindung mit der seriellen Schnittstelle
|
||||
serialHost=Host
|
||||
serialHostDescription=Das System für den Zugriff auf die serielle Schnittstelle auf
|
||||
serialPortConfiguration=Konfiguration der seriellen Schnittstelle
|
||||
serialPortConfigurationDescription=Konfigurationsparameter des angeschlossenen seriellen Geräts
|
||||
serialInformation=Serielle Informationen
|
||||
openXShell=In XShell öffnen
|
||||
|
|
|
@ -334,4 +334,21 @@ dockerContextActions=Context actions
|
|||
k8sPodActions=Pod actions
|
||||
openVnc=Set up VNC
|
||||
commandGroup.displayName=Command group
|
||||
commandGroup.displayDescription=Group available commands for a system
|
||||
commandGroup.displayDescription=Group available commands for a system
|
||||
serial.displayName=Serial connection
|
||||
serial.displayDescription=Open a serial connection in a terminal
|
||||
serialPort=Serial port
|
||||
serialPortDescription=The serial port / device to connect to
|
||||
baudRate=Baud rate
|
||||
dataBits=Data bits
|
||||
stopBits=Stop bits
|
||||
parity=Parity
|
||||
flowControlWindow=Flow control
|
||||
serialImplementation=Serial implementation
|
||||
serialImplementationDescription=The tool to use to connect to the serial port
|
||||
serialHost=Host
|
||||
serialHostDescription=The system to access the serial port on
|
||||
serialPortConfiguration=Serial port configuration
|
||||
serialPortConfigurationDescription=Configuration parameters of the connected serial device
|
||||
serialInformation=Serial information
|
||||
openXShell=Open in XShell
|
||||
|
|
|
@ -333,3 +333,20 @@ k8sPodActions=Acciones del pod
|
|||
openVnc=Configurar VNC
|
||||
commandGroup.displayName=Grupo de comandos
|
||||
commandGroup.displayDescription=Agrupa los comandos disponibles para un sistema
|
||||
serial.displayName=Conexión en serie
|
||||
serial.displayDescription=Abrir una conexión serie en un terminal
|
||||
serialPort=Puerto serie
|
||||
serialPortDescription=El puerto serie / dispositivo al que conectarse
|
||||
baudRate=Velocidad en baudios
|
||||
dataBits=Bits de datos
|
||||
stopBits=Bits de parada
|
||||
parity=Paridad
|
||||
flowControlWindow=Control de flujo
|
||||
serialImplementation=Aplicación en serie
|
||||
serialImplementationDescription=La herramienta que hay que utilizar para conectarse al puerto serie
|
||||
serialHost=Anfitrión
|
||||
serialHostDescription=El sistema para acceder al puerto serie en
|
||||
serialPortConfiguration=Configuración del puerto serie
|
||||
serialPortConfigurationDescription=Parámetros de configuración del dispositivo serie conectado
|
||||
serialInformation=Información en serie
|
||||
openXShell=Abrir en XShell
|
||||
|
|
|
@ -333,3 +333,20 @@ k8sPodActions=Actions de pods
|
|||
openVnc=Configurer VNC
|
||||
commandGroup.displayName=Groupe de commande
|
||||
commandGroup.displayDescription=Groupe de commandes disponibles pour un système
|
||||
serial.displayName=Connexion série
|
||||
serial.displayDescription=Ouvrir une connexion série dans un terminal
|
||||
serialPort=Port série
|
||||
serialPortDescription=Le port série / le périphérique à connecter
|
||||
baudRate=Taux de bauds
|
||||
dataBits=Bits de données
|
||||
stopBits=Bits d'arrêt
|
||||
parity=Parité
|
||||
flowControlWindow=Contrôle de flux
|
||||
serialImplementation=Implémentation en série
|
||||
serialImplementationDescription=L'outil à utiliser pour se connecter au port série
|
||||
serialHost=Hôte
|
||||
serialHostDescription=Le système pour accéder au port série sur
|
||||
serialPortConfiguration=Configuration du port série
|
||||
serialPortConfigurationDescription=Paramètres de configuration de l'appareil en série connecté
|
||||
serialInformation=Informations en série
|
||||
openXShell=Ouvrir dans XShell
|
||||
|
|
|
@ -333,3 +333,20 @@ k8sPodActions=Azioni del pod
|
|||
openVnc=Configurare VNC
|
||||
commandGroup.displayName=Gruppo di comando
|
||||
commandGroup.displayDescription=Gruppo di comandi disponibili per un sistema
|
||||
serial.displayName=Connessione seriale
|
||||
serial.displayDescription=Aprire una connessione seriale in un terminale
|
||||
serialPort=Porta seriale
|
||||
serialPortDescription=La porta seriale/dispositivo a cui connettersi
|
||||
baudRate=Velocità di trasmissione
|
||||
dataBits=Bit di dati
|
||||
stopBits=Bit di stop
|
||||
parity=Parità
|
||||
flowControlWindow=Controllo del flusso
|
||||
serialImplementation=Implementazione seriale
|
||||
serialImplementationDescription=Lo strumento da utilizzare per collegarsi alla porta seriale
|
||||
serialHost=Ospite
|
||||
serialHostDescription=Il sistema per accedere alla porta seriale su
|
||||
serialPortConfiguration=Configurazione della porta seriale
|
||||
serialPortConfigurationDescription=Parametri di configurazione del dispositivo seriale collegato
|
||||
serialInformation=Informazioni di serie
|
||||
openXShell=Apri in XShell
|
||||
|
|
|
@ -333,3 +333,20 @@ k8sPodActions=ポッドアクション
|
|||
openVnc=VNCを設定する
|
||||
commandGroup.displayName=コマンドグループ
|
||||
commandGroup.displayDescription=システムで使用可能なコマンドをグループ化する
|
||||
serial.displayName=シリアル接続
|
||||
serial.displayDescription=ターミナルでシリアル接続を開く
|
||||
serialPort=シリアルポート
|
||||
serialPortDescription=接続するシリアルポート/デバイス
|
||||
baudRate=ボーレート
|
||||
dataBits=データビット
|
||||
stopBits=ストップビット
|
||||
parity=パリティ
|
||||
flowControlWindow=フロー制御
|
||||
serialImplementation=シリアルの実装
|
||||
serialImplementationDescription=シリアルポートに接続するために使用するツール
|
||||
serialHost=ホスト
|
||||
serialHostDescription=のシリアルポートにアクセスするシステム
|
||||
serialPortConfiguration=シリアルポートの設定
|
||||
serialPortConfigurationDescription=接続されたシリアル・デバイスの設定パラメーター
|
||||
serialInformation=シリアル情報
|
||||
openXShell=XShellで開く
|
||||
|
|
|
@ -333,3 +333,20 @@ k8sPodActions=Pod acties
|
|||
openVnc=VNC instellen
|
||||
commandGroup.displayName=Opdrachtgroep
|
||||
commandGroup.displayDescription=Groep beschikbare commando's voor een systeem
|
||||
serial.displayName=Seriële verbinding
|
||||
serial.displayDescription=Een seriële verbinding in een terminal openen
|
||||
serialPort=Seriële poort
|
||||
serialPortDescription=De seriële poort / het apparaat waarmee verbinding moet worden gemaakt
|
||||
baudRate=Baudrate
|
||||
dataBits=Gegevensbits
|
||||
stopBits=Stopbits
|
||||
parity=Pariteit
|
||||
flowControlWindow=Debietregeling
|
||||
serialImplementation=Seriële implementatie
|
||||
serialImplementationDescription=Het gereedschap om verbinding te maken met de seriële poort
|
||||
serialHost=Host
|
||||
serialHostDescription=Het systeem om toegang te krijgen tot de seriële poort op
|
||||
serialPortConfiguration=Seriële poort configuratie
|
||||
serialPortConfigurationDescription=Configuratieparameters van het aangesloten seriële apparaat
|
||||
serialInformation=Seriële informatie
|
||||
openXShell=Openen in XShell
|
||||
|
|
|
@ -333,3 +333,20 @@ k8sPodActions=Acções de pod
|
|||
openVnc=Configura o VNC
|
||||
commandGroup.displayName=Grupo de comandos
|
||||
commandGroup.displayDescription=Agrupa os comandos disponíveis para um sistema
|
||||
serial.displayName=Ligação em série
|
||||
serial.displayDescription=Abre uma ligação de série num terminal
|
||||
serialPort=Porta de série
|
||||
serialPortDescription=A porta de série / dispositivo a ligar
|
||||
baudRate=Taxa de transmissão
|
||||
dataBits=Bits de dados
|
||||
stopBits=Bits de paragem
|
||||
parity=Paridade
|
||||
flowControlWindow=Controlo de fluxo
|
||||
serialImplementation=Implementação em série
|
||||
serialImplementationDescription=A ferramenta a utilizar para ligar à porta série
|
||||
serialHost=Apresenta
|
||||
serialHostDescription=O sistema para aceder à porta série em
|
||||
serialPortConfiguration=Configuração da porta de série
|
||||
serialPortConfigurationDescription=Parâmetros de configuração do dispositivo de série ligado
|
||||
serialInformation=Informação de série
|
||||
openXShell=Abre no XShell
|
||||
|
|
|
@ -333,3 +333,20 @@ k8sPodActions=Действия в капсуле
|
|||
openVnc=Настройте VNC
|
||||
commandGroup.displayName=Группа команд
|
||||
commandGroup.displayDescription=Группа доступных команд для системы
|
||||
serial.displayName=Последовательное соединение
|
||||
serial.displayDescription=Открыть последовательное соединение в терминале
|
||||
serialPort=Последовательный порт
|
||||
serialPortDescription=Последовательный порт/устройство, к которому нужно подключиться
|
||||
baudRate=Скорость передачи данных
|
||||
dataBits=Биты данных
|
||||
stopBits=Стоп-биты
|
||||
parity=Четность
|
||||
flowControlWindow=Контроль потока
|
||||
serialImplementation=Последовательная реализация
|
||||
serialImplementationDescription=Инструмент, который нужно использовать для подключения к последовательному порту
|
||||
serialHost=Хост
|
||||
serialHostDescription=Система для доступа к последовательному порту на
|
||||
serialPortConfiguration=Конфигурация последовательного порта
|
||||
serialPortConfigurationDescription=Параметры конфигурации подключенного последовательного устройства
|
||||
serialInformation=Серийная информация
|
||||
openXShell=Открыть в XShell
|
||||
|
|
|
@ -333,3 +333,20 @@ k8sPodActions=Pod eylemleri
|
|||
openVnc=VNC'yi ayarlama
|
||||
commandGroup.displayName=Komuta grubu
|
||||
commandGroup.displayDescription=Bir sistem için mevcut komutları gruplama
|
||||
serial.displayName=Seri bağlantı
|
||||
serial.displayDescription=Terminalde bir seri bağlantı açın
|
||||
serialPort=Seri bağlantı noktası
|
||||
serialPortDescription=Bağlanılacak seri port / cihaz
|
||||
baudRate=Baud hızı
|
||||
dataBits=Veri bitleri
|
||||
stopBits=Dur bitleri
|
||||
parity=Parite
|
||||
flowControlWindow=Akış kontrolü
|
||||
serialImplementation=Seri uygulama
|
||||
serialImplementationDescription=Seri porta bağlanmak için kullanılacak araç
|
||||
serialHost=Ev sahibi
|
||||
serialHostDescription=Seri porta erişmek için sistem
|
||||
serialPortConfiguration=Seri bağlantı noktası yapılandırması
|
||||
serialPortConfigurationDescription=Bağlı seri cihazın konfigürasyon parametreleri
|
||||
serialInformation=Seri bilgileri
|
||||
openXShell=XShell'de Aç
|
||||
|
|
|
@ -333,3 +333,20 @@ k8sPodActions=Pod 操作
|
|||
openVnc=设置 VNC
|
||||
commandGroup.displayName=命令组
|
||||
commandGroup.displayDescription=系统可用命令组
|
||||
serial.displayName=串行连接
|
||||
serial.displayDescription=在终端中打开串行连接
|
||||
serialPort=串行端口
|
||||
serialPortDescription=要连接的串行端口/设备
|
||||
baudRate=波特率
|
||||
dataBits=数据位
|
||||
stopBits=停止位
|
||||
parity=奇偶校验
|
||||
flowControlWindow=流量控制
|
||||
serialImplementation=串行实施
|
||||
serialImplementationDescription=用于连接串行端口的工具
|
||||
serialHost=主机
|
||||
serialHostDescription=访问串行端口的系统
|
||||
serialPortConfiguration=串行端口配置
|
||||
serialPortConfigurationDescription=所连接串行设备的配置参数
|
||||
serialInformation=序列信息
|
||||
openXShell=在 XShell 中打开
|
||||
|
|
10
lang/proc/texts/serialImplementation_da.md
Normal file
10
lang/proc/texts/serialImplementation_da.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
# Implementeringer
|
||||
|
||||
XPipe uddelegerer den serielle håndtering til eksterne værktøjer.
|
||||
Der er flere tilgængelige værktøjer, som XPipe kan uddelegere til, hver med deres egne fordele og ulemper.
|
||||
For at bruge dem kræves det, at de er tilgængelige på værtssystemet.
|
||||
De fleste muligheder burde være understøttet af alle værktøjer, men nogle mere eksotiske muligheder er det måske ikke.
|
||||
|
||||
Før der oprettes forbindelse, kontrollerer XPipe, at det valgte værktøj er installeret og understøtter alle konfigurerede muligheder.
|
||||
Hvis denne kontrol er vellykket, starter det valgte værktøj.
|
||||
|
10
lang/proc/texts/serialImplementation_de.md
Normal file
10
lang/proc/texts/serialImplementation_de.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
# Implementierungen
|
||||
|
||||
XPipe delegiert die serielle Verarbeitung an externe Tools.
|
||||
Es gibt mehrere Tools, an die XPipe delegieren kann, jedes mit seinen eigenen Vor- und Nachteilen.
|
||||
Um sie zu nutzen, müssen sie auf dem Hostsystem verfügbar sein.
|
||||
Die meisten Optionen sollten von allen Tools unterstützt werden, aber einige exotischere Optionen sind es vielleicht nicht.
|
||||
|
||||
Bevor eine Verbindung hergestellt wird, prüft XPipe, ob das ausgewählte Tool installiert ist und alle konfigurierten Optionen unterstützt.
|
||||
Wenn diese Prüfung erfolgreich ist, wird das ausgewählte Tool gestartet.
|
||||
|
10
lang/proc/texts/serialImplementation_en.md
Normal file
10
lang/proc/texts/serialImplementation_en.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
# Implementations
|
||||
|
||||
XPipe delegates the serial handling to external tools.
|
||||
There are multiple available tools XPipe can delegate to, each with their own advantages and disadvantages.
|
||||
To use them, it is required that they are available on the host system.
|
||||
Most options should be supported by all tools, but some more exotic options might not be.
|
||||
|
||||
Before connecting, XPipe will verify that the selected tool is installed and supports all configured options.
|
||||
If that check is successful, the selected tool will launch.
|
||||
|
10
lang/proc/texts/serialImplementation_es.md
Normal file
10
lang/proc/texts/serialImplementation_es.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
# Implementaciones
|
||||
|
||||
XPipe delega el manejo de la serie en herramientas externas.
|
||||
Hay múltiples herramientas disponibles en las que XPipe puede delegar, cada una con sus propias ventajas e inconvenientes.
|
||||
Para utilizarlas, es necesario que estén disponibles en el sistema anfitrión.
|
||||
La mayoría de las opciones deberían estar soportadas por todas las herramientas, pero algunas opciones más exóticas podrían no estarlo.
|
||||
|
||||
Antes de conectarse, XPipe comprobará que la herramienta seleccionada está instalada y admite todas las opciones configuradas.
|
||||
Si la comprobación es correcta, se iniciará la herramienta seleccionada.
|
||||
|
10
lang/proc/texts/serialImplementation_fr.md
Normal file
10
lang/proc/texts/serialImplementation_fr.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
# Implantations
|
||||
|
||||
XPipe délègue la gestion de la série à des outils externes.
|
||||
Il existe plusieurs outils disponibles auxquels XPipe peut déléguer, chacun ayant ses propres avantages et inconvénients.
|
||||
Pour les utiliser, il faut qu'ils soient disponibles sur le système hôte.
|
||||
La plupart des options devraient être supportées par tous les outils, mais certaines options plus exotiques pourraient ne pas l'être.
|
||||
|
||||
Avant de se connecter, XPipe vérifie que l'outil sélectionné est installé et qu'il prend en charge toutes les options configurées.
|
||||
Si cette vérification est concluante, l'outil sélectionné sera lancé.
|
||||
|
10
lang/proc/texts/serialImplementation_it.md
Normal file
10
lang/proc/texts/serialImplementation_it.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
# Implementazioni
|
||||
|
||||
XPipe delega la gestione della serialità a strumenti esterni.
|
||||
Esistono diversi strumenti a cui XPipe può delegare, ognuno con i propri vantaggi e svantaggi.
|
||||
Per poterli utilizzare, è necessario che siano disponibili sul sistema host.
|
||||
La maggior parte delle opzioni dovrebbe essere supportata da tutti gli strumenti, ma alcune opzioni più esotiche potrebbero non esserlo.
|
||||
|
||||
Prima di connettersi, XPipe verifica che lo strumento selezionato sia installato e che supporti tutte le opzioni configurate.
|
||||
Se la verifica ha esito positivo, lo strumento selezionato viene avviato.
|
||||
|
10
lang/proc/texts/serialImplementation_ja.md
Normal file
10
lang/proc/texts/serialImplementation_ja.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
# 実装
|
||||
|
||||
XPipeはシリアル処理を外部ツールに委譲する。
|
||||
XPipeが委譲できるツールは複数あり、それぞれに長所と短所がある。
|
||||
それらを使用するには、ホストシステム上で使用可能であることが必要である。
|
||||
ほとんどのオプションはすべてのツールでサポートされているはずだが、よりエキゾチックなオプションはサポートされていないかもしれない。
|
||||
|
||||
接続する前に、XPipeは、選択したツールがインストールされ、設定されたすべてのオプションに対応しているかどうかを確認する。
|
||||
チェックが成功すると、選択したツールが起動する。
|
||||
|
10
lang/proc/texts/serialImplementation_nl.md
Normal file
10
lang/proc/texts/serialImplementation_nl.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
# Implementaties
|
||||
|
||||
XPipe delegeert de seriële afhandeling naar externe tools.
|
||||
Er zijn meerdere beschikbare tools waaraan XPipe kan delegeren, elk met hun eigen voor- en nadelen.
|
||||
Om ze te gebruiken is het vereist dat ze beschikbaar zijn op het hostsysteem.
|
||||
De meeste opties zouden door alle gereedschappen ondersteund moeten worden, maar sommige meer exotische opties misschien niet.
|
||||
|
||||
Voordat er verbinding wordt gemaakt, controleert XPipe of het geselecteerde gereedschap is geïnstalleerd en alle geconfigureerde opties ondersteunt.
|
||||
Als die controle succesvol is, wordt het geselecteerde gereedschap gestart.
|
||||
|
10
lang/proc/texts/serialImplementation_pt.md
Normal file
10
lang/proc/texts/serialImplementation_pt.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
# Implementações
|
||||
|
||||
XPipe delega o manuseio serial para ferramentas externas.
|
||||
Existem várias ferramentas disponíveis para as quais o XPipe pode delegar, cada uma com suas próprias vantagens e desvantagens.
|
||||
Para as utilizar, é necessário que estejam disponíveis no sistema anfitrião.
|
||||
A maioria das opções deve ser suportada por todas as ferramentas, mas algumas opções mais exóticas podem não ser.
|
||||
|
||||
Antes de ligar, o XPipe verifica se a ferramenta selecionada está instalada e se suporta todas as opções configuradas.
|
||||
Se essa verificação for bem sucedida, a ferramenta selecionada será iniciada.
|
||||
|
10
lang/proc/texts/serialImplementation_ru.md
Normal file
10
lang/proc/texts/serialImplementation_ru.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
# Реализации
|
||||
|
||||
XPipe делегирует работу с последовательным интерфейсом внешним инструментам.
|
||||
Существует несколько доступных инструментов, которым XPipe может делегировать свои полномочия, каждый из которых имеет свои преимущества и недостатки.
|
||||
Чтобы использовать их, необходимо, чтобы они были доступны в хост-системе.
|
||||
Большинство опций должны поддерживаться всеми инструментами, но некоторые более экзотические опции могут не поддерживаться.
|
||||
|
||||
Перед подключением XPipe проверит, что выбранный инструмент установлен и поддерживает все настроенные опции.
|
||||
Если проверка прошла успешно, выбранный инструмент будет запущен.
|
||||
|
10
lang/proc/texts/serialImplementation_tr.md
Normal file
10
lang/proc/texts/serialImplementation_tr.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
# Uygulamalar
|
||||
|
||||
XPipe seri işlemeyi harici araçlara devreder.
|
||||
XPipe'ın temsilci olarak kullanabileceği, her biri kendi avantaj ve dezavantajlarına sahip birden fazla araç mevcuttur.
|
||||
Bunları kullanmak için, ana sistemde mevcut olmaları gerekir.
|
||||
Çoğu seçenek tüm araçlar tarafından desteklenmelidir, ancak bazı daha egzotik seçenekler desteklenmeyebilir.
|
||||
|
||||
XPipe bağlanmadan önce seçilen aracın yüklü olduğunu ve yapılandırılan tüm seçenekleri desteklediğini doğrular.
|
||||
Bu kontrol başarılı olursa, seçilen araç başlatılır.
|
||||
|
10
lang/proc/texts/serialImplementation_zh.md
Normal file
10
lang/proc/texts/serialImplementation_zh.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
# 实现
|
||||
|
||||
XPipe将串行处理委托给外部工具。
|
||||
XPipe 可以委托多种可用工具,每种工具都有自己的优缺点。
|
||||
要使用这些工具,主机系统上必须有这些工具。
|
||||
大多数选项应为所有工具所支持,但一些较为特殊的选项可能不支持。
|
||||
|
||||
在连接之前,XPipe 将验证所选工具是否已安装并支持所有配置选项。
|
||||
如果检查成功,所选工具将启动。
|
||||
|
20
lang/proc/texts/serialPort_da.md
Normal file
20
lang/proc/texts/serialPort_da.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
## Windows
|
||||
|
||||
På Windows-systemer henviser man typisk til serielle porte via `COM<index>`.
|
||||
XPipe understøtter også blot at angive indekset uden præfikset `COM`.
|
||||
For at adressere porte større end 9 skal du bruge UNC-stiformen med `\\.\COM<index>`.
|
||||
|
||||
Hvis du har installeret en WSL1-distribution, kan du også henvise til de serielle porte inde fra WSL-distributionen via `/dev/ttyS<index>`.
|
||||
Dette virker dog ikke længere med WSL2.
|
||||
Hvis du har et WSL1-system, kan du bruge det som vært for den serielle forbindelse og bruge tty-notationen til at få adgang til det med XPipe.
|
||||
|
||||
## Linux
|
||||
|
||||
På Linux-systemer kan du typisk få adgang til de serielle porte via `/dev/ttyS<index>`.
|
||||
Hvis du kender ID'et på den tilsluttede enhed, men ikke ønsker at holde styr på den serielle port, kan du også henvise til dem via `/dev/serial/by-id/<device id>`.
|
||||
Du kan få en liste over alle tilgængelige serielle porte med deres ID'er ved at køre `ls /dev/serial/by-id/*`.
|
||||
|
||||
## macOS
|
||||
|
||||
På macOS kan de serielle portnavne være stort set hvad som helst, men har normalt formen `/dev/tty.<id>`, hvor id er den interne enhedsidentifikator.
|
||||
Ved at køre `ls /dev/tty.*` kan man finde tilgængelige serielle porte.
|
20
lang/proc/texts/serialPort_de.md
Normal file
20
lang/proc/texts/serialPort_de.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
## Windows
|
||||
|
||||
Auf Windows-Systemen bezeichnest du serielle Schnittstellen normalerweise mit `COM<index>`.
|
||||
XPipe unterstützt auch die bloße Angabe des Index ohne das Präfix `COM`.
|
||||
Um Ports größer als 9 anzusprechen, musst du die UNC-Pfadform mit `\.\COM<index>` verwenden.
|
||||
|
||||
Wenn du eine WSL1-Distribution installiert hast, kannst du die seriellen Schnittstellen auch aus der WSL-Distribution heraus über `/dev/ttyS<index>` ansprechen.
|
||||
Das funktioniert allerdings nicht mehr mit WSL2.
|
||||
Wenn du ein WSL1-System hast, kannst du dieses als Host für diese serielle Verbindung verwenden und die tty-Notation nutzen, um mit XPipe darauf zuzugreifen.
|
||||
|
||||
## Linux
|
||||
|
||||
Auf Linux-Systemen kannst du normalerweise über `/dev/ttyS<index>` auf die seriellen Schnittstellen zugreifen.
|
||||
Wenn du die ID des angeschlossenen Geräts kennst, dir aber die serielle Schnittstelle nicht merken willst, kannst du sie auch über `/dev/serial/by-id/<device id>` ansprechen.
|
||||
Du kannst alle verfügbaren seriellen Schnittstellen mit ihren IDs auflisten, indem du `ls /dev/serial/by-id/*` ausführst.
|
||||
|
||||
## macOS
|
||||
|
||||
Unter macOS können die Namen der seriellen Schnittstellen so ziemlich alles sein, aber normalerweise haben sie die Form `/dev/tty.<id>`, wobei id die interne Gerätekennung ist.
|
||||
Wenn du `ls /dev/tty.*` ausführst, solltest du die verfügbaren seriellen Schnittstellen finden.
|
20
lang/proc/texts/serialPort_en.md
Normal file
20
lang/proc/texts/serialPort_en.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
## Windows
|
||||
|
||||
On Windows systems you typically refer to serial ports via `COM<index>`.
|
||||
XPipe also supports just specifying the index without the `COM` prefix.
|
||||
To address ports greater than 9, you have to use the UNC path form with `\\.\COM<index>`.
|
||||
|
||||
If you have a WSL1 distribution installed, you can also reference the serial ports from within the WSL distribution via `/dev/ttyS<index>`.
|
||||
This it does not work with WSL2 anymore though.
|
||||
If you have a WSL1 system, you can use this one as the host for this serial connection and use the tty notation to access it with XPipe.
|
||||
|
||||
## Linux
|
||||
|
||||
On Linux systems you can typically access the serial ports via `/dev/ttyS<index>`.
|
||||
If you know the ID of the connected device but don't want to keep track of the serial port, you can also reference them via `/dev/serial/by-id/<device id>`.
|
||||
You can list all available serial ports with their IDs by running `ls /dev/serial/by-id/*`.
|
||||
|
||||
## macOS
|
||||
|
||||
On macOS, the serial port names can be pretty much anything, but usually have the form of `/dev/tty.<id>` where the id the internal device identifier.
|
||||
Running `ls /dev/tty.*` should find available serial ports.
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue