Included-In dialog polish

Add a filter textbox and behavior to the Included-In dialog and align
the padding with other dialogs. To accommodate filtering, empty groups
are hidden.

Change-Id: I481f266ce8cc67de07f1dc8dfb9129b7d36e081b
This commit is contained in:
Wyatt Allen
2018-03-16 12:55:58 -07:00
committed by Paladox none
parent 3810c5e7c4
commit 8e32422334
4 changed files with 76 additions and 38 deletions

View File

@@ -205,7 +205,6 @@ limitations under the License.
overflow: auto;
}
#includedInOverlay {
padding: 2em;
width: 65em;
}
@media screen and (min-width: 80em) {

View File

@@ -23,22 +23,35 @@ limitations under the License.
<style include="shared-styles">
:host {
display: block;
padding: 1em;
max-height: 80vh;
overflow-y: auto;
padding: 4.5em 1em 1em 1em;
}
h1 {
header {
background: #fff;
border-bottom: 1px solid #cdcdcd;
left: 0;
padding: 1em;
position: absolute;
right: 0;
top: 0;
}
#title {
display: inline-block;
font-size: 1.2rem;
margin-top: .2em;
}
h2 {
font-size: 1rem;
}
.closeButtonContainer {
position: absolute;
right: 2em;
top: 2em;
#filterInput {
display: inline-block;
float: right;
margin: 0 1em;
padding: .2em;
}
.container {
max-height: 80vh;
overflow-y: scroll;
.closeButtonContainer {
float: right;
}
ul {
margin-bottom: 1em;
@@ -55,29 +68,32 @@ limitations under the License.
}
</style>
<header>
<h1>Included In:</h1>
<h1 id="title">Included In:</h1>
<span class="closeButtonContainer">
<gr-button id="closeButton"
link
on-tap="_handleCloseTap">Close</gr-button>
</span>
<input
id="filterInput"
is="iron-input"
placeholder="Filter"
on-bind-value-changed="_onFilterChanged">
</header>
<div class$="[[_computeLoadingClass(_loaded)]]">Loading...</div>
<div class="container">
<template
is="dom-repeat"
items="[[_computeGroups(_includedIn)]]"
as="group">
<div>
<h2>[[group.title]]:</h2>
<ul>
<template is="dom-repeat" items="[[group.items]]">
<li>[[item]]</li>
</template>
</ul>
</div>
</template>
</div>
<template
is="dom-repeat"
items="[[_computeGroups(_includedIn, _filterText)]]"
as="group">
<div>
<h2>[[group.title]]:</h2>
<ul>
<template is="dom-repeat" items="[[group.items]]">
<li>[[item]]</li>
</template>
</ul>
</div>
</template>
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
</template>
<script src="gr-included-in-dialog.js"></script>

View File

@@ -35,10 +35,15 @@
type: Boolean,
value: false,
},
_filterText: {
type: String,
value: '',
},
},
loadData() {
if (!this.changeNum) { return; }
this._filterText = '';
return this.$.restAPI.getChangeIncludedIn(this.changeNum).then(
configs => {
if (!configs) { return; }
@@ -52,22 +57,25 @@
this._loaded = false;
},
_computeGroups(includedIn) {
_computeGroups(includedIn, filterText) {
if (!includedIn) { return []; }
const filter = item => !filterText.length ||
item.toLowerCase().indexOf(filterText.toLowerCase()) !== -1;
const groups = [
{title: 'Branches', items: includedIn.branches},
{title: 'Tags', items: includedIn.tags},
{title: 'Branches', items: includedIn.branches.filter(filter)},
{title: 'Tags', items: includedIn.tags.filter(filter)},
];
if (includedIn.external) {
for (const externalKey of Object.keys(includedIn.external)) {
groups.push({
title: externalKey,
items: includedIn.external[externalKey],
items: includedIn.external[externalKey].filter(filter),
});
}
}
return groups;
return groups.filter(g => g.items.length);
},
_handleCloseTap(e) {
@@ -78,5 +86,11 @@
_computeLoadingClass(loaded) {
return loaded ? 'loading loaded' : 'loading';
},
_onFilterChanged() {
this.debounce('filter-change', () => {
this._filterText = this.$.filterInput.bindValue;
}, 100);
},
});
})();

View File

@@ -45,30 +45,39 @@ limitations under the License.
test('_computeGroups', () => {
const includedIn = {branches: [], tags: []};
assert.deepEqual(element._computeGroups(includedIn), [
{title: 'Branches', items: []},
{title: 'Tags', items: []},
]);
let filterText = '';
assert.deepEqual(element._computeGroups(includedIn, filterText), []);
includedIn.branches.push('master', 'development', 'stable-2.0');
includedIn.tags.push('v1.9', 'v2.0', 'v2.1');
assert.deepEqual(element._computeGroups(includedIn), [
assert.deepEqual(element._computeGroups(includedIn, filterText), [
{title: 'Branches', items: ['master', 'development', 'stable-2.0']},
{title: 'Tags', items: ['v1.9', 'v2.0', 'v2.1']},
]);
includedIn.external = {};
assert.deepEqual(element._computeGroups(includedIn), [
assert.deepEqual(element._computeGroups(includedIn, filterText), [
{title: 'Branches', items: ['master', 'development', 'stable-2.0']},
{title: 'Tags', items: ['v1.9', 'v2.0', 'v2.1']},
]);
includedIn.external.foo = ['abc', 'def', 'ghi'];
assert.deepEqual(element._computeGroups(includedIn), [
assert.deepEqual(element._computeGroups(includedIn, filterText), [
{title: 'Branches', items: ['master', 'development', 'stable-2.0']},
{title: 'Tags', items: ['v1.9', 'v2.0', 'v2.1']},
{title: 'foo', items: ['abc', 'def', 'ghi']},
]);
filterText = 'v2';
assert.deepEqual(element._computeGroups(includedIn, filterText), [
{title: 'Tags', items: ['v2.0', 'v2.1']},
]);
// Filtering is case-insensitive.
filterText = 'V2';
assert.deepEqual(element._computeGroups(includedIn, filterText), [
{title: 'Tags', items: ['v2.0', 'v2.1']},
]);
});
});
</script>