This commit is contained in:
crschnick
2026-03-09 20:36:37 +00:00
parent 7c23cb9b3a
commit 19eea8a210
30 changed files with 118 additions and 77 deletions

View File

@@ -19,5 +19,7 @@ public interface LauncherUrlProvider extends ActionProvider {
String getScheme();
String getPlaceholder();
AbstractAction createAction(URI uri) throws Exception;
}

View File

@@ -9,6 +9,11 @@ public class XPipeUrlProvider implements LauncherUrlProvider {
return "xpipe";
}
@Override
public String getPlaceholder() {
return "xpipe://action?<name>[&param=value]";
}
@Override
public AbstractAction createAction(URI uri) throws Exception {
var a = uri.getHost();

View File

@@ -95,6 +95,10 @@ public class StoreFilterFieldComp extends SimpleRegionBuilder {
field.clear();
event.consume();
}
} else if (event.getCode() == KeyCode.ESCAPE) {
field.clear();
field.getScene().getRoot().requestFocus();
event.consume();
}
});

View File

@@ -90,6 +90,9 @@ public class StoreFilterState {
INSTANCE.recentQuickConnections.setContent(recentQuickConnections);
}
public void set(String s) {
rawText.setValue(s);
}
public void putFilter(String s) {
synchronized (recentSearches) {

View File

@@ -1,5 +1,7 @@
package io.xpipe.app.hub.comp;
import atlantafx.base.theme.Styles;
import io.xpipe.app.action.LauncherUrlProvider;
import io.xpipe.app.action.QuickConnectProvider;
import io.xpipe.app.comp.SimpleRegionBuilder;
import io.xpipe.app.comp.base.ButtonComp;
@@ -10,64 +12,85 @@ import io.xpipe.app.platform.OptionsBuilder;
import javafx.beans.binding.Bindings;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Pos;
import javafx.scene.layout.Region;
import java.util.List;
public class StoreFilterStateComp extends SimpleRegionBuilder {
private ButtonComp createButton(String text, String value) {
var button = new ButtonComp(new ReadOnlyObjectWrapper<>(text), () -> {
if (value != null) {
StoreFilterState.get().set(value);
}
});
button.disable(value == null);
button.apply(r -> r.setAlignment(Pos.CENTER_LEFT));
button.style(Styles.FLAT);
button.maxWidth(10000);
return button;
}
@Override
protected Region createSimple() {
var state = StoreFilterState.get();
var searches = state.getRecentSearches().getList();
var searchesEmpty = Bindings.isEmpty(searches);
var searchList = new ListBoxViewComp<String>(searches, searches, s -> {
return new ButtonComp(new ReadOnlyObjectWrapper<>(s), () -> {
var searchesList = new ListBoxViewComp<String>(searches, searches, s -> createButton(s, null), false);
});
}, false);
searchList.hide(searchesEmpty);
var searchesLabel = new LabelComp(AppI18n.observable("recent"));
searchesLabel.hide(searchesEmpty);
var searchesPlaceholders = FXCollections.observableList(List.of(AppI18n.get("recentSearchesDescriptionNames"),
AppI18n.get("recentSearchesDescriptionTags"), AppI18n.get("recentSearchesDescriptionTypes")));
var searchesEmptyList = new ListBoxViewComp<String>(searchesPlaceholders, searchesPlaceholders, s -> createButton(s, null), false);
var quickConnections = state.getRecentQuickConnections().getList();
var quickConnectionsEmpty = Bindings.isEmpty(searches);
var quickConnectionsList = new ListBoxViewComp<String>(quickConnections, quickConnections, s -> {
return new ButtonComp(new ReadOnlyObjectWrapper<>(s), () -> {
});
}, false);
var quickConnectionsEmpty = Bindings.isEmpty(quickConnections);
var quickConnectionsList = new ListBoxViewComp<String>(quickConnections, quickConnections, s -> createButton(s, null), false);
var quickConnectionsPlaceholders = FXCollections.observableArrayList(QuickConnectProvider.getAll().stream()
.map(quickConnectProvider -> quickConnectProvider.getPlaceholder())
.map(p -> p.getPlaceholder())
.toList());
var quickConnectionsEmptyList = new ListBoxViewComp<String>(quickConnectionsPlaceholders, quickConnectionsPlaceholders, s -> {
return new ButtonComp(new ReadOnlyObjectWrapper<>(s), () -> {
var quickConnectionsEmptyList = new ListBoxViewComp<String>(quickConnectionsPlaceholders, quickConnectionsPlaceholders, s -> createButton(s, null), false);
});
}, false);
var urls = state.getRecentUrls().getList();
var urlsEmpty = Bindings.isEmpty(urls);
var urlList = new ListBoxViewComp<String>(urls, urls, s -> createButton(s, null), false);
var quickConnectionsLabel = new LabelComp(AppI18n.observable("recent"));
quickConnectionsLabel.hide(quickConnectionsEmpty);
var otherLabel = new LabelComp(AppI18n.observable("recent"));
var otherList = List.of("ssh://user@host", "sftp://user@host", "s3://host/path", "xpipe://action?...");
var urlPlaceholders = FXCollections.observableArrayList(LauncherUrlProvider.getAll().stream()
.map(p -> p.getPlaceholder())
.toList());
var urlEmptyList = new ListBoxViewComp<String>(urlPlaceholders, urlPlaceholders, s -> createButton(s, null), false);
var options = new OptionsBuilder()
.name("recent")
.addComp(searchList)
.addComp(new LabelComp(AppI18n.observable("recentSearches")))
.hide(searchesEmpty)
.addComp(searchesLabel)
.addComp(searchesList)
.hide(searchesEmpty)
.addComp(new LabelComp(AppI18n.observable("recentSearchesDescription")))
.hide(searchesEmpty.not())
.name("recent")
.addComp(searchesEmptyList)
.hide(searchesEmpty.not())
.addComp(new LabelComp(AppI18n.observable("recentQuickConnections")))
.hide(quickConnectionsEmpty)
.addComp(quickConnectionsList)
.hide(quickConnectionsEmpty)
.addComp(new LabelComp(AppI18n.observable("recentQuickConnectionsDescription")))
.hide(quickConnectionsEmpty.not())
.addComp(quickConnectionsEmptyList)
.hide(quickConnectionsEmpty.not())
.addComp(new LabelComp(AppI18n.observable("recentUrls")))
.hide(urlsEmpty)
.addComp(urlList)
.hide(urlsEmpty)
.addComp(new LabelComp(AppI18n.observable("recentUrlsDescription")))
.hide(urlsEmpty.not())
.addComp(urlEmptyList)
.hide(urlsEmpty.not())
.build();
options.getStyleClass().add("store-filter-state-comp");
return options;
}
}

View File

@@ -211,14 +211,14 @@ public class OptionsBuilder {
return this;
}
public OptionsBuilder addTitle(String titleKey) {
public OptionsBuilder title(String titleKey) {
finishCurrent();
entries.add(new OptionsComp.Entry(
null, null, null, new LabelComp(AppI18n.observable(titleKey)).style("title-header")));
return this;
}
public OptionsBuilder addTitle(ObservableValue<String> title) {
public OptionsBuilder title(ObservableValue<String> title) {
finishCurrent();
entries.add(new OptionsComp.Entry(null, null, null, new LabelComp(title).style("title-header")));
return this;

View File

@@ -22,7 +22,7 @@ public class ApiCategory extends AppPrefsCategory {
var prefs = AppPrefs.get();
return new OptionsBuilder()
.addTitle("httpServer")
.title("httpServer")
.sub(new OptionsBuilder()
.pref(prefs.enableHttpApi)
.addToggle(prefs.enableHttpApi)

View File

@@ -52,7 +52,7 @@ public class ConnectionHubCategory extends AppPrefsCategory {
.addToggle(prefs.openConnectionSearchWindowOnConnectionCreation)
.pref(prefs.requireDoubleClickForConnections)
.addToggle(prefs.requireDoubleClickForConnections);
var options = new OptionsBuilder().addTitle("connectionHub").sub(connectionsBuilder);
var options = new OptionsBuilder().title("connectionHub").sub(connectionsBuilder);
return options.buildComp();
}

View File

@@ -79,6 +79,6 @@ public class DeveloperCategory extends AppPrefsCategory {
.addToggle(prefs.developerDisableSshTunnelGateways);
}
sub.nameAndDescription("shellCommandTest").addComp(runLocalCommand);
return new OptionsBuilder().addTitle("developer").sub(sub).buildComp();
return new OptionsBuilder().title("developer").sub(sub).buildComp();
}
}

View File

@@ -29,7 +29,7 @@ public class DisplayCategory extends AppPrefsCategory {
protected BaseRegionBuilder<?, ?> create() {
var prefs = AppPrefs.get();
return new OptionsBuilder()
.addTitle("displayOptions")
.title("displayOptions")
.sub(new OptionsBuilder()
.pref(prefs.uiScale)
.addComp(
@@ -47,7 +47,7 @@ public class DisplayCategory extends AppPrefsCategory {
.pref(prefs.limitedTouchscreenMode)
.addToggle(prefs.limitedTouchscreenMode)
.hide(OsType.ofLocal() != OsType.LINUX))
.addTitle("windowOptions")
.title("windowOptions")
.sub(new OptionsBuilder()
.pref(prefs.windowOpacity)
.addComp(

View File

@@ -77,7 +77,7 @@ public class EditorCategory extends AppPrefsCategory {
@Override
protected BaseRegionBuilder<?, ?> create() {
return new OptionsBuilder()
.addTitle("editorConfiguration")
.title("editorConfiguration")
.sub(editorChoice())
.buildComp();
}

View File

@@ -27,7 +27,7 @@ public class FileBrowserCategory extends AppPrefsCategory {
protected BaseRegionBuilder<?, ?> create() {
var prefs = AppPrefs.get();
return new OptionsBuilder()
.addTitle("fileBrowser")
.title("fileBrowser")
.sub(new OptionsBuilder()
.pref(prefs.editFilesWithDoubleClick)
.addToggle(prefs.editFilesWithDoubleClick)

View File

@@ -52,7 +52,7 @@ public class IconsCategory extends AppPrefsCategory {
@Override
protected BaseRegionBuilder<?, ?> create() {
return new OptionsBuilder()
.addTitle("customIcons")
.title("customIcons")
.sub(new OptionsBuilder()
.nameAndDescription("iconSources")
.documentationLink(DocumentationLink.ICONS)

View File

@@ -15,7 +15,7 @@ public class LinksCategory extends AppPrefsCategory {
private BaseRegionBuilder<?, ?> createLinks() {
return new OptionsBuilder()
.addTitle("links")
.title("links")
.addComp(RegionBuilder.vspacer(19))
.addComp(
new TileButtonComp("activeLicense", "activeLicenseDescription", "mdi2k-key-outline", e -> {

View File

@@ -1,11 +1,9 @@
package io.xpipe.app.prefs;
import atlantafx.base.theme.Styles;
import io.xpipe.app.beacon.AppBeaconServer;
import io.xpipe.app.comp.BaseRegionBuilder;
import io.xpipe.app.comp.RegionBuilder;
import io.xpipe.app.comp.base.IntegratedTextAreaComp;
import io.xpipe.app.comp.base.TextAreaComp;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.AppNames;
import io.xpipe.app.platform.LabelGraphic;
@@ -131,7 +129,7 @@ public class McpCategory extends AppPrefsCategory {
});
return new OptionsBuilder()
.addTitle("mcpServer")
.title("mcpServer")
.sub(new OptionsBuilder()
.pref(prefs.enableMcpServer)
.addToggle(prefs.enableMcpServer)

View File

@@ -3,7 +3,6 @@ package io.xpipe.app.prefs;
import io.xpipe.app.comp.BaseRegionBuilder;
import io.xpipe.app.comp.base.ButtonComp;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.platform.BindingsHelper;
import io.xpipe.app.platform.LabelGraphic;
import io.xpipe.app.platform.OptionsBuilder;
import io.xpipe.app.platform.OptionsChoiceBuilder;
@@ -11,7 +10,6 @@ import io.xpipe.app.pwman.PasswordManager;
import io.xpipe.app.util.*;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleStringProperty;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
@@ -69,7 +67,7 @@ public class PasswordManagerCategory extends AppPrefsCategory {
@Override
protected BaseRegionBuilder<?, ?> create() {
return new OptionsBuilder()
.addTitle("passwordManager")
.title("passwordManager")
.sub(passwordManagerChoice())
.buildComp();
}

View File

@@ -96,7 +96,7 @@ public class PersonalizationCategory extends AppPrefsCategory {
@Override
protected BaseRegionBuilder<?, ?> create() {
return new OptionsBuilder()
.addTitle("personalization")
.title("personalization")
.sub(new OptionsBuilder().sub(languageChoice()).sub(themeChoice()))
.buildComp();
}

View File

@@ -55,7 +55,7 @@ public class RdpCategory extends AppPrefsCategory {
.build();
return new OptionsBuilder()
.addTitle("rdpConfiguration")
.title("rdpConfiguration")
.sub(new OptionsBuilder()
.nameAndDescription("rdpClient")
.documentationLink(DocumentationLink.RDP)

View File

@@ -19,7 +19,7 @@ public class SecurityCategory extends AppPrefsCategory {
public BaseRegionBuilder<?, ?> create() {
var prefs = AppPrefs.get();
var builder = new OptionsBuilder();
builder.addTitle("security")
builder.title("security")
.sub(new OptionsBuilder()
.pref(prefs.alwaysConfirmElevation)
.addToggle(prefs.alwaysConfirmElevation)

View File

@@ -1,34 +1,18 @@
package io.xpipe.app.prefs;
import atlantafx.base.theme.Styles;
import io.xpipe.app.comp.BaseRegionBuilder;
import io.xpipe.app.comp.base.ButtonComp;
import io.xpipe.app.comp.base.ContextualFileReferenceChoiceComp;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.cred.CustomAgentStrategy;
import io.xpipe.app.cred.SshAgentTestComp;
import io.xpipe.app.cred.SshIdentityStateManager;
import io.xpipe.app.ext.ProcessControlProvider;
import io.xpipe.app.issue.ErrorEventFactory;
import io.xpipe.app.platform.LabelGraphic;
import io.xpipe.app.platform.OptionsBuilder;
import io.xpipe.app.process.LocalShell;
import io.xpipe.app.process.ShellScript;
import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.terminal.TerminalLaunch;
import io.xpipe.app.util.ThreadHelper;
import io.xpipe.core.OsType;
import javafx.application.Platform;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.SimpleObjectProperty;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.layout.Region;
import org.kordamp.ikonli.javafx.FontIcon;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
public class SshCategory extends AppPrefsCategory {
@@ -45,7 +29,7 @@ public class SshCategory extends AppPrefsCategory {
@Override
protected BaseRegionBuilder<?, ?> create() {
var prefs = AppPrefs.get();
var options = new OptionsBuilder().addTitle("sshConfiguration");
var options = new OptionsBuilder().title("sshConfiguration");
if (OsType.ofLocal() == OsType.WINDOWS) {
options.addComp(prefs.getCustomOptions("x11WslInstance").buildComp());
}

View File

@@ -68,7 +68,7 @@ public class SyncCategory extends AppPrefsCategory {
remoteRepo.disable(prefs.enableGitStorage.not());
var builder = new OptionsBuilder();
builder.addTitle("gitSync")
builder.title("gitSync")
.sub(new OptionsBuilder()
.pref(prefs.enableGitStorage)
.addToggle(prefs.enableGitStorage)

View File

@@ -23,7 +23,7 @@ public class SystemCategory extends AppPrefsCategory {
public BaseRegionBuilder<?, ?> create() {
var prefs = AppPrefs.get();
var builder = new OptionsBuilder();
builder.addTitle("system")
builder.title("system")
.sub(new OptionsBuilder()
.pref(prefs.startupBehaviour)
.addComp(ChoiceComp.ofTranslatable(

View File

@@ -22,7 +22,6 @@ import io.xpipe.app.terminal.*;
import io.xpipe.app.util.*;
import io.xpipe.core.OsType;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleObjectProperty;
import javafx.geometry.Insets;
@@ -165,13 +164,13 @@ public class TerminalCategory extends AppPrefsCategory {
var splitViewSupported = Bindings.isNotNull(TerminalSplitStrategy.getEffectiveSplitStrategyObservable());
return new OptionsBuilder()
.addTitle("terminalConfiguration")
.title("terminalConfiguration")
.sub(terminalChoice(true))
.sub(terminalPrompt())
.sub(terminalProxy())
.sub(terminalMultiplexer())
// .sub(terminalInitScript())
.addTitle("sessionLogging")
.title("sessionLogging")
.sub(new OptionsBuilder()
.pref(prefs.enableTerminalLogging)
.addToggle(prefs.enableTerminalLogging)
@@ -187,7 +186,7 @@ public class TerminalCategory extends AppPrefsCategory {
}
})
.disable(prefs.enableTerminalLogging.not())))
.addTitle("terminalBehaviour")
.title("terminalBehaviour")
.sub(
new OptionsBuilder()
.pref(prefs.enableConnectionHubTerminalDocking)

View File

@@ -53,7 +53,7 @@ public class TroubleshootCategory extends AppPrefsCategory {
protected BaseRegionBuilder<?, ?> create() {
var prefs = AppPrefs.get();
OptionsBuilder b = new OptionsBuilder()
.addTitle("troubleshootingOptions")
.title("troubleshootingOptions")
.sub(new OptionsBuilder().pref(prefs.sshVerboseOutput).addToggle(prefs.sshVerboseOutput))
.spacer(19)
.addComp(

View File

@@ -19,7 +19,7 @@ public class UpdatesCategory extends AppPrefsCategory {
public BaseRegionBuilder<?, ?> create() {
var prefs = AppPrefs.get();
var builder = new OptionsBuilder();
builder.addTitle("updates")
builder.title("updates")
.sub(new OptionsBuilder()
.pref(prefs.automaticallyCheckForUpdates)
.addToggle(prefs.automaticallyCheckForUpdates)

View File

@@ -78,7 +78,7 @@ public class VaultCategory extends AppPrefsCategory {
uh.setCurrentGroupStrategy(nv);
});
builder.addTitle("vault")
builder.title("vault")
.sub(new OptionsBuilder()
.name("vaultTypeName" + vaultTypeKey)
.description("vaultTypeContent" + vaultTypeKey)

View File

@@ -22,7 +22,7 @@ public class WorkspacesCategory extends AppPrefsCategory {
@Override
protected BaseRegionBuilder<?, ?> create() {
return new OptionsBuilder()
.addTitle("manageWorkspaces")
.title("manageWorkspaces")
.sub(new OptionsBuilder()
.nameAndDescription("workspaceAdd")
.licenseRequirement("workspaces")

View File

@@ -53,7 +53,7 @@ public class VncCategory extends AppPrefsCategory {
.build();
var choice = choiceBuilder.build().buildComp().maxWidth(600);
return new OptionsBuilder()
.addTitle("vncClient")
.title("vncClient")
.sub(new OptionsBuilder().pref(prefs.vncClient).addComp(choice))
.buildComp();
}

View File

@@ -246,3 +246,19 @@
.agent-socket-choice:disabled .text-field {
-fx-opacity: 1.0;
}
.store-filter-state-comp {
-fx-padding: 5 15 5 15;
}
.store-filter-state-comp .button {
-fx-padding: 5 10 5 10;
}
.store-filter-state-comp .button:disabled {
-fx-opacity: 1.0;
}
.store-filter-state-comp .label {
-fx-padding: 10 0 0 0;
}

View File

@@ -2039,3 +2039,12 @@ hashicorpVaultSecretId=SecretID
hashicorpVaultSecretIdDescription=The matching secret of the AppRole
hashicorpVaultToken=Token
hashicorpVaultTokenDescription=The authentication token to use
recentSearches=Recent searches
recentSearchesDescription=Filter for connection attributes
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
recentUrls=Recent URLs
recentUrlsDescription=Quick connect via connection URLs