• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package autotest.tko;
2 
3 import autotest.common.StatusSummary;
4 import autotest.common.Utils;
5 import autotest.common.CustomHistory.HistoryToken;
6 import autotest.common.table.DataTable;
7 import autotest.common.table.DynamicTable;
8 import autotest.common.table.RpcDataSource;
9 import autotest.common.table.SelectionManager;
10 import autotest.common.table.SimpleFilter;
11 import autotest.common.table.TableDecorator;
12 import autotest.common.table.DataSource.SortDirection;
13 import autotest.common.table.DataSource.SortSpec;
14 import autotest.common.table.DataTable.TableWidgetFactory;
15 import autotest.common.table.DynamicTable.DynamicTableListener;
16 import autotest.common.ui.ContextMenu;
17 import autotest.common.ui.DoubleListSelector;
18 import autotest.common.ui.MultiListSelectPresenter;
19 import autotest.common.ui.NotifyManager;
20 import autotest.common.ui.MultiListSelectPresenter.Item;
21 import autotest.common.ui.TableActionsPanel.TableActionsWithExportCsvListener;
22 import autotest.tko.CommonPanel.CommonPanelListener;
23 
24 import com.google.gwt.event.dom.client.ClickEvent;
25 import com.google.gwt.event.dom.client.ClickHandler;
26 import com.google.gwt.json.client.JSONArray;
27 import com.google.gwt.json.client.JSONObject;
28 import com.google.gwt.user.client.Command;
29 import com.google.gwt.user.client.Event;
30 import com.google.gwt.user.client.History;
31 import com.google.gwt.user.client.ui.Button;
32 import com.google.gwt.user.client.ui.CheckBox;
33 import com.google.gwt.user.client.ui.HTML;
34 import com.google.gwt.user.client.ui.Panel;
35 import com.google.gwt.user.client.ui.SimplePanel;
36 import com.google.gwt.user.client.ui.VerticalPanel;
37 import com.google.gwt.user.client.ui.Widget;
38 
39 import java.util.ArrayList;
40 import java.util.Arrays;
41 import java.util.Collection;
42 import java.util.Iterator;
43 import java.util.List;
44 import java.util.ListIterator;
45 import java.util.Map;
46 
47 public class TableView extends ConditionTabView
48                        implements DynamicTableListener, TableActionsWithExportCsvListener,
49                                   ClickHandler, TableWidgetFactory, CommonPanelListener,
50                                   MultiListSelectPresenter.GeneratorHandler {
51     private static final int ROWS_PER_PAGE = 30;
52     private static final String COUNT_NAME = "Count in group";
53     private static final String STATUS_COUNTS_NAME = "Test pass rate";
54     private static final String[] DEFAULT_COLUMNS =
55         {"Test index", "Test name", "Job tag", "Hostname", "Status"};
56     private static final String[] TRIAGE_GROUP_COLUMNS =
57         {"Test name", "Status", COUNT_NAME, "Reason"};
58     private static final String[] PASS_RATE_GROUP_COLUMNS =
59         {"Hostname", STATUS_COUNTS_NAME};
60     private static final SortSpec[] TRIAGE_SORT_SPECS = {
61         new SortSpec("test_name", SortDirection.ASCENDING),
62         new SortSpec("status", SortDirection.ASCENDING),
63         new SortSpec("reason", SortDirection.ASCENDING),
64     };
65 
66     private static enum GroupingType {NO_GROUPING, TEST_GROUPING, STATUS_COUNTS}
67 
68     /**
69      * HeaderField representing a grouped count of some kind.
70      */
71     private static class GroupCountField extends HeaderField {
GroupCountField(String name, String sqlName)72         public GroupCountField(String name, String sqlName) {
73             super(name, sqlName);
74         }
75 
76         @Override
getItem()77         public Item getItem() {
78             return Item.createGeneratedItem(getName(), getSqlName());
79         }
80 
81         @Override
getSqlCondition(String value)82         public String getSqlCondition(String value) {
83             throw new UnsupportedOperationException();
84         }
85 
86         @Override
isUserSelectable()87         public boolean isUserSelectable() {
88             return false;
89         }
90     }
91 
92     private GroupCountField groupCountField =
93         new GroupCountField(COUNT_NAME, TestGroupDataSource.GROUP_COUNT_FIELD);
94     private GroupCountField statusCountsField =
95         new GroupCountField(STATUS_COUNTS_NAME, DataTable.WIDGET_COLUMN);
96 
97     private TestSelectionListener listener;
98 
99     private DynamicTable table;
100     private TableDecorator tableDecorator;
101     private SelectionManager selectionManager;
102     private SimpleFilter sqlConditionFilter = new SimpleFilter();
103     private RpcDataSource testDataSource = new TestViewDataSource();
104     private TestGroupDataSource groupDataSource = TestGroupDataSource.getTestGroupDataSource();
105 
106     private HeaderFieldCollection headerFields = commonPanel.getHeaderFields();
107     private HeaderSelect columnSelect = new HeaderSelect(headerFields, new HeaderSelect.State());
108 
109     private DoubleListSelector columnSelectDisplay = new DoubleListSelector();
110     private CheckBox groupCheckbox = new CheckBox("Group by these columns and show counts");
111     private CheckBox statusGroupCheckbox =
112         new CheckBox("Group by these columns and show pass rates");
113     private Button queryButton = new Button("Query");
114     private Panel tablePanel = new SimplePanel();
115 
116     private List<SortSpec> tableSorts = new ArrayList<SortSpec>();
117 
118     public enum TableViewConfig {
119         DEFAULT, PASS_RATE, TRIAGE
120     }
121 
122     public static interface TableSwitchListener extends TestSelectionListener {
onSwitchToTable(TableViewConfig config)123         public void onSwitchToTable(TableViewConfig config);
124     }
125 
TableView(TestSelectionListener listener)126     public TableView(TestSelectionListener listener) {
127         this.listener = listener;
128         commonPanel.addListener(this);
129         columnSelect.setGeneratorHandler(this);
130         columnSelect.bindDisplay(columnSelectDisplay);
131     }
132 
133     @Override
getElementId()134     public String getElementId() {
135         return "table_view";
136     }
137 
138     @Override
initialize()139     public void initialize() {
140         super.initialize();
141 
142         headerFields.add(groupCountField);
143         headerFields.add(statusCountsField);
144 
145         selectColumnsByName(DEFAULT_COLUMNS);
146         updateViewFromState();
147 
148         queryButton.addClickHandler(this);
149         groupCheckbox.addClickHandler(this);
150         statusGroupCheckbox.addClickHandler(this);
151 
152         Panel columnPanel = new VerticalPanel();
153         columnPanel.add(columnSelectDisplay);
154         columnPanel.add(groupCheckbox);
155         columnPanel.add(statusGroupCheckbox);
156 
157         addWidget(columnPanel, "table_column_select");
158         addWidget(queryButton, "table_query_controls");
159         addWidget(tablePanel, "table_table");
160     }
161 
selectColumnsByName(String[] columnNames)162     private void selectColumnsByName(String[] columnNames) {
163         List<HeaderField> fields = new ArrayList<HeaderField>();
164         for (String name : columnNames) {
165             fields.add(headerFields.getFieldByName(name));
166         }
167         columnSelect.setSelectedItems(fields);
168         cleanupSortsForNewColumns();
169     }
170 
setupDefaultView()171     public void setupDefaultView() {
172         tableSorts.clear();
173         selectColumnsByName(DEFAULT_COLUMNS);
174         updateViewFromState();
175     }
176 
setupJobTriage()177     public void setupJobTriage() {
178         selectColumnsByName(TRIAGE_GROUP_COLUMNS);
179         // need to copy it so we can mutate it
180         tableSorts = new ArrayList<SortSpec>(Arrays.asList(TRIAGE_SORT_SPECS));
181         updateViewFromState();
182     }
183 
setupPassRate()184     public void setupPassRate() {
185         tableSorts.clear();
186         selectColumnsByName(PASS_RATE_GROUP_COLUMNS);
187         updateViewFromState();
188     }
189 
createTable()190     private void createTable() {
191         String[][] columns = buildColumnSpecs();
192 
193         table = new DynamicTable(columns, getDataSource());
194         table.addFilter(sqlConditionFilter);
195         table.setRowsPerPage(ROWS_PER_PAGE);
196         table.makeClientSortable();
197         table.setClickable(true);
198         table.sinkRightClickEvents();
199         table.addListener(this);
200         table.setWidgetFactory(this);
201         restoreTableSorting();
202 
203         tableDecorator = new TableDecorator(table);
204         tableDecorator.addPaginators();
205         selectionManager = tableDecorator.addSelectionManager(false);
206         tableDecorator.addTableActionsWithExportCsvListener(this);
207         tablePanel.clear();
208         tablePanel.add(tableDecorator);
209 
210         selectionManager = new SelectionManager(table, false);
211     }
212 
buildColumnSpecs()213     private String[][] buildColumnSpecs() {
214         int numColumns = savedColumns().size();
215         String[][] columns = new String[numColumns][2];
216         int i = 0;
217         for (HeaderField field : savedColumns()) {
218             columns[i][0] = field.getSqlName();
219             columns[i][1] = field.getName();
220             i++;
221         }
222         return columns;
223     }
224 
savedColumns()225     private List<HeaderField> savedColumns() {
226         return columnSelect.getSelectedItems();
227     }
228 
getDataSource()229     private RpcDataSource getDataSource() {
230         GroupingType groupingType = getActiveGrouping();
231         if (groupingType == GroupingType.NO_GROUPING) {
232             return testDataSource;
233         } else if (groupingType == GroupingType.TEST_GROUPING) {
234             groupDataSource = TestGroupDataSource.getTestGroupDataSource();
235         } else {
236             groupDataSource = TestGroupDataSource.getStatusCountDataSource();
237         }
238 
239         updateGroupColumns();
240         return groupDataSource;
241     }
242 
updateStateFromView()243     private void updateStateFromView() {
244         commonPanel.updateStateFromView();
245         columnSelect.updateStateFromView();
246     }
247 
updateViewFromState()248     private void updateViewFromState() {
249         commonPanel.updateViewFromState();
250         columnSelect.updateViewFromState();
251     }
252 
updateGroupColumns()253     private void updateGroupColumns() {
254         List<String> groupFields = new ArrayList<String>();
255         for (HeaderField field : savedColumns()) {
256             if (!isGroupField(field)) {
257                 groupFields.add(field.getSqlName());
258             }
259         }
260 
261         groupDataSource.setGroupColumns(groupFields.toArray(new String[0]));
262     }
263 
isGroupField(HeaderField field)264     private boolean isGroupField(HeaderField field) {
265         return field instanceof GroupCountField;
266     }
267 
saveTableSorting()268     private void saveTableSorting() {
269         if (table != null) {
270             // we need our own copy so we can modify it later
271             tableSorts = new ArrayList<SortSpec>(table.getSortSpecs());
272         }
273     }
274 
restoreTableSorting()275     private void restoreTableSorting() {
276         for (ListIterator<SortSpec> i = tableSorts.listIterator(tableSorts.size());
277              i.hasPrevious();) {
278             SortSpec sortSpec = i.previous();
279             table.sortOnColumn(sortSpec.getField(), sortSpec.getDirection());
280         }
281     }
282 
cleanupSortsForNewColumns()283     private void cleanupSortsForNewColumns() {
284         // remove sorts on columns that we no longer have
285         for (Iterator<SortSpec> i = tableSorts.iterator(); i.hasNext();) {
286             String attribute = i.next().getField();
287             if (!isAttributeSelected(attribute)) {
288                 i.remove();
289             }
290         }
291 
292         if (tableSorts.isEmpty()) {
293             // default to sorting on the first column
294             HeaderField field = savedColumns().iterator().next();
295             SortSpec sortSpec = new SortSpec(field.getSqlName(), SortDirection.ASCENDING);
296             tableSorts = new ArrayList<SortSpec>();
297             tableSorts.add(sortSpec);
298         }
299     }
300 
isAttributeSelected(String attribute)301     private boolean isAttributeSelected(String attribute) {
302         for (HeaderField field : savedColumns()) {
303             if (field.getSqlName().equals(attribute)) {
304                 return true;
305             }
306         }
307         return false;
308     }
309 
310     @Override
refresh()311     public void refresh() {
312         createTable();
313         JSONObject condition = commonPanel.getConditionArgs();
314         sqlConditionFilter.setAllParameters(condition);
315         table.refresh();
316     }
317 
318     @Override
doQuery()319     public void doQuery() {
320         if (savedColumns().isEmpty()) {
321             NotifyManager.getInstance().showError("You must select columns");
322             return;
323         }
324         updateStateFromView();
325         refresh();
326     }
327 
328     @Override
onRowClicked(int rowIndex, JSONObject row, boolean isRightClick)329     public void onRowClicked(int rowIndex, JSONObject row, boolean isRightClick) {
330         Event event = Event.getCurrentEvent();
331         TestSet testSet = getTestSet(row);
332         if (isRightClick) {
333             if (selectionManager.getSelectedObjects().size() > 0) {
334                 testSet = getTestSet(selectionManager.getSelectedObjects());
335             }
336             ContextMenu menu = getContextMenu(testSet);
337             menu.showAtWindow(event.getClientX(), event.getClientY());
338             return;
339         }
340 
341         if (isSelectEvent(event)) {
342             selectionManager.toggleSelected(row);
343             return;
344         }
345 
346         HistoryToken historyToken;
347         if (isAnyGroupingEnabled()) {
348             historyToken = getDrilldownHistoryToken(testSet);
349         } else {
350             historyToken = listener.getSelectTestHistoryToken(testSet.getTestIndex());
351         }
352         openHistoryToken(historyToken);
353     }
354 
getContextMenu(final TestSet testSet)355     private ContextMenu getContextMenu(final TestSet testSet) {
356         TestContextMenu menu = new TestContextMenu(testSet, listener);
357 
358         if (!menu.addViewDetailsIfSingleTest() && isAnyGroupingEnabled()) {
359             menu.addItem("Drill down", new Command() {
360                 public void execute() {
361                     doDrilldown(testSet);
362                 }
363             });
364         }
365 
366         menu.addLabelItems();
367         return menu;
368     }
369 
getDrilldownHistoryToken(TestSet testSet)370     private HistoryToken getDrilldownHistoryToken(TestSet testSet) {
371         saveHistoryState();
372         commonPanel.refineCondition(testSet);
373         selectColumnsByName(DEFAULT_COLUMNS);
374         HistoryToken historyToken = getHistoryArguments();
375         restoreHistoryState();
376         return historyToken;
377     }
378 
doDrilldown(TestSet testSet)379     private void doDrilldown(TestSet testSet) {
380         History.newItem(getDrilldownHistoryToken(testSet).toString());
381     }
382 
getTestSet(JSONObject row)383     private TestSet getTestSet(JSONObject row) {
384         if (!isAnyGroupingEnabled()) {
385             return new SingleTestSet((int) row.get("test_idx").isNumber().doubleValue());
386         }
387 
388         ConditionTestSet testSet = new ConditionTestSet(commonPanel.getConditionArgs());
389         for (HeaderField field : savedColumns()) {
390             if (isGroupField(field)) {
391                 continue;
392             }
393 
394             String value = Utils.jsonToString(row.get(field.getSqlName()));
395             testSet.addCondition(field.getSqlCondition(value));
396         }
397         return testSet;
398     }
399 
getTestSet(Collection<JSONObject> selectedObjects)400     private TestSet getTestSet(Collection<JSONObject> selectedObjects) {
401         CompositeTestSet compositeSet = new CompositeTestSet();
402         for (JSONObject row : selectedObjects) {
403             compositeSet.add(getTestSet(row));
404         }
405         return compositeSet;
406     }
407 
onTableRefreshed()408     public void onTableRefreshed() {
409         selectionManager.refreshSelection();
410         saveTableSorting();
411         updateHistory();
412     }
413 
setCheckboxesEnabled()414     private void setCheckboxesEnabled() {
415         assert !(groupCheckbox.getValue() && statusGroupCheckbox.getValue());
416 
417         groupCheckbox.setEnabled(true);
418         statusGroupCheckbox.setEnabled(true);
419         if (groupCheckbox.getValue()) {
420             statusGroupCheckbox.setEnabled(false);
421         } else if (statusGroupCheckbox.getValue()) {
422             groupCheckbox.setEnabled(false);
423         }
424     }
425 
updateFieldsFromCheckboxes()426     private void updateFieldsFromCheckboxes() {
427         columnSelect.deselectItemInView(groupCountField);
428         columnSelect.deselectItemInView(statusCountsField);
429 
430         if (groupCheckbox.getValue()) {
431             columnSelect.selectItemInView(groupCountField);
432         } else if (statusGroupCheckbox.getValue()) {
433             columnSelect.selectItemInView(statusCountsField);
434         }
435     }
436 
updateCheckboxesFromFields()437     private void updateCheckboxesFromFields() {
438         groupCheckbox.setValue(false);
439         statusGroupCheckbox.setValue(false);
440 
441         GroupingType grouping = getGroupingFromFields(
442             columnSelect.getStateFromView().getSelectedFields());
443         if (grouping == GroupingType.TEST_GROUPING) {
444             groupCheckbox.setValue(true);
445         } else if (grouping == GroupingType.STATUS_COUNTS) {
446             statusGroupCheckbox.setValue(true);
447         }
448 
449         setCheckboxesEnabled();
450     }
451 
getActionMenu()452     public ContextMenu getActionMenu() {
453         TestSet tests;
454         if (selectionManager.isEmpty()) {
455             tests = getWholeTableSet();
456         } else {
457             tests = getTestSet(selectionManager.getSelectedObjects());
458         }
459         return getContextMenu(tests);
460     }
461 
getWholeTableSet()462     private ConditionTestSet getWholeTableSet() {
463         return new ConditionTestSet(commonPanel.getConditionArgs());
464     }
465 
466     @Override
getHistoryArguments()467     public HistoryToken getHistoryArguments() {
468         HistoryToken arguments = super.getHistoryArguments();
469         if (table != null) {
470             columnSelect.addHistoryArguments(arguments, "columns");
471             arguments.put("sort", Utils.joinStrings(",", tableSorts));
472             commonPanel.addHistoryArguments(arguments);
473         }
474         return arguments;
475     }
476 
477     @Override
handleHistoryArguments(Map<String, String> arguments)478     public void handleHistoryArguments(Map<String, String> arguments) {
479         super.handleHistoryArguments(arguments);
480         columnSelect.handleHistoryArguments(arguments, "columns");
481         handleSortString(arguments.get("sort"));
482         updateViewFromState();
483     }
484 
485     @Override
fillDefaultHistoryValues(Map<String, String> arguments)486     protected void fillDefaultHistoryValues(Map<String, String> arguments) {
487         HeaderField defaultSortField = headerFields.getFieldByName(DEFAULT_COLUMNS[0]);
488         Utils.setDefaultValue(arguments, "sort", defaultSortField.getSqlName());
489         Utils.setDefaultValue(arguments, "columns",
490                         Utils.joinStrings(",", Arrays.asList(DEFAULT_COLUMNS)));
491     }
492 
handleSortString(String sortString)493     private void handleSortString(String sortString) {
494         tableSorts.clear();
495         String[] components = sortString.split(",");
496         for (String component : components) {
497             tableSorts.add(SortSpec.fromString(component));
498         }
499     }
500 
onClick(ClickEvent event)501     public void onClick(ClickEvent event) {
502         if (event.getSource() == queryButton) {
503             doQueryWithCommonPanelCheck();
504             updateHistory();
505         } else if (event.getSource() == groupCheckbox || event.getSource() == statusGroupCheckbox) {
506             updateFieldsFromCheckboxes();
507             setCheckboxesEnabled();
508         }
509     }
510 
511     @Override
onRemoveGeneratedItem(Item generatedItem)512     public void onRemoveGeneratedItem(Item generatedItem) {
513         updateCheckboxesFromFields();
514     }
515 
isAnyGroupingEnabled()516     private boolean isAnyGroupingEnabled() {
517         return getActiveGrouping() != GroupingType.NO_GROUPING;
518     }
519 
getGroupingFromFields(List<HeaderField> fields)520     private GroupingType getGroupingFromFields(List<HeaderField> fields) {
521         for (HeaderField field : fields) {
522             if (field.getName().equals(COUNT_NAME)) {
523                 return GroupingType.TEST_GROUPING;
524             }
525             if (field.getName().equals(STATUS_COUNTS_NAME)) {
526                 return GroupingType.STATUS_COUNTS;
527             }
528         }
529         return GroupingType.NO_GROUPING;
530     }
531 
532     /**
533      * Get grouping currently active for displayed table.
534      */
getActiveGrouping()535     private GroupingType getActiveGrouping() {
536         return getGroupingFromFields(savedColumns());
537     }
538 
createWidget(int row, int cell, JSONObject rowObject)539     public Widget createWidget(int row, int cell, JSONObject rowObject) {
540         assert getActiveGrouping() == GroupingType.STATUS_COUNTS;
541         StatusSummary statusSummary = StatusSummary.getStatusSummary(
542             rowObject,
543             TestGroupDataSource.PASS_COUNT_FIELD,
544             TestGroupDataSource.COMPLETE_COUNT_FIELD,
545             TestGroupDataSource.INCOMPLETE_COUNT_FIELD,
546             TestGroupDataSource.GROUP_COUNT_FIELD);
547         SimplePanel panel = new SimplePanel();
548         panel.add(new HTML(statusSummary.formatContents()));
549         panel.getElement().addClassName(statusSummary.getCssClass());
550         return panel;
551     }
552 
553     @Override
hasFirstQueryOccurred()554     protected boolean hasFirstQueryOccurred() {
555         return table != null;
556     }
557 
558     @Override
onSetControlsVisible(boolean visible)559     public void onSetControlsVisible(boolean visible) {
560         TkoUtils.setElementVisible("table_all_controls", visible);
561     }
562 
563     @Override
onFieldsChanged()564     public void onFieldsChanged() {
565         columnSelect.refreshFields();
566     }
567 
onExportCsv()568     public void onExportCsv() {
569         JSONObject extraParams = new JSONObject();
570         extraParams.put("columns", buildCsvColumnSpecs());
571         TkoUtils.doCsvRequest((RpcDataSource) table.getDataSource(), table.getCurrentQuery(),
572                               extraParams);
573     }
574 
buildCsvColumnSpecs()575     private JSONArray buildCsvColumnSpecs() {
576         String[][] columnSpecs = buildColumnSpecs();
577         JSONArray jsonColumnSpecs = new JSONArray();
578         for (String[] columnSpec : columnSpecs) {
579             JSONArray jsonColumnSpec = Utils.stringsToJSON(Arrays.asList(columnSpec));
580             jsonColumnSpecs.set(jsonColumnSpecs.size(), jsonColumnSpec);
581         }
582         return jsonColumnSpecs;
583     }
584 }
585