mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-17 10:11:27 +00:00
optimized implementation
This commit is contained in:
@@ -32,17 +32,14 @@ public class ErrorCode {
|
||||
this.rootCauseSpecificFrames = rootCauseSpecificFrames;
|
||||
}
|
||||
|
||||
// visible for testing
|
||||
String methodCode() {
|
||||
public String methodCode() {
|
||||
return format(traceCode(rootCause, LATEST_FRAME));
|
||||
}
|
||||
|
||||
// visible for testing
|
||||
String rootCauseCode() {
|
||||
public String rootCauseCode() {
|
||||
return format(traceCode(rootCause, rootCauseSpecificFrames));
|
||||
}
|
||||
|
||||
// visible for testing
|
||||
String throwableCode() {
|
||||
return format(traceCode(throwable, ALL_FRAMES));
|
||||
}
|
||||
|
||||
19
src/main/java/org/cryptomator/ui/common/HttpHelper.java
Normal file
19
src/main/java/org/cryptomator/ui/common/HttpHelper.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package org.cryptomator.ui.common;
|
||||
|
||||
import com.google.common.io.CharStreams;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class HttpHelper {
|
||||
|
||||
public static String readBody(HttpResponse<InputStream> response) throws IOException {
|
||||
try (var in = response.body(); var reader = new InputStreamReader(in, StandardCharsets.UTF_8)) {
|
||||
return CharStreams.toString(reader);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,13 +2,11 @@ package org.cryptomator.ui.error;
|
||||
|
||||
import com.google.common.reflect.TypeToken;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.cryptomator.common.Environment;
|
||||
import org.cryptomator.common.ErrorCode;
|
||||
import org.cryptomator.common.Nullable;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javafx.application.Application;
|
||||
@@ -20,32 +18,22 @@ import javafx.scene.Scene;
|
||||
import javafx.scene.input.Clipboard;
|
||||
import javafx.scene.input.ClipboardContent;
|
||||
import javafx.stage.Stage;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.google.gson.JsonParser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Set;
|
||||
|
||||
public class ErrorController implements FxController {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ErrorController.class);
|
||||
private static final String ERROR_CODES_URL = "https://gist.githubusercontent.com/cryptobot/accba9fb9555e7192271b85606f97230/raw/errorcodes.json";
|
||||
private static final String SEARCH_URL_FORMAT = "https://github.com/cryptomator/cryptomator/discussions/categories/errors?discussions_q=category:Errors+%s";
|
||||
private static final String REPORT_URL_FORMAT = "https://github.com/cryptomator/cryptomator/discussions/new?category=Errors&title=Error+%s&body=%s";
|
||||
@@ -70,100 +58,28 @@ public class ErrorController implements FxController {
|
||||
private final Stage window;
|
||||
private final Environment environment;
|
||||
|
||||
private BooleanProperty copiedDetails = new SimpleBooleanProperty();
|
||||
private BooleanProperty lookUpSolutionVisibility = new SimpleBooleanProperty();
|
||||
private final HttpClient httpClient;
|
||||
|
||||
List<ErrorDiscussion> errorDiscussionList;
|
||||
private final BooleanProperty copiedDetails = new SimpleBooleanProperty();
|
||||
private final BooleanProperty lookUpSolutionVisibility = new SimpleBooleanProperty();
|
||||
private final BooleanProperty isLoadingHttpResponse = new SimpleBooleanProperty();
|
||||
private ErrorDiscussion matchingErrorDiscussion;
|
||||
|
||||
@Inject
|
||||
ErrorController(Application application, @Named("stackTrace") String stackTrace, ErrorCode errorCode, @Nullable Scene previousScene, Stage window, Environment environment) {
|
||||
ErrorController(Application application, @Named("stackTrace") String stackTrace, ErrorCode errorCode, @Nullable Scene previousScene, Stage window, Environment environment, ExecutorService executorService) {
|
||||
this.application = application;
|
||||
this.stackTrace = stackTrace;
|
||||
this.errorCode = errorCode;
|
||||
this.previousScene = previousScene;
|
||||
this.window = window;
|
||||
this.environment = environment;
|
||||
this.httpClient = HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1).build();
|
||||
|
||||
|
||||
|
||||
HttpClient httpClient = HttpClient.newHttpClient();
|
||||
isLoadingHttpResponse.set(true);
|
||||
HttpClient httpClient = HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1).build();
|
||||
HttpRequest httpRequest = HttpRequest.newBuilder()
|
||||
.uri(URI.create(ERROR_CODES_URL))
|
||||
.build();
|
||||
|
||||
CompletableFuture<HttpResponse<String>> future = httpClient.sendAsync(httpRequest, HttpResponse.BodyHandlers.ofString());
|
||||
|
||||
future.thenAcceptAsync(response -> {
|
||||
int statusCode = response.statusCode();
|
||||
if (statusCode == 200) {
|
||||
String jsonString = response.body();
|
||||
//LOG.debug("jpkED - jsonString : " + jsonString);
|
||||
//System.out.println(jsonString);
|
||||
|
||||
//JsonObject jsonObject = (JsonObject)new JsonParser().parse(jsonString);
|
||||
|
||||
jsonString = "[{\"id\":\"D_kwDOAPryk84ASwC1\",\"upvoteCount\":4,\"title\":\"Error GH1B:GH1B:NJFJ\",\"url\":\"https://github.com/cryptomator/cryptomator/discussions/2710\",\"answer\":{\"url\":\"https://github.com/cryptomator/cryptomator/discussions/2710#discussioncomment-5191708\",\"upvoteCount\":3},\"comments\":8},{\"id\":\"D_kwDOAPryk84ASw_I\",\"upvoteCount\":1,\"title\":\"Error GH1B:GH1B:NJFJ\",\"url\":\"https://github.com/cryptomator/cryptomator/discussions/2716\",\"answer\":null,\"comments\":2},{\"id\":\"D_kwDOAPryk84ASxAg\",\"upvoteCount\":1,\"title\":\"Error GH1B:GH1B:NJFJ\",\"url\":\"https://github.com/cryptomator/cryptomator/discussions/2717\",\"answer\":{\"url\":\"https://github.com/cryptomator/cryptomator/discussions/2717#discussioncomment-5181996\",\"upvoteCount\":2},\"comments\":3},{\"id\":\"D_kwDOAPryk84ASxDK\",\"upvoteCount\":1,\"title\":\"Error GH1B:GH1B:NJFJ\",\"url\":\"https://github.com/cryptomator/cryptomator/discussions/2718\",\"answer\":null,\"comments\":0},{\"id\":\"D_kwDOAPryk84ATj-U\",\"upvoteCount\":1,\"title\":\"ErrorCode N05M:GEAO:GEAO\",\"url\":\"https://github.com/cryptomator/cryptomator/discussions/2877\",\"answer\":null,\"comments\":1},{\"id\":\"D_kwDOAPryk84ATl2o\",\"upvoteCount\":1,\"title\":\"Error GH1B:GH1B:NJFJ\",\"url\":\"https://github.com/cryptomator/cryptomator/discussions/2883\",\"answer\":{\"url\":\"https://github.com/cryptomator/cryptomator/discussions/2883#discussioncomment-5769879\",\"upvoteCount\":1},\"comments\":1},{\"id\":\"D_kwDOAPryk84ATqCM\",\"upvoteCount\":1,\"title\":\"Error Code 4VHF:1S9S:5EOP\",\"url\":\"https://github.com/cryptomator/cryptomator/discussions/2887\",\"answer\":null,\"comments\":0},{\"id\":\"D_kwDOAPryk84ATqDF\",\"upvoteCount\":1,\"title\":\"Error H1VR:OTAS:OTAS\",\"url\":\"https://github.com/cryptomator/cryptomator/discussions/2888\",\"answer\":null,\"comments\":0},{\"id\":\"D_kwDOAPryk84ATrPD\",\"upvoteCount\":1,\"title\":\"Error S4DB:IV2H:I3UI\",\"url\":\"https://github.com/cryptomator/cryptomator/discussions/2891\",\"answer\":{\"url\":\"https://github.com/cryptomator/cryptomator/discussions/2891#discussioncomment-5797329\",\"upvoteCount\":1},\"comments\":1},{\"id\":\"D_kwDOAPryk84ATtJZ\",\"upvoteCount\":1,\"title\":\"Error 3MAT:BDUS:BDUS\",\"url\":\"https://github.com/cryptomator/cryptomator/discussions/2894\",\"answer\":null,\"comments\":0},{\"id\":\"D_kwDOAPryk84ATuDc\",\"upvoteCount\":1,\"title\":\"Error QPDR:AFGD:AFGD\",\"url\":\"https://github.com/cryptomator/cryptomator/discussions/2895\",\"answer\":null,\"comments\":0}]";
|
||||
|
||||
Gson gson = new Gson();
|
||||
Type listType = new TypeToken<List<ErrorDiscussion>>(){}.getType();
|
||||
errorDiscussionList = gson.fromJson(jsonString,listType);
|
||||
|
||||
|
||||
|
||||
loadJsonToErrorDiscussionList();
|
||||
|
||||
|
||||
|
||||
|
||||
LOG.debug("jpkED - errorDiscussionList loaded | amount:"+errorDiscussionList.size()+"");
|
||||
|
||||
//find exact matching
|
||||
List<ErrorDiscussion> newErrorDiscussionList = new ArrayList<>();
|
||||
newErrorDiscussionList.addAll(errorDiscussionList);
|
||||
newErrorDiscussionList.removeIf(errorDiscussion -> !errorDiscussion.getErrorCode().contains(getErrorCode()));
|
||||
if(newErrorDiscussionList.size()>0){
|
||||
errorDiscussionList.clear();
|
||||
errorDiscussionList.addAll(newErrorDiscussionList);
|
||||
LOG.debug("jpkED - exact match | amount:"+errorDiscussionList.size()+"");
|
||||
|
||||
lookUpSolutionVisibility.set(true);
|
||||
}
|
||||
else{
|
||||
//find method code matching
|
||||
newErrorDiscussionList.clear();
|
||||
newErrorDiscussionList.addAll(errorDiscussionList);
|
||||
newErrorDiscussionList.removeIf(errorDiscussion -> !errorDiscussion.getErrorCode().contains(getErrorCodeMethodCode()));
|
||||
if(newErrorDiscussionList.size()>0){
|
||||
errorDiscussionList.clear();
|
||||
errorDiscussionList.addAll(newErrorDiscussionList);
|
||||
LOG.debug("jpkED - method match | amount:"+errorDiscussionList.size()+"");
|
||||
}
|
||||
else{
|
||||
errorDiscussionList.clear();
|
||||
LOG.debug("jpkED - nothing found");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if(errorDiscussionList.size()!=0){
|
||||
//answered
|
||||
newErrorDiscussionList.clear();
|
||||
newErrorDiscussionList.addAll(errorDiscussionList);
|
||||
newErrorDiscussionList.removeIf(errorDiscussion -> errorDiscussion.answer == null);
|
||||
if(newErrorDiscussionList.size()>0){
|
||||
errorDiscussionList.clear();
|
||||
errorDiscussionList.addAll(newErrorDiscussionList);
|
||||
LOG.debug("jpkED - answered | amount:"+errorDiscussionList.size()+"");
|
||||
}
|
||||
Collections.sort(errorDiscussionList, this::errorDiscussionComparator);
|
||||
LOG.debug("jpkED - most upvote | id: " + errorDiscussionList.get(0).id + " | title: " + errorDiscussionList.get(0).title + " | upvoteCount:" + errorDiscussionList.get(0).upvoteCount);
|
||||
}
|
||||
}
|
||||
}).join();
|
||||
|
||||
|
||||
httpClient.sendAsync(httpRequest, HttpResponse.BodyHandlers.ofInputStream())
|
||||
.thenAcceptAsync(this::loadHttpResponse, executorService)
|
||||
.whenCompleteAsync((r,e) -> isLoadingHttpResponse.set(false), Platform::runLater);
|
||||
}
|
||||
|
||||
@FXML
|
||||
@@ -180,8 +96,9 @@ public class ErrorController implements FxController {
|
||||
|
||||
@FXML
|
||||
public void showSolution() {
|
||||
if(errorDiscussionList.size()!=0) {
|
||||
application.getHostServices().showDocument(errorDiscussionList.get(0).url);
|
||||
if(matchingErrorDiscussion != null){
|
||||
//TODO: errorDiscussion.url or errorDiscussion.answer.url
|
||||
application.getHostServices().showDocument(matchingErrorDiscussion.url);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,8 +132,75 @@ public class ErrorController implements FxController {
|
||||
});
|
||||
}
|
||||
|
||||
/* Getter/Setter */
|
||||
private void loadHttpResponse(HttpResponse<InputStream> response){
|
||||
if (response.statusCode() == 200) {
|
||||
Map<String,ErrorDiscussion> map = new Gson().fromJson(
|
||||
new InputStreamReader(response.body(),StandardCharsets.UTF_8),
|
||||
new TypeToken<Map<String,ErrorDiscussion>>(){}.getType());
|
||||
|
||||
if(!map.values().stream().filter(this::isPartialMatchFilter).findFirst().isEmpty()) {
|
||||
lookUpSolutionVisibility.set(true);
|
||||
Comparator<ErrorDiscussion> comp = this::compareExactMatch;
|
||||
matchingErrorDiscussion = map.values().stream().sorted(comp
|
||||
.thenComparing(this::compareSecondLevelMatch)
|
||||
.thenComparing(this::compareThirdLevelMatch)
|
||||
.thenComparing(this::compareIsAnswered)
|
||||
.thenComparing(this::compareUpvoteCount)
|
||||
).findFirst().get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isPartialMatchFilter(ErrorDiscussion errorDiscussion) {
|
||||
return errorDiscussion.title.contains(" " +errorCode.methodCode());
|
||||
}
|
||||
|
||||
public int compareUpvoteCount(ErrorDiscussion ed1, ErrorDiscussion ed2) {
|
||||
return Integer.compare(ed2.upvoteCount, ed1.upvoteCount);
|
||||
}
|
||||
|
||||
public int compareIsAnswered(ErrorDiscussion ed1, ErrorDiscussion ed2) {
|
||||
if (ed1.answer!=null && ed2.answer==null) {
|
||||
return -1;
|
||||
} else if (ed1.answer==null && ed2.answer!=null) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
public int compareExactMatch(ErrorDiscussion ed1, ErrorDiscussion ed2) {
|
||||
if (ed1.title.contains(getErrorCode()) && !ed2.title.contains(getErrorCode())) {
|
||||
return -1;
|
||||
} else if (!ed1.title.contains(getErrorCode()) && ed2.title.contains(getErrorCode())) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public int compareSecondLevelMatch(ErrorDiscussion ed1, ErrorDiscussion ed2) {
|
||||
String value = " " + errorCode.methodCode() + ErrorCode.DELIM + errorCode.rootCauseCode();
|
||||
if (ed1.title.contains(value) && !ed2.title.contains(value)) {
|
||||
return -1;
|
||||
} else if (!ed1.title.contains(value) && ed2.title.contains(value)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public int compareThirdLevelMatch(ErrorDiscussion ed1, ErrorDiscussion ed2) {
|
||||
String value = " " + errorCode.methodCode();
|
||||
if (ed1.title.contains(value) && !ed2.title.contains(value)) {
|
||||
return -1;
|
||||
} else if (!ed1.title.contains(value) && ed2.title.contains(value)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Getter/Setter */
|
||||
public boolean isPreviousScenePresent() {
|
||||
return previousScene != null;
|
||||
}
|
||||
@@ -226,11 +210,7 @@ public class ErrorController implements FxController {
|
||||
}
|
||||
|
||||
public String getErrorCode() {
|
||||
//return "GH1B:GH1B:NJFJ"; // 31 exact match - 4 answered
|
||||
//return "GIJU:E215:E215"; // 1 exact match - 0 answered
|
||||
//return "6PHE:UG0C:UG0C"; // 0 exact match - 8 method match - 3 answered
|
||||
//return "0000:0000:0000"; // 0 match
|
||||
return errorCode.toString(); // 0 exact match - 8 method match - 3 answered
|
||||
return errorCode.toString();
|
||||
}
|
||||
|
||||
public String getDetailText() {
|
||||
@@ -253,56 +233,12 @@ public class ErrorController implements FxController {
|
||||
return lookUpSolutionVisibility.get();
|
||||
}
|
||||
|
||||
public String getDetailTexts() {
|
||||
return "```\nError Code " + getErrorCode() + "\n" + getStackTrace() + "\n```";
|
||||
public BooleanProperty isLoadingHttpResponseProperty() {
|
||||
return isLoadingHttpResponse;
|
||||
}
|
||||
|
||||
private void filterListByMethodCode(){
|
||||
List<ErrorDiscussion> newErrorDiscussionList = new ArrayList<>();
|
||||
for (int i = 0; i < errorDiscussionList.size(); i++) {
|
||||
ErrorDiscussion errorDiscussion = errorDiscussionList.get(i);
|
||||
if(errorDiscussion.getMethodCode().equals(getErrorCodeMethodCode())){
|
||||
newErrorDiscussionList.add(errorDiscussion);
|
||||
}
|
||||
}
|
||||
if(newErrorDiscussionList.size()!=0){
|
||||
errorDiscussionList = newErrorDiscussionList;
|
||||
lookUpSolutionVisibility.set(true);
|
||||
LOG.debug("jpkED - found matching method code | amount:"+errorDiscussionList.size()+"");
|
||||
}
|
||||
else{
|
||||
errorDiscussionList = newErrorDiscussionList; // to clear results
|
||||
LOG.debug("jpkED - no matching method code found");
|
||||
}
|
||||
public boolean getIsLoadingHttpResponse() {
|
||||
return isLoadingHttpResponse.get();
|
||||
}
|
||||
|
||||
private int errorDiscussionComparator(ErrorDiscussion t, ErrorDiscussion t1) {
|
||||
return Integer.compare(t1.upvoteCount, t.upvoteCount);
|
||||
}
|
||||
|
||||
private String getErrorCodeMethodCode(){
|
||||
return getErrorCode().substring(0,4);
|
||||
}
|
||||
|
||||
private void loadJsonToErrorDiscussionList(){
|
||||
String errorCodesUrl = "https://gist.githubusercontent.com/cryptobot/accba9fb9555e7192271b85606f97230/raw/errorcodes.json";
|
||||
try (InputStream is = new URL(errorCodesUrl).openStream()) { //TODO: HttpClient(){ async request
|
||||
|
||||
JsonObject jsonObject = (JsonObject)new JsonParser().parse(new InputStreamReader(is,"UTF-8"));
|
||||
|
||||
LOG.debug("jpkED - jsonObject | "+jsonObject.toString());
|
||||
|
||||
Set<String> keys = jsonObject.keySet();
|
||||
errorDiscussionList = new ArrayList<>();
|
||||
for (int i = 0; i < jsonObject.size(); i++) {
|
||||
errorDiscussionList.add(new Gson().fromJson(jsonObject.get(keys.stream().toList().get(i)),ErrorDiscussion.class));
|
||||
}
|
||||
LOG.debug("jpkED - errorDiscussionList loaded | amount:"+errorDiscussionList.size()+"");
|
||||
} catch (MalformedURLException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -2,27 +2,11 @@ package org.cryptomator.ui.error;
|
||||
|
||||
public class ErrorDiscussion {
|
||||
|
||||
String id;
|
||||
int upvoteCount;
|
||||
String title;
|
||||
String url;
|
||||
int comments;
|
||||
Answer answer;
|
||||
|
||||
String getUpvoteCount(){return upvoteCount+"";}
|
||||
|
||||
String getErrorCode(){return title.substring(6);}
|
||||
String getMethodCode(){
|
||||
return title.substring(6,10);
|
||||
}
|
||||
String getRootCauseCode(){
|
||||
return title.substring(11,15);
|
||||
}
|
||||
|
||||
String getThrowableCode(){
|
||||
return title.substring(16,20);
|
||||
}
|
||||
|
||||
class Answer{
|
||||
private String url;
|
||||
private int upvoteCount;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
|
||||
<?import org.cryptomator.ui.controls.FontAwesome5Spinner?>
|
||||
<?import org.cryptomator.ui.controls.FormattedLabel?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
@@ -31,26 +32,28 @@
|
||||
</StackPane>
|
||||
<VBox spacing="6" HBox.hgrow="ALWAYS">
|
||||
<FormattedLabel styleClass="label-extra-large" format="%error.message" arg1="${controller.errorCode}"/>
|
||||
<Label text="%error.existingSolutionDescription" wrapText="true" visible="${controller.lookUpSolutionVisibility}" managed="${controller.lookUpSolutionVisibility}"/>
|
||||
<Label text="%error.description" wrapText="true" visible="${!controller.lookUpSolutionVisibility}" managed="${!controller.lookUpSolutionVisibility}"/>
|
||||
<Hyperlink styleClass="hyperlink-underline" text="%error.hyperlink.solution" onAction="#showSolution" contentDisplay="LEFT" visible="${controller.lookUpSolutionVisibility}" managed="${controller.lookUpSolutionVisibility}">
|
||||
<graphic>
|
||||
<FontAwesome5IconView glyph="LINK" glyphSize="12"/>
|
||||
</graphic>
|
||||
</Hyperlink>
|
||||
<Hyperlink styleClass="hyperlink-underline" text="%error.hyperlink.lookup" onAction="#searchError" contentDisplay="LEFT" visible="${!controller.lookUpSolutionVisibility}" managed="${!controller.lookUpSolutionVisibility}">
|
||||
<graphic>
|
||||
<FontAwesome5IconView glyph="LINK" glyphSize="12"/>
|
||||
</graphic>
|
||||
</Hyperlink>
|
||||
<Hyperlink styleClass="hyperlink-underline" text="%error.hyperlink.report" onAction="#reportError" contentDisplay="LEFT" visible="${!controller.lookUpSolutionVisibility}" managed="${!controller.lookUpSolutionVisibility}">
|
||||
<graphic>
|
||||
<FontAwesome5IconView glyph="LINK" glyphSize="12"/>
|
||||
</graphic>
|
||||
</Hyperlink>
|
||||
<FontAwesome5Spinner glyphSize="24" visible="${controller.isLoadingHttpResponse}" managed="${controller.isLoadingHttpResponse}"/>
|
||||
<VBox visible="${!controller.isLoadingHttpResponse}" managed="${!controller.isLoadingHttpResponse}">
|
||||
<Label text="%error.existingSolutionDescription" wrapText="true" visible="${controller.lookUpSolutionVisibility}" managed="${controller.lookUpSolutionVisibility}"/>
|
||||
<Hyperlink styleClass="hyperlink-underline" text="%error.hyperlink.solution" onAction="#showSolution" contentDisplay="LEFT" visible="${controller.lookUpSolutionVisibility}" managed="${controller.lookUpSolutionVisibility}">
|
||||
<graphic>
|
||||
<FontAwesome5IconView glyph="LINK" glyphSize="12"/>
|
||||
</graphic>
|
||||
</Hyperlink>
|
||||
<Label text="%error.description" wrapText="true" visible="${!controller.lookUpSolutionVisibility}" managed="${!controller.lookUpSolutionVisibility}"/>
|
||||
<Hyperlink styleClass="hyperlink-underline" text="%error.hyperlink.lookup" onAction="#searchError" contentDisplay="LEFT" visible="${!controller.lookUpSolutionVisibility}" managed="${!controller.lookUpSolutionVisibility}">
|
||||
<graphic>
|
||||
<FontAwesome5IconView glyph="LINK" glyphSize="12"/>
|
||||
</graphic>
|
||||
</Hyperlink>
|
||||
<Hyperlink styleClass="hyperlink-underline" text="%error.hyperlink.report" onAction="#reportError" contentDisplay="LEFT" visible="${!controller.lookUpSolutionVisibility}" managed="${!controller.lookUpSolutionVisibility}">
|
||||
<graphic>
|
||||
<FontAwesome5IconView glyph="LINK" glyphSize="12"/>
|
||||
</graphic>
|
||||
</Hyperlink>
|
||||
</VBox>
|
||||
</VBox>
|
||||
</HBox>
|
||||
|
||||
<VBox spacing="6" VBox.vgrow="ALWAYS">
|
||||
<HBox>
|
||||
<Label text="%error.technicalDetails"/>
|
||||
@@ -66,7 +69,7 @@
|
||||
</graphic>
|
||||
</Hyperlink>
|
||||
</HBox>
|
||||
<TextArea VBox.vgrow="ALWAYS" text="${controller.detailTexts}" prefRowCount="5" editable="false"/>
|
||||
<TextArea VBox.vgrow="ALWAYS" text="${controller.detailText}" prefRowCount="5" editable="false"/>
|
||||
</VBox>
|
||||
|
||||
<ButtonBar buttonMinWidth="120" buttonOrder="B+C">
|
||||
|
||||
Reference in New Issue
Block a user