| <!-- The <comp-page-sk> custom element declaration. |
| |
| Displays a comparison grid that allows to compare digests against each other. |
| |
| Attributes: |
| None |
| |
| Events: |
| None |
| |
| Methods: |
| pageSelected - Called by the router when view is visible. |
| |
| pageDeselected - Called by the router when the view is no longer visible. |
| |
| --> |
| |
| <link rel="import" href="bower_components/polymer/polymer.html"> |
| <link rel="import" href="bower_components/iron-flex-layout/iron-flex-layout-classes.html"> |
| <link rel="import" href="bower_components/paper-toggle-button/paper-toggle-button.html"> |
| <link rel="import" href="bower_components/iron-icons/iron-icons.html"> |
| <link rel="import" href="bower_components/iron-icons/notification-icons.html"> |
| <link rel="import" href="bower_components/paper-button/paper-button.html"> |
| <link rel="import" href="bower_components/paper-dropdown-menu/paper-dropdown-menu.html"> |
| <link rel="import" href="bower_components/paper-listbox/paper-listbox.html"> |
| <link rel="import" href="bower_components/paper-item/paper-item.html"> |
| <link rel="import" href="bower_components/paper-dialog/paper-dialog.html"> |
| |
| <link rel="import" href="../common/imp/paramset.html"> |
| |
| <link rel="import" href="digest-details-sk.html"> |
| <link rel="import" href="activity-sk.html"> |
| <link rel="import" href="grid-sk.html"> |
| <link rel="import" href="search-controls-sk.html"> |
| <link rel="import" href="select-popup-sk.html"> |
| <link rel="import" href="zoom-dialog-sk.html"> |
| <link rel="import" href="sort-control-sk.html"> |
| <link rel="import" href="shared-styles.html"> |
| |
| <dom-module id="comp-page-sk"> |
| <template> |
| <style include="iron-flex iron-flex-alignment"></style> |
| <style include="shared-styles"> |
| #heading { |
| margin: 0; |
| } |
| |
| #heading > span { |
| font-weight: bold; |
| margin-right: 1.5em; |
| vertical-align: middle; |
| } |
| |
| .headingContainer { |
| padding-bottom: 2em; |
| } |
| |
| .name { |
| color: #7570B3; |
| } |
| |
| .pos { |
| color: #1B9E77; |
| } |
| |
| .neg { |
| color: #E7298A; |
| } |
| |
| .unt { |
| color: #A6761D; |
| } |
| |
| .gridContainer { |
| margin: 0 5em 3em 2em; |
| overflow-x: auto; |
| } |
| |
| .compDiffContainer { |
| width: 50em; |
| } |
| |
| .modButtonContainer { |
| margin-bottom: 7em; |
| width: 10em; |
| } |
| |
| .diffMetricLabel { |
| font-weight: bold; |
| margin-left: 20em; |
| } |
| |
| paper-dropdown-menu.diffMetricSelect { |
| width: 8em; |
| --paper-input-container-underline: { |
| display: none; |
| }; |
| } |
| |
| .moreColumns { |
| vertical-align: middle; |
| } |
| |
| .contentWrapper { |
| padding: 0.5em; |
| } |
| |
| #columnSortControl, #rowSortControl { |
| width: 10em; |
| } |
| |
| #rowSortControl { |
| margin-top: 2em; |
| } |
| </style> |
| <activity-sk id="activityCompare" busy="{{_hideAll}}"></activity-sk> |
| <div class="vertical layout contentWrapper"> |
| <div class="horizontal layout center headingContainer"> |
| <div id="heading" hidden$="[[!_data.summary]]"> |
| <span class="name">Name: [[_data.summary.name]]</span> |
| <span class="pos">Pos: [[_data.summary.pos]]</span> |
| <span class="neg">Neg: [[_data.summary.neg]]</span> |
| <span class="unt">Unt: [[_data.summary.untriaged]]</span> |
| </div> |
| |
| <div> |
| <!-- Note:The values of the dropdown need to match the metric ids on the backend --> |
| <span class="diffMetricLabel">Diff Metric:</span> |
| <paper-dropdown-menu label="Diff metric" class="diffMetricSelect" no-label-float> |
| <paper-listbox id="diffMetric" class="dropdown-content" selected="{{_diffMetric}}" attr-for-selected="value"> |
| <paper-item value="combined">Combined</paper-item> |
| <paper-item value="percent">Percent</paper-item> |
| </paper-listbox> |
| </paper-dropdown-menu> |
| </div> |
| </div> |
| |
| <div id="mainContent" class="horizontal layout wrap"> |
| <!-- left column --> |
| <div class="vertical layout leftColumn"> |
| <div class="vertical layout modButtonContainer"> |
| <select-popup-sk id="paramsSelect"></select-popup-sk> |
| |
| </div> |
| <search-controls-sk id="rowSearchControls" orientation="vertical"></search-controls-sk> |
| <sort-control-sk id="rowSortControl" selection="{{_rowSorting}}" disabled="[[_hideAll]]"></sort-control-sk> |
| </div> |
| |
| <!-- main column with grid --> |
| <div class="vertical layout gridContainer"> |
| <div class="horizontal layout"> |
| <search-controls-sk id="colSearchControls" orientation="horizontal"></search-controls-sk> |
| <sort-control-sk id="columnSortControl" selection="{{_colSorting}}" disabled="[[_hideAll]]"></sort-control-sk> |
| </div> |
| |
| <div class="horizontal layout center"> |
| <div class="layout vertical center"> |
| <grid-sk id="gridCompare"></grid-sk> |
| <paper-button id="moreRowsButton" hidden$="[[_noMoreRows(_data)]]"> |
| <iron-icon icon="icons:expand-more"></iron-icon> |
| </paper-button> |
| </div> |
| <div class="moreColumns"> |
| <paper-button id="moreColumnsButton" hidden$="[[_noMoreColumns(_data)]]"> |
| <iron-icon icon="icons:chevron-right"></iron-icon> |
| </paper-button> |
| </div> |
| </div> |
| </div> |
| <div class="vertical layout compDiffContainer"> |
| <activity-sk id="activityCompDiff"></activity-sk> |
| <digest-details-sk id="digestDetails" |
| mode="detail" |
| details="[[_digestDetails.digest]]" |
| commits="[[_digestDetails.commits]]"> |
| </digest-details-sk> |
| |
| <digest-details-sk |
| id="compDetails" |
| mode="diff" |
| details="[[_diffData.left]]" |
| right="[[_diffData.right]]" |
| diff="[[_diffData.diff]]" |
| embedded> |
| </digest-details-sk> |
| </div> |
| </div> |
| </div> |
| |
| <!-- zoom dialog --> |
| <zoom-dialog-sk></zoom-dialog-sk> |
| </template> |
| <script> |
| (function() { |
| // The current state of the page. |
| var defaultQuery = { |
| rowQuery: null, |
| columnQuery: null, |
| match: gold.DEFAULT_MATCH_CONFIGS, |
| sortRows: "", |
| rowsDir: "", |
| sortColumns: "", |
| columnsDir: "", |
| metric: "" |
| }; |
| |
| // Default values for the row and column queries. |
| var defaultRowQuery = sk.object.shallowCopy(gold.defaultSearchState); |
| defaultRowQuery.limit = 10; |
| var defaultColumnQuery = sk.object.shallowCopy(gold.defaultSearchState); |
| defaultColumnQuery.pos = true; |
| defaultColumnQuery.neg = true; |
| defaultColumnQuery.unt = false; |
| defaultColumnQuery.limit = 10; |
| |
| // Sort options for the row and column query. |
| var SORT_FIELD_N_IMAGES = "count"; |
| var SORT_FIELD_DIFF = "diff"; |
| |
| var rowSortOptions = [ |
| {field: SORT_FIELD_N_IMAGES, label: "#images"}, |
| {field: SORT_FIELD_DIFF, label: "Diff"} |
| ]; |
| var colSortOptions = [ {field: SORT_FIELD_DIFF, label: "Diff"} ]; |
| var defaultRowSorting = {dir: gold.SORT_DESC, field: SORT_FIELD_DIFF}; |
| var defaultColSorting = {dir: gold.SORT_ASC, field: SORT_FIELD_DIFF}; |
| |
| // ids fo the different diff metrics. |
| var METRIC_COMBINED = "combined"; |
| var METRIC_PERCENT = "percent"; |
| |
| Polymer({ |
| is: "comp-page-sk", |
| |
| behaviors: [gold.ZoomTargetBehavior, gold.PageStateBehavior], |
| |
| properties: { |
| _data: { |
| type: Object, |
| value: null |
| }, |
| _syncParams: { |
| type: Boolean, |
| }, |
| _diffMetric: { |
| type: String |
| } |
| }, |
| |
| ready: function() { |
| this.listen(this.$.paramsSelect, 'changed-selection', '_handleMatchChanged'); |
| this.listen(this.$.gridCompare, 'diff-click', '_handleGridClick'); |
| this.listen(this.$.gridCompare, 'diff-dblclick', '_handleGridDblClick'); |
| this.listen(this.$.compDetails, 'zoom-clicked', "_handleZoomClicked"); |
| this.listen(this.$.rowSearchControls, 'state-change', '_handleRowQueryChange'); |
| this.listen(this.$.colSearchControls, 'state-change', '_handleColumnQueryChange'); |
| this.listen(this.$.moreColumnsButton, 'click', '_handleMoreColumns'); |
| this.listen(this.$.moreRowsButton, 'click', '_handleMoreRows'); |
| this.listen(this.$.rowSortControl, 'sort-changed', '_load'); |
| this.listen(this.$.columnSortControl, 'sort-changed', '_load'); |
| this.listen(this.$.diffMetric, 'iron-select', '_load'); |
| this.listen(this.$.digestDetails, 'triage', '_handleTriage'); |
| this.listen(this.$.compDetails, 'triage', '_handleTriage'); |
| this.$.rowSortControl.setItems(rowSortOptions); |
| this.$.columnSortControl.setItems(colSortOptions); |
| this._setDefaultState(gold.defaultSearchState, true); |
| }, |
| |
| pageSelected: function(ctx) { |
| this._query = sk.object.shallowCopy(defaultQuery); |
| this._query.match = gold.DEFAULT_MATCH_CONFIGS.slice() |
| |
| // Use the _state variable to as the row query and reflect the URL parameters. |
| this._initState(ctx, this._getDefaultStateWithCorpus(defaultRowQuery)); |
| |
| this._query.columnQuery = this._getDefaultStateWithCorpus(defaultColumnQuery); |
| this._query.columnQuery.head = this._state.head; |
| this._query.columnQuery.include = this._state.include; |
| this._query.columnQuery.query = ''; |
| this._query.columnQuery = this._addCorpus(this._query.columnQuery); |
| |
| this.set("_colSorting", sk.object.shallowCopy(defaultColSorting)); |
| this.set("_rowSorting", sk.object.shallowCopy(defaultRowSorting)); |
| this.set("_diffMetric", METRIC_COMBINED); |
| this._load(); |
| }, |
| |
| pageDeselected: function() {}, |
| |
| // _reset clears the detail views. |
| _reset: function() { |
| this.set('_diffData', {}); |
| this.set('_digestDetails', {}); |
| }, |
| |
| _load: function() { |
| this._reset(); |
| sk.get("/json/paramset").then(JSON.parse).then(function (json) { |
| this.$.rowSearchControls.setParamSet(json); |
| this.$.rowSearchControls.setState(this._state); |
| |
| this.$.colSearchControls.setParamSet(json); |
| this.$.colSearchControls.setState(this._query.columnQuery); |
| this.$.paramsSelect.setParamSet(json); |
| this.$.paramsSelect.setSelection(this._query.match); |
| }.bind(this)).catch(sk.errorMessage); |
| |
| // Update the query object. |
| this._query.sortRows = this._rowSorting.field; |
| this._query.rowsDir = this._rowSorting.dir; |
| this._query.sortColumns = this._colSorting.field, |
| this._query.columnsDir = this._colSorting.dir; |
| this._query.metric = this._diffMetric; |
| this._query.rowQuery = sk.object.shallowCopy(this._state); |
| |
| var activity = this.$.activityCompare; |
| activity.startSpinner("Loading..."); |
| this.set("_data", null); |
| sk.post("/json/cmp", JSON.stringify(this._query)).then(JSON.parse).then(function (json) { |
| activity.stopSpinner(); |
| |
| // If there is only one test set the summary. Otherwise inject it |
| // into the individual rows. |
| if (Object.keys(json.summaries).length === 1) { |
| json.summary = json.summaries[json.grid.rows[0].test]; |
| json.summary.name = json.grid.rows[0].test; |
| } else { |
| // Inject the summaries into every test. |
| for(var i=0; i < json.grid.rows.length; i++) { |
| json.grid.rows[i].summary = json.summaries[json.grid.rows[i].test]; |
| } |
| } |
| |
| this.set("_data", json); |
| this.$.gridCompare.setValue(json.grid); |
| }.bind(this)).catch(function(e) { |
| activity.stopSpinner(); |
| sk.errorMessage(e); |
| }); |
| }, |
| |
| _handleGridClick: function(ev) { |
| this.$.compDetails.clear(); |
| this.$.digestDetails.clear(); |
| if (ev.detail.colDigest) { |
| var url = "/json/diff" + gold.diffQuery(ev.detail.test, ev.detail.rowDigest, ev.detail.colDigest); |
| this.$.gridCompare.clearSelection(); |
| gold.loadWithActivity(this, url, this.$.activityCompDiff, function(json) { |
| this.set('_diffData', json); |
| this.$.gridCompare.selectCell(ev.detail.rowIndex, ev.detail.columnIndex); |
| }.bind(this)); |
| } else { |
| var url = "/json/details" + gold.detailQuery(ev.detail.test, ev.detail.rowDigest); |
| this.$.gridCompare.clearSelection(); |
| gold.loadWithActivity(this, url, this.$.activityCompDiff, function(json) { |
| this.set('_digestDetails', json); |
| this.$.gridCompare.selectRow(ev.detail.rowIndex); |
| }.bind(this)); |
| } |
| }, |
| |
| _handleGridDblClick: function(ev) { |
| if (ev.detail.colDigest) { |
| var zoomDetail = { |
| leftImgUrl: gold.imgHref(ev.detail.rowDigest), |
| rightImgUrl: gold.imgHref(ev.detail.colDigest), |
| middleImgUrl: gold.diffImgHref(ev.detail.rowDigest, ev.detail.colDigest), |
| llabel: "Row", |
| rlabel: "Column" |
| }; |
| $$$('zoom-dialog-sk', this).open(zoomDetail); |
| } |
| }, |
| |
| _handleTriage: function(ev) { |
| ev.stopPropagation(); |
| sk.post('/json/triage', JSON.stringify(ev.detail)).catch(sk.errorMessage); |
| }, |
| |
| _handleMatchChanged: function(ev) { |
| this._query.match = ev.detail; |
| this._load(); |
| }, |
| |
| _handleRowQueryChange: function(ev) { |
| // Reload the page with the new state in the query parameters. |
| this._redirectToState(ev.detail); |
| }, |
| |
| _handleColumnQueryChange: function(ev) { |
| this._query.columnQuery = this._addCorpus(ev.detail); |
| this._load(); |
| }, |
| |
| // copy the query string from the row query to the column query. |
| _copyQueryStr: function() { |
| var newState = sk.object.shallowCopy(this.$.colSearchControls.state); |
| newState.query = this._state.query; |
| this.$.colSearchControls.setState(this._state, true); |
| }, |
| |
| _handleMoreRows: function() { |
| this._state.limit += 10; |
| this._load(); |
| }, |
| |
| _handleMoreColumns: function() { |
| if (this._data) { |
| this._query.columnQuery.limit += 10; |
| this._load(); |
| } |
| }, |
| |
| _noMoreRows: function(data) { |
| return data && (data.grid.rows.length >= data.grid.rowTotal); |
| }, |
| |
| _noMoreColumns: function(data) { |
| if (data) { |
| for(var i=0; i < data.grid.rows.length; i++) { |
| if (data.grid.rows[i].values.length >= data.grid.columnsTotal) { |
| return true; |
| } |
| } |
| return false; |
| } |
| return true; |
| } |
| }); |
| |
| })(); |
| |
| </script> |
| </dom-module> |