blob: a51439d0d458d453229a54efc231b63e237c070a [file] [log] [blame]
<!-- The <search-controls-sk> custom element declaration.
This is a general element to be used by all pages that
call a search endpoint on the backend.
It encapsulates the state of the query. When that state
is changed through some of the controls it updates the URL
and send an update to the host element to reload data based
on the new query state.
The state object contains these fields:
- pos: show positive (boolean).
- neg: show negative (boolean).
- unt: show untriaged (boolean).
- include: show ignored digests (boolean).
- head: only digests that are currently in HEAD.
- query: query string to select configuration.
Attributes:
state - The current query state.
disabled - Boolean to indicate whether to disable all the controls.
beta - Boolean to enable beta-level functions.
Events:
'state-change' - Fired when the state of the query changes and
it needs to be reloaded. The 'detail' field of the event contains
the new state represented by the controls.
Methods:
setState(state) - Set the state of the controls to 'state'.
setParamSet(params) - Sets the parameters of the enclosed query-dialog-sk element
and enables the controls accordingly.
setCommitInfo(commitinfo) - Where commitinfo is an array of objects of the form:
{
author: "foo@example.org"
commit_time: 1428574804
hash: "d9f8862ab6bed4195cbfe5dda48693e1062b01e2"
}
-->
<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/image-icons.html">
<link rel="import" href="bower_components/paper-button/paper-button.html">
<link rel="import" href="query-dialog-sk.html">
<link rel="import" href="filter-dialog-sk.html">
<link rel="import" href="shared-styles.html">
<dom-module id="search-controls-sk">
<template>
<style include="iron-flex iron-flex-alignment"></style>
<style include="shared-styles">
.horizontalTopControl {
font-weight: bold;
}
.horizontalTopControl {
margin: 0 2em 0 0;
}
.horizontal.currSelection {
margin-left: 1em;
margin-right: 3em;
max-width: 20em;
}
.corpus_label {
font-weight: bold;
margin: auto 0;
}
</style>
<div class="vertical layout">
<div class="horizontal layout">
<paper-toggle-button class="horizontalTopControl" checked="{{state.pos}}" disabled={{disabled}}>Positive</paper-toggle-button>
<paper-toggle-button class="horizontalTopControl" checked="{{state.neg}}" disabled={{disabled}}>Negative</paper-toggle-button>
<paper-toggle-button class="horizontalTopControl" checked="{{state.unt}}" disabled={{disabled}}>Untriaged</paper-toggle-button>
<paper-toggle-button class="horizontalTopControl" checked="{{state.head}}" disabled={{disabled}}>Head</paper-toggle-button>
<paper-toggle-button class="horizontalTopControl" checked="{{state.include}}" disabled={{disabled}}>Ignored</paper-toggle-button>
<paper-button id="filterButton" class$="topControl" raised disabled="[[disabled]]"
title="Metrics Filter"><iron-icon icon="icons:filter-list"></iron-icon>
</paper-button>
</div>
<div class="horizontal layout">
<span class=corpus_label>Corpus:</span>
<corpus-selector-sk id="corpusSelector"></corpus-selector-sk>
</div>
<div class="horizontal layout">
<paper-button id="searchButton" class$="topControl" raised disabled="[[disabled]]"
title="Filter Traces"><iron-icon icon="image:tune"></iron-icon></paper-button>
<div class="horizontal currSelection">
[[_splitAmp(state.query)]]
</div>
</div>
</div>
<query-dialog-sk id="queryDialog" trigger="searchButton"></query-dialog-sk>
<filter-dialog-sk id="filterDialog" trigger="filterButton"></filter-dialog-sk>
</template>
<script>
Polymer({
is: "search-controls-sk",
properties: {
state: {
type: Object
},
disabled: {
type: Boolean,
value: false
},
beta: {
type: Boolean,
value: false
}
},
observers: [
'_fireStateChange(state.*)'
],
ready: function() {
this.listen(this.$.searchButton, 'tap', '_handleSearchButton');
this.listen(this.$.filterButton, 'tap', '_handleFilterButton');
this.listen(this.$.queryDialog, 'edit', '_handleQueryEdit');
this.listen(this.$.filterDialog, 'edit', '_handleFilterEdit');
this.listen(this.$.corpusSelector, 'corpus_selected', '_handleCorpusChange');
// If the corpus changes make sure we do cleanup work.
this.async(function() {
this._statusEle = $$$("gold-status-sk");
if (this._statusEle) {
this.listen(this._statusEle, 'corpus-change', '_handleCorpusChange');
}
});
},
setState: function(state, fireEvent) {
this._noFire = !fireEvent;
this.set('state', sk.object.shallowCopy(state));
this.$.filterDialog.setValue(this.state);
const query = sk.query.toParamSet(state.query);
const corporaSelected = query['source_type'];
if (corporaSelected && corporaSelected.length) {
this.$.corpusSelector.selectedCorpus = corporaSelected[0];
} else {
this.$.corpusSelector.selectedCorpus = sk.app_config.defaultCorpus;
}
},
setParamSet: function(params) {
this.$.queryDialog.queryEle.setParamSet(params);
this.$.filterDialog.setParamSet(params);
// TODO(kjlubick) in the lit-html version, this should reflect of digests as matched by
// the positive/negative/diff selector (i.e. the things above it).
const corpora = params['source_type'].map((name) => {
return {
name: name,
};
});
this.$.corpusSelector.corpora = corpora;
},
setCommitInfo: function(commits) {
this.$.filterDialog.setCommitInfo(commits);
},
_handleQueryEdit: function(ev) {
ev.stopPropagation();
// TODO(kjlubick) ev.detail does not include the source_type because there was some
// special logic in gold.js to add it on when the state changed. This is very confusing
// and no longer works (because the corpus selector was moved into the page). Thus,
// we need to append the corpus ourselves. This will be not needed when we port this
// page to lit-html.
const existingCorpus = sk.query.toParamSet(this.state.query).source_type;
const newQuery = `source_type=${encodeURIComponent(existingCorpus)}&${ev.detail}`;
console.debug('updating search to ', newQuery);
this.set('state.query', newQuery);
},
_handleFilterEdit: function(ev) {
ev.stopPropagation();
// merge filter into state
var newState = sk.object.applyDelta(ev.detail, this.state);
this.set('state', newState);
},
_handleSearchButton: function(ev) {
ev.stopPropagation();
this.$.queryDialog.open(this.state.query);
},
_handleFilterButton: function(ev) {
ev.stopPropagation();
this.$.filterDialog.open(this.state.filter);
},
_handleCorpusChange: function(ev) {
this.$.queryDialog.close();
// TODO(kjlubick) This is a dirty ugly hack, making the corpus change reload the entire
// page. However, the port to lit-html is coming soon, and I don't feel like making
// more changes to this Polymer code than is necessary.
const params = sk.query.toParamSet(this.state.query);
params.source_type = [ev.detail.corpus];
this.state.query = sk.query.fromParamSet(params);
window.location = window.location.pathname + gold.queryFromState(this.state);
},
_fireStateChange: function() {
if (this._noFire) {
this._noFire = false;
return;
}
var detail = sk.object.shallowCopy(this.state);
this.fire('state-change', detail);
},
_splitAmp: function(qStr) {
return sk.query.splitAmp(qStr, ', ');
}
});
</script>
</dom-module>