Index: frontend/client/src/autotest/planner/triage/FailureTable.java |
diff --git a/frontend/client/src/autotest/planner/triage/FailureTable.java b/frontend/client/src/autotest/planner/triage/FailureTable.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..683a138c6135a5dfd19cae96daf186314dd26d14 |
--- /dev/null |
+++ b/frontend/client/src/autotest/planner/triage/FailureTable.java |
@@ -0,0 +1,187 @@ |
+package autotest.planner.triage; |
+ |
+import autotest.common.spreadsheet.Spreadsheet; |
+import autotest.common.spreadsheet.Spreadsheet.CellInfo; |
+import autotest.common.spreadsheet.Spreadsheet.Header; |
+import autotest.common.spreadsheet.Spreadsheet.HeaderImpl; |
+import autotest.common.spreadsheet.Spreadsheet.SpreadsheetListener; |
+import autotest.common.ui.NotifyManager; |
+ |
+import com.google.gwt.json.client.JSONObject; |
+import com.google.gwt.user.client.IncrementalCommand; |
+ |
+import java.util.ArrayList; |
+import java.util.Collections; |
+import java.util.Iterator; |
+import java.util.LinkedList; |
+import java.util.List; |
+ |
+class FailureTable implements SpreadsheetListener, TriagePopup.Listener { |
+ |
+ public interface Display { |
+ public Spreadsheet getSpreadsheet(); |
+ public TriagePopup.Display generateTriagePopupDisplay(); |
+ } |
+ |
+ private static class Failure { |
+ int id; |
+ String machine; |
+ boolean blocked; |
+ String testName; |
+ String reason; |
+ boolean seen; |
+ |
+ private Failure(int id, String machine, boolean blocked, |
+ String testName, String reason, boolean seen) { |
+ this.id = id; |
+ this.machine = machine; |
+ this.blocked = blocked; |
+ this.testName = testName; |
+ this.reason = reason; |
+ this.seen = seen; |
+ } |
+ |
+ public static Failure fromJsonObject(JSONObject failureObj) { |
+ return new Failure((int) failureObj.get("id").isNumber().doubleValue(), |
+ failureObj.get("machine").isString().stringValue(), |
+ failureObj.get("blocked").isBoolean().booleanValue(), |
+ failureObj.get("test_name").isString().stringValue(), |
+ failureObj.get("reason").isString().stringValue(), |
+ failureObj.get("seen").isBoolean().booleanValue()); |
+ } |
+ } |
+ |
+ private Display display; |
+ private String group; |
+ private LinkedList<Failure> failures = new LinkedList<Failure>(); |
+ private boolean rendered; |
+ |
+ public FailureTable(String group) { |
+ this.group = group; |
+ } |
+ |
+ public void bindDisplay(Display display) { |
+ this.display = display; |
+ display.getSpreadsheet().setListener(this); |
+ } |
+ |
+ public void addFailure(JSONObject failureObj) { |
+ setRendered(false); |
+ |
+ Failure failure = Failure.fromJsonObject(failureObj); |
+ |
+ if (failure.seen) { |
+ failures.addLast(failure); |
+ } else { |
+ failures.addFirst(failure); |
+ } |
+ } |
+ |
+ public Display getDisplay() { |
+ if (!rendered) { |
+ renderDisplay(); |
+ } |
+ |
+ return display; |
+ } |
+ |
+ private void setRendered(boolean rendered) { |
+ this.rendered = rendered; |
+ display.getSpreadsheet().setVisible(rendered); |
+ } |
+ |
+ public void renderDisplay() { |
+ Spreadsheet spreadsheet = display.getSpreadsheet(); |
+ spreadsheet.clear(); |
+ |
+ Header rowFields = HeaderImpl.fromBaseType(Collections.singletonList("machine")); |
+ Header columnFields = new HeaderImpl(); |
+ columnFields.add("group"); |
+ columnFields.add("failure"); |
+ spreadsheet.setHeaderFields(rowFields, columnFields); |
+ |
+ for (int i = 0; i < failures.size(); i++) { |
+ Failure failure = failures.get(i); |
+ String machine = (i+1) + ": " + failure.machine; |
+ if (failure.blocked) { |
+ machine += " (blocked)"; |
+ } |
+ spreadsheet.addRowHeader(Collections.singletonList(machine)); |
+ } |
+ spreadsheet.addColumnHeader(createHeaderGroup("Test")); |
+ spreadsheet.addColumnHeader(createHeaderGroup("Reason")); |
+ |
+ spreadsheet.prepareForData(); |
+ |
+ for (int row = 0; row < failures.size(); row++) { |
+ CellInfo test = spreadsheet.getCellInfo(row, 0); |
+ CellInfo reason = spreadsheet.getCellInfo(row, 1); |
+ Failure failure = failures.get(row); |
+ |
+ test.contents = failure.testName; |
+ reason.contents = failure.reason; |
+ test.testIndex = failure.id; |
+ reason.testIndex = failure.id; |
+ |
+ if (!failure.seen) { |
+ test.contents = "<b>" + test.contents + "</b>"; |
+ reason.contents = "<b>" + reason.contents + "</b>"; |
+ } |
+ } |
+ |
+ spreadsheet.setVisible(true); |
+ |
+ spreadsheet.render(new IncrementalCommand() { |
+ @Override |
+ public boolean execute() { |
+ setRendered(true); |
+ return false; |
+ } |
+ }); |
+ } |
+ |
+ private List<String> createHeaderGroup(String label) { |
+ List<String> header = new ArrayList<String>(); |
+ header.add(group); |
+ header.add(label); |
+ return header; |
+ } |
+ |
+ @Override |
+ public void onCellClicked(CellInfo cellInfo, boolean isRightClick) { |
+ if (cellInfo.testIndex == 0) { |
+ return; |
+ } |
+ |
+ TriagePopup popup = new TriagePopup(this, cellInfo.testIndex); |
+ popup.bindDisplay(display.generateTriagePopupDisplay()); |
+ popup.render(); |
+ } |
+ |
+ @Override |
+ public void onTriage(TriagePopup source) { |
+ if (removeFailure(source.getId())) { |
+ renderDisplay(); |
+ } |
+ } |
+ |
+ private boolean removeFailure(int id) { |
+ setRendered(false); |
+ |
+ Iterator<Failure> iter = failures.iterator(); |
+ while (iter.hasNext()) { |
+ if (iter.next().id == id) { |
+ iter.remove(); |
+ return true; |
+ } |
+ } |
+ |
+ /* |
+ * TODO: throw an Exception instead, and register a handler with |
+ * GWT.setUncaughtExceptionHandler() |
+ */ |
+ NotifyManager.getInstance().showError("Did not find failure id " + id); |
+ setRendered(true); |
+ return false; |
+ } |
+} |