mirror of
https://github.com/xpipe-io/xpipe.git
synced 2026-09-26 10:25:44 +00:00
Rework
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
package io.xpipe.app.action;
|
||||
|
||||
import io.xpipe.app.ext.DataStore;
|
||||
import io.xpipe.app.ext.DataStoreProvider;
|
||||
import io.xpipe.app.ext.DataStoreProviders;
|
||||
import io.xpipe.app.storage.DataStorage;
|
||||
import io.xpipe.app.storage.DataStoreEntry;
|
||||
|
||||
@@ -28,4 +30,10 @@ public interface QuickConnectProvider extends ActionProvider {
|
||||
DataStore createStore(String arguments, DataStore existing);
|
||||
|
||||
String getPlaceholder();
|
||||
|
||||
boolean skipDialogIfPossible();
|
||||
|
||||
default void open(DataStoreEntry e) throws Exception {
|
||||
e.getProvider().launch(e).run();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ public class XPipeUrlProvider implements LauncherUrlProvider {
|
||||
|
||||
@Override
|
||||
public String getPlaceholder() {
|
||||
return "xpipe://action?<name>[¶m=value]";
|
||||
return "xpipe://action?<name>";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -2,8 +2,10 @@ package io.xpipe.app.beacon;
|
||||
|
||||
import io.xpipe.app.beacon.mcp.AppMcpServer;
|
||||
import io.xpipe.app.core.AppLocalTemp;
|
||||
import io.xpipe.app.core.AppProperties;
|
||||
import io.xpipe.app.issue.ErrorEventFactory;
|
||||
import io.xpipe.app.issue.TrackEvent;
|
||||
import io.xpipe.app.prefs.AppPrefs;
|
||||
import io.xpipe.app.util.DocumentationLink;
|
||||
import io.xpipe.beacon.BeaconConfig;
|
||||
import io.xpipe.beacon.BeaconInterface;
|
||||
@@ -170,13 +172,15 @@ public class AppBeaconServer {
|
||||
}
|
||||
|
||||
private boolean handleCorsHeaders(HttpExchange exchange) throws IOException {
|
||||
exchange.getResponseHeaders()
|
||||
.add("Origin", "http://localhost:" + AppBeaconServer.get().getPort());
|
||||
exchange.getResponseHeaders().add("Vary", "Origin");
|
||||
exchange.getResponseHeaders().add("Access-Control-Allow-Origin", "*");
|
||||
exchange.getResponseHeaders().add("Access-Control-Allow-Credentials", "true");
|
||||
exchange.getResponseHeaders().add("Access-Control-Allow-Headers", "*");
|
||||
exchange.getResponseHeaders().add("Access-Control-Allow-Methods", "*");
|
||||
if (AppPrefs.get().enableHttpApi().get()) {
|
||||
exchange.getResponseHeaders().add("Origin", "http://localhost:" + AppBeaconServer.get().getPort());
|
||||
exchange.getResponseHeaders().add("Vary", "Origin");
|
||||
exchange.getResponseHeaders().add("Access-Control-Allow-Origin", "*");
|
||||
exchange.getResponseHeaders().add("Access-Control-Allow-Credentials", "true");
|
||||
exchange.getResponseHeaders().add("Access-Control-Allow-Headers", "*");
|
||||
exchange.getResponseHeaders().add("Access-Control-Allow-Methods", "*");
|
||||
}
|
||||
|
||||
if (exchange.getRequestMethod().equals("OPTIONS")) {
|
||||
exchange.sendResponseHeaders(HttpURLConnection.HTTP_OK, -1);
|
||||
return true;
|
||||
|
||||
@@ -213,6 +213,7 @@ public class AppBaseMode extends AppOperationMode {
|
||||
AppBeaconServer.reset();
|
||||
KeePassXcPasswordManager.reset();
|
||||
StoreViewState.reset();
|
||||
StoreFilterState.reset();
|
||||
AppLayoutModel.reset();
|
||||
AppTheme.reset();
|
||||
PlatformState.teardown();
|
||||
|
||||
@@ -15,6 +15,7 @@ import io.xpipe.app.platform.PlatformThread;
|
||||
import io.xpipe.app.prefs.AppPrefs;
|
||||
import io.xpipe.app.util.ObservableSubscriber;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.geometry.Bounds;
|
||||
import javafx.scene.Cursor;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.input.KeyCodeCombination;
|
||||
@@ -51,6 +52,10 @@ public class StoreFilterFieldComp extends SimpleRegionBuilder {
|
||||
field.focusedProperty().subscribe(focus -> {
|
||||
if (focus) {
|
||||
popover.hide();
|
||||
} else {
|
||||
if (state.getIsSearchString().get()) {
|
||||
state.open();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -114,9 +119,18 @@ public class StoreFilterFieldComp extends SimpleRegionBuilder {
|
||||
|
||||
state.getRawText().subscribe(val -> {
|
||||
PlatformThread.runLaterIfNeeded(() -> {
|
||||
var wasFocused = field.isFocused();
|
||||
if (!wasFocused) {
|
||||
field.requestFocus();
|
||||
}
|
||||
|
||||
if (!Objects.equals(field.getText(), val) && !(val == null && "".equals(field.getText()))) {
|
||||
field.setText(val);
|
||||
}
|
||||
|
||||
if (!wasFocused) {
|
||||
field.end();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -125,7 +139,8 @@ public class StoreFilterFieldComp extends SimpleRegionBuilder {
|
||||
});
|
||||
|
||||
var menuButton = new IconButtonComp("mdi2a-animation-play", () -> {
|
||||
popover.show(field);
|
||||
Bounds bounds = field.localToScreen(field.getBoundsInLocal());
|
||||
popover.show(field, bounds.getMinX() + (field.getWidth() / 1.6), bounds.getMaxY() - 4.0);
|
||||
});
|
||||
menuButton.describe(d -> d.nameKey("quickConnect"));
|
||||
menuButton.style("quick-connect-button");
|
||||
|
||||
@@ -84,10 +84,10 @@ public class StoreFilterState {
|
||||
INSTANCE.recentUrls.setContent(recentUrls);
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
AppCache.update("recentSearches", recentSearches);
|
||||
AppCache.update("recentQuickConnections", recentQuickConnections);
|
||||
AppCache.update("recentUrls", recentUrls);
|
||||
public static void reset() {
|
||||
AppCache.update("recentSearches", INSTANCE.recentSearches.getList());
|
||||
AppCache.update("recentQuickConnections", INSTANCE.recentQuickConnections.getList());
|
||||
AppCache.update("recentUrls", INSTANCE.recentUrls.getList());
|
||||
INSTANCE = null;
|
||||
}
|
||||
|
||||
@@ -135,6 +135,10 @@ public class StoreFilterState {
|
||||
}
|
||||
|
||||
public boolean open() {
|
||||
if (rawText.getValue() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isSearchString.getValue()) {
|
||||
putFilter(rawText.getValue());
|
||||
return false;
|
||||
|
||||
@@ -38,7 +38,7 @@ public class StoreFilterStateComp extends SimpleRegionBuilder {
|
||||
|
||||
var searches = state.getRecentSearches().getList();
|
||||
var searchesEmpty = Bindings.isEmpty(searches);
|
||||
var searchesList = new ListBoxViewComp<String>(searches, searches, s -> createButton(s, null), false);
|
||||
var searchesList = new ListBoxViewComp<String>(searches, searches, s -> createButton(s, s), false);
|
||||
|
||||
var searchesPlaceholders = FXCollections.observableList(List.of(AppI18n.get("recentSearchesDescriptionNames"),
|
||||
AppI18n.get("recentSearchesDescriptionTags"), AppI18n.get("recentSearchesDescriptionTypes")));
|
||||
@@ -46,16 +46,16 @@ public class StoreFilterStateComp extends SimpleRegionBuilder {
|
||||
|
||||
var quickConnections = state.getRecentQuickConnections().getList();
|
||||
var quickConnectionsEmpty = Bindings.isEmpty(quickConnections);
|
||||
var quickConnectionsList = new ListBoxViewComp<String>(quickConnections, quickConnections, s -> createButton(s, null), false);
|
||||
var quickConnectionsList = new ListBoxViewComp<String>(quickConnections, quickConnections, s -> createButton(s, s), false);
|
||||
|
||||
var quickConnectionsPlaceholders = FXCollections.observableArrayList(QuickConnectProvider.getAll().stream()
|
||||
.map(p -> p.getPlaceholder())
|
||||
.toList());
|
||||
var quickConnectionsEmptyList = new ListBoxViewComp<String>(quickConnectionsPlaceholders, quickConnectionsPlaceholders, s -> createButton(s, null), false);
|
||||
var quickConnectionsEmptyList = new ListBoxViewComp<String>(quickConnectionsPlaceholders, quickConnectionsPlaceholders, s -> createButton(s, s.split(" ")[0] + " "), false);
|
||||
|
||||
var urls = state.getRecentUrls().getList();
|
||||
var urlsEmpty = Bindings.isEmpty(urls);
|
||||
var urlList = new ListBoxViewComp<String>(urls, urls, s -> createButton(s, null), false);
|
||||
var urlList = new ListBoxViewComp<String>(urls, urls, s -> createButton(s, s), false);
|
||||
|
||||
var urlPlaceholders = FXCollections.observableArrayList(LauncherUrlProvider.getAll().stream()
|
||||
.map(p -> p.getPlaceholder())
|
||||
|
||||
@@ -71,23 +71,39 @@ public class StoreQuickConnect {
|
||||
if (newStore.isComplete()) {
|
||||
var existing = provider.get().findExisting(newStore);
|
||||
if (existing.isPresent()) {
|
||||
try {
|
||||
existing.get().getProvider().launch(existing.get()).run();
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
ErrorEventFactory.fromThrowable(e).handle();
|
||||
return false;
|
||||
}
|
||||
ThreadHelper.runAsync(() -> {
|
||||
try {
|
||||
provider.get().open(existing.get());
|
||||
} catch (Exception e) {
|
||||
ErrorEventFactory.fromThrowable(e).handle();
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
DataStorage.get().updateEntryStore(quickConnectEntry, newStore);
|
||||
if (provider.get().skipDialogIfPossible() && newStore.isComplete()) {
|
||||
update(newStore);
|
||||
ThreadHelper.runAsync(() -> {
|
||||
try {
|
||||
DataStorage.get().addStoreEntryInProgress(quickConnectEntry);
|
||||
provider.get().open(quickConnectEntry);
|
||||
} catch (Exception e) {
|
||||
ErrorEventFactory.fromThrowable(e).handle();
|
||||
} finally {
|
||||
DataStorage.get().removeStoreEntryInProgress(quickConnectEntry);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
var model = StoreCreationDialog.showEdit(quickConnectEntry, newStore, false, finished -> {
|
||||
update(finished.getStore());
|
||||
ThreadHelper.runAsync(() -> {
|
||||
try {
|
||||
DataStorage.get().addStoreEntryInProgress(quickConnectEntry);
|
||||
quickConnectEntry.getProvider().launch(quickConnectEntry).run();
|
||||
provider.get().open(quickConnectEntry);
|
||||
} catch (Exception e) {
|
||||
ErrorEventFactory.fromThrowable(e).handle();
|
||||
} finally {
|
||||
|
||||
@@ -336,7 +336,7 @@ public abstract class DataStorage {
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
} while ((c = DataStorage.get().getDefaultDisplayParent(c).orElse(null)) != null);
|
||||
} while ((c = getDefaultDisplayParent(c).orElse(null)) != null);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -359,8 +359,8 @@ public abstract class DataStorage {
|
||||
newEntry.setIcon(icon, true);
|
||||
}
|
||||
|
||||
var oldParent = DataStorage.get().getDefaultDisplayParent(entry);
|
||||
var newParent = DataStorage.get().getDefaultDisplayParent(newEntry);
|
||||
var oldParent = getDefaultDisplayParent(entry);
|
||||
var newParent = getDefaultDisplayParent(newEntry);
|
||||
var sameParent = Objects.equals(oldParent, newParent);
|
||||
|
||||
finalizeWithDependencies(entry);
|
||||
@@ -457,7 +457,9 @@ public abstract class DataStorage {
|
||||
}
|
||||
entry.setStoreInternal(store, false);
|
||||
|
||||
saveAsync();
|
||||
if (storeEntries.containsKey(entry)) {
|
||||
saveAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public void updateCategory(DataStoreCategory category, DataStoreCategory newCategory) {
|
||||
@@ -470,7 +472,7 @@ public abstract class DataStorage {
|
||||
public void updateCategoryConfig(DataStoreCategory category, DataStoreCategoryConfig config) {
|
||||
if (category.setConfig(config)) {
|
||||
// Update git remote if needed
|
||||
DataStorage.get().saveAsync();
|
||||
saveAsync();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,23 @@ public class HostHelper {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isLocalhost(String host) {
|
||||
host = host.strip();
|
||||
if (host.equalsIgnoreCase("localhost")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (host.equals("127.0.0.1")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (host.equals("::1") || host.equals("[::1]")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isLocalNetworkAddress(String host) {
|
||||
Inet4Address inet4Address;
|
||||
try {
|
||||
|
||||
@@ -34,6 +34,7 @@ public class MultiIdentityStoreProvider extends IdentityStoreProvider {
|
||||
public GuiDialog guiDialog(DataStoreEntry entry, Property<DataStore> store) {
|
||||
MultiIdentityStore st = (MultiIdentityStore) store.getValue();
|
||||
|
||||
var initialIdentities = new ArrayList<>(st.getAvailableIdentities());
|
||||
var identities = new SimpleListProperty<>(FXCollections.observableArrayList(st.getAvailableIdentities()));
|
||||
|
||||
return new OptionsBuilder()
|
||||
@@ -47,7 +48,14 @@ public class MultiIdentityStoreProvider extends IdentityStoreProvider {
|
||||
for (DataStoreEntryRef<IdentityStore> identity : identities) {
|
||||
uuids.add(identity.get().getUuid());
|
||||
}
|
||||
uuids.addAll(st.getIdentities());
|
||||
for (UUID storeIdentity : st.getIdentities()) {
|
||||
if (initialIdentities.stream().anyMatch(ref -> ref.get().getUuid().equals(storeIdentity))) {
|
||||
var wasRemoved = identities.stream().noneMatch(ref -> ref.get().getUuid().equals(storeIdentity));
|
||||
if (!wasRemoved) {
|
||||
uuids.add(storeIdentity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return MultiIdentityStore.builder()
|
||||
.identities(new ArrayList<>(uuids))
|
||||
|
||||
Generated
+4
-3
@@ -802,7 +802,8 @@ identityChoice=User identity
|
||||
identityChoiceDescription=Choose a predefined identity or specify login details just for this connection
|
||||
defineNewIdentityOrSelect=Enter new or choose existing
|
||||
localIdentity.displayName=Local identity
|
||||
localIdentity.displayDescription=Create a reusable identity for this local desktop
|
||||
#force
|
||||
localIdentity.displayDescription=Create a reusable identity for this local system
|
||||
syncedIdentity.displayName=Synced identity
|
||||
syncedIdentity.displayDescription=Create a reusable identity that is synced across systems
|
||||
localIdentity=Local identity
|
||||
@@ -2045,6 +2046,6 @@ recentSearchesDescriptionNames=<name>, e.g. "Local Machine"
|
||||
recentSearchesDescriptionTags=<tag>, e.g. "my-custom-tag"
|
||||
recentSearchesDescriptionTypes=<type>, e.g. "Docker container"
|
||||
recentQuickConnections=Recent quick connections
|
||||
recentQuickConnectionsDescription=Quick connect via connection string
|
||||
recentQuickConnectionsDescription=Quick connect via string
|
||||
recentUrls=Recent URLs
|
||||
recentUrlsDescription=Quick connect via connection URLs
|
||||
recentUrlsDescription=Quick connect via URLs
|
||||
|
||||
Reference in New Issue
Block a user