mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-10-03 10:36:52 +13:00
More rework
This commit is contained in:
parent
02b9ba6062
commit
31af3d6045
20 changed files with 322 additions and 155 deletions
|
@ -27,8 +27,9 @@ public class BrowserEntry {
|
||||||
if (rawFileEntry == null) {
|
if (rawFileEntry == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
rawFileEntry = rawFileEntry.resolved();
|
||||||
|
|
||||||
if (rawFileEntry.getKind() == FileKind.DIRECTORY) {
|
if (rawFileEntry.getKind() != FileKind.FILE) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,6 +46,7 @@ public class BrowserEntry {
|
||||||
if (rawFileEntry == null) {
|
if (rawFileEntry == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
rawFileEntry = rawFileEntry.resolved();
|
||||||
|
|
||||||
if (rawFileEntry.getKind() != FileKind.DIRECTORY) {
|
if (rawFileEntry.getKind() != FileKind.DIRECTORY) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -58,13 +60,14 @@ public class BrowserEntry {
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getIcon() {
|
public String getIcon() {
|
||||||
if (fileType != null) {
|
if (fileType != null) {
|
||||||
return fileType.getIcon();
|
return fileType.getIcon();
|
||||||
} else if (directoryType != null) {
|
} else if (directoryType != null) {
|
||||||
return directoryType.getIcon(rawFileEntry, false);
|
return directoryType.getIcon(rawFileEntry, false);
|
||||||
} else {
|
} else {
|
||||||
return rawFileEntry.getKind() == FileKind.DIRECTORY
|
return rawFileEntry != null && rawFileEntry.resolved().getKind() == FileKind.DIRECTORY
|
||||||
? "default_folder.svg"
|
? "default_folder.svg"
|
||||||
: "default_file.svg";
|
: "default_file.svg";
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,6 +60,7 @@ public class StoreToggleComp extends SimpleComp {
|
||||||
v -> {
|
v -> {
|
||||||
setter.accept(section.getWrapper().getEntry().getStore().asNeeded(), v);
|
setter.accept(section.getWrapper().getEntry().getStore().asNeeded(), v);
|
||||||
});
|
});
|
||||||
|
t.tooltipKey("enabled");
|
||||||
t.value.subscribe((newValue) -> {
|
t.value.subscribe((newValue) -> {
|
||||||
val.set(newValue);
|
val.set(newValue);
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,6 +6,7 @@ import io.xpipe.app.fxcomps.util.LabelGraphic;
|
||||||
import io.xpipe.app.fxcomps.util.PlatformThread;
|
import io.xpipe.app.fxcomps.util.PlatformThread;
|
||||||
import javafx.beans.property.Property;
|
import javafx.beans.property.Property;
|
||||||
import javafx.beans.value.ObservableValue;
|
import javafx.beans.value.ObservableValue;
|
||||||
|
import javafx.css.PseudoClass;
|
||||||
import javafx.scene.input.KeyCode;
|
import javafx.scene.input.KeyCode;
|
||||||
import javafx.scene.input.KeyEvent;
|
import javafx.scene.input.KeyEvent;
|
||||||
import javafx.scene.layout.Region;
|
import javafx.scene.layout.Region;
|
||||||
|
@ -44,6 +45,7 @@ public class ToggleSwitchComp extends SimpleComp {
|
||||||
}
|
}
|
||||||
if (graphic != null) {
|
if (graphic != null) {
|
||||||
s.graphicProperty().bind(PlatformThread.sync(graphic.map(labelGraphic -> labelGraphic.createGraphicNode())));
|
s.graphicProperty().bind(PlatformThread.sync(graphic.map(labelGraphic -> labelGraphic.createGraphicNode())));
|
||||||
|
s.pseudoClassStateChanged(PseudoClass.getPseudoClass("has-graphic"),true);
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
|
@ -167,7 +167,7 @@ public class StoreEntryWrapper {
|
||||||
try {
|
try {
|
||||||
var newProviders = ActionProvider.ALL.stream()
|
var newProviders = ActionProvider.ALL.stream()
|
||||||
.filter(dataStoreActionProvider -> {
|
.filter(dataStoreActionProvider -> {
|
||||||
return !dataStoreActionProvider.equals(defaultProvider) && showActionProvider(dataStoreActionProvider);
|
return showActionProvider(dataStoreActionProvider);
|
||||||
})
|
})
|
||||||
.sorted(Comparator.comparing(
|
.sorted(Comparator.comparing(
|
||||||
actionProvider -> actionProvider.getLeafDataStoreCallSite() != null &&
|
actionProvider -> actionProvider.getLeafDataStoreCallSite() != null &&
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
package io.xpipe.app.ext;
|
||||||
|
|
||||||
|
import io.xpipe.app.comp.base.StoreToggleComp;
|
||||||
|
import io.xpipe.app.comp.store.StoreEntryComp;
|
||||||
|
import io.xpipe.app.comp.store.StoreSection;
|
||||||
|
import io.xpipe.app.comp.store.StoreViewState;
|
||||||
|
import io.xpipe.app.fxcomps.util.BindingsHelper;
|
||||||
|
import io.xpipe.app.storage.DataStorage;
|
||||||
|
import io.xpipe.app.storage.DataStoreEntry;
|
||||||
|
import io.xpipe.core.store.EnabledStoreState;
|
||||||
|
import io.xpipe.core.store.StatefulDataStore;
|
||||||
|
|
||||||
|
public interface EnabledParentStoreProvider extends DataStoreProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public default StoreEntryComp customEntryComp(StoreSection sec, boolean preferLarge) {
|
||||||
|
if (sec.getWrapper().getValidity().getValue() != DataStoreEntry.Validity.COMPLETE) {
|
||||||
|
return StoreEntryComp.create(sec.getWrapper(), null, preferLarge);
|
||||||
|
}
|
||||||
|
|
||||||
|
var enabled = StoreToggleComp.<StatefulDataStore<EnabledStoreState>>enableToggle(
|
||||||
|
null, sec, s -> s.getState().isEnabled(), (s, aBoolean) -> {
|
||||||
|
var state = s.getState().toBuilder().enabled(aBoolean).build();
|
||||||
|
s.setState(state);
|
||||||
|
});
|
||||||
|
|
||||||
|
var e = sec.getWrapper().getEntry();
|
||||||
|
var parent = DataStorage.get().getDefaultDisplayParent(e);
|
||||||
|
if (parent.isPresent()) {
|
||||||
|
var parentWrapper = StoreViewState.get().getEntryWrapper(parent.get());
|
||||||
|
// Disable selection if parent is already made enabled
|
||||||
|
enabled.setCustomVisibility(BindingsHelper.map(parentWrapper.getPersistentState(), o -> {
|
||||||
|
EnabledStoreState state = (EnabledStoreState) o;
|
||||||
|
return !state.isEnabled();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
return StoreEntryComp.create(sec.getWrapper(), enabled, preferLarge);
|
||||||
|
}
|
||||||
|
}
|
25
app/src/main/java/io/xpipe/app/ext/EnabledStoreProvider.java
Normal file
25
app/src/main/java/io/xpipe/app/ext/EnabledStoreProvider.java
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
package io.xpipe.app.ext;
|
||||||
|
|
||||||
|
import io.xpipe.app.comp.base.StoreToggleComp;
|
||||||
|
import io.xpipe.app.comp.store.StoreEntryComp;
|
||||||
|
import io.xpipe.app.comp.store.StoreSection;
|
||||||
|
import io.xpipe.app.storage.DataStoreEntry;
|
||||||
|
import io.xpipe.core.store.EnabledStoreState;
|
||||||
|
import io.xpipe.core.store.StatefulDataStore;
|
||||||
|
|
||||||
|
public interface EnabledStoreProvider extends DataStoreProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public default StoreEntryComp customEntryComp(StoreSection sec, boolean preferLarge) {
|
||||||
|
if (sec.getWrapper().getValidity().getValue() != DataStoreEntry.Validity.COMPLETE) {
|
||||||
|
return StoreEntryComp.create(sec.getWrapper(), null, preferLarge);
|
||||||
|
}
|
||||||
|
|
||||||
|
var enabled = StoreToggleComp.<StatefulDataStore<EnabledStoreState>>enableToggle(
|
||||||
|
null, sec, s -> s.getState().isEnabled(), (s, aBoolean) -> {
|
||||||
|
var state = s.getState().toBuilder().enabled(aBoolean).build();
|
||||||
|
s.setState(state);
|
||||||
|
});
|
||||||
|
return StoreEntryComp.create(sec.getWrapper(), enabled, preferLarge);
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,12 +6,14 @@ import io.xpipe.app.comp.store.StoreEntryComp;
|
||||||
import io.xpipe.app.comp.store.StoreEntryWrapper;
|
import io.xpipe.app.comp.store.StoreEntryWrapper;
|
||||||
import io.xpipe.app.comp.store.StoreSection;
|
import io.xpipe.app.comp.store.StoreSection;
|
||||||
import io.xpipe.app.fxcomps.Comp;
|
import io.xpipe.app.fxcomps.Comp;
|
||||||
|
import io.xpipe.app.fxcomps.util.LabelGraphic;
|
||||||
import io.xpipe.app.util.ThreadHelper;
|
import io.xpipe.app.util.ThreadHelper;
|
||||||
import io.xpipe.core.store.SingletonSessionStore;
|
import io.xpipe.core.store.SingletonSessionStore;
|
||||||
|
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.property.SimpleBooleanProperty;
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
import javafx.beans.value.ObservableBooleanValue;
|
import javafx.beans.value.ObservableBooleanValue;
|
||||||
|
import javafx.beans.value.ObservableValue;
|
||||||
|
|
||||||
public interface SingletonSessionStoreProvider extends DataStoreProvider {
|
public interface SingletonSessionStoreProvider extends DataStoreProvider {
|
||||||
|
|
||||||
|
@ -38,7 +40,9 @@ public interface SingletonSessionStoreProvider extends DataStoreProvider {
|
||||||
enabled.set(s.isSessionEnabled());
|
enabled.set(s.isSessionEnabled());
|
||||||
});
|
});
|
||||||
|
|
||||||
var t = new StoreToggleComp(null, null, sec, enabled, aBoolean -> {
|
ObservableValue<LabelGraphic> g = enabled.map(aBoolean -> aBoolean ?
|
||||||
|
new LabelGraphic.IconGraphic("mdi2c-circle-slice-8") : new LabelGraphic.IconGraphic("mdi2p-power"));
|
||||||
|
var t = new StoreToggleComp(null, g, sec, enabled, aBoolean -> {
|
||||||
SingletonSessionStore<?> s = sec.getWrapper().getEntry().getStore().asNeeded();
|
SingletonSessionStore<?> s = sec.getWrapper().getEntry().getStore().asNeeded();
|
||||||
if (s.isSessionEnabled() != aBoolean) {
|
if (s.isSessionEnabled() != aBoolean) {
|
||||||
ThreadHelper.runFailableAsync(() -> {
|
ThreadHelper.runFailableAsync(() -> {
|
||||||
|
@ -50,6 +54,7 @@ public interface SingletonSessionStoreProvider extends DataStoreProvider {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
t.tooltipKey("enabled");
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,12 +29,12 @@ The XPipe application will start up an HTTP server that can be used to send requ
|
||||||
You can change the port of it in the settings menu.
|
You can change the port of it in the settings menu.
|
||||||
Note that this server is HTTP-only for now as it runs only on localhost. HTTPS requests are not accepted.
|
Note that this server is HTTP-only for now as it runs only on localhost. HTTPS requests are not accepted.
|
||||||
|
|
||||||
The main use case for the API right now is programmatically managing remote systems.
|
This allows you to programmatically manage remote systems.
|
||||||
To start off, you can query connections based on various filters.
|
To start off, you can query connections based on various filters.
|
||||||
With the matched connections, you can start remote shell sessions for each one and run arbitrary commands in them.
|
With the matched connections, you can start remote shell sessions for each one and run arbitrary commands in them.
|
||||||
You get the command exit code and output as a response, allowing you to adapt your control flow based on command outputs.
|
You get the command exit code and output as a response, allowing you to adapt your control flow based on command outputs.
|
||||||
Any kind of passwords another secret are automatically provided by XPipe when establishing a shell connection.
|
Any kind of passwords and other secrets are automatically provided by XPipe when establishing a shell connection.
|
||||||
If required password is not stored and is set to be dynamically prompted, the running XPipe application will ask you to enter any required passwords.
|
If a required password is not stored and is set to be dynamically prompted, the running XPipe application will ask you to enter any required passwords.
|
||||||
|
|
||||||
You can quickly get started by either using this page as an API reference or alternatively import the [OpenAPI definition file](/openapi.yaml) into your API client of choice.
|
You can quickly get started by either using this page as an API reference or alternatively import the [OpenAPI definition file](/openapi.yaml) into your API client of choice.
|
||||||
See the authentication handshake below on how to authenticate prior to sending requests.
|
See the authentication handshake below on how to authenticate prior to sending requests.
|
||||||
|
@ -102,9 +102,6 @@ Note that for development you can also turn off the required authentication in t
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|The handshake was successful. The returned token can be used for authentication in this session. The token is valid as long as XPipe is running.|[HandshakeResponse](#schemahandshakeresponse)|
|
|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|The handshake was successful. The returned token can be used for authentication in this session. The token is valid as long as XPipe is running.|[HandshakeResponse](#schemahandshakeresponse)|
|
||||||
|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad request. Please check error message and your parameters.|None|
|
|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad request. Please check error message and your parameters.|None|
|
||||||
|401|[Unauthorized](https://tools.ietf.org/html/rfc7235#section-3.1)|Authorization failed. Please supply a `Bearer` token via the `Authorization` header.|None|
|
|
||||||
|403|[Forbidden](https://tools.ietf.org/html/rfc7231#section-6.5.3)|Authorization failed. Please supply a valid `Bearer` token via the `Authorization` header.|None|
|
|
||||||
|404|[Not Found](https://tools.ietf.org/html/rfc7231#section-6.5.4)|The requested resource could not be found.|None|
|
|
||||||
|500|[Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1)|Internal error.|None|
|
|500|[Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1)|Internal error.|None|
|
||||||
|
|
||||||
<aside class="success">
|
<aside class="success">
|
||||||
|
@ -152,26 +149,48 @@ headers = {
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json'
|
||||||
}
|
}
|
||||||
|
|
||||||
r = requests.post('http://localhost:21721/handshake', headers = headers)
|
data = """
|
||||||
|
{
|
||||||
|
"auth": {
|
||||||
|
"type": "ApiKey",
|
||||||
|
"key": "<API key>"
|
||||||
|
},
|
||||||
|
"client": {
|
||||||
|
"type": "Api",
|
||||||
|
"name": "My client name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
r = requests.post('http://localhost:21721/handshake', headers = headers, data = data)
|
||||||
|
|
||||||
print(r.json())
|
print(r.json())
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
```java
|
```java
|
||||||
URL obj = new URL("http://localhost:21721/handshake");
|
var uri = URI.create("http://localhost:21721/handshake");
|
||||||
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
|
var client = HttpClient.newHttpClient();
|
||||||
con.setRequestMethod("POST");
|
var request = HttpRequest
|
||||||
int responseCode = con.getResponseCode();
|
.newBuilder()
|
||||||
BufferedReader in = new BufferedReader(
|
.uri(uri)
|
||||||
new InputStreamReader(con.getInputStream()));
|
.header("Content-Type", "application/json")
|
||||||
String inputLine;
|
.header("Accept", "application/json")
|
||||||
StringBuffer response = new StringBuffer();
|
.POST(HttpRequest.BodyPublishers.ofString("""
|
||||||
while ((inputLine = in.readLine()) != null) {
|
{
|
||||||
response.append(inputLine);
|
"auth": {
|
||||||
|
"type": "ApiKey",
|
||||||
|
"key": "<API key>"
|
||||||
|
},
|
||||||
|
"client": {
|
||||||
|
"type": "Api",
|
||||||
|
"name": "My client name"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
in.close();
|
"""))
|
||||||
System.out.println(response.toString());
|
.build();
|
||||||
|
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
|
||||||
|
System.out.println(response.statusCode());
|
||||||
|
System.out.println(response.body());
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -204,8 +223,19 @@ func main() {
|
||||||
```shell
|
```shell
|
||||||
# You can also use wget
|
# You can also use wget
|
||||||
curl -X POST http://localhost:21721/handshake \
|
curl -X POST http://localhost:21721/handshake \
|
||||||
-H 'Content-Type: application/json' \
|
-H 'Content-Type: application/json' \ -H 'Accept: application/json' \
|
||||||
-H 'Accept: application/json'
|
--data '
|
||||||
|
{
|
||||||
|
"auth": {
|
||||||
|
"type": "ApiKey",
|
||||||
|
"key": "<API key>"
|
||||||
|
},
|
||||||
|
"client": {
|
||||||
|
"type": "Api",
|
||||||
|
"name": "My client name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -326,26 +356,39 @@ headers = {
|
||||||
'Authorization': 'Bearer {access-token}'
|
'Authorization': 'Bearer {access-token}'
|
||||||
}
|
}
|
||||||
|
|
||||||
r = requests.post('http://localhost:21721/connection/query', headers = headers)
|
data = """
|
||||||
|
{
|
||||||
|
"categoryFilter": "*",
|
||||||
|
"connectionFilter": "*",
|
||||||
|
"typeFilter": "*"
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
r = requests.post('http://localhost:21721/connection/query', headers = headers, data = data)
|
||||||
|
|
||||||
print(r.json())
|
print(r.json())
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
```java
|
```java
|
||||||
URL obj = new URL("http://localhost:21721/connection/query");
|
var uri = URI.create("http://localhost:21721/connection/query");
|
||||||
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
|
var client = HttpClient.newHttpClient();
|
||||||
con.setRequestMethod("POST");
|
var request = HttpRequest
|
||||||
int responseCode = con.getResponseCode();
|
.newBuilder()
|
||||||
BufferedReader in = new BufferedReader(
|
.uri(uri)
|
||||||
new InputStreamReader(con.getInputStream()));
|
.header("Content-Type", "application/json")
|
||||||
String inputLine;
|
.header("Accept", "application/json")
|
||||||
StringBuffer response = new StringBuffer();
|
.header("Authorization", "Bearer {access-token}")
|
||||||
while ((inputLine = in.readLine()) != null) {
|
.POST(HttpRequest.BodyPublishers.ofString("""
|
||||||
response.append(inputLine);
|
{
|
||||||
|
"categoryFilter": "*",
|
||||||
|
"connectionFilter": "*",
|
||||||
|
"typeFilter": "*"
|
||||||
}
|
}
|
||||||
in.close();
|
"""))
|
||||||
System.out.println(response.toString());
|
.build();
|
||||||
|
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
|
||||||
|
System.out.println(response.statusCode());
|
||||||
|
System.out.println(response.body());
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -379,9 +422,14 @@ func main() {
|
||||||
```shell
|
```shell
|
||||||
# You can also use wget
|
# You can also use wget
|
||||||
curl -X POST http://localhost:21721/connection/query \
|
curl -X POST http://localhost:21721/connection/query \
|
||||||
-H 'Content-Type: application/json' \
|
-H 'Content-Type: application/json' \ -H 'Accept: application/json' \ -H 'Authorization: Bearer {access-token}' \
|
||||||
-H 'Accept: application/json' \
|
--data '
|
||||||
-H 'Authorization: Bearer {access-token}'
|
{
|
||||||
|
"categoryFilter": "*",
|
||||||
|
"connectionFilter": "*",
|
||||||
|
"typeFilter": "*"
|
||||||
|
}
|
||||||
|
'
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -462,26 +510,34 @@ headers = {
|
||||||
'Authorization': 'Bearer {access-token}'
|
'Authorization': 'Bearer {access-token}'
|
||||||
}
|
}
|
||||||
|
|
||||||
r = requests.post('http://localhost:21721/shell/start', headers = headers)
|
data = """
|
||||||
|
{
|
||||||
|
"uuid": "f0ec68aa-63f5-405c-b178-9a4454556d6b"
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
r = requests.post('http://localhost:21721/shell/start', headers = headers, data = data)
|
||||||
|
|
||||||
print(r.json())
|
print(r.json())
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
```java
|
```java
|
||||||
URL obj = new URL("http://localhost:21721/shell/start");
|
var uri = URI.create("http://localhost:21721/shell/start");
|
||||||
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
|
var client = HttpClient.newHttpClient();
|
||||||
con.setRequestMethod("POST");
|
var request = HttpRequest
|
||||||
int responseCode = con.getResponseCode();
|
.newBuilder()
|
||||||
BufferedReader in = new BufferedReader(
|
.uri(uri)
|
||||||
new InputStreamReader(con.getInputStream()));
|
.header("Content-Type", "application/json")
|
||||||
String inputLine;
|
.header("Authorization", "Bearer {access-token}")
|
||||||
StringBuffer response = new StringBuffer();
|
.POST(HttpRequest.BodyPublishers.ofString("""
|
||||||
while ((inputLine = in.readLine()) != null) {
|
{
|
||||||
response.append(inputLine);
|
"uuid": "f0ec68aa-63f5-405c-b178-9a4454556d6b"
|
||||||
}
|
}
|
||||||
in.close();
|
"""))
|
||||||
System.out.println(response.toString());
|
.build();
|
||||||
|
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
|
||||||
|
System.out.println(response.statusCode());
|
||||||
|
System.out.println(response.body());
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -514,8 +570,12 @@ func main() {
|
||||||
```shell
|
```shell
|
||||||
# You can also use wget
|
# You can also use wget
|
||||||
curl -X POST http://localhost:21721/shell/start \
|
curl -X POST http://localhost:21721/shell/start \
|
||||||
-H 'Content-Type: application/json' \
|
-H 'Content-Type: application/json' \ -H 'Authorization: Bearer {access-token}' \
|
||||||
-H 'Authorization: Bearer {access-token}'
|
--data '
|
||||||
|
{
|
||||||
|
"uuid": "f0ec68aa-63f5-405c-b178-9a4454556d6b"
|
||||||
|
}
|
||||||
|
'
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -596,26 +656,34 @@ headers = {
|
||||||
'Authorization': 'Bearer {access-token}'
|
'Authorization': 'Bearer {access-token}'
|
||||||
}
|
}
|
||||||
|
|
||||||
r = requests.post('http://localhost:21721/shell/stop', headers = headers)
|
data = """
|
||||||
|
{
|
||||||
|
"uuid": "f0ec68aa-63f5-405c-b178-9a4454556d6b"
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
r = requests.post('http://localhost:21721/shell/stop', headers = headers, data = data)
|
||||||
|
|
||||||
print(r.json())
|
print(r.json())
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
```java
|
```java
|
||||||
URL obj = new URL("http://localhost:21721/shell/stop");
|
var uri = URI.create("http://localhost:21721/shell/stop");
|
||||||
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
|
var client = HttpClient.newHttpClient();
|
||||||
con.setRequestMethod("POST");
|
var request = HttpRequest
|
||||||
int responseCode = con.getResponseCode();
|
.newBuilder()
|
||||||
BufferedReader in = new BufferedReader(
|
.uri(uri)
|
||||||
new InputStreamReader(con.getInputStream()));
|
.header("Content-Type", "application/json")
|
||||||
String inputLine;
|
.header("Authorization", "Bearer {access-token}")
|
||||||
StringBuffer response = new StringBuffer();
|
.POST(HttpRequest.BodyPublishers.ofString("""
|
||||||
while ((inputLine = in.readLine()) != null) {
|
{
|
||||||
response.append(inputLine);
|
"uuid": "f0ec68aa-63f5-405c-b178-9a4454556d6b"
|
||||||
}
|
}
|
||||||
in.close();
|
"""))
|
||||||
System.out.println(response.toString());
|
.build();
|
||||||
|
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
|
||||||
|
System.out.println(response.statusCode());
|
||||||
|
System.out.println(response.body());
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -648,8 +716,12 @@ func main() {
|
||||||
```shell
|
```shell
|
||||||
# You can also use wget
|
# You can also use wget
|
||||||
curl -X POST http://localhost:21721/shell/stop \
|
curl -X POST http://localhost:21721/shell/stop \
|
||||||
-H 'Content-Type: application/json' \
|
-H 'Content-Type: application/json' \ -H 'Authorization: Bearer {access-token}' \
|
||||||
-H 'Authorization: Bearer {access-token}'
|
--data '
|
||||||
|
{
|
||||||
|
"uuid": "f0ec68aa-63f5-405c-b178-9a4454556d6b"
|
||||||
|
}
|
||||||
|
'
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -755,26 +827,37 @@ headers = {
|
||||||
'Authorization': 'Bearer {access-token}'
|
'Authorization': 'Bearer {access-token}'
|
||||||
}
|
}
|
||||||
|
|
||||||
r = requests.post('http://localhost:21721/shell/exec', headers = headers)
|
data = """
|
||||||
|
{
|
||||||
|
"uuid": "f0ec68aa-63f5-405c-b178-9a4454556d6b",
|
||||||
|
"command": "echo $USER"
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
r = requests.post('http://localhost:21721/shell/exec', headers = headers, data = data)
|
||||||
|
|
||||||
print(r.json())
|
print(r.json())
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
```java
|
```java
|
||||||
URL obj = new URL("http://localhost:21721/shell/exec");
|
var uri = URI.create("http://localhost:21721/shell/exec");
|
||||||
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
|
var client = HttpClient.newHttpClient();
|
||||||
con.setRequestMethod("POST");
|
var request = HttpRequest
|
||||||
int responseCode = con.getResponseCode();
|
.newBuilder()
|
||||||
BufferedReader in = new BufferedReader(
|
.uri(uri)
|
||||||
new InputStreamReader(con.getInputStream()));
|
.header("Content-Type", "application/json")
|
||||||
String inputLine;
|
.header("Accept", "application/json")
|
||||||
StringBuffer response = new StringBuffer();
|
.header("Authorization", "Bearer {access-token}")
|
||||||
while ((inputLine = in.readLine()) != null) {
|
.POST(HttpRequest.BodyPublishers.ofString("""
|
||||||
response.append(inputLine);
|
{
|
||||||
|
"uuid": "f0ec68aa-63f5-405c-b178-9a4454556d6b",
|
||||||
|
"command": "echo $USER"
|
||||||
}
|
}
|
||||||
in.close();
|
"""))
|
||||||
System.out.println(response.toString());
|
.build();
|
||||||
|
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
|
||||||
|
System.out.println(response.statusCode());
|
||||||
|
System.out.println(response.body());
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -808,9 +891,13 @@ func main() {
|
||||||
```shell
|
```shell
|
||||||
# You can also use wget
|
# You can also use wget
|
||||||
curl -X POST http://localhost:21721/shell/exec \
|
curl -X POST http://localhost:21721/shell/exec \
|
||||||
-H 'Content-Type: application/json' \
|
-H 'Content-Type: application/json' \ -H 'Accept: application/json' \ -H 'Authorization: Bearer {access-token}' \
|
||||||
-H 'Accept: application/json' \
|
--data '
|
||||||
-H 'Authorization: Bearer {access-token}'
|
{
|
||||||
|
"uuid": "f0ec68aa-63f5-405c-b178-9a4454556d6b",
|
||||||
|
"command": "echo $USER"
|
||||||
|
}
|
||||||
|
'
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -5,11 +5,11 @@
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.toggle-switch .label {
|
.toggle-switch:has-graphic .label {
|
||||||
-fx-font-size: 1.7em;
|
-fx-font-size: 1.7em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toggle-switch {
|
.toggle-switch:has-graphic {
|
||||||
-fx-font-size: 0.8em;
|
-fx-font-size: 0.8em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
package io.xpipe.core.store;
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.experimental.FieldDefaults;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
|
import lombok.extern.jackson.Jacksonized;
|
||||||
|
|
||||||
|
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
|
||||||
|
@Getter
|
||||||
|
@EqualsAndHashCode(callSuper=true)
|
||||||
|
@SuperBuilder(toBuilder = true)
|
||||||
|
@Jacksonized
|
||||||
|
public class EnabledStoreState extends DataStoreState {
|
||||||
|
|
||||||
|
boolean enabled;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataStoreState mergeCopy(DataStoreState newer) {
|
||||||
|
var n = (EnabledStoreState) newer;
|
||||||
|
return EnabledStoreState.builder().enabled(n.enabled).build();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
package io.xpipe.core.store;
|
package io.xpipe.core.store;
|
||||||
|
|
||||||
|
import io.xpipe.core.process.ShellControl;
|
||||||
|
|
||||||
public abstract class NetworkTunnelSession extends Session {
|
public abstract class NetworkTunnelSession extends Session {
|
||||||
|
|
||||||
protected NetworkTunnelSession(SessionListener listener) {
|
protected NetworkTunnelSession(SessionListener listener) {
|
||||||
|
@ -9,4 +11,6 @@ public abstract class NetworkTunnelSession extends Session {
|
||||||
public abstract int getLocalPort();
|
public abstract int getLocalPort();
|
||||||
|
|
||||||
public abstract int getRemotePort();
|
public abstract int getRemotePort();
|
||||||
|
|
||||||
|
public abstract ShellControl getShellControl();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package io.xpipe.core.store;
|
package io.xpipe.core.store;
|
||||||
|
|
||||||
|
import io.xpipe.core.process.ShellControl;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
@ -119,6 +121,11 @@ public interface NetworkTunnelStore extends DataStore {
|
||||||
public int getRemotePort() {
|
public int getRemotePort() {
|
||||||
return remotePort;
|
return remotePort;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ShellControl getShellControl() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package io.xpipe.core.store;
|
package io.xpipe.core.store;
|
||||||
|
|
||||||
|
import io.xpipe.core.process.ShellControl;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class SessionChain extends NetworkTunnelSession {
|
public class SessionChain extends NetworkTunnelSession {
|
||||||
|
@ -15,6 +17,10 @@ public class SessionChain extends NetworkTunnelSession {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ShellControl getShellControl() {
|
||||||
|
return sessions.getLast().getShellControl();
|
||||||
|
}
|
||||||
|
|
||||||
public int getLocalPort() {
|
public int getLocalPort() {
|
||||||
return sessions.getFirst().getLocalPort();
|
return sessions.getFirst().getLocalPort();
|
||||||
}
|
}
|
||||||
|
|
4
dist/changelogs/10.0.md
vendored
4
dist/changelogs/10.0.md
vendored
|
@ -47,9 +47,13 @@ You can now order connections relative to other sibling connections. This orderi
|
||||||
|
|
||||||
## Other
|
## Other
|
||||||
|
|
||||||
|
- Support VMs for VNC tunneling
|
||||||
- The Linux installers now contain application icons from multiple sizes it should increase the icon display quality
|
- The Linux installers now contain application icons from multiple sizes it should increase the icon display quality
|
||||||
- The Linux builds now list socat as a dependency such that the kitty terminal integration will work without issues
|
- The Linux builds now list socat as a dependency such that the kitty terminal integration will work without issues
|
||||||
- Searching for connections has been improved to show children as well
|
- Searching for connections has been improved to show children as well
|
||||||
- The welcome screen will now also contain the option to straight up jump to the synchronization settings
|
- The welcome screen will now also contain the option to straight up jump to the synchronization settings
|
||||||
- Add support for foot terminal
|
- Add support for foot terminal
|
||||||
- Fix elementary terminal not launching correctly
|
- Fix elementary terminal not launching correctly
|
||||||
|
- Fix kubernetes not elevating correctly for non-default contexts
|
||||||
|
- Fix ohmyzsh update notification freezing shell
|
||||||
|
- Fix file browser icons being broken for links
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
package io.xpipe.ext.base.script;
|
package io.xpipe.ext.base.script;
|
||||||
|
|
||||||
import io.xpipe.app.comp.base.StoreToggleComp;
|
|
||||||
import io.xpipe.app.comp.base.SystemStateComp;
|
import io.xpipe.app.comp.base.SystemStateComp;
|
||||||
import io.xpipe.app.comp.store.*;
|
import io.xpipe.app.comp.store.StoreEntryWrapper;
|
||||||
|
import io.xpipe.app.comp.store.StoreViewState;
|
||||||
import io.xpipe.app.ext.DataStoreProvider;
|
import io.xpipe.app.ext.DataStoreProvider;
|
||||||
|
import io.xpipe.app.ext.EnabledStoreProvider;
|
||||||
import io.xpipe.app.ext.GuiDialog;
|
import io.xpipe.app.ext.GuiDialog;
|
||||||
import io.xpipe.app.fxcomps.Comp;
|
import io.xpipe.app.fxcomps.Comp;
|
||||||
import io.xpipe.app.fxcomps.impl.DataStoreChoiceComp;
|
import io.xpipe.app.fxcomps.impl.DataStoreChoiceComp;
|
||||||
|
@ -18,21 +19,7 @@ import lombok.SneakyThrows;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class ScriptGroupStoreProvider implements DataStoreProvider {
|
public class ScriptGroupStoreProvider implements EnabledStoreProvider, DataStoreProvider {
|
||||||
|
|
||||||
@Override
|
|
||||||
public StoreEntryComp customEntryComp(StoreSection sec, boolean preferLarge) {
|
|
||||||
if (sec.getWrapper().getValidity().getValue() != DataStoreEntry.Validity.COMPLETE) {
|
|
||||||
return new DenseStoreEntryComp(sec.getWrapper(), true, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
var enabled = StoreToggleComp.<ScriptGroupStore>enableToggle(
|
|
||||||
null, sec, s -> s.getState().isEnabled(), (s, aBoolean) -> {
|
|
||||||
var state = s.getState().toBuilder().enabled(aBoolean).build();
|
|
||||||
s.setState(state);
|
|
||||||
});
|
|
||||||
return new DenseStoreEntryComp(sec.getWrapper(), true, enabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Comp<?> stateDisplay(StoreEntryWrapper w) {
|
public Comp<?> stateDisplay(StoreEntryWrapper w) {
|
||||||
|
@ -89,6 +76,11 @@ public class ScriptGroupStoreProvider implements DataStoreProvider {
|
||||||
return new SimpleStringProperty(scriptStore.getDescription());
|
return new SimpleStringProperty(scriptStore.getDescription());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String summaryString(StoreEntryWrapper wrapper) {
|
||||||
|
return "Script group";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getDisplayIconFileName(DataStore store) {
|
public String getDisplayIconFileName(DataStore store) {
|
||||||
return "proc:shellEnvironment_icon.svg";
|
return "proc:shellEnvironment_icon.svg";
|
||||||
|
|
|
@ -9,20 +9,21 @@ import io.xpipe.app.util.Validators;
|
||||||
import io.xpipe.core.process.ShellControl;
|
import io.xpipe.core.process.ShellControl;
|
||||||
import io.xpipe.core.process.ShellInitCommand;
|
import io.xpipe.core.process.ShellInitCommand;
|
||||||
import io.xpipe.core.store.DataStore;
|
import io.xpipe.core.store.DataStore;
|
||||||
import io.xpipe.core.store.DataStoreState;
|
import io.xpipe.core.store.EnabledStoreState;
|
||||||
import io.xpipe.core.store.FileNames;
|
import io.xpipe.core.store.FileNames;
|
||||||
import io.xpipe.core.store.StatefulDataStore;
|
import io.xpipe.core.store.StatefulDataStore;
|
||||||
import io.xpipe.core.util.JacksonizedValue;
|
import io.xpipe.core.util.JacksonizedValue;
|
||||||
import lombok.*;
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Singular;
|
||||||
import lombok.experimental.SuperBuilder;
|
import lombok.experimental.SuperBuilder;
|
||||||
import lombok.extern.jackson.Jacksonized;
|
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@SuperBuilder
|
@SuperBuilder
|
||||||
@Getter
|
@Getter
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public abstract class ScriptStore extends JacksonizedValue implements DataStore, StatefulDataStore<ScriptStore.State> {
|
public abstract class ScriptStore extends JacksonizedValue implements DataStore, StatefulDataStore<EnabledStoreState> {
|
||||||
|
|
||||||
protected final DataStoreEntryRef<ScriptGroupStore> group;
|
protected final DataStoreEntryRef<ScriptGroupStore> group;
|
||||||
|
|
||||||
|
@ -185,8 +186,8 @@ public abstract class ScriptStore extends JacksonizedValue implements DataStore,
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class<State> getStateClass() {
|
public Class<EnabledStoreState> getStateClass() {
|
||||||
return State.class;
|
return EnabledStoreState.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -211,12 +212,4 @@ public abstract class ScriptStore extends JacksonizedValue implements DataStore,
|
||||||
protected abstract void queryFlattenedScripts(LinkedHashSet<SimpleScriptStore> all);
|
protected abstract void queryFlattenedScripts(LinkedHashSet<SimpleScriptStore> all);
|
||||||
|
|
||||||
public abstract List<DataStoreEntryRef<ScriptStore>> getEffectiveScripts();
|
public abstract List<DataStoreEntryRef<ScriptStore>> getEffectiveScripts();
|
||||||
|
|
||||||
@Value
|
|
||||||
@EqualsAndHashCode(callSuper=true)
|
|
||||||
@SuperBuilder(toBuilder = true)
|
|
||||||
@Jacksonized
|
|
||||||
public static class State extends DataStoreState {
|
|
||||||
boolean enabled;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,18 @@
|
||||||
package io.xpipe.ext.base.script;
|
package io.xpipe.ext.base.script;
|
||||||
|
|
||||||
import io.xpipe.app.comp.base.*;
|
import io.xpipe.app.comp.base.IntegratedTextAreaComp;
|
||||||
import io.xpipe.app.comp.store.*;
|
import io.xpipe.app.comp.base.ListSelectorComp;
|
||||||
|
import io.xpipe.app.comp.base.SystemStateComp;
|
||||||
|
import io.xpipe.app.comp.store.StoreEntryWrapper;
|
||||||
|
import io.xpipe.app.comp.store.StoreViewState;
|
||||||
import io.xpipe.app.core.AppExtensionManager;
|
import io.xpipe.app.core.AppExtensionManager;
|
||||||
import io.xpipe.app.core.AppI18n;
|
import io.xpipe.app.core.AppI18n;
|
||||||
import io.xpipe.app.ext.DataStoreProvider;
|
import io.xpipe.app.ext.DataStoreProvider;
|
||||||
|
import io.xpipe.app.ext.EnabledParentStoreProvider;
|
||||||
import io.xpipe.app.ext.GuiDialog;
|
import io.xpipe.app.ext.GuiDialog;
|
||||||
import io.xpipe.app.fxcomps.Comp;
|
import io.xpipe.app.fxcomps.Comp;
|
||||||
import io.xpipe.app.fxcomps.impl.DataStoreChoiceComp;
|
import io.xpipe.app.fxcomps.impl.DataStoreChoiceComp;
|
||||||
import io.xpipe.app.fxcomps.impl.DataStoreListChoiceComp;
|
import io.xpipe.app.fxcomps.impl.DataStoreListChoiceComp;
|
||||||
import io.xpipe.app.fxcomps.util.BindingsHelper;
|
|
||||||
import io.xpipe.app.storage.DataStoreEntry;
|
import io.xpipe.app.storage.DataStoreEntry;
|
||||||
import io.xpipe.app.util.MarkdownBuilder;
|
import io.xpipe.app.util.MarkdownBuilder;
|
||||||
import io.xpipe.app.util.OptionsBuilder;
|
import io.xpipe.app.util.OptionsBuilder;
|
||||||
|
@ -31,7 +34,7 @@ import java.util.List;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class SimpleScriptStoreProvider implements DataStoreProvider {
|
public class SimpleScriptStoreProvider implements EnabledParentStoreProvider, DataStoreProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean editByDefault() {
|
public boolean editByDefault() {
|
||||||
|
@ -43,30 +46,6 @@ public class SimpleScriptStoreProvider implements DataStoreProvider {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public StoreEntryComp customEntryComp(StoreSection sec, boolean preferLarge) {
|
|
||||||
if (sec.getWrapper().getValidity().getValue() != DataStoreEntry.Validity.COMPLETE) {
|
|
||||||
return new DenseStoreEntryComp(sec.getWrapper(), true, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
var enabled = StoreToggleComp.<SimpleScriptStore>enableToggle(
|
|
||||||
null, sec, s -> s.getState().isEnabled(), (s, aBoolean) -> {
|
|
||||||
var state = s.getState().toBuilder().enabled(aBoolean).build();
|
|
||||||
s.setState(state);
|
|
||||||
});
|
|
||||||
|
|
||||||
SimpleScriptStore s = sec.getWrapper().getEntry().getStore().asNeeded();
|
|
||||||
var groupWrapper = StoreViewState.get().getEntryWrapper(s.getGroup().getEntry());
|
|
||||||
|
|
||||||
// Disable selection if parent group is already made enabled
|
|
||||||
enabled.setCustomVisibility(BindingsHelper.map(groupWrapper.getPersistentState(), o -> {
|
|
||||||
ScriptStore.State state = (ScriptStore.State) o;
|
|
||||||
return !state.isEnabled();
|
|
||||||
}));
|
|
||||||
|
|
||||||
return new DenseStoreEntryComp(sec.getWrapper(), true, enabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldHaveChildren() {
|
public boolean shouldHaveChildren() {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -32,6 +32,7 @@ open module io.xpipe.ext.base {
|
||||||
requires static io.xpipe.app;
|
requires static io.xpipe.app;
|
||||||
requires org.kordamp.ikonli.javafx;
|
requires org.kordamp.ikonli.javafx;
|
||||||
requires atlantafx.base;
|
requires atlantafx.base;
|
||||||
|
requires jdk.jfr;
|
||||||
|
|
||||||
provides BrowserAction with RunScriptAction,
|
provides BrowserAction with RunScriptAction,
|
||||||
FollowLinkAction,
|
FollowLinkAction,
|
||||||
|
|
Binary file not shown.
|
@ -63,12 +63,6 @@ paths:
|
||||||
$ref: '#/components/schemas/HandshakeResponse'
|
$ref: '#/components/schemas/HandshakeResponse'
|
||||||
400:
|
400:
|
||||||
$ref: '#/components/responses/BadRequest'
|
$ref: '#/components/responses/BadRequest'
|
||||||
401:
|
|
||||||
$ref: '#/components/responses/Unauthorized'
|
|
||||||
403:
|
|
||||||
$ref: '#/components/responses/Forbidden'
|
|
||||||
404:
|
|
||||||
$ref: '#/components/responses/NotFound'
|
|
||||||
500:
|
500:
|
||||||
$ref: '#/components/responses/InternalServerError'
|
$ref: '#/components/responses/InternalServerError'
|
||||||
/connection/query:
|
/connection/query:
|
||||||
|
|
Loading…
Reference in a new issue