From b47b0aa2b905c3dd5c4c26fe022bf43cd12292e4 Mon Sep 17 00:00:00 2001 From: chimp1984 Date: Fri, 13 Dec 2019 21:48:26 -0500 Subject: [PATCH 1/2] Add report feature for disputes At the dispute views (mediator, refund agent both for trader and dispute agents) the shortcut cmd+k (or crtl+k or alt+k) will open a popup displaying all disputes as compact summary. A copy to clipboard button make it easy to copy the text to a text editor and post the relevant disputes for the mediators/refund agents report. --- .../main/support/dispute/DisputeView.java | 212 +++++++++++++----- 1 file changed, 150 insertions(+), 62 deletions(-) diff --git a/desktop/src/main/java/bisq/desktop/main/support/dispute/DisputeView.java b/desktop/src/main/java/bisq/desktop/main/support/dispute/DisputeView.java index d2b889c7a6d..f04e2b5436e 100644 --- a/desktop/src/main/java/bisq/desktop/main/support/dispute/DisputeView.java +++ b/desktop/src/main/java/bisq/desktop/main/support/dispute/DisputeView.java @@ -18,7 +18,6 @@ package bisq.desktop.main.support.dispute; import bisq.desktop.common.view.ActivatableView; -import bisq.desktop.common.view.FxmlView; import bisq.desktop.components.AutoTooltipButton; import bisq.desktop.components.AutoTooltipLabel; import bisq.desktop.components.AutoTooltipTableColumn; @@ -41,6 +40,7 @@ import bisq.core.support.dispute.Dispute; import bisq.core.support.dispute.DisputeList; import bisq.core.support.dispute.DisputeManager; +import bisq.core.support.dispute.DisputeResult; import bisq.core.support.dispute.DisputeSession; import bisq.core.trade.Contract; import bisq.core.trade.Trade; @@ -96,6 +96,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.concurrent.atomic.AtomicInteger; import lombok.Getter; @@ -224,67 +225,9 @@ public void initialize() { keyEventEventHandler = event -> { if (Utilities.isAltOrCtrlPressed(KeyCode.L, event)) { - Map> map = new HashMap<>(); - disputeManager.getDisputesAsObservableList().forEach(dispute -> { - String tradeId = dispute.getTradeId(); - List list; - if (!map.containsKey(tradeId)) - map.put(tradeId, new ArrayList<>()); - - list = map.get(tradeId); - list.add(dispute); - }); - List> disputeGroups = new ArrayList<>(); - map.forEach((key, value) -> disputeGroups.add(value)); - disputeGroups.sort(Comparator.comparing(o -> !o.isEmpty() ? o.get(0).getOpeningDate() : new Date(0))); - StringBuilder stringBuilder = new StringBuilder(); - - // We don't translate that as it is not intended for the public - stringBuilder.append("Summary of all disputes (No. of disputes: ").append(disputeGroups.size()).append(")\n\n"); - disputeGroups.forEach(disputeGroup -> { - Dispute dispute0 = disputeGroup.get(0); - stringBuilder.append("##########################################################################################/\n") - .append("## Trade ID: ") - .append(dispute0.getTradeId()) - .append("\n") - .append("## Date: ") - .append(DisplayUtils.formatDateTime(dispute0.getOpeningDate())) - .append("\n") - .append("## Is support ticket: ") - .append(dispute0.isSupportTicket()) - .append("\n"); - if (dispute0.disputeResultProperty().get() != null && dispute0.disputeResultProperty().get().getReason() != null) { - stringBuilder.append("## Reason: ") - .append(dispute0.disputeResultProperty().get().getReason()) - .append("\n"); - } - stringBuilder.append("##########################################################################################/\n") - .append("\n"); - disputeGroup.forEach(dispute -> { - stringBuilder - .append("*******************************************************************************************\n") - .append("** Trader's ID: ") - .append(dispute.getTraderId()) - .append("\n*******************************************************************************************\n") - .append("\n"); - dispute.getChatMessages().forEach(m -> { - String role = m.isSenderIsTrader() ? ">> Trader's msg: " : "<< Arbitrator's msg: "; - stringBuilder.append(role) - .append(m.getMessage()) - .append("\n"); - }); - stringBuilder.append("\n"); - }); - stringBuilder.append("\n"); - }); - String message = stringBuilder.toString(); - // We don't translate that as it is not intended for the public - new Popup().headLine("All disputes (" + disputeGroups.size() + ")") - .information(message) - .width(1000) - .actionButtonText("Copy") - .onAction(() -> Utilities.copyToClipboard(message)) - .show(); + showFullReport(); + } else if (Utilities.isAltOrCtrlPressed(KeyCode.K, event)) { + showCompactReport(); } else if (Utilities.isAltOrCtrlPressed(KeyCode.U, event)) { // Hidden shortcut to re-open a dispute. Allow it also for traders not only arbitrator. if (selectedDispute != null) { @@ -317,6 +260,151 @@ public void initialize() { chatView.initialize(); } + private void showCompactReport() { + Map> map = new HashMap<>(); + Map> disputesByReason = new HashMap<>(); + disputeManager.getDisputesAsObservableList().forEach(dispute -> { + String tradeId = dispute.getTradeId(); + List list; + if (!map.containsKey(tradeId)) + map.put(tradeId, new ArrayList<>()); + + list = map.get(tradeId); + list.add(dispute); + }); + + List> disputeGroups = new ArrayList<>(); + map.forEach((key, value) -> disputeGroups.add(value)); + disputeGroups.sort(Comparator.comparing(o -> !o.isEmpty() ? o.get(0).getOpeningDate() : new Date(0))); + StringBuilder stringBuilder = new StringBuilder(); + AtomicInteger disputeIndex = new AtomicInteger(); + disputeGroups.forEach(disputeGroup -> { + if (disputeGroup.size() > 0) { + Dispute dispute0 = disputeGroup.get(0); + stringBuilder.append("\n") + .append("Dispute nr. ") + .append(disputeIndex.incrementAndGet()) + .append("\n") + .append("Opening date: ") + .append(DisplayUtils.formatDateTime(dispute0.getOpeningDate())) + .append("\n"); + + DisputeResult disputeResult0 = dispute0.getDisputeResultProperty().get(); + String summaryNotes0 = ""; + if (disputeResult0 != null) { + stringBuilder.append("Close date: ") + .append(DisplayUtils.formatDateTime(disputeResult0.getCloseDate())) + .append("\n"); + + summaryNotes0 = disputeResult0.getSummaryNotesProperty().get(); + stringBuilder.append("Summary notes: ").append(summaryNotes0).append("\n"); + } + + // We might have a different summary notes at second trader. Only if it + // is different we show it. + if (disputeGroup.size() > 1) { + Dispute dispute1 = disputeGroup.get(1); + DisputeResult disputeResult1 = dispute1.getDisputeResultProperty().get(); + if (disputeResult1 != null) { + String summaryNotes1 = disputeResult1.getSummaryNotesProperty().get(); + if (!summaryNotes1.equals(summaryNotes0)) { + stringBuilder.append("Summary notes (trader 2): ").append(summaryNotes1).append("\n"); + } + } + } + + if (dispute0.disputeResultProperty().get() != null) { + DisputeResult.Reason reason = dispute0.disputeResultProperty().get().getReason(); + if (dispute0.disputeResultProperty().get().getReason() != null) { + disputesByReason.putIfAbsent(reason.name(), new ArrayList<>()); + disputesByReason.get(reason.name()).add(dispute0); + stringBuilder.append("Reason: ") + .append(reason.name()) + .append("\n"); + } + } + } + }); + stringBuilder.append("\n").append("Summary of reasons for disputes: ").append("\n"); + disputesByReason.forEach((k, v) -> { + stringBuilder.append(k).append(": ").append(v.size()).append("\n"); + }); + + + String message = stringBuilder.toString(); + new Popup().headLine("Compact summary of all disputes (" + disputeGroups.size() + ")") + .information(message) + .width(1000) + .actionButtonText("Copy to clipboard") + .onAction(() -> Utilities.copyToClipboard(message)) + .show(); + + } + + private void showFullReport() { + Map> map = new HashMap<>(); + disputeManager.getDisputesAsObservableList().forEach(dispute -> { + String tradeId = dispute.getTradeId(); + List list; + if (!map.containsKey(tradeId)) + map.put(tradeId, new ArrayList<>()); + + list = map.get(tradeId); + list.add(dispute); + }); + List> disputeGroups = new ArrayList<>(); + map.forEach((key, value) -> disputeGroups.add(value)); + disputeGroups.sort(Comparator.comparing(o -> !o.isEmpty() ? o.get(0).getOpeningDate() : new Date(0))); + StringBuilder stringBuilder = new StringBuilder(); + + // We don't translate that as it is not intended for the public + stringBuilder.append("Summary of all disputes (No. of disputes: ").append(disputeGroups.size()).append(")\n\n"); + disputeGroups.forEach(disputeGroup -> { + Dispute dispute0 = disputeGroup.get(0); + stringBuilder.append("##########################################################################################/\n") + .append("## Trade ID: ") + .append(dispute0.getTradeId()) + .append("\n") + .append("## Date: ") + .append(DisplayUtils.formatDateTime(dispute0.getOpeningDate())) + .append("\n") + .append("## Is support ticket: ") + .append(dispute0.isSupportTicket()) + .append("\n"); + if (dispute0.disputeResultProperty().get() != null && dispute0.disputeResultProperty().get().getReason() != null) { + stringBuilder.append("## Reason: ") + .append(dispute0.disputeResultProperty().get().getReason()) + .append("\n"); + } + stringBuilder.append("##########################################################################################/\n") + .append("\n"); + disputeGroup.forEach(dispute -> { + stringBuilder + .append("*******************************************************************************************\n") + .append("** Trader's ID: ") + .append(dispute.getTraderId()) + .append("\n*******************************************************************************************\n") + .append("\n"); + dispute.getChatMessages().forEach(m -> { + String role = m.isSenderIsTrader() ? ">> Trader's msg: " : "<< Arbitrator's msg: "; + stringBuilder.append(role) + .append(m.getMessage()) + .append("\n"); + }); + stringBuilder.append("\n"); + }); + stringBuilder.append("\n"); + }); + String message = stringBuilder.toString(); + // We don't translate that as it is not intended for the public + new Popup().headLine("All disputes (" + disputeGroups.size() + ")") + .information(message) + .width(1000) + .actionButtonText("Copy") + .onAction(() -> Utilities.copyToClipboard(message)) + .show(); + } + @Override protected void activate() { filterTextField.textProperty().addListener(filterTextFieldListener); From 7af7fa10a63f15f26701068288e3d14236f060d8 Mon Sep 17 00:00:00 2001 From: chimp1984 Date: Fri, 13 Dec 2019 22:06:21 -0500 Subject: [PATCH 2/2] Add duration --- .../main/support/dispute/DisputeView.java | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/desktop/src/main/java/bisq/desktop/main/support/dispute/DisputeView.java b/desktop/src/main/java/bisq/desktop/main/support/dispute/DisputeView.java index f04e2b5436e..4aa53c620cd 100644 --- a/desktop/src/main/java/bisq/desktop/main/support/dispute/DisputeView.java +++ b/desktop/src/main/java/bisq/desktop/main/support/dispute/DisputeView.java @@ -45,6 +45,7 @@ import bisq.core.trade.Contract; import bisq.core.trade.Trade; import bisq.core.trade.TradeManager; +import bisq.core.util.FormattingUtils; import bisq.core.util.coin.CoinFormatter; import bisq.network.p2p.NodeAddress; @@ -281,19 +282,24 @@ private void showCompactReport() { disputeGroups.forEach(disputeGroup -> { if (disputeGroup.size() > 0) { Dispute dispute0 = disputeGroup.get(0); + Date openingDate = dispute0.getOpeningDate(); stringBuilder.append("\n") .append("Dispute nr. ") .append(disputeIndex.incrementAndGet()) .append("\n") .append("Opening date: ") - .append(DisplayUtils.formatDateTime(dispute0.getOpeningDate())) + .append(DisplayUtils.formatDateTime(openingDate)) .append("\n"); - DisputeResult disputeResult0 = dispute0.getDisputeResultProperty().get(); String summaryNotes0 = ""; if (disputeResult0 != null) { + Date closeDate = disputeResult0.getCloseDate(); + long duration = closeDate.getTime() - openingDate.getTime(); stringBuilder.append("Close date: ") - .append(DisplayUtils.formatDateTime(disputeResult0.getCloseDate())) + .append(DisplayUtils.formatDateTime(closeDate)) + .append("\n") + .append("Duration: ") + .append(FormattingUtils.formatDurationAsWords(duration)) .append("\n"); summaryNotes0 = disputeResult0.getSummaryNotesProperty().get(); @@ -330,11 +336,11 @@ private void showCompactReport() { stringBuilder.append(k).append(": ").append(v.size()).append("\n"); }); - String message = stringBuilder.toString(); new Popup().headLine("Compact summary of all disputes (" + disputeGroups.size() + ")") + .maxMessageLength(500) .information(message) - .width(1000) + .width(1200) .actionButtonText("Copy to clipboard") .onAction(() -> Utilities.copyToClipboard(message)) .show(); @@ -398,8 +404,9 @@ private void showFullReport() { String message = stringBuilder.toString(); // We don't translate that as it is not intended for the public new Popup().headLine("All disputes (" + disputeGroups.size() + ")") + .maxMessageLength(1000) .information(message) - .width(1000) + .width(1200) .actionButtonText("Copy") .onAction(() -> Utilities.copyToClipboard(message)) .show();