mirror of
https://github.com/xpipe-io/xpipe.git
synced 2026-04-22 07:29:05 -04:00
Reformat
This commit is contained in:
@@ -57,7 +57,7 @@ dependencies {
|
||||
api 'io.xpipe:vernacular:1.15'
|
||||
api 'org.bouncycastle:bcprov-jdk18on:1.81'
|
||||
api 'info.picocli:picocli:4.7.6'
|
||||
api 'org.apache.commons:commons-lang3:3.17.0'
|
||||
api 'org.apache.commons:commons-lang3:3.18.0'
|
||||
api 'io.sentry:sentry:8.13.3'
|
||||
api 'commons-io:commons-io:2.19.0'
|
||||
api group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: "2.19.1"
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package io.xpipe.app.beacon;
|
||||
|
||||
import io.xpipe.app.beacon.mcp.AppMcpServer;
|
||||
import io.xpipe.app.issue.ErrorEventFactory;
|
||||
import io.xpipe.app.issue.TrackEvent;
|
||||
import io.xpipe.app.beacon.mcp.AppMcpServer;
|
||||
import io.xpipe.app.util.DocumentationLink;
|
||||
import io.xpipe.beacon.BeaconConfig;
|
||||
import io.xpipe.beacon.BeaconInterface;
|
||||
|
||||
@@ -21,9 +21,7 @@ public class DaemonModeExchangeImpl extends DaemonModeExchange {
|
||||
}
|
||||
|
||||
OperationMode.switchToSyncIfPossible(mode);
|
||||
return DaemonModeExchange.Response.builder()
|
||||
.usedMode(msg.getMode())
|
||||
.build();
|
||||
return DaemonModeExchange.Response.builder().usedMode(msg.getMode()).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
package io.xpipe.app.beacon.mcp;
|
||||
|
||||
import io.xpipe.app.core.AppProperties;
|
||||
import io.xpipe.app.issue.ErrorEventFactory;
|
||||
import io.xpipe.app.prefs.AppPrefs;
|
||||
import io.xpipe.app.util.ThreadHelper;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import com.sun.net.httpserver.HttpHandler;
|
||||
import io.modelcontextprotocol.server.McpServerFeatures;
|
||||
import io.modelcontextprotocol.server.McpSyncServer;
|
||||
import io.modelcontextprotocol.spec.McpSchema;
|
||||
import io.xpipe.app.core.AppProperties;
|
||||
import io.xpipe.app.issue.ErrorEventFactory;
|
||||
import io.xpipe.app.prefs.AppPrefs;
|
||||
import io.xpipe.app.util.ThreadHelper;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.Value;
|
||||
|
||||
@@ -74,40 +75,40 @@ public class AppMcpServer {
|
||||
syncServer.notifyToolsListChanged();
|
||||
});
|
||||
|
||||
// syncServer.addResource(McpResources.connections());
|
||||
// syncServer.addResource(McpResources.categories());
|
||||
//
|
||||
// DataStorage.get().addListener(new StorageListener() {
|
||||
// @Override
|
||||
// public void onStoreListUpdate() {
|
||||
// syncServer.notifyResourcesListChanged();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onStoreAdd(DataStoreEntry... entry) {
|
||||
// syncServer.notifyResourcesListChanged();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onStoreRemove(DataStoreEntry... entry) {
|
||||
// syncServer.notifyResourcesListChanged();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onCategoryAdd(DataStoreCategory category) {
|
||||
// syncServer.notifyResourcesListChanged();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onCategoryRemove(DataStoreCategory category) {
|
||||
// syncServer.notifyResourcesListChanged();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onEntryCategoryChange() {
|
||||
// syncServer.notifyResourcesListChanged();
|
||||
// }
|
||||
// });
|
||||
// syncServer.addResource(McpResources.connections());
|
||||
// syncServer.addResource(McpResources.categories());
|
||||
//
|
||||
// DataStorage.get().addListener(new StorageListener() {
|
||||
// @Override
|
||||
// public void onStoreListUpdate() {
|
||||
// syncServer.notifyResourcesListChanged();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onStoreAdd(DataStoreEntry... entry) {
|
||||
// syncServer.notifyResourcesListChanged();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onStoreRemove(DataStoreEntry... entry) {
|
||||
// syncServer.notifyResourcesListChanged();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onCategoryAdd(DataStoreCategory category) {
|
||||
// syncServer.notifyResourcesListChanged();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onCategoryRemove(DataStoreCategory category) {
|
||||
// syncServer.notifyResourcesListChanged();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onEntryCategoryChange() {
|
||||
// syncServer.notifyResourcesListChanged();
|
||||
// }
|
||||
// });
|
||||
|
||||
INSTANCE = new AppMcpServer(syncServer, transportProvider);
|
||||
}
|
||||
@@ -124,7 +125,8 @@ public class AppMcpServer {
|
||||
}
|
||||
|
||||
if (!AppPrefs.get().enableMcpServer().get()) {
|
||||
transportProvider.sendError(exchange, 403, "MCP server is not enabled in the API settings menu");
|
||||
transportProvider.sendError(
|
||||
exchange, 403, "MCP server is not enabled in the API settings menu");
|
||||
if (exchange.getRequestMethod().equals("POST")) {
|
||||
ThreadHelper.runAsync(() -> {
|
||||
ErrorEventFactory.fromMessage(
|
||||
@@ -151,12 +153,14 @@ public class AppMcpServer {
|
||||
return;
|
||||
}
|
||||
|
||||
var correct = apiKey.replace("Bearer ", "").equals(AppPrefs.get().apiKey().get());
|
||||
var correct = apiKey.replace("Bearer ", "")
|
||||
.equals(AppPrefs.get().apiKey().get());
|
||||
if (!correct) {
|
||||
transportProvider.sendError(exchange, 403, "Invalid API key");
|
||||
if (exchange.getRequestMethod().equals("POST")) {
|
||||
ThreadHelper.runAsync(() -> {
|
||||
ErrorEventFactory.fromMessage("The Authorization header sent by the MCP client is not correct")
|
||||
ErrorEventFactory.fromMessage(
|
||||
"The Authorization header sent by the MCP client is not correct")
|
||||
.expected()
|
||||
.handle();
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,13 @@
|
||||
package io.xpipe.app.beacon.mcp;
|
||||
|
||||
import io.xpipe.app.storage.DataStorage;
|
||||
import io.xpipe.core.JacksonMapper;
|
||||
import io.xpipe.core.StorePath;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import io.modelcontextprotocol.server.McpServerFeatures;
|
||||
import io.modelcontextprotocol.spec.McpSchema;
|
||||
import io.xpipe.app.storage.DataStorage;
|
||||
import io.xpipe.core.JacksonMapper;
|
||||
import io.xpipe.core.StorePath;
|
||||
import lombok.Builder;
|
||||
import lombok.NonNull;
|
||||
import lombok.Value;
|
||||
@@ -51,7 +52,6 @@ public final class McpResources {
|
||||
Map<String, Object> internalCache;
|
||||
}
|
||||
|
||||
|
||||
@Jacksonized
|
||||
@Builder
|
||||
@Value
|
||||
@@ -85,21 +85,40 @@ public final class McpResources {
|
||||
continue;
|
||||
}
|
||||
|
||||
var names = DataStorage.get().getStorePath(DataStorage.get().getStoreCategoryIfPresent(e.getCategoryUuid()).orElseThrow()).getNames();
|
||||
var names = DataStorage.get()
|
||||
.getStorePath(DataStorage.get()
|
||||
.getStoreCategoryIfPresent(e.getCategoryUuid())
|
||||
.orElseThrow())
|
||||
.getNames();
|
||||
var cat = new StorePath(names.subList(1, names.size()));
|
||||
var cache = e.getStoreCache().entrySet().stream().filter(stringObjectEntry -> {
|
||||
return stringObjectEntry.getValue() != null && (ClassUtils.isPrimitiveOrWrapper(stringObjectEntry.getValue().getClass()) ||
|
||||
stringObjectEntry.getValue() instanceof String);
|
||||
}).collect(Collectors.toMap(stringObjectEntry -> stringObjectEntry.getKey(), stringObjectEntry -> stringObjectEntry.getValue()));
|
||||
var cache = e.getStoreCache().entrySet().stream()
|
||||
.filter(stringObjectEntry -> {
|
||||
return stringObjectEntry.getValue() != null
|
||||
&& (ClassUtils.isPrimitiveOrWrapper(
|
||||
stringObjectEntry.getValue().getClass())
|
||||
|| stringObjectEntry.getValue() instanceof String);
|
||||
})
|
||||
.collect(Collectors.toMap(
|
||||
stringObjectEntry -> stringObjectEntry.getKey(),
|
||||
stringObjectEntry -> stringObjectEntry.getValue()));
|
||||
|
||||
var resourceData = ConnectionResource.builder().lastModified(e.getLastModified()).lastUsed(e.getLastUsed())
|
||||
.category(cat).name(DataStorage.get().getStorePath(e)).connectionData(e.getStore()).usageCategory(
|
||||
e.getProvider().getUsageCategory()).type(e.getProvider().getId()).internalState(
|
||||
e.getStorePersistentState() != null ? e.getStorePersistentState() : new Object()).internalCache(cache).build();
|
||||
var resourceData = ConnectionResource.builder()
|
||||
.lastModified(e.getLastModified())
|
||||
.lastUsed(e.getLastUsed())
|
||||
.category(cat)
|
||||
.name(DataStorage.get().getStorePath(e))
|
||||
.connectionData(e.getStore())
|
||||
.usageCategory(e.getProvider().getUsageCategory())
|
||||
.type(e.getProvider().getId())
|
||||
.internalState(e.getStorePersistentState() != null ? e.getStorePersistentState() : new Object())
|
||||
.internalCache(cache)
|
||||
.build();
|
||||
|
||||
McpSchema.TextResourceContents c;
|
||||
try {
|
||||
c = new McpSchema.TextResourceContents("xpipe://connections/" + e.getUuid(), "application/json",
|
||||
c = new McpSchema.TextResourceContents(
|
||||
"xpipe://connections/" + e.getUuid(),
|
||||
"application/json",
|
||||
JacksonMapper.getDefault().writeValueAsString(resourceData));
|
||||
} catch (JsonProcessingException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
@@ -111,7 +130,6 @@ public final class McpResources {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public static McpServerFeatures.SyncResourceSpecification categories() {
|
||||
McpSchema.Annotations annotations = new McpSchema.Annotations(List.of(McpSchema.Role.ASSISTANT), 0.3);
|
||||
var resource = McpSchema.Resource.builder()
|
||||
@@ -134,7 +152,9 @@ public final class McpResources {
|
||||
|
||||
McpSchema.TextResourceContents c;
|
||||
try {
|
||||
c = new McpSchema.TextResourceContents("xpipe://categories/" + cat.getUuid(), "application/json",
|
||||
c = new McpSchema.TextResourceContents(
|
||||
"xpipe://categories/" + cat.getUuid(),
|
||||
"application/json",
|
||||
JacksonMapper.getDefault().writeValueAsString(jsonData));
|
||||
} catch (JsonProcessingException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package io.xpipe.app.beacon.mcp;
|
||||
|
||||
import io.modelcontextprotocol.spec.McpSchema;
|
||||
import io.xpipe.core.JacksonMapper;
|
||||
|
||||
import io.modelcontextprotocol.spec.McpSchema;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package io.xpipe.app.beacon.mcp;
|
||||
|
||||
import io.modelcontextprotocol.server.McpSyncServerExchange;
|
||||
import io.modelcontextprotocol.spec.McpSchema;
|
||||
import io.xpipe.app.ext.ShellStore;
|
||||
import io.xpipe.app.issue.ErrorEventFactory;
|
||||
import io.xpipe.app.storage.DataStorage;
|
||||
@@ -10,25 +8,30 @@ import io.xpipe.app.storage.DataStoreEntry;
|
||||
import io.xpipe.app.storage.DataStoreEntryRef;
|
||||
import io.xpipe.beacon.BeaconClientException;
|
||||
import io.xpipe.core.FilePath;
|
||||
|
||||
import io.modelcontextprotocol.server.McpSyncServerExchange;
|
||||
import io.modelcontextprotocol.spec.McpSchema;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
public interface McpToolHandler extends BiFunction<McpSyncServerExchange, McpSchema.CallToolRequest, McpSchema.CallToolResult>{
|
||||
public interface McpToolHandler
|
||||
extends BiFunction<McpSyncServerExchange, McpSchema.CallToolRequest, McpSchema.CallToolResult> {
|
||||
|
||||
static McpToolHandler of(McpToolHandler t) {
|
||||
return t;
|
||||
}
|
||||
|
||||
class ToolRequest {
|
||||
class ToolRequest {
|
||||
|
||||
protected final McpSyncServerExchange exchange;
|
||||
protected final McpSchema.CallToolRequest request;
|
||||
|
||||
public ToolRequest(McpSyncServerExchange exchange, McpSchema.CallToolRequest request) {
|
||||
this.exchange = exchange;
|
||||
this.request = request;}
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
public McpSchema.CallToolRequest getRawRequest() {
|
||||
return request;
|
||||
@@ -114,8 +117,8 @@ public interface McpToolHandler extends BiFunction<McpSyncServerExchange, McpSch
|
||||
var ref = getDataStoreRef(name);
|
||||
var isShell = ref.getStore() instanceof ShellStore;
|
||||
if (!isShell) {
|
||||
throw new BeaconClientException(
|
||||
"Connection " + DataStorage.get().getStorePath(ref.get()).toString() + " is not a shell connection");
|
||||
throw new BeaconClientException("Connection "
|
||||
+ DataStorage.get().getStorePath(ref.get()).toString() + " is not a shell connection");
|
||||
}
|
||||
|
||||
return ref.asNeeded();
|
||||
@@ -124,16 +127,23 @@ public interface McpToolHandler extends BiFunction<McpSyncServerExchange, McpSch
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
default McpSchema.CallToolResult apply(McpSyncServerExchange mcpSyncServerExchange, McpSchema.CallToolRequest callToolRequest) {
|
||||
default McpSchema.CallToolResult apply(
|
||||
McpSyncServerExchange mcpSyncServerExchange, McpSchema.CallToolRequest callToolRequest) {
|
||||
var req = new ToolRequest(mcpSyncServerExchange, callToolRequest);
|
||||
try {
|
||||
return handle(req);
|
||||
} catch (BeaconClientException e) {
|
||||
ErrorEventFactory.fromThrowable(e).expected().omit().handle();
|
||||
return McpSchema.CallToolResult.builder().addTextContent(e.getMessage()).isError(true).build();
|
||||
return McpSchema.CallToolResult.builder()
|
||||
.addTextContent(e.getMessage())
|
||||
.isError(true)
|
||||
.build();
|
||||
} catch (Throwable e) {
|
||||
ErrorEventFactory.fromThrowable(e).handle();
|
||||
return McpSchema.CallToolResult.builder().addTextContent(e.getMessage()).isError(true).build();
|
||||
return McpSchema.CallToolResult.builder()
|
||||
.addTextContent(e.getMessage())
|
||||
.isError(true)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
package io.xpipe.app.beacon.mcp;
|
||||
|
||||
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
|
||||
import io.modelcontextprotocol.server.McpServerFeatures;
|
||||
import io.modelcontextprotocol.spec.McpSchema;
|
||||
import io.xpipe.app.beacon.AppBeaconServer;
|
||||
import io.xpipe.app.core.AppExtensionManager;
|
||||
import io.xpipe.app.ext.ConnectionFileSystem;
|
||||
@@ -20,6 +17,10 @@ import io.xpipe.core.FileInfo;
|
||||
import io.xpipe.core.FilePath;
|
||||
import io.xpipe.core.JacksonMapper;
|
||||
|
||||
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
|
||||
import io.modelcontextprotocol.server.McpServerFeatures;
|
||||
import io.modelcontextprotocol.spec.McpSchema;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -29,273 +30,346 @@ public final class McpTools {
|
||||
|
||||
public static McpServerFeatures.SyncToolSpecification readFile() throws IOException {
|
||||
var tool = McpSchemaFiles.loadTool("read_file.json");
|
||||
return McpServerFeatures.SyncToolSpecification.builder().tool(tool).callHandler(McpToolHandler.of((req) -> {
|
||||
var path = req.getFilePath("path");
|
||||
var system = req.getStringArgument("system");
|
||||
var shellStore = req.getShellStoreRef(system);
|
||||
var shellSession = AppBeaconServer.get().getCache().getOrStart(shellStore);
|
||||
var fs = new ConnectionFileSystem(shellSession.getControl());
|
||||
return McpServerFeatures.SyncToolSpecification.builder()
|
||||
.tool(tool)
|
||||
.callHandler(McpToolHandler.of((req) -> {
|
||||
var path = req.getFilePath("path");
|
||||
var system = req.getStringArgument("system");
|
||||
var shellStore = req.getShellStoreRef(system);
|
||||
var shellSession = AppBeaconServer.get().getCache().getOrStart(shellStore);
|
||||
var fs = new ConnectionFileSystem(shellSession.getControl());
|
||||
|
||||
if (!fs.fileExists(path)) {
|
||||
throw new BeaconClientException("File " + path + " does not exist");
|
||||
}
|
||||
if (!fs.fileExists(path)) {
|
||||
throw new BeaconClientException("File " + path + " does not exist");
|
||||
}
|
||||
|
||||
try (var in = fs.openInput(path)) {
|
||||
var b = in.readAllBytes();
|
||||
var s = new String(b, StandardCharsets.UTF_8);
|
||||
return McpSchema.CallToolResult.builder().addTextContent(s).build();
|
||||
}
|
||||
})).build();
|
||||
try (var in = fs.openInput(path)) {
|
||||
var b = in.readAllBytes();
|
||||
var s = new String(b, StandardCharsets.UTF_8);
|
||||
return McpSchema.CallToolResult.builder()
|
||||
.addTextContent(s)
|
||||
.build();
|
||||
}
|
||||
}))
|
||||
.build();
|
||||
}
|
||||
|
||||
public static McpServerFeatures.SyncToolSpecification listFiles() throws IOException {
|
||||
var tool = McpSchemaFiles.loadTool("list_files.json");
|
||||
return McpServerFeatures.SyncToolSpecification.builder().tool(tool).callHandler(McpToolHandler.of((req) -> {
|
||||
var path = req.getFilePath("path");
|
||||
var system = req.getStringArgument("system");
|
||||
var recursive = req.getOptionalBooleanArgument("recursive").orElse(false);
|
||||
var shellStore = req.getShellStoreRef(system);
|
||||
var shellSession = AppBeaconServer.get().getCache().getOrStart(shellStore);
|
||||
var fs = new ConnectionFileSystem(shellSession.getControl());
|
||||
return McpServerFeatures.SyncToolSpecification.builder()
|
||||
.tool(tool)
|
||||
.callHandler(McpToolHandler.of((req) -> {
|
||||
var path = req.getFilePath("path");
|
||||
var system = req.getStringArgument("system");
|
||||
var recursive = req.getOptionalBooleanArgument("recursive").orElse(false);
|
||||
var shellStore = req.getShellStoreRef(system);
|
||||
var shellSession = AppBeaconServer.get().getCache().getOrStart(shellStore);
|
||||
var fs = new ConnectionFileSystem(shellSession.getControl());
|
||||
|
||||
if (!fs.directoryExists(path)) {
|
||||
throw new BeaconClientException("Directory " + path + " does not exist");
|
||||
}
|
||||
if (!fs.directoryExists(path)) {
|
||||
throw new BeaconClientException("Directory " + path + " does not exist");
|
||||
}
|
||||
|
||||
try (var stream = recursive ? fs.listFilesRecursively(fs, path) : fs.listFiles(fs, path)) {
|
||||
var list = stream.toList();
|
||||
var builder = McpSchema.CallToolResult.builder();
|
||||
for (FileEntry e : list) {
|
||||
builder.addTextContent(e.getPath().toString());
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
})).build();
|
||||
try (var stream = recursive ? fs.listFilesRecursively(fs, path) : fs.listFiles(fs, path)) {
|
||||
var list = stream.toList();
|
||||
var builder = McpSchema.CallToolResult.builder();
|
||||
for (FileEntry e : list) {
|
||||
builder.addTextContent(e.getPath().toString());
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
}))
|
||||
.build();
|
||||
}
|
||||
|
||||
public static McpServerFeatures.SyncToolSpecification findFile() throws IOException {
|
||||
var tool = McpSchemaFiles.loadTool("find_file.json");
|
||||
return McpServerFeatures.SyncToolSpecification.builder().tool(tool).callHandler(McpToolHandler.of((req) -> {
|
||||
var path = req.getFilePath("path");
|
||||
var system = req.getStringArgument("system");
|
||||
var recursive = req.getOptionalBooleanArgument("recursive").orElse(false);
|
||||
var pattern = req.getStringArgument("name");
|
||||
var shellStore = req.getShellStoreRef(system);
|
||||
var shellSession = AppBeaconServer.get().getCache().getOrStart(shellStore);
|
||||
var fs = new ConnectionFileSystem(shellSession.getControl());
|
||||
return McpServerFeatures.SyncToolSpecification.builder()
|
||||
.tool(tool)
|
||||
.callHandler(McpToolHandler.of((req) -> {
|
||||
var path = req.getFilePath("path");
|
||||
var system = req.getStringArgument("system");
|
||||
var recursive = req.getOptionalBooleanArgument("recursive").orElse(false);
|
||||
var pattern = req.getStringArgument("name");
|
||||
var shellStore = req.getShellStoreRef(system);
|
||||
var shellSession = AppBeaconServer.get().getCache().getOrStart(shellStore);
|
||||
var fs = new ConnectionFileSystem(shellSession.getControl());
|
||||
|
||||
if (!fs.directoryExists(path)) {
|
||||
throw new BeaconClientException("Directory " + path + " does not exist");
|
||||
}
|
||||
if (!fs.directoryExists(path)) {
|
||||
throw new BeaconClientException("Directory " + path + " does not exist");
|
||||
}
|
||||
|
||||
var regex = Pattern.compile(DataStorageQuery.toRegex(pattern));
|
||||
try (var stream = recursive ? fs.listFilesRecursively(fs, path) : fs.listFiles(fs, path)) {
|
||||
var list = stream.toList();
|
||||
var builder = McpSchema.CallToolResult.builder();
|
||||
list.stream().filter(fileEntry -> regex.matcher(fileEntry.getPath().toString()).find()).forEach(fileEntry -> {
|
||||
builder.addTextContent(fileEntry.getPath().toString());
|
||||
});
|
||||
return builder.build();
|
||||
}
|
||||
})).build();
|
||||
var regex = Pattern.compile(DataStorageQuery.toRegex(pattern));
|
||||
try (var stream = recursive ? fs.listFilesRecursively(fs, path) : fs.listFiles(fs, path)) {
|
||||
var list = stream.toList();
|
||||
var builder = McpSchema.CallToolResult.builder();
|
||||
list.stream()
|
||||
.filter(fileEntry -> regex.matcher(
|
||||
fileEntry.getPath().toString())
|
||||
.find())
|
||||
.forEach(fileEntry -> {
|
||||
builder.addTextContent(fileEntry.getPath().toString());
|
||||
});
|
||||
return builder.build();
|
||||
}
|
||||
}))
|
||||
.build();
|
||||
}
|
||||
|
||||
public static McpServerFeatures.SyncToolSpecification getFileInfo() throws IOException {
|
||||
var tool = McpSchemaFiles.loadTool("get_file_info.json");
|
||||
return McpServerFeatures.SyncToolSpecification.builder().tool(tool).callHandler(McpToolHandler.of((req) -> {
|
||||
var path = req.getFilePath("path");
|
||||
var system = req.getStringArgument("system");
|
||||
var shellStore = req.getShellStoreRef(system);
|
||||
var shellSession = AppBeaconServer.get().getCache().getOrStart(shellStore);
|
||||
var fs = new ConnectionFileSystem(shellSession.getControl());
|
||||
return McpServerFeatures.SyncToolSpecification.builder()
|
||||
.tool(tool)
|
||||
.callHandler(McpToolHandler.of((req) -> {
|
||||
var path = req.getFilePath("path");
|
||||
var system = req.getStringArgument("system");
|
||||
var shellStore = req.getShellStoreRef(system);
|
||||
var shellSession = AppBeaconServer.get().getCache().getOrStart(shellStore);
|
||||
var fs = new ConnectionFileSystem(shellSession.getControl());
|
||||
|
||||
if (!fs.fileExists(path)) {
|
||||
throw new BeaconClientException("File " + path + " does not exist");
|
||||
}
|
||||
if (!fs.fileExists(path)) {
|
||||
throw new BeaconClientException("File " + path + " does not exist");
|
||||
}
|
||||
|
||||
var entry = fs.getFileInfo(path);
|
||||
if (entry.isEmpty()) {
|
||||
throw new BeaconClientException("File " + path + " does not exist");
|
||||
}
|
||||
var entry = fs.getFileInfo(path);
|
||||
if (entry.isEmpty()) {
|
||||
throw new BeaconClientException("File " + path + " does not exist");
|
||||
}
|
||||
|
||||
var map = new LinkedHashMap<String, Object>();
|
||||
map.put("path", entry.get().getPath().toString());
|
||||
map.put("size", entry.get().getSize());
|
||||
if (entry.get().getInfo() instanceof FileInfo.Unix u) {
|
||||
map.put("permissions", u.getPermissions());
|
||||
map.put("user", u.getUser());
|
||||
map.put("group", u.getGroup());
|
||||
} else if (entry.get().getInfo() instanceof FileInfo.Windows w) {
|
||||
map.put("attributes", w.getAttributes());
|
||||
}
|
||||
map.put("type", entry.get().getKind().toString().toLowerCase());
|
||||
map.put("date", entry.get().getDate().toString());
|
||||
map.entrySet().removeIf(e -> e.getValue() == null);
|
||||
var map = new LinkedHashMap<String, Object>();
|
||||
map.put("path", entry.get().getPath().toString());
|
||||
map.put("size", entry.get().getSize());
|
||||
if (entry.get().getInfo() instanceof FileInfo.Unix u) {
|
||||
map.put("permissions", u.getPermissions());
|
||||
map.put("user", u.getUser());
|
||||
map.put("group", u.getGroup());
|
||||
} else if (entry.get().getInfo() instanceof FileInfo.Windows w) {
|
||||
map.put("attributes", w.getAttributes());
|
||||
}
|
||||
map.put("type", entry.get().getKind().toString().toLowerCase());
|
||||
map.put("date", entry.get().getDate().toString());
|
||||
map.entrySet().removeIf(e -> e.getValue() == null);
|
||||
|
||||
return McpSchema.CallToolResult.builder().structuredContent(map).build();
|
||||
})).build();
|
||||
return McpSchema.CallToolResult.builder()
|
||||
.structuredContent(map)
|
||||
.build();
|
||||
}))
|
||||
.build();
|
||||
}
|
||||
|
||||
public static McpServerFeatures.SyncToolSpecification createFile() throws IOException {
|
||||
var tool = McpSchemaFiles.loadTool("create_file.json");
|
||||
return McpServerFeatures.SyncToolSpecification.builder().tool(tool).callHandler(McpToolHandler.of((req) -> {
|
||||
var path = req.getFilePath("path");
|
||||
var system = req.getStringArgument("system");
|
||||
var shellStore = req.getShellStoreRef(system);
|
||||
var shellSession = AppBeaconServer.get().getCache().getOrStart(shellStore);
|
||||
var fs = new ConnectionFileSystem(shellSession.getControl());
|
||||
return McpServerFeatures.SyncToolSpecification.builder()
|
||||
.tool(tool)
|
||||
.callHandler(McpToolHandler.of((req) -> {
|
||||
var path = req.getFilePath("path");
|
||||
var system = req.getStringArgument("system");
|
||||
var shellStore = req.getShellStoreRef(system);
|
||||
var shellSession = AppBeaconServer.get().getCache().getOrStart(shellStore);
|
||||
var fs = new ConnectionFileSystem(shellSession.getControl());
|
||||
|
||||
if (fs.fileExists(path)) {
|
||||
throw new BeaconClientException("File " + path + " does already exist");
|
||||
}
|
||||
if (fs.fileExists(path)) {
|
||||
throw new BeaconClientException("File " + path + " does already exist");
|
||||
}
|
||||
|
||||
fs.touch(path);
|
||||
fs.touch(path);
|
||||
|
||||
if (req.getRawRequest().arguments().containsKey("content")) {
|
||||
var s = req.getRawRequest().arguments().get("content").toString();
|
||||
var b = s.getBytes(StandardCharsets.UTF_8);
|
||||
try (var out = fs.openOutput(path, b.length)) {
|
||||
out.write(b);
|
||||
}
|
||||
}
|
||||
if (req.getRawRequest().arguments().containsKey("content")) {
|
||||
var s = req.getRawRequest().arguments().get("content").toString();
|
||||
var b = s.getBytes(StandardCharsets.UTF_8);
|
||||
try (var out = fs.openOutput(path, b.length)) {
|
||||
out.write(b);
|
||||
}
|
||||
}
|
||||
|
||||
return McpSchema.CallToolResult.builder().addTextContent("File created successfully").build();
|
||||
})).build();
|
||||
return McpSchema.CallToolResult.builder()
|
||||
.addTextContent("File created successfully")
|
||||
.build();
|
||||
}))
|
||||
.build();
|
||||
}
|
||||
|
||||
public static McpServerFeatures.SyncToolSpecification writeFile() throws IOException {
|
||||
var tool = McpSchemaFiles.loadTool("write_file.json");
|
||||
return McpServerFeatures.SyncToolSpecification.builder().tool(tool).callHandler(McpToolHandler.of((req) -> {
|
||||
var path = req.getFilePath("path");
|
||||
var system = req.getStringArgument("system");
|
||||
var content = req.getStringArgument("content");
|
||||
var shellStore = req.getShellStoreRef(system);
|
||||
var shellSession = AppBeaconServer.get().getCache().getOrStart(shellStore);
|
||||
var fs = new ConnectionFileSystem(shellSession.getControl());
|
||||
return McpServerFeatures.SyncToolSpecification.builder()
|
||||
.tool(tool)
|
||||
.callHandler(McpToolHandler.of((req) -> {
|
||||
var path = req.getFilePath("path");
|
||||
var system = req.getStringArgument("system");
|
||||
var content = req.getStringArgument("content");
|
||||
var shellStore = req.getShellStoreRef(system);
|
||||
var shellSession = AppBeaconServer.get().getCache().getOrStart(shellStore);
|
||||
var fs = new ConnectionFileSystem(shellSession.getControl());
|
||||
|
||||
var b = content.getBytes(StandardCharsets.UTF_8);
|
||||
try (var out = fs.openOutput(path, b.length)) {
|
||||
out.write(b);
|
||||
}
|
||||
var b = content.getBytes(StandardCharsets.UTF_8);
|
||||
try (var out = fs.openOutput(path, b.length)) {
|
||||
out.write(b);
|
||||
}
|
||||
|
||||
return McpSchema.CallToolResult.builder().addTextContent("File written successfully").build();
|
||||
})).build();
|
||||
return McpSchema.CallToolResult.builder()
|
||||
.addTextContent("File written successfully")
|
||||
.build();
|
||||
}))
|
||||
.build();
|
||||
}
|
||||
|
||||
public static McpServerFeatures.SyncToolSpecification createDirectory() throws IOException {
|
||||
var tool = McpSchemaFiles.loadTool("create_directory.json");
|
||||
return McpServerFeatures.SyncToolSpecification.builder().tool(tool).callHandler(McpToolHandler.of((req) -> {
|
||||
var path = req.getFilePath("path");
|
||||
var system = req.getStringArgument("system");
|
||||
var shellStore = req.getShellStoreRef(system);
|
||||
var shellSession = AppBeaconServer.get().getCache().getOrStart(shellStore);
|
||||
var fs = new ConnectionFileSystem(shellSession.getControl());
|
||||
return McpServerFeatures.SyncToolSpecification.builder()
|
||||
.tool(tool)
|
||||
.callHandler(McpToolHandler.of((req) -> {
|
||||
var path = req.getFilePath("path");
|
||||
var system = req.getStringArgument("system");
|
||||
var shellStore = req.getShellStoreRef(system);
|
||||
var shellSession = AppBeaconServer.get().getCache().getOrStart(shellStore);
|
||||
var fs = new ConnectionFileSystem(shellSession.getControl());
|
||||
|
||||
if (fs.fileExists(path)) {
|
||||
throw new BeaconClientException("Directory " + path + " does already exist");
|
||||
}
|
||||
if (fs.fileExists(path)) {
|
||||
throw new BeaconClientException("Directory " + path + " does already exist");
|
||||
}
|
||||
|
||||
fs.mkdirs(path);
|
||||
fs.mkdirs(path);
|
||||
|
||||
return McpSchema.CallToolResult.builder().addTextContent("Directory created successfully").build();
|
||||
})).build();
|
||||
return McpSchema.CallToolResult.builder()
|
||||
.addTextContent("Directory created successfully")
|
||||
.build();
|
||||
}))
|
||||
.build();
|
||||
}
|
||||
|
||||
public static McpServerFeatures.SyncToolSpecification runCommand() throws IOException {
|
||||
var tool = McpSchemaFiles.loadTool("run_command.json");
|
||||
return McpServerFeatures.SyncToolSpecification.builder().tool(tool).callHandler(McpToolHandler.of((req) -> {
|
||||
var command = req.getStringArgument("command");
|
||||
var system = req.getStringArgument("system");
|
||||
var shellStore = req.getShellStoreRef(system);
|
||||
var shellSession = AppBeaconServer.get().getCache().getOrStart(shellStore);
|
||||
return McpServerFeatures.SyncToolSpecification.builder()
|
||||
.tool(tool)
|
||||
.callHandler(McpToolHandler.of((req) -> {
|
||||
var command = req.getStringArgument("command");
|
||||
var system = req.getStringArgument("system");
|
||||
var shellStore = req.getShellStoreRef(system);
|
||||
var shellSession = AppBeaconServer.get().getCache().getOrStart(shellStore);
|
||||
|
||||
var out = shellSession.getControl().command(command).readStdoutOrThrow();
|
||||
var formatted = CommandDialog.formatOutput(out);
|
||||
var out = shellSession.getControl().command(command).readStdoutOrThrow();
|
||||
var formatted = CommandDialog.formatOutput(out);
|
||||
|
||||
return McpSchema.CallToolResult.builder().addTextContent(formatted).build();
|
||||
})).build();
|
||||
return McpSchema.CallToolResult.builder()
|
||||
.addTextContent(formatted)
|
||||
.build();
|
||||
}))
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
public static McpServerFeatures.SyncToolSpecification runScript() throws IOException {
|
||||
var tool = McpSchemaFiles.loadTool("run_script.json");
|
||||
return McpServerFeatures.SyncToolSpecification.builder().tool(tool).callHandler(McpToolHandler.of((req) -> {
|
||||
var system = req.getStringArgument("system");
|
||||
var script = req.getDataStoreRef("script");
|
||||
var directory = req.getFilePath("directory");
|
||||
var arguments = req.getStringArgument("arguments");
|
||||
return McpServerFeatures.SyncToolSpecification.builder()
|
||||
.tool(tool)
|
||||
.callHandler(McpToolHandler.of((req) -> {
|
||||
var system = req.getStringArgument("system");
|
||||
var script = req.getDataStoreRef("script");
|
||||
var directory = req.getFilePath("directory");
|
||||
var arguments = req.getStringArgument("arguments");
|
||||
|
||||
var shellStore = req.getShellStoreRef(system);
|
||||
var shellSession = AppBeaconServer.get().getCache().getOrStart(shellStore);
|
||||
var shellStore = req.getShellStoreRef(system);
|
||||
var shellSession = AppBeaconServer.get().getCache().getOrStart(shellStore);
|
||||
|
||||
var clazz = Class.forName(AppExtensionManager.getInstance().getExtendedLayer().findModule("io.xpipe.ext.base").orElseThrow(),
|
||||
"io.xpipe.ext.base.script.SimpleScriptStore");
|
||||
var method = clazz.getDeclaredMethod("assembleScriptChain", ShellControl.class);
|
||||
var command = (String) method.invoke(script.getStore(), shellSession.getControl());
|
||||
var scriptFile = ScriptHelper.createExecScript(shellSession.getControl(), command);
|
||||
var out = shellSession.getControl()
|
||||
.command(shellSession.getControl().getShellDialect()
|
||||
.runScriptCommand(shellSession.getControl(), scriptFile.toString()) + arguments)
|
||||
.withWorkingDirectory(directory).readStdoutOrThrow();
|
||||
var formatted = CommandDialog.formatOutput(out);
|
||||
var clazz = Class.forName(
|
||||
AppExtensionManager.getInstance()
|
||||
.getExtendedLayer()
|
||||
.findModule("io.xpipe.ext.base")
|
||||
.orElseThrow(),
|
||||
"io.xpipe.ext.base.script.SimpleScriptStore");
|
||||
var method = clazz.getDeclaredMethod("assembleScriptChain", ShellControl.class);
|
||||
var command = (String) method.invoke(script.getStore(), shellSession.getControl());
|
||||
var scriptFile = ScriptHelper.createExecScript(shellSession.getControl(), command);
|
||||
var out = shellSession
|
||||
.getControl()
|
||||
.command(shellSession
|
||||
.getControl()
|
||||
.getShellDialect()
|
||||
.runScriptCommand(shellSession.getControl(), scriptFile.toString())
|
||||
+ arguments)
|
||||
.withWorkingDirectory(directory)
|
||||
.readStdoutOrThrow();
|
||||
var formatted = CommandDialog.formatOutput(out);
|
||||
|
||||
return McpSchema.CallToolResult.builder().addTextContent(formatted).build();
|
||||
})).build();
|
||||
return McpSchema.CallToolResult.builder()
|
||||
.addTextContent(formatted)
|
||||
.build();
|
||||
}))
|
||||
.build();
|
||||
}
|
||||
|
||||
public static McpServerFeatures.SyncToolSpecification openTerminal() throws IOException {
|
||||
var tool = McpSchemaFiles.loadTool("open_terminal.json");
|
||||
return McpServerFeatures.SyncToolSpecification.builder().tool(tool).callHandler(McpToolHandler.of((req) -> {
|
||||
var system = req.getStringArgument("system");
|
||||
var directory = req.getOptionalStringArgument("directory");
|
||||
var shellStore = req.getShellStoreRef(system);
|
||||
var shellSession = AppBeaconServer.get().getCache().getOrStart(shellStore);
|
||||
return McpServerFeatures.SyncToolSpecification.builder()
|
||||
.tool(tool)
|
||||
.callHandler(McpToolHandler.of((req) -> {
|
||||
var system = req.getStringArgument("system");
|
||||
var directory = req.getOptionalStringArgument("directory");
|
||||
var shellStore = req.getShellStoreRef(system);
|
||||
var shellSession = AppBeaconServer.get().getCache().getOrStart(shellStore);
|
||||
|
||||
TerminalLaunch.builder()
|
||||
.entry(shellStore.get())
|
||||
.directory(FilePath.of(directory.orElse(null)))
|
||||
.command(shellSession.getControl())
|
||||
.launch();
|
||||
TerminalLaunch.builder()
|
||||
.entry(shellStore.get())
|
||||
.directory(FilePath.of(directory.orElse(null)))
|
||||
.command(shellSession.getControl())
|
||||
.launch();
|
||||
|
||||
return McpSchema.CallToolResult.builder().addTextContent("Terminal is launching").build();
|
||||
})).build();
|
||||
return McpSchema.CallToolResult.builder()
|
||||
.addTextContent("Terminal is launching")
|
||||
.build();
|
||||
}))
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
public static McpServerFeatures.SyncToolSpecification openTerminalInline() throws IOException {
|
||||
var tool = McpSchemaFiles.loadTool("open_terminal_inline.json");
|
||||
return McpServerFeatures.SyncToolSpecification.builder().tool(tool).callHandler(McpToolHandler.of((req) -> {
|
||||
var system = req.getStringArgument("system");
|
||||
var directory = req.getOptionalStringArgument("directory");
|
||||
var shellStore = req.getShellStoreRef(system);
|
||||
var shellSession = AppBeaconServer.get().getCache().getOrStart(shellStore);
|
||||
return McpServerFeatures.SyncToolSpecification.builder()
|
||||
.tool(tool)
|
||||
.callHandler(McpToolHandler.of((req) -> {
|
||||
var system = req.getStringArgument("system");
|
||||
var directory = req.getOptionalStringArgument("directory");
|
||||
var shellStore = req.getShellStoreRef(system);
|
||||
var shellSession = AppBeaconServer.get().getCache().getOrStart(shellStore);
|
||||
|
||||
var script = shellSession.getControl().prepareTerminalOpen(TerminalInitScriptConfig.ofName(shellStore.get().getName()), directory.isPresent() ?
|
||||
WorkingDirectoryFunction.fixed(FilePath.parse(directory.get())) : WorkingDirectoryFunction.none());
|
||||
var script = shellSession
|
||||
.getControl()
|
||||
.prepareTerminalOpen(
|
||||
TerminalInitScriptConfig.ofName(
|
||||
shellStore.get().getName()),
|
||||
directory.isPresent()
|
||||
? WorkingDirectoryFunction.fixed(FilePath.parse(directory.get()))
|
||||
: WorkingDirectoryFunction.none());
|
||||
|
||||
var json = JsonNodeFactory.instance.objectNode();
|
||||
json.put("command", script);
|
||||
return McpSchema.CallToolResult.builder().structuredContent(JacksonMapper.getDefault().writeValueAsString(json)).build();
|
||||
})).build();
|
||||
var json = JsonNodeFactory.instance.objectNode();
|
||||
json.put("command", script);
|
||||
return McpSchema.CallToolResult.builder()
|
||||
.structuredContent(JacksonMapper.getDefault().writeValueAsString(json))
|
||||
.build();
|
||||
}))
|
||||
.build();
|
||||
}
|
||||
|
||||
public static McpServerFeatures.SyncToolSpecification toggleState() throws IOException {
|
||||
var tool = McpSchemaFiles.loadTool("toggle_state.json");
|
||||
return McpServerFeatures.SyncToolSpecification.builder().tool(tool).callHandler(McpToolHandler.of((req) -> {
|
||||
var system = req.getStringArgument("system");
|
||||
var state = req.getBooleanArgument("state");
|
||||
var ref = req.getDataStoreRef(system);
|
||||
return McpServerFeatures.SyncToolSpecification.builder()
|
||||
.tool(tool)
|
||||
.callHandler(McpToolHandler.of((req) -> {
|
||||
var system = req.getStringArgument("system");
|
||||
var state = req.getBooleanArgument("state");
|
||||
var ref = req.getDataStoreRef(system);
|
||||
|
||||
if (!(ref.getStore() instanceof SingletonSessionStore<?> singletonSessionStore)) {
|
||||
throw new BeaconClientException("Not a toggleable connection");
|
||||
}
|
||||
if (state) {
|
||||
singletonSessionStore.startSessionIfNeeded();
|
||||
} else {
|
||||
singletonSessionStore.stopSessionIfNeeded();
|
||||
}
|
||||
if (!(ref.getStore() instanceof SingletonSessionStore<?> singletonSessionStore)) {
|
||||
throw new BeaconClientException("Not a toggleable connection");
|
||||
}
|
||||
if (state) {
|
||||
singletonSessionStore.startSessionIfNeeded();
|
||||
} else {
|
||||
singletonSessionStore.stopSessionIfNeeded();
|
||||
}
|
||||
|
||||
return McpSchema.CallToolResult.builder().addTextContent("Connection state set to " + state).build();
|
||||
})).build();
|
||||
return McpSchema.CallToolResult.builder()
|
||||
.addTextContent("Connection state set to " + state)
|
||||
.build();
|
||||
}))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,8 @@ public class BrowserAbstractSessionModel<T extends BrowserSessionTab> {
|
||||
}
|
||||
|
||||
public void openSync(T e, BooleanProperty externalBusy) throws Exception {
|
||||
try (var ignored = new BooleanScope(externalBusy != null ? externalBusy : new SimpleBooleanProperty()).start()) {
|
||||
try (var ignored =
|
||||
new BooleanScope(externalBusy != null ? externalBusy : new SimpleBooleanProperty()).start()) {
|
||||
e.init();
|
||||
// Prevent multiple calls from interfering with each other
|
||||
synchronized (this) {
|
||||
|
||||
@@ -89,7 +89,8 @@ public class BrowserFileChooserSessionModel extends BrowserAbstractSessionModel<
|
||||
ThreadHelper.runFailableAsync(() -> {
|
||||
BrowserFileSystemTabModel model;
|
||||
|
||||
try (var ignored = new BooleanScope(externalBusy != null ? externalBusy : new SimpleBooleanProperty()).start()) {
|
||||
try (var ignored =
|
||||
new BooleanScope(externalBusy != null ? externalBusy : new SimpleBooleanProperty()).start()) {
|
||||
model = new BrowserFileSystemTabModel(this, store, selectionMode);
|
||||
model.init();
|
||||
// Prevent multiple calls from interfering with each other
|
||||
|
||||
@@ -221,7 +221,8 @@ public class BrowserFullSessionModel extends BrowserAbstractSessionModel<Browser
|
||||
boolean select)
|
||||
throws Exception {
|
||||
BrowserFileSystemTabModel model;
|
||||
try (var ignored = new BooleanScope(externalBusy != null ? externalBusy : new SimpleBooleanProperty()).start()) {
|
||||
try (var ignored =
|
||||
new BooleanScope(externalBusy != null ? externalBusy : new SimpleBooleanProperty()).start()) {
|
||||
try (var ignored2 = new BooleanScope(busy).exclusive().start()) {
|
||||
model = new BrowserFileSystemTabModel(this, store, BrowserFileSystemTabModel.SelectionMode.ALL);
|
||||
model.init();
|
||||
|
||||
@@ -4,8 +4,8 @@ import io.xpipe.app.ext.FileEntry;
|
||||
import io.xpipe.app.ext.ProcessControlProvider;
|
||||
import io.xpipe.app.issue.ErrorEventFactory;
|
||||
import io.xpipe.app.util.GlobalClipboard;
|
||||
|
||||
import io.xpipe.app.util.GlobalObjectProperty;
|
||||
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.scene.input.ClipboardContent;
|
||||
import javafx.scene.input.DataFormat;
|
||||
|
||||
@@ -62,9 +62,10 @@ public final class BrowserFileSystemTabModel extends BrowserStoreSessionTab<File
|
||||
private BrowserFileSystemCache cache;
|
||||
|
||||
private final Property<BrowserTransferProgress> progress = new SimpleObjectProperty<>();
|
||||
private final ObservableList<BrowserTransferProgress> progressesIntervalHistory = FXCollections.observableArrayList();
|
||||
private final LongProperty progressTransferSpeed = new SimpleLongProperty();
|
||||
private final Property<Duration> progressRemaining = new SimpleObjectProperty<>();
|
||||
private final ObservableList<BrowserTransferProgress> progressesIntervalHistory =
|
||||
FXCollections.observableArrayList();
|
||||
private final LongProperty progressTransferSpeed = new SimpleLongProperty();
|
||||
private final Property<Duration> progressRemaining = new SimpleObjectProperty<>();
|
||||
|
||||
public BrowserFileSystemTabModel(
|
||||
BrowserAbstractSessionModel<?> model,
|
||||
@@ -89,7 +90,9 @@ public final class BrowserFileSystemTabModel extends BrowserStoreSessionTab<File
|
||||
|
||||
var changedHistory = false;
|
||||
if (progress.getValue() != null) {
|
||||
var last = progressesIntervalHistory.isEmpty() ? Instant.EPOCH : progressesIntervalHistory.getLast().getTimestamp();
|
||||
var last = progressesIntervalHistory.isEmpty()
|
||||
? Instant.EPOCH
|
||||
: progressesIntervalHistory.getLast().getTimestamp();
|
||||
var elapsed = Duration.between(last, n.getTimestamp());
|
||||
if (elapsed.toMillis() >= 1000) {
|
||||
progressesIntervalHistory.add(progress.getValue());
|
||||
@@ -109,7 +112,8 @@ public final class BrowserFileSystemTabModel extends BrowserStoreSessionTab<File
|
||||
var estimate = remaining / (double) speed;
|
||||
|
||||
var newDuration = Duration.ofMillis((long) (estimate * 1000.0));
|
||||
var smooth = progressRemaining.getValue() != null && progressRemaining.getValue().toSeconds() + 1 == newDuration.toSeconds();
|
||||
var smooth = progressRemaining.getValue() != null
|
||||
&& progressRemaining.getValue().toSeconds() + 1 == newDuration.toSeconds();
|
||||
if (!smooth) {
|
||||
progressRemaining.setValue(newDuration);
|
||||
}
|
||||
@@ -522,7 +526,14 @@ public final class BrowserFileSystemTabModel extends BrowserStoreSessionTab<File
|
||||
&& !(fullSessionModel.getSplits().get(this) instanceof BrowserTerminalDockTabModel)) {
|
||||
fullSessionModel.splitTab(this, new BrowserTerminalDockTabModel(browserModel, this, terminalRequests));
|
||||
}
|
||||
TerminalLaunch.builder().entry(entry.get()).title(name).directory(directory).command(processControl).request(uuid).preferTabs(!dock).launch();
|
||||
TerminalLaunch.builder()
|
||||
.entry(entry.get())
|
||||
.title(name)
|
||||
.directory(directory)
|
||||
.command(processControl)
|
||||
.request(uuid)
|
||||
.preferTabs(!dock)
|
||||
.launch();
|
||||
|
||||
// Restart connection as we will have to start it anyway, so we speed it up by doing it preemptively
|
||||
startIfNeeded();
|
||||
|
||||
@@ -286,7 +286,11 @@ public class BrowserFileTransferOperation {
|
||||
return;
|
||||
}
|
||||
|
||||
var rel = fileEntry.getPath().relativize(baseRelative).toUnix().toString();
|
||||
var rel = fileEntry
|
||||
.getPath()
|
||||
.relativize(baseRelative)
|
||||
.toUnix()
|
||||
.toString();
|
||||
flatFiles.put(fileEntry, rel);
|
||||
if (fileEntry.getKind() == FileKind.FILE) {
|
||||
// This one is up-to-date and does not need to be recalculated
|
||||
@@ -347,13 +351,7 @@ public class BrowserFileTransferOperation {
|
||||
}
|
||||
}
|
||||
|
||||
transfer(
|
||||
sourceFile.getPath(),
|
||||
optimizedSourceFs,
|
||||
targetFile,
|
||||
targetFs,
|
||||
transferred,
|
||||
totalSize);
|
||||
transfer(sourceFile.getPath(), optimizedSourceFs, targetFile, targetFs, transferred, totalSize);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
@@ -503,8 +501,8 @@ public class BrowserFileTransferOperation {
|
||||
outputStream.write(buffer, 0, read);
|
||||
transferred.addAndGet(read);
|
||||
readCount.addAndGet(read);
|
||||
updateProgress(new BrowserTransferProgress(
|
||||
sourceFile.getFileName(), transferred.get(), total.get()));
|
||||
updateProgress(
|
||||
new BrowserTransferProgress(sourceFile.getFileName(), transferred.get(), total.get()));
|
||||
}
|
||||
|
||||
outputStream.flush();
|
||||
|
||||
@@ -79,23 +79,28 @@ public class BrowserStatusBarComp extends SimpleComp {
|
||||
}
|
||||
|
||||
private Comp<?> createProgressEstimateStatus() {
|
||||
var text = Bindings.createStringBinding(() -> {
|
||||
var p = model.getProgress().getValue();
|
||||
var expected = model.getProgressRemaining().getValue();
|
||||
if (p == null || expected == null) {
|
||||
return null;
|
||||
}
|
||||
var text = Bindings.createStringBinding(
|
||||
() -> {
|
||||
var p = model.getProgress().getValue();
|
||||
var expected = model.getProgressRemaining().getValue();
|
||||
if (p == null || expected == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var elapsed = (p.getTotal() - p.getTransferred() / (double) p.getTotal()) * expected.toMillis();
|
||||
var show = elapsed > 3000;
|
||||
if (!show) {
|
||||
return "...";
|
||||
}
|
||||
var elapsed = (p.getTotal() - p.getTransferred() / (double) p.getTotal()) * expected.toMillis();
|
||||
var show = elapsed > 3000;
|
||||
if (!show) {
|
||||
return "...";
|
||||
}
|
||||
|
||||
var time = HumanReadableFormat.duration(expected) + " @ ";
|
||||
var progress = HumanReadableFormat.transferSpeed(model.getProgressTransferSpeed().getValue());
|
||||
return time + progress;
|
||||
}, model.getProgressRemaining(), model.getProgressTransferSpeed(), model.getProgress());
|
||||
var time = HumanReadableFormat.duration(expected) + " @ ";
|
||||
var progress = HumanReadableFormat.transferSpeed(
|
||||
model.getProgressTransferSpeed().getValue());
|
||||
return time + progress;
|
||||
},
|
||||
model.getProgressRemaining(),
|
||||
model.getProgressTransferSpeed(),
|
||||
model.getProgress());
|
||||
|
||||
var progressComp = new LabelComp(text)
|
||||
.styleClass("progress")
|
||||
|
||||
@@ -35,8 +35,13 @@ public abstract class MultiExecuteMenuProvider implements BrowserMenuBranchProvi
|
||||
}
|
||||
|
||||
var cmd = sc.command(c);
|
||||
model.openTerminalAsync(entry.getRawFileEntry().getName(),
|
||||
model.getCurrentDirectory() != null ? model.getCurrentDirectory().getPath() : null, cmd, entries.size() == 1);
|
||||
model.openTerminalAsync(
|
||||
entry.getRawFileEntry().getName(),
|
||||
model.getCurrentDirectory() != null
|
||||
? model.getCurrentDirectory().getPath()
|
||||
: null,
|
||||
cmd,
|
||||
entries.size() == 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -56,14 +56,16 @@ public class ButtonComp extends Comp<CompStructure<Button>> {
|
||||
var n = t.createGraphicNode();
|
||||
button.setGraphic(n);
|
||||
if (n instanceof FontIcon f && button.getFont() != null) {
|
||||
f.iconSizeProperty().bind(new ReadOnlyIntegerWrapper((int) new Size(button.getFont().getSize(), SizeUnits.PT).pixels()));
|
||||
f.iconSizeProperty().bind(new ReadOnlyIntegerWrapper((int)
|
||||
new Size(button.getFont().getSize(), SizeUnits.PT).pixels()));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
button.fontProperty().subscribe(c -> {
|
||||
if (button.getGraphic() instanceof FontIcon f) {
|
||||
f.iconSizeProperty().bind(new ReadOnlyIntegerWrapper((int) new Size(c.getSize(), SizeUnits.PT).pixels()));
|
||||
f.iconSizeProperty()
|
||||
.bind(new ReadOnlyIntegerWrapper((int) new Size(c.getSize(), SizeUnits.PT).pixels()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -29,7 +29,9 @@ public class ComboTextFieldComp extends Comp<CompStructure<ComboBox<String>>> {
|
||||
private ObservableValue<String> prompt;
|
||||
|
||||
public ComboTextFieldComp(
|
||||
Property<String> value, ObservableList<String> predefinedValues, Supplier<ListCell<String>> customCellFactory) {
|
||||
Property<String> value,
|
||||
ObservableList<String> predefinedValues,
|
||||
Supplier<ListCell<String>> customCellFactory) {
|
||||
this.value = value;
|
||||
this.predefinedValues = predefinedValues;
|
||||
this.customCellFactory = customCellFactory;
|
||||
|
||||
@@ -208,9 +208,11 @@ public class ContextualFileReferenceChoiceComp extends Comp<CompStructure<HBox>>
|
||||
}
|
||||
};
|
||||
});
|
||||
combo.setPrompt(Bindings.createStringBinding(() -> {
|
||||
return filePath.getValue() != null ? filePath.getValue().toString() : null;
|
||||
}, filePath));
|
||||
combo.setPrompt(Bindings.createStringBinding(
|
||||
() -> {
|
||||
return filePath.getValue() != null ? filePath.getValue().toString() : null;
|
||||
},
|
||||
filePath));
|
||||
combo.hgrow();
|
||||
combo.styleClass(Styles.LEFT_PILL);
|
||||
combo.grow(false, true);
|
||||
|
||||
@@ -54,7 +54,8 @@ public class DropdownComp extends Comp<CompStructure<Button>> {
|
||||
|
||||
var graphic = new FontIcon("mdi2c-chevron-double-down");
|
||||
button.fontProperty().subscribe(c -> {
|
||||
graphic.iconSizeProperty().bind(new ReadOnlyIntegerWrapper((int) new Size(c.getSize(), SizeUnits.PT).pixels()));
|
||||
graphic.iconSizeProperty()
|
||||
.bind(new ReadOnlyIntegerWrapper((int) new Size(c.getSize(), SizeUnits.PT).pixels()));
|
||||
});
|
||||
|
||||
button.setGraphic(graphic);
|
||||
|
||||
@@ -57,13 +57,15 @@ public class IconButtonComp extends Comp<CompStructure<Button>> {
|
||||
PlatformThread.runLaterIfNeeded(() -> {
|
||||
button.setGraphic(labelGraphic.createGraphicNode());
|
||||
if (button.getGraphic() instanceof FontIcon fi) {
|
||||
fi.iconSizeProperty().bind(new ReadOnlyIntegerWrapper((int) new Size(button.getFont().getSize(), SizeUnits.PT).pixels()));
|
||||
fi.iconSizeProperty().bind(new ReadOnlyIntegerWrapper((int)
|
||||
new Size(button.getFont().getSize(), SizeUnits.PT).pixels()));
|
||||
}
|
||||
});
|
||||
});
|
||||
button.fontProperty().subscribe((n) -> {
|
||||
if (button.getGraphic() instanceof FontIcon fi) {
|
||||
fi.iconSizeProperty().bind(new ReadOnlyIntegerWrapper((int) new Size(n.getSize(), SizeUnits.PT).pixels()));
|
||||
fi.iconSizeProperty()
|
||||
.bind(new ReadOnlyIntegerWrapper((int) new Size(n.getSize(), SizeUnits.PT).pixels()));
|
||||
}
|
||||
});
|
||||
if (listener != null) {
|
||||
|
||||
@@ -68,9 +68,10 @@ public class AppExtensionManager {
|
||||
|
||||
private void determineExtensionDirectories() throws Exception {
|
||||
if (!AppProperties.get().isFullVersion()) {
|
||||
var localInstallation = !AppProperties.get().isStaging() && AppProperties.get().isLocatePtb() ?
|
||||
AppInstallation.ofDefault(true)
|
||||
: AppInstallation.ofCurrent();
|
||||
var localInstallation =
|
||||
!AppProperties.get().isStaging() && AppProperties.get().isLocatePtb()
|
||||
? AppInstallation.ofDefault(true)
|
||||
: AppInstallation.ofCurrent();
|
||||
Path p = localInstallation.getBaseInstallationPath();
|
||||
if (!Files.exists(p)) {
|
||||
throw new IllegalStateException(
|
||||
|
||||
@@ -8,17 +8,25 @@ import java.nio.file.Path;
|
||||
|
||||
public abstract class AppInstallation {
|
||||
|
||||
private static final Windows WINDOWS = AppProperties.get().isImage() ?
|
||||
new Windows(determineCurrentInstallationBasePath()) :
|
||||
new WindowsDev(determineDefaultInstallationBasePath(AppProperties.get().isStaging()), determineCurrentInstallationBasePath());
|
||||
private static final Linux LINUX = AppProperties.get().isImage() ?
|
||||
new Linux(determineCurrentInstallationBasePath()) :
|
||||
new LinuxDev(determineDefaultInstallationBasePath(AppProperties.get().isStaging()), determineCurrentInstallationBasePath());
|
||||
private static final MacOs MACOS = AppProperties.get().isImage() ?
|
||||
new MacOs(determineCurrentInstallationBasePath()) :
|
||||
new MacOsDev(determineDefaultInstallationBasePath(AppProperties.get().isStaging()), determineCurrentInstallationBasePath());
|
||||
private static final Windows WINDOWS = AppProperties.get().isImage()
|
||||
? new Windows(determineCurrentInstallationBasePath())
|
||||
: new WindowsDev(
|
||||
determineDefaultInstallationBasePath(AppProperties.get().isStaging()),
|
||||
determineCurrentInstallationBasePath());
|
||||
private static final Linux LINUX = AppProperties.get().isImage()
|
||||
? new Linux(determineCurrentInstallationBasePath())
|
||||
: new LinuxDev(
|
||||
determineDefaultInstallationBasePath(AppProperties.get().isStaging()),
|
||||
determineCurrentInstallationBasePath());
|
||||
private static final MacOs MACOS = AppProperties.get().isImage()
|
||||
? new MacOs(determineCurrentInstallationBasePath())
|
||||
: new MacOsDev(
|
||||
determineDefaultInstallationBasePath(AppProperties.get().isStaging()),
|
||||
determineCurrentInstallationBasePath());
|
||||
|
||||
private AppInstallation(Path base) {this.base = base;}
|
||||
private AppInstallation(Path base) {
|
||||
this.base = base;
|
||||
}
|
||||
|
||||
public static AppInstallation ofCurrent() {
|
||||
return switch (OsType.getLocal()) {
|
||||
@@ -100,13 +108,13 @@ public abstract class AppInstallation {
|
||||
// Resolve root path of installation relative to executable in a JPackage installation
|
||||
return switch (OsType.getLocal()) {
|
||||
case OsType.Linux ignored -> {
|
||||
yield executable.getParent().getParent();
|
||||
yield executable.getParent().getParent();
|
||||
}
|
||||
case OsType.MacOs ignored -> {
|
||||
yield executable.getParent().getParent().getParent();
|
||||
yield executable.getParent().getParent().getParent();
|
||||
}
|
||||
case OsType.Windows ignored -> {
|
||||
yield executable.getParent();
|
||||
yield executable.getParent();
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -127,7 +135,7 @@ public abstract class AppInstallation {
|
||||
.getParent();
|
||||
}
|
||||
case OsType.Windows ignored -> {
|
||||
yield executable.getParent().getParent();
|
||||
yield executable.getParent().getParent();
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -150,15 +158,15 @@ public abstract class AppInstallation {
|
||||
|
||||
public abstract Path getDaemonDebugScriptPath();
|
||||
|
||||
public abstract Path getBundledFontsPath();
|
||||
public abstract Path getBundledFontsPath();
|
||||
|
||||
public abstract Path getLangPath();
|
||||
public abstract Path getLangPath();
|
||||
|
||||
public abstract Path getCliExecutablePath();
|
||||
public abstract Path getCliExecutablePath();
|
||||
|
||||
public abstract Path getDaemonExecutablePath();
|
||||
public abstract Path getDaemonExecutablePath();
|
||||
|
||||
public abstract Path getExtensionsPath();
|
||||
public abstract Path getExtensionsPath();
|
||||
|
||||
public abstract Path getLogoPath();
|
||||
|
||||
@@ -279,7 +287,6 @@ public abstract class AppInstallation {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class LinuxDev extends Linux {
|
||||
|
||||
private final Path devBase;
|
||||
@@ -300,7 +307,7 @@ public abstract class AppInstallation {
|
||||
}
|
||||
}
|
||||
|
||||
public static class MacOs extends AppInstallation {
|
||||
public static class MacOs extends AppInstallation {
|
||||
|
||||
private MacOs(Path base) {
|
||||
super(base);
|
||||
@@ -350,7 +357,10 @@ public abstract class AppInstallation {
|
||||
return getBaseInstallationPath().resolve("dist").resolve("logo").resolve("logo.icns");
|
||||
}
|
||||
|
||||
return getBaseInstallationPath().resolve("Contents").resolve("Resources").resolve("xpipe.icns");
|
||||
return getBaseInstallationPath()
|
||||
.resolve("Contents")
|
||||
.resolve("Resources")
|
||||
.resolve("xpipe.icns");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -87,11 +87,7 @@ public interface AppLocations {
|
||||
}
|
||||
}
|
||||
|
||||
class Linux implements AppLocations {
|
||||
class Linux implements AppLocations {}
|
||||
|
||||
}
|
||||
|
||||
final class MacOs implements AppLocations {
|
||||
|
||||
}
|
||||
final class MacOs implements AppLocations {}
|
||||
}
|
||||
|
||||
@@ -317,13 +317,14 @@ public class AppLogs {
|
||||
// Only change this when debugging the logs of other libraries
|
||||
return NOPLogger.NOP_LOGGER;
|
||||
|
||||
// // Don't use fully qualified class names
|
||||
// var normalizedName = FilenameUtils.getExtension(name);
|
||||
// if (normalizedName == null || normalizedName.isEmpty()) {
|
||||
// normalizedName = name;
|
||||
// }
|
||||
//
|
||||
// return loggers.computeIfAbsent(normalizedName, s -> new Slf4jLogger());
|
||||
// // Don't use fully qualified class names
|
||||
// var normalizedName = FilenameUtils.getExtension(name);
|
||||
// if (normalizedName == null || normalizedName.isEmpty()) {
|
||||
// normalizedName = name;
|
||||
// }
|
||||
//
|
||||
// return loggers.computeIfAbsent(normalizedName, s -> new
|
||||
// Slf4jLogger());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -43,7 +43,8 @@ public class AppRestart {
|
||||
if (OsType.getLocal() == OsType.LINUX) {
|
||||
return "nohup \"" + loc.getDaemonExecutablePath() + "\"" + suffix + " </dev/null >/dev/null 2>&1 & disown";
|
||||
} else if (OsType.getLocal() == OsType.MACOS) {
|
||||
return "(sleep 1;open \"" + loc.getBaseInstallationPath() + "\" --args" + suffix + " </dev/null &>/dev/null) & disown";
|
||||
return "(sleep 1;open \"" + loc.getBaseInstallationPath() + "\" --args" + suffix
|
||||
+ " </dev/null &>/dev/null) & disown";
|
||||
} else {
|
||||
var exe = loc.getDaemonExecutablePath();
|
||||
if (ShellDialects.isPowershell(dialect)) {
|
||||
|
||||
@@ -7,9 +7,7 @@ import java.nio.file.Path;
|
||||
|
||||
public class AppSystemInfo {
|
||||
|
||||
public static class Windows {
|
||||
|
||||
}
|
||||
public static class Windows {}
|
||||
|
||||
public static Linux linux() {
|
||||
if (OsType.getLocal() != OsType.LINUX) {
|
||||
@@ -26,7 +24,5 @@ public class AppSystemInfo {
|
||||
}
|
||||
}
|
||||
|
||||
public static class MacOS {
|
||||
|
||||
}
|
||||
public static class MacOS {}
|
||||
}
|
||||
|
||||
@@ -75,11 +75,7 @@ public abstract class AppShellChecker {
|
||||
|
||||
%s
|
||||
"""
|
||||
.formatted(
|
||||
LocalShell.getDialect().getDisplayName(),
|
||||
modifyOutput(output),
|
||||
listReasons(),
|
||||
fallback);
|
||||
.formatted(LocalShell.getDialect().getDisplayName(), modifyOutput(output), listReasons(), fallback);
|
||||
}
|
||||
|
||||
protected abstract String listReasons();
|
||||
|
||||
@@ -17,7 +17,8 @@ public class AppSystemFontCheck {
|
||||
}
|
||||
|
||||
System.setProperty(
|
||||
"prism.fontdir", AppInstallation.ofCurrent().getBundledFontsPath().toString());
|
||||
"prism.fontdir",
|
||||
AppInstallation.ofCurrent().getBundledFontsPath().toString());
|
||||
System.setProperty("prism.embeddedfonts", "true");
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,8 @@ public class AppTestCommandCheck {
|
||||
sc.getShellDialect()
|
||||
.directoryExists(
|
||||
sc,
|
||||
AppInstallation.ofCurrent().getBaseInstallationPath()
|
||||
AppInstallation.ofCurrent()
|
||||
.getBaseInstallationPath()
|
||||
.toString())
|
||||
.execute();
|
||||
} catch (ProcessOutputException ex) {
|
||||
|
||||
@@ -4,6 +4,7 @@ import io.xpipe.app.action.AbstractAction;
|
||||
import io.xpipe.app.action.ActionProvider;
|
||||
import io.xpipe.app.beacon.AppBeaconServer;
|
||||
import io.xpipe.app.beacon.BlobManager;
|
||||
import io.xpipe.app.beacon.mcp.AppMcpServer;
|
||||
import io.xpipe.app.browser.BrowserFullSessionModel;
|
||||
import io.xpipe.app.browser.file.BrowserLocalFileSystem;
|
||||
import io.xpipe.app.browser.icon.BrowserIconManager;
|
||||
@@ -17,7 +18,6 @@ import io.xpipe.app.ext.ProcessControlProvider;
|
||||
import io.xpipe.app.hub.comp.StoreViewState;
|
||||
import io.xpipe.app.icon.SystemIconManager;
|
||||
import io.xpipe.app.issue.TrackEvent;
|
||||
import io.xpipe.app.beacon.mcp.AppMcpServer;
|
||||
import io.xpipe.app.prefs.AppPrefs;
|
||||
import io.xpipe.app.pwman.KeePassXcPasswordManager;
|
||||
import io.xpipe.app.storage.DataStorage;
|
||||
|
||||
@@ -79,10 +79,16 @@ public abstract class OperationMode {
|
||||
}
|
||||
|
||||
// There are some accessibility exceptions on macOS, nothing we can do about that
|
||||
if (Platform.isFxApplicationThread() && ex instanceof NullPointerException && ex.getMessage() != null && ex.getMessage().contains("Accessible")) {
|
||||
ErrorEventFactory.fromThrowable(ex).expected()
|
||||
.descriptionPrefix("An error occurred with the Accessibility implementation. A screen reader might not be supported right now")
|
||||
.build().handle();
|
||||
if (Platform.isFxApplicationThread()
|
||||
&& ex instanceof NullPointerException
|
||||
&& ex.getMessage() != null
|
||||
&& ex.getMessage().contains("Accessible")) {
|
||||
ErrorEventFactory.fromThrowable(ex)
|
||||
.expected()
|
||||
.descriptionPrefix(
|
||||
"An error occurred with the Accessibility implementation. A screen reader might not be supported right now")
|
||||
.build()
|
||||
.handle();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ public class TrayMode extends PlatformMode {
|
||||
|
||||
@Override
|
||||
public boolean isSupported() {
|
||||
return OsType.getLocal()== OsType.WINDOWS
|
||||
return OsType.getLocal() == OsType.WINDOWS
|
||||
&& super.isSupported()
|
||||
&& Desktop.isDesktopSupported()
|
||||
&& SystemTray.isSupported();
|
||||
|
||||
@@ -2,6 +2,7 @@ package io.xpipe.app.ext;
|
||||
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.hub.comp.StoreSection;
|
||||
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
|
||||
@@ -19,12 +20,13 @@ public interface CountGroupStoreProvider extends DataStoreProvider {
|
||||
|
||||
var string = all.size() == shown.size() ? all.size() : shown.size() + "/" + all.size();
|
||||
return all.size() > 0
|
||||
? (all.size() == 1 ? AppI18n.get("hasConnection", string) : AppI18n.get("hasConnections", string))
|
||||
? (all.size() == 1
|
||||
? AppI18n.get("hasConnection", string)
|
||||
: AppI18n.get("hasConnections", string))
|
||||
: AppI18n.get("noConnections");
|
||||
},
|
||||
section.getShownChildren().getList(),
|
||||
section.getAllChildren().getList(),
|
||||
AppI18n.activeLanguage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,14 +26,17 @@ public class HostAddress {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new HostAddress(host.strip(), addresses.stream().map(s -> s.strip()).toList());
|
||||
return new HostAddress(
|
||||
host.strip(), addresses.stream().map(s -> s.strip()).toList());
|
||||
}
|
||||
|
||||
private final String value;
|
||||
|
||||
@Getter
|
||||
private final List<String> available;
|
||||
|
||||
private HostAddress(String value, List<String> available) {this.value = value;
|
||||
private HostAddress(String value, List<String> available) {
|
||||
this.value = value;
|
||||
this.available = available;
|
||||
}
|
||||
|
||||
@@ -57,5 +60,4 @@ public class HostAddress {
|
||||
public String get() {
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package io.xpipe.app.ext;
|
||||
|
||||
import io.xpipe.app.util.OptionsBuilder;
|
||||
|
||||
import javafx.beans.property.*;
|
||||
import javafx.collections.FXCollections;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Value;
|
||||
|
||||
@@ -27,8 +29,7 @@ public class HostAddressChoice {
|
||||
} else {
|
||||
options.name(translationKey);
|
||||
}
|
||||
options.addComp(new HostAddressChoiceComp(val, list, allowMutation))
|
||||
.addProperty(val);
|
||||
options.addComp(new HostAddressChoiceComp(val, list, allowMutation)).addProperty(val);
|
||||
options.bind(
|
||||
() -> {
|
||||
var fullList = new ArrayList<>(list);
|
||||
@@ -36,10 +37,11 @@ public class HostAddressChoice {
|
||||
fullList.add(val.getValue());
|
||||
}
|
||||
|
||||
var effectiveValue = val.getValue() != null ? val.getValue() : fullList.size() > 0 ? fullList.getFirst() : null;
|
||||
var effectiveValue =
|
||||
val.getValue() != null ? val.getValue() : fullList.size() > 0 ? fullList.getFirst() : null;
|
||||
return HostAddress.of(effectiveValue, fullList);
|
||||
},
|
||||
value);
|
||||
return options;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
package io.xpipe.app.ext;
|
||||
|
||||
import atlantafx.base.controls.Spacer;
|
||||
import atlantafx.base.theme.Styles;
|
||||
import io.xpipe.app.comp.Comp;
|
||||
import io.xpipe.app.comp.CompStructure;
|
||||
import io.xpipe.app.comp.SimpleCompStructure;
|
||||
import io.xpipe.app.comp.base.*;
|
||||
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.collections.ListChangeListener;
|
||||
@@ -15,6 +14,9 @@ import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ListCell;
|
||||
import javafx.scene.control.skin.ComboBoxListViewSkin;
|
||||
import javafx.scene.layout.HBox;
|
||||
|
||||
import atlantafx.base.controls.Spacer;
|
||||
import atlantafx.base.theme.Styles;
|
||||
import org.kordamp.ikonli.javafx.FontIcon;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -25,7 +27,8 @@ public class HostAddressChoiceComp extends Comp<CompStructure<HBox>> {
|
||||
private final ObservableList<String> allAddresses;
|
||||
private final boolean mutable;
|
||||
|
||||
public HostAddressChoiceComp(ObjectProperty<String> currentAddress, ObservableList<String> allAddresses, boolean mutable) {
|
||||
public HostAddressChoiceComp(
|
||||
ObjectProperty<String> currentAddress, ObservableList<String> allAddresses, boolean mutable) {
|
||||
this.currentAddress = currentAddress;
|
||||
this.allAddresses = allAddresses;
|
||||
this.mutable = mutable;
|
||||
@@ -52,7 +55,7 @@ public class HostAddressChoiceComp extends Comp<CompStructure<HBox>> {
|
||||
|
||||
var nodes = new ArrayList<Comp<?>>();
|
||||
nodes.add(combo);
|
||||
if (mutable) {
|
||||
if (mutable) {
|
||||
nodes.add(addButton);
|
||||
}
|
||||
|
||||
@@ -96,9 +99,11 @@ public class HostAddressChoiceComp extends Comp<CompStructure<HBox>> {
|
||||
hbox.getChildren().add(new Label(item));
|
||||
hbox.getChildren().add(new Spacer());
|
||||
if (mutable) {
|
||||
hbox.getChildren().add(new IconButtonComp("mdi2t-trash-can-outline", () -> {
|
||||
allAddresses.remove(item);
|
||||
}).createRegion());
|
||||
hbox.getChildren()
|
||||
.add(new IconButtonComp("mdi2t-trash-can-outline", () -> {
|
||||
allAddresses.remove(item);
|
||||
})
|
||||
.createRegion());
|
||||
}
|
||||
|
||||
setGraphic(hbox);
|
||||
@@ -135,4 +140,4 @@ public class HostAddressChoiceComp extends Comp<CompStructure<HBox>> {
|
||||
combo.grow(false, true);
|
||||
return combo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import io.xpipe.app.storage.DataStoreEntry;
|
||||
import io.xpipe.core.ModuleLayerLoader;
|
||||
|
||||
import javafx.beans.value.ObservableValue;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Value;
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import io.xpipe.app.action.AbstractAction;
|
||||
import io.xpipe.app.action.ActionProvider;
|
||||
import io.xpipe.app.issue.ErrorEventFactory;
|
||||
import io.xpipe.app.storage.DataStorage;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
import lombok.extern.jackson.Jacksonized;
|
||||
|
||||
@@ -8,6 +8,7 @@ import io.xpipe.app.hub.action.HubMenuItemProvider;
|
||||
import io.xpipe.app.hub.action.StoreActionCategory;
|
||||
import io.xpipe.app.storage.DataStoreEntryRef;
|
||||
import io.xpipe.app.util.LabelGraphic;
|
||||
|
||||
import javafx.beans.property.ReadOnlyStringWrapper;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
|
||||
@@ -23,7 +24,8 @@ public class HostAddressSwitchBranchProvider implements HubBranchProvider<HostAd
|
||||
|
||||
private HostAddressProvider(boolean active, String address) {
|
||||
this.active = active;
|
||||
this.address = address;}
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(DataStoreEntryRef<HostAddressSwitchStore> ref) {
|
||||
@@ -51,9 +53,12 @@ public class HostAddressSwitchBranchProvider implements HubBranchProvider<HostAd
|
||||
|
||||
@Override
|
||||
public List<HubMenuItemProvider<?>> getChildren(DataStoreEntryRef<HostAddressSwitchStore> store) {
|
||||
return store.getStore().getHostAddress().getAvailable().stream().map(s -> {
|
||||
return new HostAddressProvider(s.equals(store.getStore().getHostAddress().get()), s);
|
||||
}).collect(Collectors.toList());
|
||||
return store.getStore().getHostAddress().getAvailable().stream()
|
||||
.map(s -> {
|
||||
return new HostAddressProvider(
|
||||
s.equals(store.getStore().getHostAddress().get()), s);
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -31,35 +31,22 @@ public class StoreChoiceComp<T extends DataStore> extends SimpleComp {
|
||||
private final Mode mode;
|
||||
private final Property<DataStoreEntryRef<T>> selected;
|
||||
|
||||
|
||||
|
||||
private final StoreChoicePopover<T> popover;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public StoreChoiceComp(
|
||||
|
||||
|
||||
Mode mode, DataStoreEntry self, Property<DataStoreEntryRef<T>> selected, Class<?> storeClass,
|
||||
|
||||
|
||||
Predicate<DataStoreEntryRef<T>> applicableCheck, StoreCategoryWrapper initialCategory
|
||||
|
||||
|
||||
) {
|
||||
|
||||
Mode mode,
|
||||
DataStoreEntry self,
|
||||
Property<DataStoreEntryRef<T>> selected,
|
||||
Class<?> storeClass,
|
||||
Predicate<DataStoreEntryRef<T>> applicableCheck,
|
||||
StoreCategoryWrapper initialCategory) {
|
||||
|
||||
this.mode = mode;
|
||||
|
||||
|
||||
this.selected = selected;
|
||||
|
||||
|
||||
this.popover = new StoreChoicePopover<>(self,selected,storeClass, applicableCheck, initialCategory, "selectConnection");
|
||||
|
||||
|
||||
this.popover = new StoreChoicePopover<>(
|
||||
self, selected, storeClass, applicableCheck, initialCategory, "selectConnection");
|
||||
}
|
||||
|
||||
public static <T extends DataStore> StoreChoiceComp<T> other(
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
package io.xpipe.app.hub.comp;
|
||||
|
||||
import atlantafx.base.controls.Popover;
|
||||
import atlantafx.base.theme.Styles;
|
||||
import io.xpipe.app.comp.Comp;
|
||||
import io.xpipe.app.comp.base.*;
|
||||
import io.xpipe.app.core.AppFontSizes;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.core.window.AppDialog;
|
||||
import io.xpipe.app.ext.DataStore;
|
||||
import io.xpipe.app.hub.comp.*;
|
||||
import io.xpipe.app.storage.DataStorage;
|
||||
import io.xpipe.app.storage.DataStoreEntry;
|
||||
import io.xpipe.app.storage.DataStoreEntryRef;
|
||||
import io.xpipe.app.util.BindingsHelper;
|
||||
import io.xpipe.app.util.DataStoreCategoryChoiceComp;
|
||||
import io.xpipe.app.util.LabelGraphic;
|
||||
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
@@ -26,6 +24,9 @@ import javafx.scene.Node;
|
||||
import javafx.scene.control.MenuButton;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
import atlantafx.base.controls.Popover;
|
||||
import atlantafx.base.theme.Styles;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.kordamp.ikonli.javafx.FontIcon;
|
||||
|
||||
@@ -73,8 +74,9 @@ public class StoreChoicePopover<T extends DataStore> {
|
||||
Predicate<StoreEntryWrapper> applicable = storeEntryWrapper -> {
|
||||
var e = storeEntryWrapper.getEntry();
|
||||
|
||||
if (self != null && (e.equals(self)
|
||||
|| DataStorage.get().getStoreParentHierarchy(e).contains(self))) {
|
||||
if (self != null
|
||||
&& (e.equals(self)
|
||||
|| DataStorage.get().getStoreParentHierarchy(e).contains(self))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -124,9 +126,9 @@ public class StoreChoicePopover<T extends DataStore> {
|
||||
initialExpanded);
|
||||
|
||||
var category = new DataStoreCategoryChoiceComp(
|
||||
initialCategory != null ? initialCategory.getRoot() : null,
|
||||
StoreViewState.get().getActiveCategory(),
|
||||
selectedCategory)
|
||||
initialCategory != null ? initialCategory.getRoot() : null,
|
||||
StoreViewState.get().getActiveCategory(),
|
||||
selectedCategory)
|
||||
.styleClass(Styles.LEFT_PILL);
|
||||
var filter =
|
||||
new FilterComp(filterText).styleClass(Styles.CENTER_PILL).hgrow();
|
||||
|
||||
@@ -96,7 +96,6 @@ public class StoreCreationMenu {
|
||||
menu.getItems().add(setupMenu());
|
||||
|
||||
menu.getItems().add(actionMenu);
|
||||
|
||||
}
|
||||
|
||||
private static Menu categoryMenu(
|
||||
@@ -149,7 +148,6 @@ public class StoreCreationMenu {
|
||||
return menu;
|
||||
}
|
||||
|
||||
|
||||
private static Menu setupMenu() {
|
||||
var menu = new Menu();
|
||||
menu.setGraphic(new FontIcon("mdi2t-toy-brick-plus-outline"));
|
||||
@@ -160,7 +158,8 @@ public class StoreCreationMenu {
|
||||
item.textProperty().bind(AppI18n.observable(p.getNameKey()));
|
||||
item.setGraphic(p.getGraphic().createGraphicNode());
|
||||
item.setOnAction(event -> {
|
||||
var action = SetupToolActionProvider.Action.builder().type(p.getId()).build();
|
||||
var action =
|
||||
SetupToolActionProvider.Action.builder().type(p.getId()).build();
|
||||
action.executeAsync();
|
||||
event.consume();
|
||||
});
|
||||
|
||||
@@ -269,7 +269,8 @@ public class StoreEntryWrapper {
|
||||
.or(() -> {
|
||||
if (entry.getStore() instanceof GroupStore<?>) {
|
||||
return Optional.empty();
|
||||
} else if (entry.getProvider() != null && entry.getProvider().canConfigure()) {
|
||||
} else if (entry.getProvider() != null
|
||||
&& entry.getProvider().canConfigure()) {
|
||||
return Optional.of(new EditHubLeafProvider());
|
||||
} else {
|
||||
return Optional.empty();
|
||||
|
||||
@@ -67,7 +67,9 @@ public class SystemIconManager {
|
||||
var split = id.split("/");
|
||||
if (split.length == 2) {
|
||||
var source = split[0];
|
||||
var foundSource = getAllSources().stream().filter(systemIconSource -> systemIconSource.getId().equals(source)).findFirst();
|
||||
var foundSource = getAllSources().stream()
|
||||
.filter(systemIconSource -> systemIconSource.getId().equals(source))
|
||||
.findFirst();
|
||||
if (foundSource.isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import io.xpipe.app.comp.base.TextFieldComp;
|
||||
import io.xpipe.app.core.AppProperties;
|
||||
import io.xpipe.app.util.LabelGraphic;
|
||||
import io.xpipe.app.util.OptionsBuilder;
|
||||
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
|
||||
@@ -26,8 +27,10 @@ public class ApiCategory extends AppPrefsCategory {
|
||||
protected Comp<?> create() {
|
||||
var prefs = AppPrefs.get();
|
||||
|
||||
var mcpConfig = Bindings.createStringBinding(() -> {
|
||||
var template = """
|
||||
var mcpConfig = Bindings.createStringBinding(
|
||||
() -> {
|
||||
var template =
|
||||
"""
|
||||
{
|
||||
"mcpServers": {
|
||||
"%s": {
|
||||
@@ -40,11 +43,15 @@ public class ApiCategory extends AppPrefsCategory {
|
||||
}
|
||||
}
|
||||
""";
|
||||
return template.formatted(
|
||||
AppProperties.get().isStaging() ? "xpipe-ptb" : "xpipe",
|
||||
AppBeaconServer.get().getPort(),
|
||||
prefs.apiKey().get() != null ? prefs.apiKey().get() : "?").strip();
|
||||
}, prefs.apiKey());
|
||||
return template.formatted(
|
||||
AppProperties.get().isStaging() ? "xpipe-ptb" : "xpipe",
|
||||
AppBeaconServer.get().getPort(),
|
||||
prefs.apiKey().get() != null
|
||||
? prefs.apiKey().get()
|
||||
: "?")
|
||||
.strip();
|
||||
},
|
||||
prefs.apiKey());
|
||||
var mcpConfigProp = new SimpleStringProperty();
|
||||
mcpConfigProp.bind(mcpConfig);
|
||||
|
||||
@@ -56,9 +63,9 @@ public class ApiCategory extends AppPrefsCategory {
|
||||
.pref(prefs.apiKey)
|
||||
.addComp(new TextFieldComp(prefs.apiKey).maxWidth(getCompWidth()), prefs.apiKey)
|
||||
.pref(prefs.disableApiAuthentication)
|
||||
.addToggle(prefs.disableApiAuthentication)
|
||||
)
|
||||
.addTitle("mcpServer").sub(new OptionsBuilder()
|
||||
.addToggle(prefs.disableApiAuthentication))
|
||||
.addTitle("mcpServer")
|
||||
.sub(new OptionsBuilder()
|
||||
.pref(prefs.enableMcpServer)
|
||||
.addToggle(prefs.enableMcpServer)
|
||||
.pref(prefs.enableMcpMutationTools)
|
||||
@@ -68,8 +75,7 @@ public class ApiCategory extends AppPrefsCategory {
|
||||
struc.getTextArea().setEditable(false);
|
||||
struc.getTextArea().setPrefRowCount(11);
|
||||
}))
|
||||
.hide(prefs.enableMcpServer.not())
|
||||
)
|
||||
.hide(prefs.enableMcpServer.not()))
|
||||
.buildComp();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,6 +362,7 @@ public class AppPrefs {
|
||||
public ObservableBooleanValue pinLocalMachineOnStartup() {
|
||||
return pinLocalMachineOnStartup;
|
||||
}
|
||||
|
||||
@Getter
|
||||
private final List<AppPrefsCategory> categories;
|
||||
|
||||
@@ -751,8 +752,8 @@ public class AppPrefs {
|
||||
Class<?> valueType,
|
||||
boolean vaultSpecific,
|
||||
boolean requiresRestart,
|
||||
boolean log, DocumentationLink documentationLink
|
||||
) {
|
||||
boolean log,
|
||||
DocumentationLink documentationLink) {
|
||||
this.key = key;
|
||||
this.property = property;
|
||||
this.valueType = SimpleType.constructUnsafe(valueType);
|
||||
@@ -769,8 +770,8 @@ public class AppPrefs {
|
||||
JavaType valueType,
|
||||
boolean vaultSpecific,
|
||||
boolean requiresRestart,
|
||||
boolean log, DocumentationLink documentationLink
|
||||
) {
|
||||
boolean log,
|
||||
DocumentationLink documentationLink) {
|
||||
this.key = key;
|
||||
this.property = property;
|
||||
this.valueType = valueType;
|
||||
|
||||
@@ -59,7 +59,7 @@ public class AppPrefsComp extends SimpleComp {
|
||||
});
|
||||
});
|
||||
|
||||
AppPrefs.get().getSelectedCategory().addListener((observable, oldValue, val) -> {
|
||||
AppPrefs.get().getSelectedCategory().addListener((observable, oldValue, val) -> {
|
||||
if (val == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@ import io.xpipe.app.util.*;
|
||||
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Pos;
|
||||
|
||||
import javafx.scene.layout.Region;
|
||||
|
||||
import org.kordamp.ikonli.javafx.FontIcon;
|
||||
|
||||
import java.util.List;
|
||||
@@ -48,16 +48,17 @@ public class EditorCategory extends AppPrefsCategory {
|
||||
.apply(struc -> struc.get().setAlignment(Pos.CENTER_LEFT));
|
||||
|
||||
var choice = ChoiceComp.ofTranslatable(
|
||||
prefs.externalEditor, PrefsChoiceValue.getSupported(ExternalEditorType.class), false);
|
||||
prefs.externalEditor, PrefsChoiceValue.getSupported(ExternalEditorType.class), false);
|
||||
|
||||
var visit = new ButtonComp(AppI18n.observable("website"), new FontIcon("mdi2w-web"), () -> {
|
||||
var t = prefs.externalEditor().getValue();
|
||||
if (t == null || t.getWebsite() == null) {
|
||||
return;
|
||||
}
|
||||
var t = prefs.externalEditor().getValue();
|
||||
if (t == null || t.getWebsite() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Hyperlinks.open(t.getWebsite());
|
||||
}).minWidth(Region.USE_PREF_SIZE);
|
||||
Hyperlinks.open(t.getWebsite());
|
||||
})
|
||||
.minWidth(Region.USE_PREF_SIZE);
|
||||
|
||||
var h = new HorizontalComp(List.of(choice.hgrow(), visit)).apply(struc -> {
|
||||
struc.get().setAlignment(Pos.CENTER_LEFT);
|
||||
|
||||
@@ -415,10 +415,12 @@ public interface ExternalEditorType extends PrefsChoiceValue {
|
||||
LinuxPathType MOUSEPAD = new LinuxPathType("app.mousepad", "mousepad", "https://docs.xfce.org/apps/mousepad/start");
|
||||
|
||||
LinuxPathType PLUMA = new LinuxPathType("app.pluma", "pluma", "https://github.com/mate-desktop/pluma");
|
||||
ExternalEditorType TEXT_EDIT = new MacOsEditor("app.textEdit", "TextEdit", "https://support.apple.com/en-gb/guide/textedit/welcome/mac");
|
||||
ExternalEditorType TEXT_EDIT =
|
||||
new MacOsEditor("app.textEdit", "TextEdit", "https://support.apple.com/en-gb/guide/textedit/welcome/mac");
|
||||
ExternalEditorType BBEDIT = new MacOsEditor("app.bbedit", "BBEdit", "https://www.barebones.com/products/bbedit/");
|
||||
ExternalEditorType SUBLIME_MACOS = new MacOsEditor("app.sublime", "Sublime Text", "https://www.sublimetext.com/");
|
||||
ExternalEditorType VSCODE_MACOS = new MacOsEditor("app.vscode", "Visual Studio Code", "https://code.visualstudio.com/");
|
||||
ExternalEditorType VSCODE_MACOS =
|
||||
new MacOsEditor("app.vscode", "Visual Studio Code", "https://code.visualstudio.com/");
|
||||
ExternalEditorType VSCODIUM_MACOS = new MacOsEditor("app.vscodium", "VSCodium", "https://vscodium.com/");
|
||||
ExternalEditorType CURSOR_MACOS = new MacOsEditor("app.cursor", "Cursor", "https://cursor.com/");
|
||||
ExternalEditorType VOID_MACOS = new MacOsEditor("app.void", "Void", "https://voideditor.com/");
|
||||
@@ -456,8 +458,12 @@ public interface ExternalEditorType extends PrefsChoiceValue {
|
||||
var command = CommandBuilder.of()
|
||||
.add(ExternalApplicationHelper.replaceVariableArgument(format, "FILE", file.toString()));
|
||||
if (AppPrefs.get().customEditorCommandInTerminal().get()) {
|
||||
TerminalLaunch.builder().title(file.toString()).localScript(sc -> new ShellScript(command.buildFull(sc)))
|
||||
.logIfEnabled(false).preferTabs(false).launch();
|
||||
TerminalLaunch.builder()
|
||||
.title(file.toString())
|
||||
.localScript(sc -> new ShellScript(command.buildFull(sc)))
|
||||
.logIfEnabled(false)
|
||||
.preferTabs(false)
|
||||
.launch();
|
||||
} else {
|
||||
ExternalApplicationHelper.startAsync(command);
|
||||
}
|
||||
@@ -470,8 +476,10 @@ public interface ExternalEditorType extends PrefsChoiceValue {
|
||||
};
|
||||
ExternalEditorType FLEET = new GenericPathType("app.fleet", "fleet", false, "https://www.jetbrains.com/fleet/");
|
||||
ExternalEditorType INTELLIJ = new GenericPathType("app.intellij", "idea", false, "https://www.jetbrains.com/idea/");
|
||||
ExternalEditorType PYCHARM = new GenericPathType("app.pycharm", "pycharm", false, "https://www.jetbrains.com/pycharm/");
|
||||
ExternalEditorType WEBSTORM = new GenericPathType("app.webstorm", "webstorm", false, "https://www.jetbrains.com/webstorm/");
|
||||
ExternalEditorType PYCHARM =
|
||||
new GenericPathType("app.pycharm", "pycharm", false, "https://www.jetbrains.com/pycharm/");
|
||||
ExternalEditorType WEBSTORM =
|
||||
new GenericPathType("app.webstorm", "webstorm", false, "https://www.jetbrains.com/webstorm/");
|
||||
ExternalEditorType CLION = new GenericPathType("app.clion", "clion", false, "https://www.jetbrains.com/clion/");
|
||||
List<ExternalEditorType> WINDOWS_EDITORS = List.of(
|
||||
VOID_WINDOWS,
|
||||
|
||||
@@ -5,6 +5,7 @@ import io.xpipe.app.comp.base.ContextualFileReferenceChoiceComp;
|
||||
import io.xpipe.app.storage.DataStorage;
|
||||
import io.xpipe.app.util.LabelGraphic;
|
||||
import io.xpipe.app.util.OptionsBuilder;
|
||||
|
||||
import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||
|
||||
import java.util.List;
|
||||
@@ -33,8 +34,14 @@ public class FileBrowserCategory extends AppPrefsCategory {
|
||||
.addToggle(prefs.editFilesWithDoubleClick)
|
||||
.pref(prefs.downloadsDirectory)
|
||||
.addComp(
|
||||
new ContextualFileReferenceChoiceComp(new ReadOnlyObjectWrapper<>(DataStorage.get().local().ref()), prefs.downloadsDirectory, null,
|
||||
List.of()).maxWidth(getCompWidth()),
|
||||
new ContextualFileReferenceChoiceComp(
|
||||
new ReadOnlyObjectWrapper<>(DataStorage.get()
|
||||
.local()
|
||||
.ref()),
|
||||
prefs.downloadsDirectory,
|
||||
null,
|
||||
List.of())
|
||||
.maxWidth(getCompWidth()),
|
||||
prefs.downloadsDirectory)
|
||||
.pref(prefs.pinLocalMachineOnStartup)
|
||||
.addToggle(prefs.pinLocalMachineOnStartup))
|
||||
|
||||
@@ -94,7 +94,9 @@ public class IconsCategory extends AppPrefsCategory {
|
||||
.remote(remote.get())
|
||||
.id(UUID.randomUUID().toString())
|
||||
.build();
|
||||
if (sources.stream().noneMatch(s -> s instanceof SystemIconSource.GitRepository g && g.getRemote().equals(remote.get()))) {
|
||||
if (sources.stream()
|
||||
.noneMatch(s -> s instanceof SystemIconSource.GitRepository g
|
||||
&& g.getRemote().equals(remote.get()))) {
|
||||
sources.add(source);
|
||||
var nl = new ArrayList<>(
|
||||
AppPrefs.get().getIconSources().getValue());
|
||||
@@ -135,7 +137,9 @@ public class IconsCategory extends AppPrefsCategory {
|
||||
.path(path)
|
||||
.id(UUID.randomUUID().toString())
|
||||
.build();
|
||||
if (sources.stream().noneMatch(s -> s instanceof SystemIconSource.Directory d && d.getPath().equals(path))) {
|
||||
if (sources.stream()
|
||||
.noneMatch(s -> s instanceof SystemIconSource.Directory d
|
||||
&& d.getPath().equals(path))) {
|
||||
sources.add(source);
|
||||
var nl = new ArrayList<>(
|
||||
AppPrefs.get().getIconSources().getValue());
|
||||
|
||||
@@ -46,7 +46,8 @@ public class PasswordManagerCategory extends AppPrefsCategory {
|
||||
websiteLinkButton.minWidth(Region.USE_PREF_SIZE);
|
||||
websiteLinkButton.disable(Bindings.createBooleanBinding(
|
||||
() -> {
|
||||
return prefs.passwordManager.getValue() == null || prefs.passwordManager.getValue().getWebsite() == null;
|
||||
return prefs.passwordManager.getValue() == null
|
||||
|| prefs.passwordManager.getValue().getWebsite() == null;
|
||||
},
|
||||
prefs.passwordManager));
|
||||
|
||||
|
||||
@@ -12,7 +12,9 @@ import io.xpipe.app.util.DocumentationLink;
|
||||
import io.xpipe.app.util.Hyperlinks;
|
||||
import io.xpipe.app.util.LabelGraphic;
|
||||
import io.xpipe.app.util.OptionsBuilder;
|
||||
|
||||
import javafx.geometry.Pos;
|
||||
|
||||
import org.kordamp.ikonli.javafx.FontIcon;
|
||||
|
||||
import java.util.List;
|
||||
@@ -58,10 +60,12 @@ public class RdpCategory extends AppPrefsCategory {
|
||||
.longDescription(DocumentationLink.RDP)
|
||||
.addComp(h, prefs.rdpClientType)
|
||||
.nameAndDescription("customRdpClientCommand")
|
||||
.addComp(new TextFieldComp(prefs.customRdpClientCommand, true)
|
||||
.apply(struc -> struc.get().setPromptText("myrdpclient -c $FILE"))
|
||||
.hide(prefs.rdpClientType.isNotEqualTo(ExternalRdpClient.CUSTOM))
|
||||
.prefWidth(600), prefs.customRdpClientCommand))
|
||||
.addComp(
|
||||
new TextFieldComp(prefs.customRdpClientCommand, true)
|
||||
.apply(struc -> struc.get().setPromptText("myrdpclient -c $FILE"))
|
||||
.hide(prefs.rdpClientType.isNotEqualTo(ExternalRdpClient.CUSTOM))
|
||||
.prefWidth(600),
|
||||
prefs.customRdpClientCommand))
|
||||
.buildComp();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,8 +164,7 @@ public class TerminalCategory extends AppPrefsCategory {
|
||||
.localScript(new ShellScript(ProcessControlProvider.get()
|
||||
.getEffectiveLocalDialect()
|
||||
.getEchoCommand(
|
||||
"If you can read this, the terminal integration works",
|
||||
false)))
|
||||
"If you can read this, the terminal integration works", false)))
|
||||
.preferTabs(false)
|
||||
.logIfEnabled(false)
|
||||
.launch();
|
||||
@@ -177,7 +176,7 @@ public class TerminalCategory extends AppPrefsCategory {
|
||||
|
||||
var builder = new OptionsBuilder().pref(prefs.terminalType);
|
||||
if (!docsLink) {
|
||||
builder.longDescription((DocumentationLink) null);
|
||||
builder.longDescription((DocumentationLink) null);
|
||||
}
|
||||
builder.addComp(h, prefs.terminalType);
|
||||
builder.pref(prefs.customTerminalCommand)
|
||||
@@ -317,7 +316,9 @@ public class TerminalCategory extends AppPrefsCategory {
|
||||
.build();
|
||||
var choice = choiceBuilder.build().buildComp();
|
||||
choice.maxWidth(getCompWidth());
|
||||
return new OptionsBuilder().nameAndDescription("terminalPrompt")
|
||||
.longDescription(DocumentationLink.TERMINAL_PROMPT).addComp(choice, prefs.terminalPrompt);
|
||||
return new OptionsBuilder()
|
||||
.nameAndDescription("terminalPrompt")
|
||||
.longDescription(DocumentationLink.TERMINAL_PROMPT)
|
||||
.addComp(choice, prefs.terminalPrompt);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +93,8 @@ public class TroubleshootCategory extends AppPrefsCategory {
|
||||
"openInstallationDirectoryDescription",
|
||||
"mdomz-snippet_folder",
|
||||
e -> {
|
||||
DesktopHelper.browsePathLocal(AppInstallation.ofCurrent().getBaseInstallationPath());
|
||||
DesktopHelper.browsePathLocal(
|
||||
AppInstallation.ofCurrent().getBaseInstallationPath());
|
||||
e.consume();
|
||||
})
|
||||
.grow(true, false),
|
||||
@@ -159,7 +160,8 @@ public class TroubleshootCategory extends AppPrefsCategory {
|
||||
"uninstallApplicationDescription",
|
||||
"mdi2d-dump-truck",
|
||||
e -> {
|
||||
var file = AppInstallation.ofCurrent().getBaseInstallationPath()
|
||||
var file = AppInstallation.ofCurrent()
|
||||
.getBaseInstallationPath()
|
||||
.resolve("Contents")
|
||||
.resolve("Resources")
|
||||
.resolve("scripts")
|
||||
|
||||
@@ -10,7 +10,6 @@ import io.xpipe.app.issue.ErrorEventFactory;
|
||||
import io.xpipe.app.util.*;
|
||||
import io.xpipe.core.OsType;
|
||||
|
||||
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
|
||||
public class WorkspaceCreationDialog {
|
||||
@@ -45,7 +44,9 @@ public class WorkspaceCreationDialog {
|
||||
var file =
|
||||
switch (OsType.getLocal()) {
|
||||
case OsType.Windows ignored -> {
|
||||
var exec = AppInstallation.ofCurrent().getDaemonExecutablePath().toString();
|
||||
var exec = AppInstallation.ofCurrent()
|
||||
.getDaemonExecutablePath()
|
||||
.toString();
|
||||
yield DesktopShortcuts.create(
|
||||
exec,
|
||||
"-Dio.xpipe.app.dataDir=\""
|
||||
@@ -53,7 +54,8 @@ public class WorkspaceCreationDialog {
|
||||
shortcutName);
|
||||
}
|
||||
default -> {
|
||||
var exec = AppInstallation.ofCurrent().getCliExecutablePath()
|
||||
var exec = AppInstallation.ofCurrent()
|
||||
.getCliExecutablePath()
|
||||
.toString();
|
||||
yield DesktopShortcuts.create(
|
||||
exec,
|
||||
|
||||
@@ -45,5 +45,4 @@ public interface ProcessControl extends AutoCloseable {
|
||||
InputStream getStderr();
|
||||
|
||||
Charset getCharset();
|
||||
|
||||
}
|
||||
|
||||
@@ -15,5 +15,4 @@ public interface ShellLaunchCommand {
|
||||
}
|
||||
|
||||
List<String> loginCommand(OsType.Any os);
|
||||
|
||||
}
|
||||
|
||||
@@ -49,7 +49,11 @@ public class BitwardenPasswordManager implements PasswordManager {
|
||||
var script = ShellScript.lines(
|
||||
sc.getShellDialect().getEchoCommand("Log in into your Bitwarden account from the CLI:", false),
|
||||
"bw login");
|
||||
TerminalLaunch.builder().title("Bitwarden login").localScript(script).logIfEnabled(false).launch();
|
||||
TerminalLaunch.builder()
|
||||
.title("Bitwarden login")
|
||||
.localScript(script)
|
||||
.logIfEnabled(false)
|
||||
.launch();
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,11 @@ public class DashlanePasswordManager implements PasswordManager {
|
||||
var script = ShellScript.lines(
|
||||
sc.getShellDialect().getEchoCommand("Log in into your Dashlane account from the CLI:", false),
|
||||
"dcli accounts whoami");
|
||||
TerminalLaunch.builder().title("Dashlane login").localScript(script).logIfEnabled(false).launch();
|
||||
TerminalLaunch.builder()
|
||||
.title("Dashlane login")
|
||||
.localScript(script)
|
||||
.logIfEnabled(false)
|
||||
.launch();
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,11 @@ public class KeeperPasswordManager implements PasswordManager {
|
||||
var script = ShellScript.lines(
|
||||
sc.getShellDialect().getEchoCommand("Log in into your Keeper account from the CLI:", false),
|
||||
getExecutable(sc) + " login");
|
||||
TerminalLaunch.builder().title("Keeper login").localScript(script).logIfEnabled(false).launch();
|
||||
TerminalLaunch.builder()
|
||||
.title("Keeper login")
|
||||
.localScript(script)
|
||||
.logIfEnabled(false)
|
||||
.launch();
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,11 @@ public class LastpassPasswordManager implements PasswordManager {
|
||||
sc.getShellDialect()
|
||||
.getEchoCommand("Log in into your LastPass account from the CLI:", false),
|
||||
"lpass login --trust \"" + email.get() + "\"");
|
||||
TerminalLaunch.builder().title("LastPass login").localScript(script).logIfEnabled(false).launch();
|
||||
TerminalLaunch.builder()
|
||||
.title("LastPass login")
|
||||
.localScript(script)
|
||||
.logIfEnabled(false)
|
||||
.launch();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -625,8 +625,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
||||
|
||||
static ExternalTerminalType determineDefault(ExternalTerminalType existing) {
|
||||
// Check for incompatibility with fallback shell
|
||||
if (ExternalTerminalType.CMD.equals(existing)
|
||||
&& LocalShell.getDialect() != ShellDialects.CMD) {
|
||||
if (ExternalTerminalType.CMD.equals(existing) && LocalShell.getDialect() != ShellDialects.CMD) {
|
||||
return ExternalTerminalType.POWERSHELL;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ import io.xpipe.app.util.ShellTemp;
|
||||
import io.xpipe.app.util.ThreadHelper;
|
||||
import io.xpipe.core.FilePath;
|
||||
|
||||
|
||||
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
|
||||
|
||||
public interface KittyTerminalType extends ExternalTerminalType, TrackableTerminalType {
|
||||
@@ -37,8 +36,7 @@ public interface KittyTerminalType extends ExternalTerminalType, TrackableTermin
|
||||
payload.put("tab_title", configuration.getColoredTitle());
|
||||
payload.put("type", "tab");
|
||||
payload.put("logo_alpha", 0.01);
|
||||
payload.put(
|
||||
"logo", AppInstallation.ofCurrent().getLogoPath().toString());
|
||||
payload.put("logo", AppInstallation.ofCurrent().getLogoPath().toString());
|
||||
|
||||
var json = JsonNodeFactory.instance.objectNode();
|
||||
json.put("cmd", "launch");
|
||||
|
||||
@@ -13,6 +13,7 @@ import io.xpipe.app.storage.DataStoreEntry;
|
||||
import io.xpipe.app.util.LocalShell;
|
||||
import io.xpipe.core.FailableFunction;
|
||||
import io.xpipe.core.FilePath;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Value;
|
||||
|
||||
@@ -27,14 +28,19 @@ public class TerminalLaunch {
|
||||
FilePath directory;
|
||||
ProcessControl command;
|
||||
UUID request;
|
||||
|
||||
@Builder.Default
|
||||
boolean preferTabs = true;
|
||||
|
||||
@Builder.Default
|
||||
boolean logIfEnabled = true;
|
||||
|
||||
ExternalTerminalType terminal;
|
||||
|
||||
public String getFullTitle() {
|
||||
return entry != null ? DataStorage.get().getStoreEntryDisplayName(entry) + (title != null ? " - " + title : "") : title != null ? title : "?";
|
||||
return entry != null
|
||||
? DataStorage.get().getStoreEntryDisplayName(entry) + (title != null ? " - " + title : "")
|
||||
: title != null ? title : "?";
|
||||
}
|
||||
|
||||
public void launch() throws Exception {
|
||||
@@ -45,12 +51,23 @@ public class TerminalLaunch {
|
||||
|
||||
if (OperationMode.get() == null) {
|
||||
if (command instanceof CommandControl cc) {
|
||||
TerminalLauncher.openDirect(getFullTitle(), sc -> new ShellScript(cc.getTerminalCommand().buildFull(sc)), ExternalTerminalType.determineFallbackTerminalToOpen(type));
|
||||
TerminalLauncher.openDirect(
|
||||
getFullTitle(),
|
||||
sc -> new ShellScript(cc.getTerminalCommand().buildFull(sc)),
|
||||
ExternalTerminalType.determineFallbackTerminalToOpen(type));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
TerminalLauncher.open(entry, getFullTitle(), directory, command, request != null ? request : UUID.randomUUID(), preferTabs, logIfEnabled, type);
|
||||
TerminalLauncher.open(
|
||||
entry,
|
||||
getFullTitle(),
|
||||
directory,
|
||||
command,
|
||||
request != null ? request : UUID.randomUUID(),
|
||||
preferTabs,
|
||||
logIfEnabled,
|
||||
type);
|
||||
}
|
||||
|
||||
public static class TerminalLaunchBuilder {
|
||||
@@ -65,7 +82,8 @@ public class TerminalLaunch {
|
||||
return command(c);
|
||||
}
|
||||
|
||||
public TerminalLaunchBuilder localScript(FailableFunction<ShellControl, ShellScript, Exception> script) throws Exception {
|
||||
public TerminalLaunchBuilder localScript(FailableFunction<ShellControl, ShellScript, Exception> script)
|
||||
throws Exception {
|
||||
var c = LocalShell.getShell().command(script.apply(LocalShell.getShell()));
|
||||
return command(c);
|
||||
}
|
||||
|
||||
@@ -126,7 +126,8 @@ public class TerminalLaunchConfiguration {
|
||||
var cliExecutable = TerminalProxyManager.getProxy()
|
||||
.orElse(LocalShell.getShell())
|
||||
.getLocalSystemAccess()
|
||||
.translateFromLocalSystemPath(FilePath.of(AppInstallation.ofCurrent().getCliExecutablePath()));
|
||||
.translateFromLocalSystemPath(
|
||||
FilePath.of(AppInstallation.ofCurrent().getCliExecutablePath()));
|
||||
var scriptCommand = sc.getOsType() == OsType.MACOS || sc.getOsType() == OsType.BSD
|
||||
? "script -e -q '%s' \"%s\"".formatted(logFile, command)
|
||||
: "script --quiet --command '%s' \"%s\"".formatted(command, logFile);
|
||||
|
||||
@@ -11,7 +11,6 @@ import io.xpipe.app.util.ScriptHelper;
|
||||
import io.xpipe.core.FailableFunction;
|
||||
import io.xpipe.core.FilePath;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
@@ -115,7 +114,8 @@ public class TerminalLauncher {
|
||||
UUID request,
|
||||
boolean preferTabs,
|
||||
boolean enableLogging,
|
||||
ExternalTerminalType type) throws Exception {
|
||||
ExternalTerminalType type)
|
||||
throws Exception {
|
||||
var color = entry != null ? DataStorage.get().getEffectiveColor(entry) : null;
|
||||
var prefix = entry != null && color != null && type.useColoredTitle() ? color.getEmoji() + " " : "";
|
||||
var cleanTitle = (title != null ? title : entry != null ? entry.getName() : "Unknown");
|
||||
@@ -161,8 +161,7 @@ public class TerminalLauncher {
|
||||
return;
|
||||
}
|
||||
|
||||
var changedDialect =
|
||||
config.getScriptDialect() != LocalShell.getDialect();
|
||||
var changedDialect = config.getScriptDialect() != LocalShell.getDialect();
|
||||
config = config.withScript(
|
||||
LocalShell.getDialect(),
|
||||
getTerminalRegisterCommand(request) + "\n"
|
||||
@@ -258,12 +257,7 @@ public class TerminalLauncher {
|
||||
proxyControl.get().start();
|
||||
var fullLocalCommand = getTerminalRegisterCommand(request) + "\n" + proxyLaunchCommand;
|
||||
return Optional.of(new TerminalLaunchConfiguration(
|
||||
null,
|
||||
"XPipe",
|
||||
"XPipe",
|
||||
false,
|
||||
fullLocalCommand,
|
||||
LocalShell.getDialect()));
|
||||
null, "XPipe", "XPipe", false, fullLocalCommand, LocalShell.getDialect()));
|
||||
} else {
|
||||
var multiplexerCommand = multiplexer
|
||||
.get()
|
||||
@@ -276,12 +270,7 @@ public class TerminalLauncher {
|
||||
WorkingDirectoryFunction.none());
|
||||
var fullLocalCommand = getTerminalRegisterCommand(request) + "\n" + launchCommand;
|
||||
return Optional.of(new TerminalLaunchConfiguration(
|
||||
null,
|
||||
"XPipe",
|
||||
"XPipe",
|
||||
false,
|
||||
fullLocalCommand,
|
||||
LocalShell.getDialect()));
|
||||
null, "XPipe", "XPipe", false, fullLocalCommand, LocalShell.getDialect()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,7 +291,6 @@ public class TerminalLauncher {
|
||||
// Restart for the next time
|
||||
proxyControl.get().start();
|
||||
var fullLocalCommand = getTerminalRegisterCommand(request) + "\n" + launchCommand;
|
||||
return Optional.ofNullable(launchConfiguration.withScript(
|
||||
LocalShell.getDialect(), fullLocalCommand));
|
||||
return Optional.ofNullable(launchConfiguration.withScript(LocalShell.getDialect(), fullLocalCommand));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package io.xpipe.app.terminal;
|
||||
|
||||
import io.xpipe.app.util.NativeWinWindowControl;
|
||||
import io.xpipe.app.issue.TrackEvent;
|
||||
import io.xpipe.app.prefs.AppPrefs;
|
||||
import io.xpipe.app.prefs.ExternalApplicationType;
|
||||
import io.xpipe.app.util.NativeWinWindowControl;
|
||||
import io.xpipe.app.util.ThreadHelper;
|
||||
import io.xpipe.core.OsType;
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import io.xpipe.app.process.CommandBuilder;
|
||||
import io.xpipe.app.util.CommandSupport;
|
||||
import io.xpipe.app.util.LocalShell;
|
||||
|
||||
|
||||
public interface WaveTerminalType extends ExternalTerminalType, TrackableTerminalType {
|
||||
|
||||
ExternalTerminalType WAVE_WINDOWS = new Windows();
|
||||
@@ -66,7 +65,9 @@ public interface WaveTerminalType extends ExternalTerminalType, TrackableTermina
|
||||
.formatted(
|
||||
inPath
|
||||
? "xpipe open"
|
||||
: "\"" + AppInstallation.ofCurrent().getCliExecutablePath() + "\" open");
|
||||
: "\""
|
||||
+ AppInstallation.ofCurrent()
|
||||
.getCliExecutablePath() + "\" open");
|
||||
throw ErrorEventFactory.expected(new IllegalStateException(msg));
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ import io.xpipe.app.util.LocalShell;
|
||||
import io.xpipe.core.FilePath;
|
||||
import io.xpipe.core.JacksonMapper;
|
||||
|
||||
|
||||
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -8,7 +8,6 @@ import io.xpipe.app.util.LocalExec;
|
||||
import io.xpipe.app.util.Translatable;
|
||||
import io.xpipe.core.OsType;
|
||||
|
||||
|
||||
import javafx.beans.value.ObservableValue;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@@ -12,7 +12,6 @@ import io.xpipe.app.util.ScriptHelper;
|
||||
import io.xpipe.core.FilePath;
|
||||
import io.xpipe.core.OsType;
|
||||
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||
@@ -65,9 +64,7 @@ public class AppInstaller {
|
||||
var logFile =
|
||||
FilePath.of(logsDir, "installer_" + file.getFileName().toString() + ".log");
|
||||
var systemWide = isSystemWide();
|
||||
var cmdScript =
|
||||
LocalShell.getDialect() == ShellDialects.CMD
|
||||
&& !systemWide;
|
||||
var cmdScript = LocalShell.getDialect() == ShellDialects.CMD && !systemWide;
|
||||
var command = cmdScript
|
||||
? getCmdCommand(file.toString(), logFile.toString())
|
||||
: getPowershellCommand(file.toString(), logFile.toString(), systemWide);
|
||||
@@ -98,7 +95,8 @@ public class AppInstaller {
|
||||
}
|
||||
|
||||
private boolean isSystemWide() {
|
||||
return Files.exists(AppInstallation.ofCurrent().getBaseInstallationPath().resolve("system"));
|
||||
return Files.exists(
|
||||
AppInstallation.ofCurrent().getBaseInstallationPath().resolve("system"));
|
||||
}
|
||||
|
||||
private String getCmdCommand(String file, String logFile) {
|
||||
@@ -168,7 +166,10 @@ public class AppInstaller {
|
||||
""",
|
||||
file, file, AppRestart.getTerminalRestartCommand()));
|
||||
OperationMode.executeAfterShutdown(() -> {
|
||||
TerminalLaunch.builder().title("XPipe Updater").localScript(command).launch();
|
||||
TerminalLaunch.builder()
|
||||
.title("XPipe Updater")
|
||||
.localScript(command)
|
||||
.launch();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -201,7 +202,10 @@ public class AppInstaller {
|
||||
""",
|
||||
file, file, AppRestart.getTerminalRestartCommand()));
|
||||
OperationMode.executeAfterShutdown(() -> {
|
||||
TerminalLaunch.builder().title("XPipe Updater").localScript(command).launch();
|
||||
TerminalLaunch.builder()
|
||||
.title("XPipe Updater")
|
||||
.localScript(command)
|
||||
.launch();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -234,7 +238,10 @@ public class AppInstaller {
|
||||
""",
|
||||
file, file, AppRestart.getTerminalRestartCommand()));
|
||||
OperationMode.executeAfterShutdown(() -> {
|
||||
TerminalLaunch.builder().title("XPipe Updater").localScript(command).launch();
|
||||
TerminalLaunch.builder()
|
||||
.title("XPipe Updater")
|
||||
.localScript(command)
|
||||
.launch();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ import io.xpipe.app.terminal.TerminalLaunch;
|
||||
import io.xpipe.app.util.Hyperlinks;
|
||||
import io.xpipe.app.util.LocalShell;
|
||||
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
@@ -120,7 +119,8 @@ public class ChocoUpdater extends UpdateHandler {
|
||||
var performedUpdate = new PerformedUpdate(p.getVersion(), p.getBody(), p.getVersion());
|
||||
AppCache.update("performedUpdate", performedUpdate);
|
||||
OperationMode.executeAfterShutdown(() -> {
|
||||
var systemWide = Files.exists(AppInstallation.ofCurrent().getBaseInstallationPath().resolve("system"));
|
||||
var systemWide = Files.exists(
|
||||
AppInstallation.ofCurrent().getBaseInstallationPath().resolve("system"));
|
||||
var propertiesArguments = systemWide ? ", --install-arguments=\"'ALLUSERS=1'\"" : "";
|
||||
TerminalLaunch.builder().title("XPipe Updater").localScript(sc -> {
|
||||
var pkg = "xpipe";
|
||||
|
||||
@@ -57,7 +57,10 @@ public class CommandUpdater extends PortableUpdater {
|
||||
var performedUpdate = new PerformedUpdate(p.getVersion(), p.getBody(), p.getVersion());
|
||||
AppCache.update("performedUpdate", performedUpdate);
|
||||
OperationMode.executeAfterShutdown(() -> {
|
||||
TerminalLaunch.builder().title("XPipe Updater").localScript(script).launch();
|
||||
TerminalLaunch.builder()
|
||||
.title("XPipe Updater")
|
||||
.localScript(script)
|
||||
.launch();
|
||||
});
|
||||
} catch (Throwable t) {
|
||||
ErrorEventFactory.fromThrowable(t).handle();
|
||||
|
||||
@@ -13,7 +13,6 @@ import io.xpipe.app.terminal.TerminalLaunch;
|
||||
import io.xpipe.app.util.Hyperlinks;
|
||||
import io.xpipe.app.util.LocalShell;
|
||||
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
@@ -121,7 +120,9 @@ public class WingetUpdater extends UpdateHandler {
|
||||
AppCache.update("performedUpdate", performedUpdate);
|
||||
OperationMode.executeAfterShutdown(() -> {
|
||||
TerminalLaunch.builder().title("XPipe Updater").localScript(sc -> {
|
||||
var systemWide = Files.exists(AppInstallation.ofCurrent().getBaseInstallationPath().resolve("system"));
|
||||
var systemWide = Files.exists(AppInstallation.ofCurrent()
|
||||
.getBaseInstallationPath()
|
||||
.resolve("system"));
|
||||
var pkgId = "xpipe-io.xpipe";
|
||||
if (systemWide) {
|
||||
return ShellScript.lines(
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package io.xpipe.app.util;
|
||||
|
||||
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
|
||||
import io.xpipe.app.ext.HostAddress;
|
||||
import io.xpipe.app.process.ShellDialect;
|
||||
import io.xpipe.app.process.ShellDialects;
|
||||
@@ -24,6 +23,7 @@ import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
|
||||
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
|
||||
import com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import com.fasterxml.jackson.databind.type.SimpleType;
|
||||
|
||||
@@ -370,15 +370,8 @@ public class AppJacksonModule extends SimpleModule {
|
||||
|
||||
public static class HostAddressSerializer extends JsonSerializer<HostAddress> {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
|
||||
public void serialize(HostAddress value, JsonGenerator jgen, SerializerProvider provider)
|
||||
throws IOException {
|
||||
public void serialize(HostAddress value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
|
||||
if (value.isSingle()) {
|
||||
jgen.writeString(value.get());
|
||||
} else {
|
||||
@@ -390,19 +383,9 @@ public class AppJacksonModule extends SimpleModule {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static class HostAddressDeserializer extends JsonDeserializer<HostAddress> {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
|
||||
public HostAddress deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
|
||||
var tree = (JsonNode) p.getCodec().readTree(p);
|
||||
if (tree.isTextual()) {
|
||||
|
||||
@@ -6,7 +6,6 @@ import io.xpipe.app.process.OsFileSystem;
|
||||
import io.xpipe.core.FilePath;
|
||||
import io.xpipe.core.OsType;
|
||||
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
|
||||
@@ -6,8 +6,7 @@ import javafx.beans.value.ChangeListener;
|
||||
|
||||
public class GlobalBooleanProperty extends SimpleBooleanProperty {
|
||||
|
||||
public GlobalBooleanProperty() {
|
||||
}
|
||||
public GlobalBooleanProperty() {}
|
||||
|
||||
public GlobalBooleanProperty(boolean initialValue) {
|
||||
super(initialValue);
|
||||
|
||||
@@ -6,8 +6,7 @@ import javafx.beans.value.ChangeListener;
|
||||
|
||||
public class GlobalDoubleProperty extends SimpleDoubleProperty {
|
||||
|
||||
public GlobalDoubleProperty() {
|
||||
}
|
||||
public GlobalDoubleProperty() {}
|
||||
|
||||
public GlobalDoubleProperty(Double initialValue) {
|
||||
super(initialValue);
|
||||
|
||||
@@ -6,8 +6,7 @@ import javafx.beans.value.ChangeListener;
|
||||
|
||||
public class GlobalObjectProperty<T> extends SimpleObjectProperty<T> {
|
||||
|
||||
public GlobalObjectProperty() {
|
||||
}
|
||||
public GlobalObjectProperty() {}
|
||||
|
||||
public GlobalObjectProperty(T initialValue) {
|
||||
super(initialValue);
|
||||
|
||||
@@ -6,8 +6,7 @@ import javafx.beans.value.ChangeListener;
|
||||
|
||||
public class GlobalStringProperty extends SimpleStringProperty {
|
||||
|
||||
public GlobalStringProperty() {
|
||||
}
|
||||
public GlobalStringProperty() {}
|
||||
|
||||
public GlobalStringProperty(String initialValue) {
|
||||
super(initialValue);
|
||||
|
||||
@@ -35,7 +35,8 @@ public class NativeBridge {
|
||||
try {
|
||||
System.setProperty(
|
||||
"jna.library.path",
|
||||
AppInstallation.ofCurrent().getBaseInstallationPath()
|
||||
AppInstallation.ofCurrent()
|
||||
.getBaseInstallationPath()
|
||||
.resolve("Contents")
|
||||
.resolve("runtime")
|
||||
.resolve("Contents")
|
||||
|
||||
@@ -183,11 +183,16 @@ public class OptionsBuilder {
|
||||
|
||||
public OptionsBuilder pref(Object property) {
|
||||
var mapping = AppPrefs.get().getMapping(property);
|
||||
pref(mapping.getKey(), mapping.isRequiresRestart(), mapping.getLicenseFeatureId(), mapping.getDocumentationLink());
|
||||
pref(
|
||||
mapping.getKey(),
|
||||
mapping.isRequiresRestart(),
|
||||
mapping.getLicenseFeatureId(),
|
||||
mapping.getDocumentationLink());
|
||||
return this;
|
||||
}
|
||||
|
||||
public OptionsBuilder pref(String key, boolean requiresRestart, String licenseFeatureId, DocumentationLink documentationLink) {
|
||||
public OptionsBuilder pref(
|
||||
String key, boolean requiresRestart, String licenseFeatureId, DocumentationLink documentationLink) {
|
||||
var name = key;
|
||||
name(name);
|
||||
if (requiresRestart) {
|
||||
|
||||
@@ -76,8 +76,10 @@ public class RemminaHelper {
|
||||
.orElseThrow()
|
||||
.getValue(),
|
||||
password != null ? password : "",
|
||||
Math.round(AppMainWindow.getInstance().getStage().getWidth()),
|
||||
Math.round(AppMainWindow.getInstance().getStage().getHeight()));
|
||||
Math.round(
|
||||
AppMainWindow.getInstance().getStage().getWidth()),
|
||||
Math.round(
|
||||
AppMainWindow.getInstance().getStage().getHeight()));
|
||||
Files.createDirectories(file.getParent());
|
||||
Files.writeString(file, string);
|
||||
return file;
|
||||
|
||||
@@ -47,8 +47,7 @@ public class ScanDialogBase {
|
||||
Runnable closeAction,
|
||||
ScanDialogAction action,
|
||||
ObservableList<DataStoreEntryRef<ShellStore>> entries,
|
||||
boolean showButton
|
||||
) {
|
||||
boolean showButton) {
|
||||
this.expand = expand;
|
||||
this.closeAction = closeAction;
|
||||
this.action = action;
|
||||
|
||||
@@ -31,7 +31,7 @@ class ScanMultiDialogComp extends ModalOverlayContentComp {
|
||||
},
|
||||
action,
|
||||
list,
|
||||
false);
|
||||
false);
|
||||
}
|
||||
|
||||
void finish() {
|
||||
|
||||
@@ -10,7 +10,6 @@ import io.xpipe.app.process.ShellControl;
|
||||
import io.xpipe.app.process.ShellDialects;
|
||||
import io.xpipe.core.FilePath;
|
||||
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@ import io.xpipe.app.browser.BrowserFullSessionModel;
|
||||
import io.xpipe.app.browser.BrowserStoreSessionTab;
|
||||
import io.xpipe.app.core.AppLayoutModel;
|
||||
import io.xpipe.app.ext.ProcessControlProvider;
|
||||
import io.xpipe.app.util.DocumentationLink;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||
import io.xpipe.app.util.DocumentationLink;
|
||||
import lombok.Builder;
|
||||
import lombok.extern.jackson.Jacksonized;
|
||||
|
||||
|
||||
@@ -37,7 +37,8 @@ public class VncLaunchConfig {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
var secret = SecretManager.retrieve(strat, "VNC login password", entry.get().getUuid(), 1, true);
|
||||
var secret =
|
||||
SecretManager.retrieve(strat, "VNC login password", entry.get().getUuid(), 1, true);
|
||||
return Optional.ofNullable(secret);
|
||||
}
|
||||
}
|
||||
|
||||
2
dist/licenses/commons-lang.properties
generated
vendored
2
dist/licenses/commons-lang.properties
generated
vendored
@@ -1,4 +1,4 @@
|
||||
name=Commons Lang
|
||||
version=3.17.0
|
||||
version=3.18.0
|
||||
license=Apache License 2.0
|
||||
link=https://commons.apache.org/proper/commons-lang/
|
||||
@@ -190,31 +190,32 @@ public class IdentitySelectComp extends Comp<CompStructure<HBox>> {
|
||||
}
|
||||
});
|
||||
|
||||
var combo = new ComboTextFieldComp(prop, FXCollections.observableList(map.keySet().stream().toList()), () -> {
|
||||
return new ListCell<>() {
|
||||
@Override
|
||||
protected void updateItem(String item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (empty) {
|
||||
return;
|
||||
}
|
||||
var combo = new ComboTextFieldComp(
|
||||
prop, FXCollections.observableList(map.keySet().stream().toList()), () -> {
|
||||
return new ListCell<>() {
|
||||
@Override
|
||||
protected void updateItem(String item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (empty) {
|
||||
return;
|
||||
}
|
||||
|
||||
setText(item);
|
||||
setText(item);
|
||||
|
||||
if (item != null) {
|
||||
var store = map.get(item);
|
||||
if (store != null) {
|
||||
var provider = store.get().getProvider();
|
||||
var image = provider.getDisplayIconFileName(store.getStore());
|
||||
setGraphic(
|
||||
PrettyImageHelper.ofFixedSize(image, 16, 16).createRegion());
|
||||
if (item != null) {
|
||||
var store = map.get(item);
|
||||
if (store != null) {
|
||||
var provider = store.get().getProvider();
|
||||
var image = provider.getDisplayIconFileName(store.getStore());
|
||||
setGraphic(PrettyImageHelper.ofFixedSize(image, 16, 16)
|
||||
.createRegion());
|
||||
}
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
};
|
||||
});
|
||||
combo.apply(struc -> struc.get().setEditable(allowUserInput));
|
||||
combo.styleClass(Styles.LEFT_PILL);
|
||||
combo.grow(false, true);
|
||||
@@ -244,8 +245,13 @@ public class IdentitySelectComp extends Comp<CompStructure<HBox>> {
|
||||
});
|
||||
|
||||
combo.apply(struc -> {
|
||||
var popover = new StoreChoicePopover<>(null, selectedReference, IdentityStore.class, null,
|
||||
StoreViewState.get().getAllIdentitiesCategory(), "selectIdentity");
|
||||
var popover = new StoreChoicePopover<>(
|
||||
null,
|
||||
selectedReference,
|
||||
IdentityStore.class,
|
||||
null,
|
||||
StoreViewState.get().getAllIdentitiesCategory(),
|
||||
"selectIdentity");
|
||||
((Region) popover.getPopover().getContentNode()).setMaxHeight(350);
|
||||
var skin = new ComboBoxListViewSkin<>(struc.get()) {
|
||||
@Override
|
||||
|
||||
@@ -23,14 +23,18 @@ public class SshIdentityStrategyHelper {
|
||||
private static OptionsBuilder agent(Property<SshIdentityStrategy.SshAgent> p, boolean allowForward) {
|
||||
var forward =
|
||||
new SimpleBooleanProperty(p.getValue() != null && p.getValue().isForwardAgent());
|
||||
var publicKey = new SimpleStringProperty(p.getValue() != null ? p.getValue().getPublicKey() : null);
|
||||
var publicKey =
|
||||
new SimpleStringProperty(p.getValue() != null ? p.getValue().getPublicKey() : null);
|
||||
return new OptionsBuilder()
|
||||
.nameAndDescription("forwardAgent")
|
||||
.addToggle(forward)
|
||||
.nonNull()
|
||||
.hide(!allowForward)
|
||||
.nameAndDescription("publicKey")
|
||||
.addComp(new TextFieldComp(publicKey).apply(struc -> struc.get().setPromptText("ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIBmhLUTJiP...== Your Comment")), publicKey)
|
||||
.addComp(
|
||||
new TextFieldComp(publicKey).apply(struc -> struc.get()
|
||||
.setPromptText("ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIBmhLUTJiP...== Your Comment")),
|
||||
publicKey)
|
||||
.bind(
|
||||
() -> {
|
||||
return new SshIdentityStrategy.SshAgent(forward.get(), publicKey.get());
|
||||
@@ -41,14 +45,18 @@ public class SshIdentityStrategyHelper {
|
||||
private static OptionsBuilder gpgAgent(Property<SshIdentityStrategy.GpgAgent> p, boolean allowForward) {
|
||||
var forward =
|
||||
new SimpleBooleanProperty(p.getValue() != null && p.getValue().isForwardAgent());
|
||||
var publicKey = new SimpleStringProperty(p.getValue() != null ? p.getValue().getPublicKey() : null);
|
||||
var publicKey =
|
||||
new SimpleStringProperty(p.getValue() != null ? p.getValue().getPublicKey() : null);
|
||||
return new OptionsBuilder()
|
||||
.nameAndDescription("forwardAgent")
|
||||
.addToggle(forward)
|
||||
.nonNull()
|
||||
.hide(!allowForward)
|
||||
.nameAndDescription("publicKey")
|
||||
.addComp(new TextFieldComp(publicKey).apply(struc -> struc.get().setPromptText("ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIBmhLUTJiP...== Your Comment")), publicKey)
|
||||
.addComp(
|
||||
new TextFieldComp(publicKey).apply(struc -> struc.get()
|
||||
.setPromptText("ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIBmhLUTJiP...== Your Comment")),
|
||||
publicKey)
|
||||
.bind(
|
||||
() -> {
|
||||
return new SshIdentityStrategy.GpgAgent(forward.get(), publicKey.get());
|
||||
@@ -59,14 +67,18 @@ public class SshIdentityStrategyHelper {
|
||||
private static OptionsBuilder pageant(Property<SshIdentityStrategy.Pageant> p, boolean allowForward) {
|
||||
var forward =
|
||||
new SimpleBooleanProperty(p.getValue() != null && p.getValue().isForwardAgent());
|
||||
var publicKey = new SimpleStringProperty(p.getValue() != null ? p.getValue().getPublicKey() : null);
|
||||
var publicKey =
|
||||
new SimpleStringProperty(p.getValue() != null ? p.getValue().getPublicKey() : null);
|
||||
return new OptionsBuilder()
|
||||
.nameAndDescription("forwardAgent")
|
||||
.addToggle(forward)
|
||||
.nonNull()
|
||||
.hide(!allowForward)
|
||||
.nameAndDescription("publicKey")
|
||||
.addComp(new TextFieldComp(publicKey).apply(struc -> struc.get().setPromptText("ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIBmhLUTJiP...== Your Comment")), publicKey)
|
||||
.addComp(
|
||||
new TextFieldComp(publicKey).apply(struc -> struc.get()
|
||||
.setPromptText("ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIBmhLUTJiP...== Your Comment")),
|
||||
publicKey)
|
||||
.bind(
|
||||
() -> {
|
||||
return new SshIdentityStrategy.Pageant(forward.get(), publicKey.get());
|
||||
@@ -78,14 +90,18 @@ public class SshIdentityStrategyHelper {
|
||||
Property<SshIdentityStrategy.PasswordManagerAgent> p, boolean allowForward) {
|
||||
var forward =
|
||||
new SimpleBooleanProperty(p.getValue() != null && p.getValue().isForwardAgent());
|
||||
var publicKey = new SimpleStringProperty(p.getValue() != null ? p.getValue().getPublicKey() : null);
|
||||
var publicKey =
|
||||
new SimpleStringProperty(p.getValue() != null ? p.getValue().getPublicKey() : null);
|
||||
return new OptionsBuilder()
|
||||
.nameAndDescription("forwardAgent")
|
||||
.addToggle(forward)
|
||||
.nonNull()
|
||||
.hide(!allowForward)
|
||||
.nameAndDescription("publicKey")
|
||||
.addComp(new TextFieldComp(publicKey).apply(struc -> struc.get().setPromptText("ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIBmhLUTJiP...== Your Comment")), publicKey)
|
||||
.addComp(
|
||||
new TextFieldComp(publicKey).apply(struc -> struc.get()
|
||||
.setPromptText("ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIBmhLUTJiP...== Your Comment")),
|
||||
publicKey)
|
||||
.bind(
|
||||
() -> {
|
||||
return new SshIdentityStrategy.PasswordManagerAgent(forward.get(), publicKey.get());
|
||||
@@ -96,14 +112,18 @@ public class SshIdentityStrategyHelper {
|
||||
private static OptionsBuilder otherExternal(Property<SshIdentityStrategy.OtherExternal> p, boolean allowForward) {
|
||||
var forward =
|
||||
new SimpleBooleanProperty(p.getValue() != null && p.getValue().isForwardAgent());
|
||||
var publicKey = new SimpleStringProperty(p.getValue() != null ? p.getValue().getPublicKey() : null);
|
||||
var publicKey =
|
||||
new SimpleStringProperty(p.getValue() != null ? p.getValue().getPublicKey() : null);
|
||||
return new OptionsBuilder()
|
||||
.nameAndDescription("forwardAgent")
|
||||
.addToggle(forward)
|
||||
.nonNull()
|
||||
.hide(!allowForward)
|
||||
.nameAndDescription("publicKey")
|
||||
.addComp(new TextFieldComp(publicKey).apply(struc -> struc.get().setPromptText("ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIBmhLUTJiP...== Your Comment")), publicKey)
|
||||
.addComp(
|
||||
new TextFieldComp(publicKey).apply(struc -> struc.get()
|
||||
.setPromptText("ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIBmhLUTJiP...== Your Comment")),
|
||||
publicKey)
|
||||
.bind(
|
||||
() -> {
|
||||
return new SshIdentityStrategy.OtherExternal(forward.get(), publicKey.get());
|
||||
|
||||
@@ -31,7 +31,11 @@ public class RunTerminalScriptActionProvider implements ActionProvider {
|
||||
public void executeImpl() throws Exception {
|
||||
var sc = ref.getStore().getOrStartSession();
|
||||
var script = scriptStore.getStore().assembleScriptChain(sc);
|
||||
TerminalLaunch.builder().entry(ref.get()).title(scriptStore.get().getName()).command(sc.command(script)).launch();
|
||||
TerminalLaunch.builder()
|
||||
.entry(ref.get())
|
||||
.title(scriptStore.get().getName())
|
||||
.command(sc.command(script))
|
||||
.launch();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,11 @@ public class IncusContainerConsoleActionProvider implements HubLeafProvider<Incu
|
||||
var d = (IncusContainerStore) ref.getStore();
|
||||
var view = new IncusCommandView(
|
||||
d.getInstall().getStore().getHost().getStore().getOrStartSession());
|
||||
TerminalLaunch.builder().entry(ref.get()).title("Console").command(view.console(d.getName())).launch();
|
||||
TerminalLaunch.builder()
|
||||
.entry(ref.get())
|
||||
.title("Console")
|
||||
.command(view.console(d.getName()))
|
||||
.launch();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,11 @@ public class IncusContainerEditConfigActionProvider implements HubLeafProvider<I
|
||||
var d = (IncusContainerStore) ref.getStore();
|
||||
var view = new IncusCommandView(
|
||||
d.getInstall().getStore().getHost().getStore().getOrStartSession());
|
||||
TerminalLaunch.builder().entry(ref.get()).title("Config").command(view.configEdit(d.getName())).launch();
|
||||
TerminalLaunch.builder()
|
||||
.entry(ref.get())
|
||||
.title("Config")
|
||||
.command(view.configEdit(d.getName()))
|
||||
.launch();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,11 @@ public class LxdContainerConsoleActionProvider implements HubLeafProvider<LxdCon
|
||||
var d = ref.getStore();
|
||||
var view = new LxdCommandView(
|
||||
d.getCmd().getStore().getHost().getStore().getOrStartSession());
|
||||
TerminalLaunch.builder().entry(ref.get()).title("Console").command(view.console(d.getName())).launch();
|
||||
TerminalLaunch.builder()
|
||||
.entry(ref.get())
|
||||
.title("Console")
|
||||
.command(view.console(d.getName()))
|
||||
.launch();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,11 @@ public class LxdContainerEditConfigActionProvider implements HubLeafProvider<Lxd
|
||||
var d = ref.getStore();
|
||||
var view = new LxdCommandView(
|
||||
d.getCmd().getStore().getHost().getStore().getOrStartSession());
|
||||
TerminalLaunch.builder().entry(ref.get()).title("Config").command(view.configEdit(d.getName())).launch();
|
||||
TerminalLaunch.builder()
|
||||
.entry(ref.get())
|
||||
.title("Config")
|
||||
.command(view.configEdit(d.getName()))
|
||||
.launch();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,11 @@ public class PodmanContainerAttachActionProvider implements HubLeafProvider<Podm
|
||||
public void executeImpl() throws Exception {
|
||||
var d = ref.getStore();
|
||||
var view = d.commandView(d.getCmd().getStore().getHost().getStore().getOrStartSession());
|
||||
TerminalLaunch.builder().entry(ref.get()).title("Attach").command(view.attach(d.getContainerName())).launch();
|
||||
TerminalLaunch.builder()
|
||||
.entry(ref.get())
|
||||
.title("Attach")
|
||||
.command(view.attach(d.getContainerName()))
|
||||
.launch();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user