diff --git a/app/src/main/java/io/xpipe/app/beacon/BeaconRequestHandler.java b/app/src/main/java/io/xpipe/app/beacon/BeaconRequestHandler.java index 32abfc79..d0d2064b 100644 --- a/app/src/main/java/io/xpipe/app/beacon/BeaconRequestHandler.java +++ b/app/src/main/java/io/xpipe/app/beacon/BeaconRequestHandler.java @@ -118,7 +118,10 @@ public class BeaconRequestHandler implements HttpHandler { exchange.sendResponseHeaders(200, -1); } } catch (IOException ioException) { - ErrorEvent.fromThrowable(ioException).omit().expected().handle(); + // The exchange implementation might have already sent a response manually + if (!"headers already sent".equals(ioException.getMessage())) { + ErrorEvent.fromThrowable(ioException).omit().expected().handle(); + } } catch (Throwable other) { ErrorEvent.fromThrowable(other).handle(); writeError(exchange, new BeaconServerErrorResponse(other), 500); diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/AskpassExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/AskpassExchangeImpl.java index 27242757..74d1a66e 100644 --- a/app/src/main/java/io/xpipe/app/beacon/impl/AskpassExchangeImpl.java +++ b/app/src/main/java/io/xpipe/app/beacon/impl/AskpassExchangeImpl.java @@ -25,7 +25,7 @@ public class AskpassExchangeImpl extends AskpassExchange { ? SecretManager.getProgress(msg.getRequest(), msg.getSecretId()) : SecretManager.getProgress(msg.getRequest()); if (found.isEmpty()) { - throw new BeaconClientException("No password was provided"); + throw new BeaconClientException("Unknown askpass request"); } var p = found.get(); diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/FsReadExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/FsReadExchangeImpl.java new file mode 100644 index 00000000..a28a6e4a --- /dev/null +++ b/app/src/main/java/io/xpipe/app/beacon/impl/FsReadExchangeImpl.java @@ -0,0 +1,26 @@ +package io.xpipe.app.beacon.impl; + +import com.sun.net.httpserver.HttpExchange; +import io.xpipe.app.beacon.AppBeaconServer; +import io.xpipe.beacon.api.FsReadExchange; +import io.xpipe.core.store.ConnectionFileSystem; +import lombok.SneakyThrows; + +public class FsReadExchangeImpl extends FsReadExchange { + + @Override + @SneakyThrows + public Object handle(HttpExchange exchange, Request msg) { + var shell = AppBeaconServer.get().getCache().getShellSession(msg.getConnection()); + var fs = new ConnectionFileSystem(shell.getControl()); + byte[] bytes; + try (var in = fs.openInput(msg.getPath().toString())) { + bytes = in.readAllBytes(); + } + exchange.sendResponseHeaders(200, bytes.length); + try (var out = exchange.getResponseBody()) { + out.write(bytes); + } + return Response.builder().build(); + } +} diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserBookmarkComp.java b/app/src/main/java/io/xpipe/app/browser/BrowserBookmarkComp.java index da3bd99d..c07d9d49 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserBookmarkComp.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserBookmarkComp.java @@ -76,7 +76,7 @@ public final class BrowserBookmarkComp extends SimpleComp { var section = new StoreSectionMiniComp( StoreSection.createTopLevel( - StoreViewState.get().getAllEntries(), this::filter, filterText, selectedCategory), + StoreViewState.get().getAllEntries(), this::filter, filterText, selectedCategory, StoreViewState.get().getEntriesListUpdateObservable()), augment, entryWrapper -> action.accept(entryWrapper, busy), true); diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryComp.java index a2f4cc9f..12cf7497 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryComp.java @@ -18,6 +18,7 @@ import io.xpipe.app.fxcomps.util.PlatformThread; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStoreColor; +import io.xpipe.app.storage.DataStoreEntry; import io.xpipe.app.update.XPipeDistributionType; import io.xpipe.app.util.*; @@ -369,57 +370,41 @@ public abstract class StoreEntryComp extends SimpleComp { }); contextMenu.getItems().add(move); } - - var order = new Menu(AppI18n.get("order"), new FontIcon("mdal-bookmarks")); - var noOrder = new MenuItem(AppI18n.get("none"), new FontIcon("mdi2r-reorder-horizontal")); - noOrder.setOnAction(event -> { - DataStorage.get().orderBefore(wrapper.getEntry(), null); - event.consume(); - }); - if (wrapper.getEntry().getOrderBefore() == null) { - noOrder.setDisable(true); - } - order.getItems().add(noOrder); - order.getItems().add(new SeparatorMenuItem()); - var stick = new MenuItem(AppI18n.get("stickToTop"), new FontIcon("mdi2o-order-bool-descending")); - stick.setOnAction(event -> { - DataStorage.get().orderBefore(wrapper.getEntry(), wrapper.getEntry()); - event.consume(); - }); - if (wrapper.getEntry().getUuid().equals(wrapper.getEntry().getOrderBefore())) { - stick.setDisable(true); - } - order.getItems().add(stick); - order.getItems().add(new SeparatorMenuItem()); - var desc = new MenuItem(AppI18n.get("orderAheadOf"), new FontIcon("mdi2o-order-bool-descending-variant")); - desc.setDisable(true); - order.getItems().add(desc); - var section = StoreViewState.get().getParentSectionForWrapper(wrapper); - if (section.isPresent()) { - section.get().getAllChildren().getList().forEach(other -> { - var ow = other.getWrapper(); - var op = ow.getEntry().getProvider(); - MenuItem m = new MenuItem( - ow.getName().getValue(), - op != null - ? PrettyImageHelper.ofFixedSizeSquare( - op.getDisplayIconFileName( - ow.getEntry().getStore()), - 16) - .createRegion() - : null); - if (other.getWrapper().equals(wrapper) - || ow.getEntry().getUuid().equals(wrapper.getEntry().getOrderBefore())) { - m.setDisable(true); - } - m.setOnAction(event -> { - wrapper.orderBefore(ow); - event.consume(); - }); - order.getItems().add(m); + { + var order = new Menu(AppI18n.get("order"), new FontIcon("mdal-bookmarks")); + var noOrder = new MenuItem(AppI18n.get("none"), new FontIcon("mdi2r-reorder-horizontal")); + noOrder.setOnAction(event -> { + wrapper.setOrder(null); + event.consume(); }); + if (wrapper.getEntry().getExplicitOrder() == null) { + noOrder.setDisable(true); + } + order.getItems().add(noOrder); + order.getItems().add(new SeparatorMenuItem()); + + var top = new MenuItem(AppI18n.get("stickToTop"), new FontIcon("mdi2o-order-bool-descending")); + top.setOnAction(event -> { + wrapper.setOrder(DataStoreEntry.Order.TOP); + event.consume(); + }); + if (DataStoreEntry.Order.TOP.equals(wrapper.getEntry().getExplicitOrder())) { + top.setDisable(true); + } + order.getItems().add(top); + + + var bottom = new MenuItem(AppI18n.get("stickToBottom"), new FontIcon("mdi2o-order-bool-ascending")); + bottom.setOnAction(event -> { + wrapper.setOrder(DataStoreEntry.Order.BOTTOM); + event.consume(); + }); + if (DataStoreEntry.Order.BOTTOM.equals(wrapper.getEntry().getExplicitOrder())) { + bottom.setDisable(true); + } + order.getItems().add(bottom); + contextMenu.getItems().add(order); } - contextMenu.getItems().add(order); contextMenu.getItems().add(new SeparatorMenuItem()); diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryWrapper.java b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryWrapper.java index 1519be85..6a5cdef1 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryWrapper.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryWrapper.java @@ -68,9 +68,9 @@ public class StoreEntryWrapper { }); } - public void orderBefore(StoreEntryWrapper other) { + public void setOrder(DataStoreEntry.Order order) { ThreadHelper.runAsync(() -> { - DataStorage.get().orderBefore(getEntry(), other.getEntry()); + DataStorage.get().setOrder(getEntry(), order); }); } diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreSection.java b/app/src/main/java/io/xpipe/app/comp/store/StoreSection.java index 655253e9..24d5f663 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreSection.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreSection.java @@ -10,6 +10,7 @@ import io.xpipe.app.storage.DataStoreEntry; import javafx.beans.binding.Bindings; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.value.ObservableBooleanValue; +import javafx.beans.value.ObservableIntegerValue; import javafx.beans.value.ObservableStringValue; import javafx.beans.value.ObservableValue; import javafx.collections.FXCollections; @@ -61,7 +62,8 @@ public class StoreSection { } private static DerivedObservableList sorted( - DerivedObservableList list, ObservableValue category) { + DerivedObservableList list, ObservableValue category, + ObservableIntegerValue updateObservable) { if (category == null) { return list; } @@ -69,36 +71,15 @@ public class StoreSection { var explicitOrderComp = Comparator.comparingInt(new ToIntFunction<>() { @Override public int applyAsInt(StoreSection value) { - var explicit = value.getWrapper().getEntry().getOrderBefore(); + var explicit = value.getWrapper().getEntry().getExplicitOrder(); if (explicit == null) { - return 1; - } - - if (explicit.equals(value.getWrapper().getEntry().getUuid())) { - return Integer.MIN_VALUE; - } - - return -count(value.getWrapper(), new HashSet<>()); - } - - private int count(StoreEntryWrapper wrapper, Set seen) { - if (seen.contains(wrapper)) { - // Loop! return 0; } - seen.add(wrapper); - var found = list.getList().stream() - .filter(section -> section.getWrapper() - .getEntry() - .getUuid() - .equals(wrapper.getEntry().getOrderBefore())) - .findFirst(); - if (found.isPresent()) { - return count(found.get().getWrapper(), seen); - } else { - return seen.size(); - } + return switch (explicit) { + case TOP -> -1; + case BOTTOM -> 1; + }; } }); var usableComp = Comparator.comparingInt( @@ -118,23 +99,25 @@ public class StoreSection { } }, mappedSortMode, - StoreViewState.get().getEntriesOrderChangeObservable()); + updateObservable); } public static StoreSection createTopLevel( DerivedObservableList all, Predicate entryFilter, ObservableStringValue filterString, - ObservableValue category) { + ObservableValue category, + ObservableIntegerValue updateObservable + ) { var topLevel = all.filtered( section -> { return DataStorage.get().isRootEntry(section.getEntry()); }, category, - StoreViewState.get().getEntriesListChangeObservable()); + updateObservable); var cached = topLevel.mapped( - storeEntryWrapper -> create(List.of(), storeEntryWrapper, 1, all, entryFilter, filterString, category)); - var ordered = sorted(cached, category); + storeEntryWrapper -> create(List.of(), storeEntryWrapper, 1, all, entryFilter, filterString, category, updateObservable)); + var ordered = sorted(cached, category, updateObservable); var shown = ordered.filtered( section -> { // matches filter @@ -160,7 +143,8 @@ public class StoreSection { DerivedObservableList all, Predicate entryFilter, ObservableStringValue filterString, - ObservableValue category) { + ObservableValue category, + ObservableIntegerValue updateObservable) { if (e.getEntry().getValidity() == DataStoreEntry.Validity.LOAD_FAILED) { return new StoreSection( e, @@ -186,11 +170,11 @@ public class StoreSection { }, e.getPersistentState(), e.getCache(), - StoreViewState.get().getEntriesListChangeObservable()); + updateObservable); var l = new ArrayList<>(parents); l.add(e); - var cached = allChildren.mapped(c -> create(l, c, depth + 1, all, entryFilter, filterString, category)); - var ordered = sorted(cached, category); + var cached = allChildren.mapped(c -> create(l, c, depth + 1, all, entryFilter, filterString, category, updateObservable)); + var ordered = sorted(cached, category, updateObservable); var filtered = ordered.filtered( section -> { // matches filter diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreViewState.java b/app/src/main/java/io/xpipe/app/comp/store/StoreViewState.java index 12f3e907..a5914b4c 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreViewState.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreViewState.java @@ -34,10 +34,7 @@ public class StoreViewState { new DerivedObservableList<>(FXCollections.observableList(new CopyOnWriteArrayList<>()), true); @Getter - private final IntegerProperty entriesOrderChangeObservable = new SimpleIntegerProperty(); - - @Getter - private final IntegerProperty entriesListChangeObservable = new SimpleIntegerProperty(); + private final IntegerProperty entriesListUpdateObservable = new SimpleIntegerProperty(); @Getter private final Property activeCategory = new SimpleObjectProperty<>(); @@ -86,7 +83,7 @@ public class StoreViewState { private void initSections() { try { currentTopLevelSection = - StoreSection.createTopLevel(allEntries, storeEntryWrapper -> true, filter, activeCategory); + StoreSection.createTopLevel(allEntries, storeEntryWrapper -> true, filter, activeCategory, entriesListUpdateObservable); } catch (Exception exception) { currentTopLevelSection = new StoreSection( null, @@ -124,15 +121,9 @@ public class StoreViewState { .orElseThrow())); } - public void toggleStoreOrderUpdate() { - PlatformThread.runLaterIfNeeded(() -> { - entriesOrderChangeObservable.set(entriesOrderChangeObservable.get() + 1); - }); - } - public void toggleStoreListUpdate() { PlatformThread.runLaterIfNeeded(() -> { - entriesListChangeObservable.set(entriesListChangeObservable.get() + 1); + entriesListUpdateObservable.set(entriesListUpdateObservable.get() + 1); }); } @@ -152,13 +143,6 @@ public class StoreViewState { // Watch out for synchronizing all calls to the entries and categories list! DataStorage.get().addListener(new StorageListener() { - @Override - public void onStoreOrderUpdate() { - Platform.runLater(() -> { - toggleStoreOrderUpdate(); - }); - } - @Override public void onStoreListUpdate() { Platform.runLater(() -> { diff --git a/app/src/main/java/io/xpipe/app/fxcomps/impl/DataStoreChoiceComp.java b/app/src/main/java/io/xpipe/app/fxcomps/impl/DataStoreChoiceComp.java index 0c3a1a59..25126a14 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/impl/DataStoreChoiceComp.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/impl/DataStoreChoiceComp.java @@ -93,7 +93,8 @@ public class DataStoreChoiceComp extends SimpleComp { }; var section = new StoreSectionMiniComp( StoreSection.createTopLevel( - StoreViewState.get().getAllEntries(), applicable, filterText, selectedCategory), + StoreViewState.get().getAllEntries(), applicable, filterText, selectedCategory, StoreViewState.get() + .getEntriesListUpdateObservable()), (s, comp) -> { if (!applicable.test(s.getWrapper())) { comp.disable(new SimpleBooleanProperty(true)); diff --git a/app/src/main/java/io/xpipe/app/storage/DataStorage.java b/app/src/main/java/io/xpipe/app/storage/DataStorage.java index bb04ff4f..6b50e7cc 100644 --- a/app/src/main/java/io/xpipe/app/storage/DataStorage.java +++ b/app/src/main/java/io/xpipe/app/storage/DataStorage.java @@ -333,9 +333,9 @@ public abstract class DataStorage { saveAsync(); } - public void orderBefore(DataStoreEntry entry, DataStoreEntry reference) { - entry.setOrderBefore(reference != null ? reference.getUuid() : null); - listeners.forEach(storageListener -> storageListener.onStoreOrderUpdate()); + public void setOrder(DataStoreEntry entry, DataStoreEntry.Order order) { + entry.setExplicitOrder(order); + listeners.forEach(storageListener -> storageListener.onStoreListUpdate()); } public boolean refreshChildren(DataStoreEntry e) { diff --git a/app/src/main/java/io/xpipe/app/storage/DataStoreEntry.java b/app/src/main/java/io/xpipe/app/storage/DataStoreEntry.java index c2840481..f60f24a8 100644 --- a/app/src/main/java/io/xpipe/app/storage/DataStoreEntry.java +++ b/app/src/main/java/io/xpipe/app/storage/DataStoreEntry.java @@ -73,7 +73,7 @@ public class DataStoreEntry extends StorageElement { String notes; @NonFinal - UUID orderBefore; + Order explicitOrder; private DataStoreEntry( Path directory, @@ -90,7 +90,8 @@ public class DataStoreEntry extends StorageElement { boolean expanded, DataStoreColor color, String notes, - UUID orderBefore) { + Order explicitOrder + ) { super(directory, uuid, name, lastUsed, lastModified, dirty); this.categoryUuid = categoryUuid; this.store = DataStorageParser.storeFromNode(storeNode); @@ -99,7 +100,7 @@ public class DataStoreEntry extends StorageElement { this.configuration = configuration; this.expanded = expanded; this.color = color; - this.orderBefore = orderBefore; + this.explicitOrder = explicitOrder; this.provider = store != null ? DataStoreProviders.byStoreClass(store.getClass()).orElse(null) : null; @@ -115,11 +116,12 @@ public class DataStoreEntry extends StorageElement { Instant lastUsed, Instant lastModified, DataStore store, - UUID orderBefore) { + Order explicitOrder + ) { super(directory, uuid, name, lastUsed, lastModified, false); this.categoryUuid = categoryUuid; this.store = store; - this.orderBefore = orderBefore; + this.explicitOrder = explicitOrder; this.storeNode = null; this.validity = Validity.INCOMPLETE; this.configuration = Configuration.defaultConfiguration(); @@ -186,7 +188,7 @@ public class DataStoreEntry extends StorageElement { boolean expanded, DataStoreColor color, String notes, - UUID orderBeforeEntry) { + Order order) { return new DataStoreEntry( directory, uuid, @@ -202,7 +204,7 @@ public class DataStoreEntry extends StorageElement { expanded, color, notes, - orderBeforeEntry); + order); } public static Optional fromDirectory(Path dir) throws Exception { @@ -237,10 +239,10 @@ public class DataStoreEntry extends StorageElement { .map(jsonNode -> jsonNode.textValue()) .map(Instant::parse) .orElse(Instant.EPOCH); - var order = Optional.ofNullable(stateJson.get("orderBefore")) + var order = Optional.ofNullable(stateJson.get("order")) .map(node -> { try { - return mapper.treeToValue(node, UUID.class); + return mapper.treeToValue(node, Order.class); } catch (JsonProcessingException e) { return null; } @@ -299,9 +301,9 @@ public class DataStoreEntry extends StorageElement { order)); } - public void setOrderBefore(UUID uuid) { - var changed = !Objects.equals(orderBefore, uuid); - this.orderBefore = uuid; + public void setExplicitOrder(Order uuid) { + var changed = !Objects.equals(explicitOrder, uuid); + this.explicitOrder = uuid; if (changed) { notifyUpdate(false, true); } @@ -415,7 +417,7 @@ public class DataStoreEntry extends StorageElement { stateObj.set("persistentState", storePersistentStateNode); obj.set("configuration", mapper.valueToTree(configuration)); stateObj.put("expanded", expanded); - stateObj.put("orderBefore", orderBefore != null ? orderBefore.toString() : null); + stateObj.put("orderBefore", explicitOrder != null ? explicitOrder.toString() : null); var entryString = mapper.writeValueAsString(obj); var stateString = mapper.writeValueAsString(stateObj); @@ -601,4 +603,13 @@ public class DataStoreEntry extends StorageElement { this.isUsable = isUsable; } } + + + @Getter + public enum Order { + @JsonProperty("top") + TOP, + @JsonProperty("bottom") + BOTTOM; + } } diff --git a/app/src/main/java/io/xpipe/app/storage/StorageListener.java b/app/src/main/java/io/xpipe/app/storage/StorageListener.java index 92b0ea47..5b3e80de 100644 --- a/app/src/main/java/io/xpipe/app/storage/StorageListener.java +++ b/app/src/main/java/io/xpipe/app/storage/StorageListener.java @@ -2,8 +2,6 @@ package io.xpipe.app.storage; public interface StorageListener { - void onStoreOrderUpdate(); - void onStoreListUpdate(); void onStoreAdd(DataStoreEntry... entry); diff --git a/app/src/main/java/module-info.java b/app/src/main/java/module-info.java index 75199566..b29466bb 100644 --- a/app/src/main/java/module-info.java +++ b/app/src/main/java/module-info.java @@ -138,7 +138,7 @@ open module io.xpipe.app { DaemonStatusExchangeImpl, DaemonStopExchangeImpl, HandshakeExchangeImpl, - DaemonModeExchangeImpl, FsBlobExchangeImpl, + DaemonModeExchangeImpl, FsBlobExchangeImpl, FsReadExchangeImpl, FsScriptExchangeImpl, FsWriteExchangeImpl, AskpassExchangeImpl, diff --git a/beacon/src/main/java/io/xpipe/beacon/api/FsReadExchange.java b/beacon/src/main/java/io/xpipe/beacon/api/FsReadExchange.java new file mode 100644 index 00000000..8aefba02 --- /dev/null +++ b/beacon/src/main/java/io/xpipe/beacon/api/FsReadExchange.java @@ -0,0 +1,33 @@ +package io.xpipe.beacon.api; + +import io.xpipe.beacon.BeaconInterface; +import io.xpipe.core.store.FilePath; +import lombok.Builder; +import lombok.NonNull; +import lombok.Value; +import lombok.extern.jackson.Jacksonized; + +import java.util.UUID; + +public class FsReadExchange extends BeaconInterface { + + @Override + public String getPath() { + return "/fs/read"; + } + + @Jacksonized + @Builder + @Value + public static class Request { + @NonNull + UUID connection; + @NonNull + FilePath path; + } + + @Jacksonized + @Builder + @Value + public static class Response {} +} diff --git a/beacon/src/main/java/module-info.java b/beacon/src/main/java/module-info.java index 8fc2fea6..f8326d8e 100644 --- a/beacon/src/main/java/module-info.java +++ b/beacon/src/main/java/module-info.java @@ -1,10 +1,9 @@ +import com.fasterxml.jackson.databind.Module; import io.xpipe.beacon.BeaconInterface; import io.xpipe.beacon.BeaconJacksonModule; import io.xpipe.beacon.api.*; import io.xpipe.core.util.ModuleLayerLoader; -import com.fasterxml.jackson.databind.Module; - open module io.xpipe.beacon { exports io.xpipe.beacon; exports io.xpipe.beacon.test; @@ -40,5 +39,9 @@ open module io.xpipe.beacon { AskpassExchange, TerminalWaitExchange, TerminalLaunchExchange, + FsReadExchange, + FsBlobExchange, + FsWriteExchange, + FsScriptExchange, DaemonVersionExchange; } diff --git a/lang/app/strings/translations_da.properties b/lang/app/strings/translations_da.properties index 469fbd8f..25e9af32 100644 --- a/lang/app/strings/translations_da.properties +++ b/lang/app/strings/translations_da.properties @@ -460,11 +460,10 @@ notes=Bemærkninger addNotes=Tilføj noter order=Bestille ... stickToTop=Hold dig på toppen +stickToBottom=Hold på bunden orderAheadOf=Bestil på forhånd ... httpServer=HTTP-server httpServerConfiguration=Konfiguration af HTTP-server -httpServerPort=Port -httpServerPortDescription=Den port, som HTTP-serveren vil lytte på.\n\nBemærk, at hvis du ændrer dette, skal alle andre programmer, der interagerer med serveren, også konfigureres til at bruge den nye port.\n\nKræver en genstart for at gælde. apiKey=API-nøgle apiKeyDescription=API-nøglen til godkendelse af XPipe-dæmonens API-anmodninger. Se den generelle API-dokumentation for at få flere oplysninger om, hvordan du godkender.\n\nKræver en genstart for at blive anvendt. disableApiAuthentication=Deaktiver API-godkendelse @@ -479,3 +478,4 @@ isOnlySupportedLimit=understøttes kun med en professionel licens, når man har areOnlySupportedLimit=understøttes kun med en professionel licens, når man har mere end $COUNT$ forbindelser enabled=Aktiveret enableGitStoragePtbDisabled=Git-synkronisering er deaktiveret for offentlige test-builds for at forhindre brug med almindelige release-git-lagre og for at modvirke, at man bruger en PTB-build som sin daglige driver. +copyId=Kopi ID diff --git a/lang/app/strings/translations_de.properties b/lang/app/strings/translations_de.properties index d2519271..835cda69 100644 --- a/lang/app/strings/translations_de.properties +++ b/lang/app/strings/translations_de.properties @@ -454,11 +454,10 @@ notes=Anmerkungen addNotes=Notizen hinzufügen order=Bestellen ... stickToTop=Oben bleiben +stickToBottom=Auf dem Boden bleiben orderAheadOf=Vorbestellen ... httpServer=HTTP-Server httpServerConfiguration=HTTP-Server-Konfiguration -httpServerPort=Port -httpServerPortDescription=Der Port, auf dem der HTTP-Server lauschen wird.\n\nWenn du diesen Wert änderst, müssen alle anderen Anwendungen, die mit dem Server interagieren, so konfiguriert werden, dass sie ebenfalls den neuen Port verwenden.\n\nZur Anwendung ist ein Neustart erforderlich. apiKey=API-Schlüssel apiKeyDescription=Der API-Schlüssel zur Authentifizierung von XPipe Daemon API-Anfragen. Weitere Informationen zur Authentifizierung findest du in der allgemeinen API-Dokumentation.\n\nErfordert einen Neustart zur Anwendung. disableApiAuthentication=API-Authentifizierung deaktivieren @@ -473,3 +472,4 @@ isOnlySupportedLimit=wird nur mit einer professionellen Lizenz unterstützt, wen areOnlySupportedLimit=werden nur mit einer professionellen Lizenz unterstützt, wenn mehr als $COUNT$ Verbindungen bestehen enabled=Aktiviert enableGitStoragePtbDisabled=Die Git-Synchronisierung ist für öffentliche Test-Builds deaktiviert, um die Verwendung mit regulären Git-Repositories zu verhindern und um davon abzuraten, einen PTB-Build als täglichen Treiber zu verwenden. +copyId=ID kopieren diff --git a/lang/app/strings/translations_en.properties b/lang/app/strings/translations_en.properties index 54ce6693..a7bfdc7d 100644 --- a/lang/app/strings/translations_en.properties +++ b/lang/app/strings/translations_en.properties @@ -458,6 +458,7 @@ addNotes=Add notes #context: verb order=Order ... stickToTop=Keep on top +stickToBottom=Keep on bottom orderAheadOf=Order ahead of ... httpServer=HTTP server httpServerConfiguration=HTTP server configuration diff --git a/lang/app/strings/translations_es.properties b/lang/app/strings/translations_es.properties index 84b5df2a..af8c9735 100644 --- a/lang/app/strings/translations_es.properties +++ b/lang/app/strings/translations_es.properties @@ -441,11 +441,10 @@ notes=Notas addNotes=Añadir notas order=Ordenar ... stickToTop=Mantener arriba +stickToBottom=Mantener en la parte inferior orderAheadOf=Haz tu pedido antes de ... httpServer=Servidor HTTP httpServerConfiguration=Configuración del servidor HTTP -httpServerPort=Puerto -httpServerPortDescription=El puerto en el que escuchará el servidor HTTP.\n\nTen en cuenta que si cambias esto, cualquier otra aplicación que interactúe con el servidor deberá configurarse para utilizar también el nuevo puerto.\n\nRequiere un reinicio para aplicarse. apiKey=Clave API apiKeyDescription=La clave API para autenticar las peticiones API del demonio XPipe. Para más información sobre cómo autenticarse, consulta la documentación general de la API.\n\nRequiere un reinicio para aplicarse. disableApiAuthentication=Desactivar la autenticación de la API @@ -460,3 +459,4 @@ isOnlySupportedLimit=sólo es compatible con una licencia profesional cuando tie areOnlySupportedLimit=sólo son compatibles con una licencia profesional cuando tienen más de $COUNT$ conexiones enabled=Activado enableGitStoragePtbDisabled=La sincronización Git está desactivada para las compilaciones públicas de prueba, para evitar que se utilicen con los repositorios git de publicación regular y para desalentar el uso de una compilación PTB como tu conductor diario. +copyId=ID de copia diff --git a/lang/app/strings/translations_fr.properties b/lang/app/strings/translations_fr.properties index a55f6295..d3668318 100644 --- a/lang/app/strings/translations_fr.properties +++ b/lang/app/strings/translations_fr.properties @@ -441,11 +441,10 @@ notes=Notes addNotes=Ajouter des notes order=Commander... stickToTop=Garde le dessus +stickToBottom=Garde en bas orderAheadOf=Commande en avance... httpServer=Serveur HTTP httpServerConfiguration=Configuration du serveur HTTP -httpServerPort=Port -httpServerPortDescription=Le port sur lequel le serveur HTTP écoutera.\n\nNote que si tu modifies ce paramètre, toutes les autres applications qui interagissent avec le serveur doivent être configurées pour utiliser également le nouveau port.\n\nIl faut redémarrer l'ordinateur pour l'appliquer. apiKey=Clé API apiKeyDescription=La clé API pour authentifier les demandes API du démon XPipe. Pour plus d'informations sur la manière de s'authentifier, voir la documentation générale de l'API.\n\nNécessite un redémarrage pour être appliquée. disableApiAuthentication=Désactiver l'authentification de l'API @@ -460,3 +459,4 @@ isOnlySupportedLimit=n'est pris en charge qu'avec une licence professionnelle lo areOnlySupportedLimit=ne sont pris en charge qu'avec une licence professionnelle lorsqu'il y a plus de $COUNT$ connexions enabled=Activé enableGitStoragePtbDisabled=La synchronisation Git est désactivée pour les versions de test publiques afin d'éviter toute utilisation avec les dépôts git des versions régulières et de décourager l'utilisation d'une version PTB comme conducteur quotidien. +copyId=ID de copie diff --git a/lang/app/strings/translations_it.properties b/lang/app/strings/translations_it.properties index 4be98ba8..c5813d28 100644 --- a/lang/app/strings/translations_it.properties +++ b/lang/app/strings/translations_it.properties @@ -441,11 +441,10 @@ notes=Note addNotes=Aggiungi note order=Ordinare ... stickToTop=Continua a essere in cima +stickToBottom=Tieni sul fondo orderAheadOf=Ordina prima di ... httpServer=Server HTTP httpServerConfiguration=Configurazione del server HTTP -httpServerPort=Porta -httpServerPortDescription=La porta su cui il server HTTP si metterà in ascolto.\n\nSe la modifichi, tutte le altre applicazioni che interagiscono con il server devono essere configurate per utilizzare la nuova porta.\n\nRichiede un riavvio per essere applicata. apiKey=Chiave API apiKeyDescription=La chiave API per autenticare le richieste API del demone XPipe. Per ulteriori informazioni sulle modalità di autenticazione, consulta la documentazione generale dell'API.\n\nRichiede un riavvio per essere applicata. disableApiAuthentication=Disabilita l'autenticazione API @@ -460,3 +459,4 @@ isOnlySupportedLimit=è supportato solo con una licenza professionale quando ci areOnlySupportedLimit=sono supportati solo con una licenza professionale quando ci sono più di $COUNT$ connessioni enabled=Abilitato enableGitStoragePtbDisabled=La sincronizzazione Git è disabilitata per le build di test pubbliche per evitare l'uso con i repository git di rilascio regolari e per scoraggiare l'uso di una build PTB come guida quotidiana. +copyId=Copia ID diff --git a/lang/app/strings/translations_ja.properties b/lang/app/strings/translations_ja.properties index fd6ed240..d93e51fd 100644 --- a/lang/app/strings/translations_ja.properties +++ b/lang/app/strings/translations_ja.properties @@ -441,11 +441,10 @@ notes=備考 addNotes=メモを追加する order=注文する stickToTop=トップをキープする +stickToBottom=底を保つ orderAheadOf=先に注文する httpServer=HTTPサーバー httpServerConfiguration=HTTPサーバーの設定 -httpServerPort=ポート -httpServerPortDescription=HTTPサーバーがリッスンするポート。\n\nこれを変更すると、サーバーとやりとりする他のアプリケーションも新しいポートを使うように設定する必要があることに注意。\n\n適用するには再起動が必要である。 apiKey=APIキー apiKeyDescription=XPipeデーモンAPIリクエストを認証するためのAPIキー。認証方法の詳細については、一般的なAPIドキュメントを参照のこと。\n\n適用には再起動が必要。 disableApiAuthentication=API認証を無効にする @@ -460,3 +459,4 @@ isOnlySupportedLimit=は、$COUNT$ を超える接続がある場合、プロフ areOnlySupportedLimit=$COUNT$ 以上の接続がある場合、プロフェッショナルライセンスでのみサポートされる。 enabled=有効にする enableGitStoragePtbDisabled=Gitの同期をパブリックテストビルドでは無効にしているのは、通常のリリース用gitリポジトリとの使い回しを防ぎ、PTBビルドをデイリードライバーとして使わないようにするためだ。 +copyId=コピーID diff --git a/lang/app/strings/translations_nl.properties b/lang/app/strings/translations_nl.properties index 86da2898..60674717 100644 --- a/lang/app/strings/translations_nl.properties +++ b/lang/app/strings/translations_nl.properties @@ -441,11 +441,10 @@ notes=Opmerkingen addNotes=Opmerkingen toevoegen order=Bestellen ... stickToTop=Bovenaan houden +stickToBottom=Onderaan houden orderAheadOf=Vooruitbestellen ... httpServer=HTTP-server httpServerConfiguration=HTTP-server configuratie -httpServerPort=Poort -httpServerPortDescription=De poort waarop de HTTP-server zal luisteren.\n\nMerk op dat als je dit verandert, andere applicaties die communiceren met de server ook geconfigureerd moeten worden om de nieuwe poort te gebruiken.\n\nVereist een herstart om toe te passen. apiKey=API-sleutel apiKeyDescription=De API sleutel om XPipe daemon API verzoeken te authenticeren. Voor meer informatie over hoe te authenticeren, zie de algemene API documentatie.\n\nVereist een herstart om toe te passen. disableApiAuthentication=API-authenticatie uitschakelen @@ -460,3 +459,4 @@ isOnlySupportedLimit=wordt alleen ondersteund met een professionele licentie bij areOnlySupportedLimit=worden alleen ondersteund met een professionele licentie bij meer dan $COUNT$ verbindingen enabled=Ingeschakeld enableGitStoragePtbDisabled=Git synchronisatie is uitgeschakeld voor publieke test builds om gebruik met reguliere release git repositories te voorkomen en om het gebruik van een PTB build als je dagelijkse driver te ontmoedigen. +copyId=ID kopiëren diff --git a/lang/app/strings/translations_pt.properties b/lang/app/strings/translations_pt.properties index 20c79f5b..aaa582ea 100644 --- a/lang/app/strings/translations_pt.properties +++ b/lang/app/strings/translations_pt.properties @@ -441,11 +441,10 @@ notes=Nota addNotes=Adiciona notas order=Encomenda ... stickToTop=Mantém-te no topo +stickToBottom=Mantém na parte inferior orderAheadOf=Encomenda antes de ... httpServer=Servidor HTTP httpServerConfiguration=Configuração do servidor HTTP -httpServerPort=Porta -httpServerPortDescription=A porta em que o servidor HTTP irá escutar.\n\nTem em atenção que, se alterares isto, quaisquer outras aplicações que interajam com o servidor têm de ser configuradas para utilizar também a nova porta.\n\nRequer uma reinicialização para ser aplicado. apiKey=Chave API apiKeyDescription=A chave da API para autenticar os pedidos de API do daemon XPipe. Para mais informações sobre como autenticar, vê a documentação geral da API.\n\nRequer um reinício para ser aplicado. disableApiAuthentication=Desativar a autenticação da API @@ -460,3 +459,4 @@ isOnlySupportedLimit=só é suportado com uma licença profissional se tiver mai areOnlySupportedLimit=só são suportados com uma licença profissional quando têm mais de $COUNT$ ligações enabled=Ativado enableGitStoragePtbDisabled=A sincronização do Git está desactivada para compilações de teste públicas para evitar a utilização com repositórios git de lançamento regulares e para desencorajar a utilização de uma compilação PTB como o teu condutor diário. +copyId=ID de cópia diff --git a/lang/app/strings/translations_ru.properties b/lang/app/strings/translations_ru.properties index e712268c..684d6577 100644 --- a/lang/app/strings/translations_ru.properties +++ b/lang/app/strings/translations_ru.properties @@ -441,11 +441,10 @@ notes=Заметки addNotes=Добавляй заметки order=Заказать ... stickToTop=Держись на высоте +stickToBottom=Держать на дне orderAheadOf=Заказать заранее ... httpServer=HTTP-сервер httpServerConfiguration=Конфигурация HTTP-сервера -httpServerPort=Порт -httpServerPortDescription=Порт, на котором будет прослушиваться HTTP-сервер.\n\nОбрати внимание, что если ты изменишь этот параметр, то все остальные приложения, которые взаимодействуют с сервером, тоже должны быть настроены на использование нового порта.\n\nТребуется перезагрузка для применения. apiKey=Ключ API apiKeyDescription=API-ключ для аутентификации API-запросов демона XPipe. Подробнее о том, как проходить аутентификацию, читай в общей документации по API.\n\nТребуется перезагрузка для применения. disableApiAuthentication=Отключить аутентификацию API @@ -460,3 +459,4 @@ isOnlySupportedLimit=поддерживается только професси areOnlySupportedLimit=поддерживаются только профессиональной лицензией при наличии более чем $COUNT$ соединений enabled=Включено enableGitStoragePtbDisabled=Git-синхронизация отключена для публичных тестовых сборок, чтобы предотвратить их использование с обычными релизными git-репозиториями и не допустить использования PTB-сборки в качестве ежедневного драйвера. +copyId=Идентификатор копии diff --git a/lang/app/strings/translations_tr.properties b/lang/app/strings/translations_tr.properties index e6a9eded..48a0751a 100644 --- a/lang/app/strings/translations_tr.properties +++ b/lang/app/strings/translations_tr.properties @@ -442,11 +442,10 @@ notes=Notlar addNotes=Notlar ekleyin order=Sipariş ... stickToTop=Zirvede kal +stickToBottom=Altta kal orderAheadOf=Önceden sipariş verin ... httpServer=HTTP sunucusu httpServerConfiguration=HTTP sunucu yapılandırması -httpServerPort=Liman -httpServerPortDescription=HTTP sunucusunun dinleyeceği bağlantı noktası.\n\nBunu değiştirirseniz, sunucuyla etkileşime giren diğer uygulamaların da yeni bağlantı noktasını kullanacak şekilde yapılandırılması gerektiğini unutmayın.\n\nUygulamak için yeniden başlatma gerekir. apiKey=API anahtarı apiKeyDescription=XPipe daemon API isteklerinin kimliğini doğrulamak için API anahtarı. Kimlik doğrulamanın nasıl yapılacağı hakkında daha fazla bilgi için genel API belgelerine bakın.\n\nUygulamak için yeniden başlatma gerekir. disableApiAuthentication=API kimlik doğrulamasını devre dışı bırakma @@ -461,3 +460,4 @@ isOnlySupportedLimit=yalnızca $COUNT$ adresinden daha fazla bağlantıya sahip areOnlySupportedLimit=yalnızca $COUNT$ adresinden daha fazla bağlantıya sahip olunduğunda profesyonel lisans ile desteklenir enabled=Etkin enableGitStoragePtbDisabled=Git senkronizasyonu, normal sürüm git depoları ile kullanımı önlemek ve günlük sürücünüz olarak bir PTB derlemesini kullanmaktan vazgeçirmek için genel test derlemeleri için devre dışı bırakılmıştır. +copyId=Kopya Kimliği diff --git a/lang/app/strings/translations_zh.properties b/lang/app/strings/translations_zh.properties index 942b535a..dd0af19a 100644 --- a/lang/app/strings/translations_zh.properties +++ b/lang/app/strings/translations_zh.properties @@ -441,11 +441,10 @@ notes=说明 addNotes=添加注释 order=订购 ... stickToTop=保持在顶部 +stickToBottom=保持在底部 orderAheadOf=提前订购... httpServer=HTTP 服务器 httpServerConfiguration=HTTP 服务器配置 -httpServerPort=端口 -httpServerPortDescription=HTTP 服务器监听的端口。\n\n请注意,如果更改端口,则与服务器交互的任何其他应用程序也需要配置为使用新端口。\n\n需要重新启动才能应用。 apiKey=应用程序接口密钥 apiKeyDescription=用于验证 XPipe 守护进程 API 请求的 API 密钥。有关如何验证的更多信息,请参阅一般 API 文档。\n\n需要重新启动才能应用。 disableApiAuthentication=禁用 API 身份验证 @@ -460,3 +459,4 @@ isOnlySupportedLimit=只有在连接数超过$COUNT$ 时才支持专业许可证 areOnlySupportedLimit=只有在连接数超过$COUNT$ 时才支持专业许可证 enabled=已启用 enableGitStoragePtbDisabled=公共测试版已禁用 Git 同步功能,以防止与常规发布版本的 git 仓库一起使用,并避免将公共测试版作为日常驱动程序使用。 +copyId=复制 ID diff --git a/lang/base/strings/translations_da.properties b/lang/base/strings/translations_da.properties index 7c1ed04b..ec5d369d 100644 --- a/lang/base/strings/translations_da.properties +++ b/lang/base/strings/translations_da.properties @@ -152,8 +152,8 @@ serviceRemotePortDescription=Den port, som tjenesten kører på serviceHost=Servicevært serviceHostDescription=Den vært, som tjenesten kører på openWebsite=Åben hjemmeside -serviceGroup.displayName=Service-gruppe -serviceGroup.displayDescription=Gruppér flere tjenester i én kategori +customServiceGroup.displayName=Service-gruppe +customServiceGroup.displayDescription=Gruppér flere tjenester i én kategori initScript=Kører på shell init shellScript=Gør script tilgængeligt under shell-session fileScript=Gør det muligt at kalde et script med filargumenter i filbrowseren @@ -163,3 +163,5 @@ fixedServiceGroup.displayName=Service-gruppe fixedServiceGroup.displayDescription=Liste over tilgængelige tjenester på et system mappedService.displayName=Service mappedService.displayDescription=Interagere med en tjeneste, der er eksponeret af en container +customService.displayName=Service +customService.displayDescription=Tilføj en brugerdefineret tjeneste til tunnel og åben diff --git a/lang/base/strings/translations_de.properties b/lang/base/strings/translations_de.properties index 5870785e..176ead9f 100644 --- a/lang/base/strings/translations_de.properties +++ b/lang/base/strings/translations_de.properties @@ -143,8 +143,8 @@ serviceRemotePortDescription=Der Port, auf dem der Dienst läuft serviceHost=Diensthost serviceHostDescription=Der Host, auf dem der Dienst läuft openWebsite=Website öffnen -serviceGroup.displayName=Dienstgruppe -serviceGroup.displayDescription=Mehrere Dienste in einer Kategorie zusammenfassen +customServiceGroup.displayName=Dienstgruppe +customServiceGroup.displayDescription=Mehrere Dienste in einer Kategorie zusammenfassen initScript=Auf der Shell init ausführen shellScript=Skript während der Shell-Sitzung verfügbar machen fileScript=Skriptaufruf mit Dateiargumenten im Dateibrowser zulassen @@ -154,3 +154,5 @@ fixedServiceGroup.displayName=Dienstgruppe fixedServiceGroup.displayDescription=Liste der verfügbaren Dienste auf einem System mappedService.displayName=Dienst mappedService.displayDescription=Interaktion mit einem Dienst, der von einem Container angeboten wird +customService.displayName=Dienst +customService.displayDescription=Einen benutzerdefinierten Dienst zum Tunnel hinzufügen und öffnen diff --git a/lang/base/strings/translations_es.properties b/lang/base/strings/translations_es.properties index edcc7e69..e81cdf0a 100644 --- a/lang/base/strings/translations_es.properties +++ b/lang/base/strings/translations_es.properties @@ -141,8 +141,8 @@ serviceRemotePortDescription=El puerto en el que se ejecuta el servicio serviceHost=Host de servicio serviceHostDescription=El host en el que se ejecuta el servicio openWebsite=Abrir sitio web -serviceGroup.displayName=Grupo de servicios -serviceGroup.displayDescription=Agrupa varios servicios en una categoría +customServiceGroup.displayName=Grupo de servicios +customServiceGroup.displayDescription=Agrupa varios servicios en una categoría initScript=Ejecutar en shell init shellScript=Hacer que el script esté disponible durante la sesión shell fileScript=Permitir llamar a un script con argumentos de archivo en el explorador de archivos @@ -152,3 +152,5 @@ fixedServiceGroup.displayName=Grupo de servicios fixedServiceGroup.displayDescription=Enumerar los servicios disponibles en un sistema mappedService.displayName=Servicio mappedService.displayDescription=Interactúa con un servicio expuesto por un contenedor +customService.displayName=Servicio +customService.displayDescription=Añade un servicio personalizado para tunelizar y abrir diff --git a/lang/base/strings/translations_fr.properties b/lang/base/strings/translations_fr.properties index 1259827a..47258232 100644 --- a/lang/base/strings/translations_fr.properties +++ b/lang/base/strings/translations_fr.properties @@ -141,8 +141,8 @@ serviceRemotePortDescription=Le port sur lequel le service fonctionne serviceHost=Hôte du service serviceHostDescription=L'hôte sur lequel le service est exécuté openWebsite=Ouvrir un site web -serviceGroup.displayName=Groupe de service -serviceGroup.displayDescription=Regrouper plusieurs services dans une même catégorie +customServiceGroup.displayName=Groupe de service +customServiceGroup.displayDescription=Regrouper plusieurs services dans une même catégorie initScript=Exécute sur le shell init shellScript=Rendre le script disponible pendant la session shell fileScript=Permet d'appeler un script avec des arguments de fichier dans le navigateur de fichiers @@ -152,3 +152,5 @@ fixedServiceGroup.displayName=Groupe de service fixedServiceGroup.displayDescription=Liste les services disponibles sur un système mappedService.displayName=Service mappedService.displayDescription=Interagir avec un service exposé par un conteneur +customService.displayName=Service +customService.displayDescription=Ajouter un service personnalisé au tunnel et à l'ouverture diff --git a/lang/base/strings/translations_it.properties b/lang/base/strings/translations_it.properties index e1fc67d2..60da790b 100644 --- a/lang/base/strings/translations_it.properties +++ b/lang/base/strings/translations_it.properties @@ -141,8 +141,8 @@ serviceRemotePortDescription=La porta su cui è in esecuzione il servizio serviceHost=Servizio host serviceHostDescription=L'host su cui è in esecuzione il servizio openWebsite=Sito web aperto -serviceGroup.displayName=Gruppo di servizio -serviceGroup.displayDescription=Raggruppa più servizi in un'unica categoria +customServiceGroup.displayName=Gruppo di servizio +customServiceGroup.displayDescription=Raggruppa più servizi in un'unica categoria initScript=Eseguire su shell init shellScript=Rendere disponibile lo script durante la sessione di shell fileScript=Consente di richiamare uno script con argomenti di file nel browser di file @@ -152,3 +152,5 @@ fixedServiceGroup.displayName=Gruppo di servizio fixedServiceGroup.displayDescription=Elenco dei servizi disponibili su un sistema mappedService.displayName=Servizio mappedService.displayDescription=Interagire con un servizio esposto da un contenitore +customService.displayName=Servizio +customService.displayDescription=Aggiungi un servizio personalizzato per il tunnel e l'apertura diff --git a/lang/base/strings/translations_ja.properties b/lang/base/strings/translations_ja.properties index 160be141..ff2bc25d 100644 --- a/lang/base/strings/translations_ja.properties +++ b/lang/base/strings/translations_ja.properties @@ -141,8 +141,8 @@ serviceRemotePortDescription=サービスが実行されているポート serviceHost=サービスホスト serviceHostDescription=サービスが稼働しているホスト openWebsite=オープンウェブサイト -serviceGroup.displayName=サービスグループ -serviceGroup.displayDescription=複数のサービスを1つのカテゴリーにまとめる +customServiceGroup.displayName=サービスグループ +customServiceGroup.displayDescription=複数のサービスを1つのカテゴリーにまとめる initScript=シェル init で実行する shellScript=シェルセッション中にスクリプトを利用可能にする fileScript=ファイルブラウザでファイル引数を指定してスクリプトを呼び出せるようにする @@ -152,3 +152,5 @@ fixedServiceGroup.displayName=サービスグループ fixedServiceGroup.displayDescription=システムで利用可能なサービスをリストアップする mappedService.displayName=サービス mappedService.displayDescription=コンテナによって公開されたサービスとやりとりする +customService.displayName=サービス +customService.displayDescription=トンネルとオープンにカスタムサービスを追加する diff --git a/lang/base/strings/translations_nl.properties b/lang/base/strings/translations_nl.properties index 1d12be15..b598f75a 100644 --- a/lang/base/strings/translations_nl.properties +++ b/lang/base/strings/translations_nl.properties @@ -141,8 +141,8 @@ serviceRemotePortDescription=De poort waarop de service draait serviceHost=Service host serviceHostDescription=De host waarop de service draait openWebsite=Open website -serviceGroup.displayName=Servicegroep -serviceGroup.displayDescription=Groepeer meerdere diensten in één categorie +customServiceGroup.displayName=Servicegroep +customServiceGroup.displayDescription=Groepeer meerdere diensten in één categorie initScript=Uitvoeren op shell init shellScript=Script beschikbaar maken tijdens shellsessie fileScript=Laat toe dat een script wordt aangeroepen met bestandsargumenten in de bestandsbrowser @@ -152,3 +152,5 @@ fixedServiceGroup.displayName=Servicegroep fixedServiceGroup.displayDescription=Een lijst van beschikbare services op een systeem mappedService.displayName=Service mappedService.displayDescription=Interactie met een service die wordt aangeboden door een container +customService.displayName=Service +customService.displayDescription=Een aangepaste service toevoegen aan tunnel en openen diff --git a/lang/base/strings/translations_pt.properties b/lang/base/strings/translations_pt.properties index 488cb4a0..a12c1bec 100644 --- a/lang/base/strings/translations_pt.properties +++ b/lang/base/strings/translations_pt.properties @@ -141,8 +141,8 @@ serviceRemotePortDescription=A porta em que o serviço está a ser executado serviceHost=Anfitrião de serviço serviceHostDescription=O anfitrião em que o serviço está a ser executado openWebsite=Abre o sítio Web -serviceGroup.displayName=Grupo de serviços -serviceGroup.displayDescription=Agrupa vários serviços numa categoria +customServiceGroup.displayName=Grupo de serviços +customServiceGroup.displayDescription=Agrupa vários serviços numa categoria initScript=Corre no shell init shellScript=Torna o script disponível durante a sessão da shell fileScript=Permite que o script seja chamado com argumentos de ficheiro no navegador de ficheiros @@ -152,3 +152,5 @@ fixedServiceGroup.displayName=Grupo de serviços fixedServiceGroup.displayDescription=Lista os serviços disponíveis num sistema mappedService.displayName=Serviço mappedService.displayDescription=Interage com um serviço exposto por um contentor +customService.displayName=Serviço +customService.displayDescription=Adiciona um serviço personalizado ao túnel e abre diff --git a/lang/base/strings/translations_ru.properties b/lang/base/strings/translations_ru.properties index b409eb00..1be17c6c 100644 --- a/lang/base/strings/translations_ru.properties +++ b/lang/base/strings/translations_ru.properties @@ -141,8 +141,8 @@ serviceRemotePortDescription=Порт, на котором работает сл serviceHost=Сервисный хост serviceHostDescription=Хост, на котором запущена служба openWebsite=Открытый сайт -serviceGroup.displayName=Группа услуг -serviceGroup.displayDescription=Сгруппируйте несколько сервисов в одну категорию +customServiceGroup.displayName=Группа услуг +customServiceGroup.displayDescription=Сгруппируйте несколько сервисов в одну категорию initScript=Запуск на shell init shellScript=Сделать скрипт доступным во время сеанса оболочки fileScript=Разрешить вызов скрипта с аргументами в виде файлов в браузере файлов @@ -152,3 +152,5 @@ fixedServiceGroup.displayName=Группа услуг fixedServiceGroup.displayDescription=Список доступных сервисов в системе mappedService.displayName=Сервис mappedService.displayDescription=Взаимодействие с сервисом, открываемым контейнером +customService.displayName=Сервис +customService.displayDescription=Добавьте пользовательский сервис для туннелирования и открытия diff --git a/lang/base/strings/translations_tr.properties b/lang/base/strings/translations_tr.properties index c63bcedd..3569e68d 100644 --- a/lang/base/strings/translations_tr.properties +++ b/lang/base/strings/translations_tr.properties @@ -141,8 +141,8 @@ serviceRemotePortDescription=Hizmetin üzerinde çalıştığı bağlantı nokta serviceHost=Hizmet sunucusu serviceHostDescription=Hizmetin üzerinde çalıştığı ana bilgisayar openWebsite=Açık web sitesi -serviceGroup.displayName=Hizmet grubu -serviceGroup.displayDescription=Birden fazla hizmeti tek bir kategoride gruplayın +customServiceGroup.displayName=Hizmet grubu +customServiceGroup.displayDescription=Birden fazla hizmeti tek bir kategoride gruplayın initScript=Kabuk başlangıcında çalıştır shellScript=Kabuk oturumu sırasında komut dosyasını kullanılabilir hale getirme fileScript=Kodun dosya tarayıcısında dosya bağımsız değişkenleriyle çağrılmasına izin ver @@ -152,3 +152,5 @@ fixedServiceGroup.displayName=Hizmet grubu fixedServiceGroup.displayDescription=Bir sistemdeki mevcut hizmetleri listeleme mappedService.displayName=Hizmet mappedService.displayDescription=Bir konteyner tarafından sunulan bir hizmetle etkileşim +customService.displayName=Hizmet +customService.displayDescription=Tünele özel bir hizmet ekleyin ve açın diff --git a/lang/base/strings/translations_zh.properties b/lang/base/strings/translations_zh.properties index b67ba34b..6e8d1ab3 100644 --- a/lang/base/strings/translations_zh.properties +++ b/lang/base/strings/translations_zh.properties @@ -141,8 +141,8 @@ serviceRemotePortDescription=服务运行的端口 serviceHost=服务主机 serviceHostDescription=服务运行的主机 openWebsite=打开网站 -serviceGroup.displayName=服务组 -serviceGroup.displayDescription=将多项服务归为一类 +customServiceGroup.displayName=服务组 +customServiceGroup.displayDescription=将多项服务归为一类 initScript=在 shell init 上运行 shellScript=在 shell 会话中提供脚本 fileScript=允许在文件浏览器中使用文件参数调用脚本 @@ -152,3 +152,5 @@ fixedServiceGroup.displayName=服务组 fixedServiceGroup.displayDescription=列出系统中可用的服务 mappedService.displayName=服务 mappedService.displayDescription=与容器暴露的服务交互 +customService.displayName=服务 +customService.displayDescription=为隧道和开放添加自定义服务 diff --git a/openapi.yaml b/openapi.yaml index 4fe7a810..7b60b47e 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -264,6 +264,40 @@ paths: $ref: '#/components/responses/NotFound' '500': $ref: '#/components/responses/InternalServerError' + /fs/read: + post: + summary: Read the content of a remote file + description: | + Reads the entire content of a remote file through an active shell session. + operationId: fsRead + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/FsReadRequest' + examples: + simple: + summary: Read file + value: { "connection": "f0ec68aa-63f5-405c-b178-9a4454556d6b", "path": "/home/user/myfile.txt" } + responses: + '200': + description: The operation was successful. The file was read. + content: + application/octet-stream: + schema: + type: string + format: binary + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' /fs/write: post: summary: Write a blob to a remote file @@ -402,6 +436,18 @@ components: - connection - blob - path + FsReadRequest: + type: object + properties: + connection: + type: string + description: The connection uuid + path: + type: string + description: The target file path + required: + - connection + - path FsScriptRequest: type: object properties: diff --git a/version b/version index 52a5db57..5c933c44 100644 --- a/version +++ b/version @@ -1 +1 @@ -10.0-10 +10.0-11