This commit is contained in:
crschnick 2025-03-06 21:52:44 +00:00
parent 153db64ae0
commit 693b82dab8
17 changed files with 92 additions and 122 deletions

View file

@ -20,7 +20,6 @@ public class AppJavaOptionsCheck {
.formatted(env)
+ " This will forcefully apply all custom JVM options to XPipe and can cause a variety of different issues."
+ " Please remove this global environment variable and use local configuration instead for your other JVM programs.")
.noDefaultActions()
.expected()
.handle();
AppCache.update("javaOptionsWarningShown", true);

View file

@ -2,6 +2,7 @@ package io.xpipe.app.core.check;
import io.xpipe.app.core.AppProperties;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.util.DocumentationLink;
import io.xpipe.app.util.LocalShell;
import io.xpipe.core.process.OsType;
@ -27,7 +28,7 @@ public class AppRosettaCheck {
ErrorEvent.fromMessage("You are running the Intel version of XPipe on an Apple Silicon system."
+ " There is a native build available that comes with much better performance."
+ " Please install that one instead.")
.noDefaultActions()
.documentationLink(DocumentationLink.MACOS_SETUP)
.expected()
.handle();
}

View file

@ -1,6 +1,7 @@
package io.xpipe.app.ext;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.util.DocumentationLink;
import io.xpipe.app.util.Hyperlinks;
import io.xpipe.core.process.CommandBuilder;
import io.xpipe.core.process.ShellControl;
@ -57,9 +58,11 @@ public class ConnectionFileSystem implements FileSystem {
if (!shellControl.getTtyState().isPreservesOutput()
|| !shellControl.getTtyState().isSupportsInput()) {
throw ErrorEvent.expected(new UnsupportedOperationException(
"Shell has a PTY allocated and as a result does not support file system operations. For more information see "
+ Hyperlinks.DOCS_TTY));
var ex = new UnsupportedOperationException(
"Shell has a PTY allocated and as a result does not support file system operations.");
ErrorEvent.preconfigure(ErrorEvent.fromThrowable(ex)
.documentationLink(DocumentationLink.TTY));
throw ex;
}
shellControl.checkLicenseOrThrow();

View file

@ -1,11 +1,12 @@
package io.xpipe.app.issue;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.util.DocumentationLink;
import io.xpipe.app.util.Hyperlinks;
public interface ErrorAction {
static ErrorAction openDocumentation(String link) {
static ErrorAction openDocumentation(DocumentationLink link) {
return new ErrorAction() {
@Override
public String getName() {
@ -19,53 +20,12 @@ public interface ErrorAction {
@Override
public boolean handle(ErrorEvent event) {
Hyperlinks.open(link);
link.open();
return false;
}
};
}
static ErrorAction reportOnGithub() {
return new ErrorAction() {
@Override
public String getName() {
return AppI18n.get("reportOnGithub");
}
@Override
public String getDescription() {
return AppI18n.get("reportOnGithubDescription");
}
@Override
public boolean handle(ErrorEvent event) {
var url = "https://github.com/xpipe-io/xpipe/issues/new";
Hyperlinks.open(url);
return false;
}
};
}
static ErrorAction automaticallyReport() {
return new ErrorAction() {
@Override
public String getName() {
return AppI18n.get("reportError");
}
@Override
public String getDescription() {
return AppI18n.get("reportErrorDescription");
}
@Override
public boolean handle(ErrorEvent event) {
UserReportComp.show(event);
return true;
}
};
}
static ErrorAction ignore() {
return new ErrorAction() {
@Override

View file

@ -1,5 +1,6 @@
package io.xpipe.app.issue;
import io.xpipe.app.util.DocumentationLink;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
@ -23,9 +24,6 @@ public class ErrorEvent {
@Builder.Default
private final boolean reportable = true;
@Setter
private boolean disableDefaultActions;
private final Throwable throwable;
@Singular
@ -43,6 +41,8 @@ public class ErrorEvent {
@Singular
private List<Path> attachments;
private DocumentationLink documentationLink;
private String email;
private String userReport;
private boolean unhandled;
@ -162,10 +162,6 @@ public class ErrorEvent {
return omit().expected();
}
public ErrorEventBuilder noDefaultActions() {
return disableDefaultActions(true);
}
public void handle() {
build().handle();
}

View file

@ -66,22 +66,6 @@ public class ErrorHandlerComp extends SimpleComp {
return b.createRegion();
}
private Region createDetails() {
var content = new ErrorDetailsComp(event).prefWidth(600).prefHeight(750);
var modal = ModalOverlay.of("errorDetails", content);
var button = new ButtonComp(
null,
new SimpleObjectProperty<>(new LabelGraphic.NodeGraphic(() -> {
return createActionButtonGraphic(AppI18n.get("showDetails"), AppI18n.get("showDetailsDescription"));
})),
() -> {
modal.show();
});
var r = button.grow(true, false).createRegion();
r.getStyleClass().add("details");
return r;
}
private Region createTop() {
var desc = event.getDescription();
if (desc == null && event.getThrowable() != null) {
@ -112,10 +96,10 @@ public class ErrorHandlerComp extends SimpleComp {
@Override
protected Region createSimple() {
var top = createTop();
var content = new VBox(top, new Separator(Orientation.HORIZONTAL));
var content = new VBox(top);
var header = new Label(AppI18n.get("possibleActions"));
AppFontSizes.xl(header);
var actionBox = new VBox(header);
var actionBox = new VBox();
actionBox.getStyleClass().add("actions");
actionBox.setFillWidth(true);
@ -137,7 +121,6 @@ public class ErrorHandlerComp extends SimpleComp {
return true;
}
});
event.setDisableDefaultActions(true);
}
var custom = event.getCustomActions();
@ -147,21 +130,17 @@ public class ErrorHandlerComp extends SimpleComp {
actionBox.getChildren().add(ac);
}
if (!event.isDisableDefaultActions()) {
for (var action :
List.of(ErrorAction.automaticallyReport(), ErrorAction.reportOnGithub(), ErrorAction.ignore())) {
var ac = createActionComp(action);
actionBox.getChildren().add(ac);
}
} else if (event.getCustomActions().isEmpty()) {
for (var action : List.of(ErrorAction.ignore())) {
var ac = createActionComp(action);
actionBox.getChildren().add(ac);
}
if (event.getDocumentationLink() != null) {
actionBox.getChildren().add(createActionComp(ErrorAction.openDocumentation(event.getDocumentationLink())));
}
if (actionBox.getChildren().size() > 0) {
actionBox.getChildren().addFirst(header);
content.getChildren().add(new Separator(Orientation.HORIZONTAL));
actionBox.getChildren().get(1).getStyleClass().addAll(BUTTON_OUTLINED);
content.getChildren().addAll(actionBox);
}
actionBox.getChildren().get(1).getStyleClass().addAll(BUTTON_OUTLINED, ACCENT);
content.getChildren().addAll(actionBox);
content.getStyleClass().add("top");
content.setFillWidth(true);
content.setMinHeight(Region.USE_PREF_SIZE);
@ -170,13 +149,6 @@ public class ErrorHandlerComp extends SimpleComp {
layout.getChildren().add(content);
layout.getStyleClass().add("error-handler-comp");
if (event.getThrowable() != null) {
content.getChildren().add(new Separator(Orientation.HORIZONTAL));
var details = createDetails();
layout.getChildren().add(details);
layout.prefHeightProperty().bind(content.heightProperty().add(65).add(details.prefHeightProperty()));
}
return layout;
}
}

View file

@ -1,5 +1,6 @@
package io.xpipe.app.issue;
import io.xpipe.app.comp.base.ModalButton;
import io.xpipe.app.comp.base.ModalOverlay;
import io.xpipe.app.core.mode.OperationMode;
import io.xpipe.app.core.window.AppDialog;
@ -44,13 +45,25 @@ public class ErrorHandlerDialog {
var comp = new ErrorHandlerComp(event, () -> {
AppDialog.closeDialog(modal.get());
});
comp.prefWidth(550);
comp.prefWidth(500);
var headerId = event.isTerminal() ? "terminalErrorOccured" : "errorOccured";
modal.set(ModalOverlay.of(headerId, comp, new LabelGraphic.NodeGraphic(() -> {
var errorModal = ModalOverlay.of(headerId, comp, new LabelGraphic.NodeGraphic(() -> {
var graphic = new FontIcon("mdomz-warning");
graphic.setIconColor(Color.RED);
return graphic;
})));
}));
if (event.getThrowable() != null && event.isReportable()) {
errorModal.addButton(new ModalButton("stackTrace", () -> {
var content = new ErrorDetailsComp(event).prefWidth(600).prefHeight(750);
var detailsModal = ModalOverlay.of("errorDetails", content);
detailsModal.show();
}, false, false));
}
errorModal.addButton(new ModalButton("report", () -> {
UserReportComp.show(event);
}, false, false));
errorModal.addButton(ModalButton.ok());
modal.set(errorModal);
AppDialog.showAndWait(modal.get());
if (comp.getTakenAction().getValue() == null) {
ErrorAction.ignore().handle(event);

View file

@ -8,6 +8,7 @@ import io.xpipe.app.comp.base.VerticalComp;
import io.xpipe.app.core.AppDistributionType;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.AppProperties;
import io.xpipe.app.util.DocumentationLink;
import io.xpipe.app.util.Hyperlinks;
import io.xpipe.app.util.JfxHelper;
import io.xpipe.app.util.OptionsBuilder;
@ -48,7 +49,7 @@ public class AboutCategory extends AppPrefsCategory {
null)
.addComp(
new TileButtonComp("privacy", "privacyDescription", "mdomz-privacy_tip", e -> {
Hyperlinks.open(Hyperlinks.DOCS_PRIVACY);
DocumentationLink.PRIVACY.open();
e.consume();
})
.grow(true, false),
@ -64,7 +65,7 @@ public class AboutCategory extends AppPrefsCategory {
.grow(true, false))
.addComp(
new TileButtonComp("eula", "eulaDescription", "mdi2c-card-text-outline", e -> {
Hyperlinks.open(Hyperlinks.DOCS_EULA);
DocumentationLink.EULA.open();
e.consume();
})
.grow(true, false),

View file

@ -4,6 +4,7 @@ import io.xpipe.app.comp.Comp;
import io.xpipe.app.comp.base.*;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.storage.DataStorageSyncHandler;
import io.xpipe.app.util.DocumentationLink;
import io.xpipe.app.util.Hyperlinks;
import io.xpipe.app.util.OptionsBuilder;
import io.xpipe.app.util.ThreadHelper;
@ -53,7 +54,7 @@ public class SyncCategory extends AppPrefsCategory {
var remoteRepo = new TextFieldComp(prefs.storageGitRemote).hgrow();
var helpButton = new ButtonComp(AppI18n.observable("help"), new FontIcon("mdi2h-help-circle-outline"), () -> {
Hyperlinks.open(Hyperlinks.DOCS_SYNC);
DocumentationLink.SYNC.open();
});
var remoteRow = new HorizontalComp(List.of(remoteRepo, helpButton)).spacing(10);
remoteRow.apply(struc -> struc.get().setAlignment(Pos.CENTER_LEFT));

View file

@ -1,6 +1,7 @@
package io.xpipe.app.update;
import io.xpipe.app.comp.base.ModalButton;
import io.xpipe.app.util.DocumentationLink;
import io.xpipe.app.util.Hyperlinks;
import java.util.List;
@ -21,7 +22,7 @@ public class WebtopUpdater extends PortableUpdater {
return;
}
Hyperlinks.open(Hyperlinks.DOCS_WEBTOP_UPDATE);
DocumentationLink.WEBTOP_UPDATE.open();
},
false,
false));

View file

@ -17,6 +17,8 @@ import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.Window;
import javax.print.Doc;
public class AskpassAlert {
public static SecretQueryResult queryRaw(String prompt, InPlaceSecretValue secretValue) {
@ -33,7 +35,7 @@ public class AskpassAlert {
alert.getButtonTypes().add(type);
var button = alert.getDialogPane().lookupButton(type);
button.addEventFilter(MouseEvent.MOUSE_PRESSED, event -> {
Hyperlinks.open(Hyperlinks.DOCS_DOUBLE_PROMPT);
DocumentationLink.DOUBLE_PROMPT.open();
event.consume();
});
}

View file

@ -0,0 +1,32 @@
package io.xpipe.app.util;
import lombok.Value;
public enum DocumentationLink {
INDEX(""),
TTY("troubleshoot/tty"),
MACOS_SETUP("guide/installation#macos"),
SSH_AGENT("troubleshoot/ssh-agent-socket"),
DOUBLE_PROMPT("troubleshoot/two-step-connections"),
LICENSE_ACTIVATION("troubleshoot/license-activation"),
PRIVACY("legal/privacy"),
EULA("legal/eula"),
WEBTOP_UPDATE("guide/webtop#updating"),
SYNC("guide/sync"),
SCRIPTING("guide/scripting"),
SSH("guide/ssh");
private final String page;
DocumentationLink(String page) {this.page = page;}
public void open() {
Hyperlinks.open("https://docs.xpipe.io/" + page);
}
public String getLink() {
return "https://docs.xpipe.io/" + page;
}
}

View file

@ -5,16 +5,6 @@ import io.xpipe.app.issue.ErrorEvent;
public class Hyperlinks {
public static final String DOCS = "https://docs.xpipe.io";
public static final String DOCS_DOUBLE_PROMPT = "https://docs.xpipe.io/troubleshoot/two-step-connections";
public static final String DOCS_AGENT_SETUP = "https://docs.xpipe.io/troubleshoot/ssh-agent-socket";
public static final String DOCS_TTY = "https://docs.xpipe.io/troubleshoot/tty";
public static final String DOCS_LICENSE_ACTIVATION = "https://docs.xpipe.io/troubleshoot/license-activation";
public static final String DOCS_PRIVACY = "https://docs.xpipe.io/legal/privacy-policy";
public static final String DOCS_EULA = "https://docs.xpipe.io/legal/end-user-license-agreement";
public static final String DOCS_SECURITY = "https://docs.xpipe.io/reference/security";
public static final String DOCS_WEBTOP_UPDATE = "https://docs.xpipe.io/guide/webtop#updating";
public static final String DOCS_SYNC = "https://docs.xpipe.io/guide/sync";
public static final String DOCS_SCRIPTING = "https://docs.xpipe.io/guide/scriptin";
public static final String GITHUB = "https://github.com/xpipe-io/xpipe";
public static final String GITHUB_PTB = "https://github.com/xpipe-io/xpipe-ptb";
public static final String GITHUB_LATEST = "https://github.com/xpipe-io/xpipe/releases/latest";

View file

@ -1,5 +1,5 @@
.error-handler-comp .top {
-fx-spacing: 1em;
-fx-spacing: 0.7em;
}
.error-handler-comp .actions {

View file

@ -3,6 +3,7 @@ package io.xpipe.ext.base.identity;
import io.xpipe.app.issue.ErrorAction;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.util.CommandSupport;
import io.xpipe.app.util.DocumentationLink;
import io.xpipe.app.util.Hyperlinks;
import io.xpipe.core.process.CommandBuilder;
import io.xpipe.core.process.OsType;
@ -73,7 +74,7 @@ public class SshIdentityStateManager {
return true;
}
};
event.customAction(shutdown).noDefaultActions().handle();
event.customAction(shutdown).handle();
if (r.get()) {
if (sc.getShellDialect().equals(ShellDialects.CMD)) {
@ -146,7 +147,7 @@ public class SshIdentityStateManager {
var r = c.readStdoutAndStderr();
if (c.getExitCode() != 0) {
var posixMessage = sc.getOsType() != OsType.WINDOWS
? " and the SSH_AUTH_SOCK variable. See " + Hyperlinks.DOCS_AGENT_SETUP + " for details"
? " and the SSH_AUTH_SOCK variable."
: "";
var ex =
new IllegalStateException("Unable to list agent identities via command ssh-add -l:\n" + r[0]
@ -154,9 +155,8 @@ public class SshIdentityStateManager {
+ r[1]
+ "\nPlease check your SSH agent CLI configuration%s.".formatted(posixMessage));
ErrorEvent.preconfigure(ErrorEvent.fromThrowable(ex)
.noDefaultActions()
.expected()
.customAction(ErrorAction.openDocumentation(Hyperlinks.DOCS_AGENT_SETUP)));
.documentationLink(DocumentationLink.SSH_AGENT));
throw ex;
}
}

View file

@ -11,10 +11,7 @@ import io.xpipe.app.ext.DataStoreProvider;
import io.xpipe.app.ext.EnabledParentStoreProvider;
import io.xpipe.app.ext.GuiDialog;
import io.xpipe.app.storage.DataStoreEntry;
import io.xpipe.app.util.DataStoreFormatter;
import io.xpipe.app.util.Hyperlinks;
import io.xpipe.app.util.OptionsBuilder;
import io.xpipe.app.util.Validator;
import io.xpipe.app.util.*;
import io.xpipe.core.process.ShellDialect;
import io.xpipe.core.process.ShellDialects;
import io.xpipe.core.store.DataStore;
@ -36,7 +33,7 @@ public class SimpleScriptStoreProvider implements EnabledParentStoreProvider, Da
@Override
public String getHelpLink() {
return Hyperlinks.DOCS_SCRIPTING;
return DocumentationLink.SCRIPTING.getLink();
}
@Override

View file

@ -1355,3 +1355,5 @@ connectionsSelected=$NUMBER$ connections selected
addConnections=Add connections
browseDirectory=Browse directory
openTerminal=Open terminal
documentation=Documentation
report=Report error