Merge changes I6f812fb5,Iffcb629d,I718d11da,Ie916fbb7
* changes: Fix bug where a Promise was not returned by the shared cache Add user links to nav Add logged-out nav menu Respect changes-per-page preference in change-list
This commit is contained in:
@@ -66,7 +66,7 @@ limitations under the License.
|
||||
<gr-ajax
|
||||
auto
|
||||
url="/changes/"
|
||||
params="[[_computeQueryParams(_query, _offset)]]"
|
||||
params="[[_computeQueryParams(_query, _offset, changesPerPage)]]"
|
||||
last-response="{{_changes}}"
|
||||
last-error="{{_lastError}}"
|
||||
loading="{{_loading}}"></gr-ajax>
|
||||
@@ -80,10 +80,11 @@ limitations under the License.
|
||||
selected-index="{{viewState.selectedChangeIndex}}"
|
||||
show-star="[[loggedIn]]"></gr-change-list>
|
||||
<nav>
|
||||
<a href$="[[_computeNavLink(_query, _offset, -1)]]"
|
||||
<a href$="[[_computeNavLink(_query, _offset, -1, changesPerPage)]]"
|
||||
hidden$="[[_hidePrevArrow(_offset)]]">← Prev</a>
|
||||
<a href$="[[_computeNavLink(_query, _offset, 1)]]"
|
||||
hidden$="[[_hideNextArrow(_changes.length)]]">Next →</a>
|
||||
<a href$="[[_computeNavLink(_query, _offset, 1, changesPerPage)]]"
|
||||
hidden$="[[_hideNextArrow(_changes.length, changesPerPage)]]">
|
||||
Next →</a>
|
||||
</nav>
|
||||
</div>
|
||||
</template>
|
||||
|
@@ -14,8 +14,6 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
var DEFAULT_NUM_CHANGES = 25;
|
||||
|
||||
Polymer({
|
||||
is: 'gr-change-list-view',
|
||||
|
||||
@@ -51,6 +49,8 @@
|
||||
value: function() { return {}; },
|
||||
},
|
||||
|
||||
changesPerPage: Number,
|
||||
|
||||
/**
|
||||
* Currently active query.
|
||||
*/
|
||||
@@ -103,13 +103,13 @@
|
||||
this.fire('title-change', {title: this._query});
|
||||
},
|
||||
|
||||
_computeQueryParams: function(query, offset) {
|
||||
_computeQueryParams: function(query, offset, changesPerPage) {
|
||||
var options = this.listChangesOptionsToHex(
|
||||
this.ListChangesOption.LABELS,
|
||||
this.ListChangesOption.DETAILED_ACCOUNTS
|
||||
);
|
||||
var obj = {
|
||||
n: DEFAULT_NUM_CHANGES, // Number of results to return.
|
||||
n: changesPerPage,
|
||||
O: options,
|
||||
S: offset || 0,
|
||||
};
|
||||
@@ -119,10 +119,10 @@
|
||||
return obj;
|
||||
},
|
||||
|
||||
_computeNavLink: function(query, offset, direction) {
|
||||
_computeNavLink: function(query, offset, direction, changesPerPage) {
|
||||
// Offset could be a string when passed from the router.
|
||||
offset = +(offset || 0);
|
||||
var newOffset = Math.max(0, offset + (25 * direction));
|
||||
var newOffset = Math.max(0, offset + (changesPerPage * direction));
|
||||
var href = '/q/' + query;
|
||||
if (newOffset > 0) {
|
||||
href += ',' + newOffset;
|
||||
@@ -142,8 +142,8 @@
|
||||
return offset == 0;
|
||||
},
|
||||
|
||||
_hideNextArrow: function(changesLen) {
|
||||
return changesLen < DEFAULT_NUM_CHANGES;
|
||||
_hideNextArrow: function(changesLen, changesPerPage) {
|
||||
return changesLen < changesPerPage;
|
||||
},
|
||||
});
|
||||
})();
|
||||
|
@@ -25,9 +25,11 @@ limitations under the License.
|
||||
<template>
|
||||
<style>
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
nav {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
}
|
||||
.bigTitle {
|
||||
color: var(--primary-text-color);
|
||||
@@ -37,6 +39,60 @@ limitations under the License.
|
||||
.bigTitle:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
ul {
|
||||
list-style: none;
|
||||
}
|
||||
.links {
|
||||
margin-left: 1em;
|
||||
}
|
||||
.links ul {
|
||||
display: none;
|
||||
}
|
||||
.links > li {
|
||||
cursor: default;
|
||||
display: inline-block;
|
||||
margin-left: 1em;
|
||||
padding: .4em 0;
|
||||
position: relative;
|
||||
}
|
||||
.links li:hover ul {
|
||||
background-color: #fff;
|
||||
box-shadow: 0 1px 1px rgba(0, 0, 0, .3);
|
||||
display: block;
|
||||
left: -.75em;
|
||||
position: absolute;
|
||||
top: 2em;
|
||||
z-index: 1000;
|
||||
}
|
||||
.links li ul li a:link,
|
||||
.links li ul li a:visited {
|
||||
color: #00e;
|
||||
display: block;
|
||||
padding: .5em .75em;
|
||||
text-decoration: none;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.links li ul li:hover a {
|
||||
background-color: var(--selection-background-color);
|
||||
}
|
||||
.linksTitle {
|
||||
display: inline-block;
|
||||
padding-right: 1em;
|
||||
position: relative;
|
||||
}
|
||||
.downArrow {
|
||||
border-left: .36em solid transparent;
|
||||
border-right: .36em solid transparent;
|
||||
border-top: .36em solid #ccc;
|
||||
height: 0;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: calc(50% - .1em);
|
||||
width: 0;
|
||||
}
|
||||
.links li:hover .downArrow {
|
||||
border-top-color: #666;
|
||||
}
|
||||
.rightItems {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
@@ -73,14 +129,30 @@ limitations under the License.
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<a href="/" class="bigTitle">PolyGerrit</a>
|
||||
<div class="rightItems">
|
||||
<gr-search-bar value="{{params.query}}" role="search"></gr-search-bar>
|
||||
<div class="accountContainer" id="accountContainer">
|
||||
<a class="loginButton" href="/login" on-tap="_loginTapHandler">Login</a>
|
||||
<gr-account-dropdown account="[[_account]]"></gr-account-dropdown>
|
||||
<nav>
|
||||
<a href="/" class="bigTitle">PolyGerrit</a>
|
||||
<ul class="links">
|
||||
<template is="dom-repeat" items="[[_links]]" as="linkGroup">
|
||||
<li>
|
||||
<span class="linksTitle">
|
||||
[[linkGroup.title]] <i class="downArrow"></i>
|
||||
</span>
|
||||
<ul>
|
||||
<template is="dom-repeat" items="[[linkGroup.links]]" as="link">
|
||||
<li><a href="[[link.url]]">[[link.name]]</a></li>
|
||||
</template>
|
||||
</ul>
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
<div class="rightItems">
|
||||
<gr-search-bar value="{{searchQuery}}" role="search"></gr-search-bar>
|
||||
<div class="accountContainer" id="accountContainer">
|
||||
<a class="loginButton" href="/login" on-tap="_loginTapHandler">Login</a>
|
||||
<gr-account-dropdown account="[[_account]]"></gr-account-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
|
||||
</template>
|
||||
<script src="gr-main-header.js"></script>
|
||||
|
@@ -14,6 +14,24 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
var DEFAULT_LINKS = [{
|
||||
title: 'Changes',
|
||||
links: [
|
||||
{
|
||||
url: '/q/status:open',
|
||||
name: 'Open',
|
||||
},
|
||||
{
|
||||
url: '/q/status:merged',
|
||||
name: 'Merged',
|
||||
},
|
||||
{
|
||||
url: '/q/status:abandoned',
|
||||
name: 'Abandoned',
|
||||
},
|
||||
],
|
||||
}];
|
||||
|
||||
Polymer({
|
||||
is: 'gr-main-header',
|
||||
|
||||
@@ -22,15 +40,74 @@
|
||||
},
|
||||
|
||||
properties: {
|
||||
searchQuery: {
|
||||
type: String,
|
||||
notify: true,
|
||||
},
|
||||
|
||||
_account: Object,
|
||||
_defaultLinks: {
|
||||
type: Array,
|
||||
value: function() {
|
||||
return DEFAULT_LINKS;
|
||||
},
|
||||
},
|
||||
_links: {
|
||||
type: Array,
|
||||
computed: '_computeLinks(_defaultLinks, _userLinks)',
|
||||
},
|
||||
_userLinks: {
|
||||
type: Array,
|
||||
value: function() { return []; },
|
||||
},
|
||||
},
|
||||
|
||||
observers: [
|
||||
'_accountLoaded(_account)',
|
||||
],
|
||||
|
||||
attached: function() {
|
||||
this._loadAccount();
|
||||
},
|
||||
|
||||
_computeLinks: function(defaultLinks, userLinks) {
|
||||
var links = defaultLinks.slice();
|
||||
if (userLinks && userLinks.length > 0) {
|
||||
links.push({
|
||||
title: 'Your',
|
||||
links: userLinks,
|
||||
});
|
||||
}
|
||||
return links;
|
||||
},
|
||||
|
||||
_loadAccount: function() {
|
||||
this.$.restAPI.getAccount().then(function(account) {
|
||||
this._account = account;
|
||||
this.$.accountContainer.classList.toggle('loggedIn', account != null);
|
||||
this.$.accountContainer.classList.toggle('loggedOut', account == null);
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
_accountLoaded: function(account) {
|
||||
if (!account) { return; }
|
||||
|
||||
this.$.restAPI.getPreferences().then(function(prefs) {
|
||||
this._userLinks =
|
||||
prefs.my.map(this._stripHashPrefix).filter(this._isSupportedLink);
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
_stripHashPrefix: function(linkObj) {
|
||||
if (linkObj.url.indexOf('#') === 0) {
|
||||
linkObj.url = linkObj.url.slice(1);
|
||||
}
|
||||
return linkObj;
|
||||
},
|
||||
|
||||
_isSupportedLink: function(linkObj) {
|
||||
// Groups are not yet supported.
|
||||
return linkObj.url.indexOf('/groups') !== 0;
|
||||
},
|
||||
});
|
||||
})();
|
||||
|
@@ -0,0 +1,89 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
Copyright (C) 2016 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
|
||||
<title>gr-main-header</title>
|
||||
|
||||
<script src="../../../bower_components/webcomponentsjs/webcomponents.min.js"></script>
|
||||
<script src="../../../bower_components/web-component-tester/browser.js"></script>
|
||||
|
||||
<link rel="import" href="../../../bower_components/iron-test-helpers/iron-test-helpers.html">
|
||||
<link rel="import" href="gr-main-header.html">
|
||||
|
||||
<test-fixture id="basic">
|
||||
<template>
|
||||
<gr-main-header></gr-main-header>
|
||||
</template>
|
||||
</test-fixture>
|
||||
|
||||
<script>
|
||||
suite('gr-main-header tests', function() {
|
||||
var element;
|
||||
|
||||
setup(function() {
|
||||
stub('gr-main-header', {
|
||||
_loadAccount: function() {},
|
||||
});
|
||||
element = fixture('basic');
|
||||
});
|
||||
|
||||
test('strip hash prefix', function() {
|
||||
assert.deepEqual([
|
||||
{url: '#/q/owner:self+is:draft'},
|
||||
{url: 'https://awesometown.com/#hashyhash'},
|
||||
].map(element._stripHashPrefix),
|
||||
[
|
||||
{url: '/q/owner:self+is:draft'},
|
||||
{url: 'https://awesometown.com/#hashyhash'},
|
||||
]);
|
||||
});
|
||||
|
||||
test('filter unsupported urls', function() {
|
||||
assert.deepEqual([
|
||||
{url: '/q/owner:self+is:draft'},
|
||||
{url: '/c/331788/'},
|
||||
{url: '/groups/self'},
|
||||
{url: 'https://awesometown.com/#hashyhash'},
|
||||
].filter(element._isSupportedLink),
|
||||
[
|
||||
{url: '/q/owner:self+is:draft'},
|
||||
{url: '/c/331788/'},
|
||||
{url: 'https://awesometown.com/#hashyhash'},
|
||||
]);
|
||||
});
|
||||
|
||||
test('user links', function() {
|
||||
var defaultLinks = [{
|
||||
title: 'Faves',
|
||||
links: [{
|
||||
name: 'Pinterest',
|
||||
url: 'https://pinterest.com',
|
||||
}],
|
||||
}];
|
||||
var userLinks = [{
|
||||
name: 'Facebook',
|
||||
url: 'https://facebook.com',
|
||||
}];
|
||||
assert.deepEqual(element._computeLinks(defaultLinks, []), defaultLinks);
|
||||
assert.deepEqual(element._computeLinks(defaultLinks, userLinks),
|
||||
defaultLinks.concat({
|
||||
title: 'Your',
|
||||
links: userLinks,
|
||||
}));
|
||||
});
|
||||
});
|
||||
</script>
|
@@ -30,12 +30,11 @@ limitations under the License.
|
||||
}
|
||||
input {
|
||||
border: 1px solid #d1d2d3;
|
||||
outline: none;
|
||||
}
|
||||
input {
|
||||
border-radius: 2px 0 0 2px;
|
||||
flex: 1;
|
||||
font: inherit;
|
||||
border-radius: 2px 0 0 2px;
|
||||
outline: none;
|
||||
padding: 0 .25em;
|
||||
}
|
||||
gr-button {
|
||||
background-color: #f1f2f3;
|
||||
|
@@ -61,12 +61,13 @@ limitations under the License.
|
||||
<gr-ajax id="diffPreferencesXHR"
|
||||
url="/accounts/self/preferences.diff"
|
||||
last-response="{{_diffPreferences}}"></gr-ajax>
|
||||
<gr-main-header></gr-main-header>
|
||||
<gr-main-header search-query="{{params.query}}"></gr-main-header>
|
||||
<main>
|
||||
<template is="dom-if" if="{{_showChangeListView}}" restamp="true">
|
||||
<gr-change-list-view
|
||||
params="[[params]]"
|
||||
view-state="{{_viewState.changeListView}}"
|
||||
changes-per-page="[[_preferences.changes_per_page]]"
|
||||
logged-in="[[_computeLoggedIn(account)]]"></gr-change-list-view>
|
||||
</template>
|
||||
<template is="dom-if" if="{{_showDashboardView}}" restamp="true">
|
||||
|
@@ -54,6 +54,7 @@
|
||||
},
|
||||
|
||||
_diffPreferences: Object,
|
||||
_preferences: Object,
|
||||
_showChangeListView: Boolean,
|
||||
_showDashboardView: Boolean,
|
||||
_showChangeView: Boolean,
|
||||
@@ -106,6 +107,10 @@
|
||||
this._resolveAccountReady();
|
||||
if (this.loggedIn) {
|
||||
this.$.diffPreferencesXHR.generateRequest();
|
||||
|
||||
this.$.restAPI.getPreferences().then(function(preferences) {
|
||||
this._preferences = preferences;
|
||||
}.bind(this));
|
||||
} else {
|
||||
// These defaults should match the defaults in
|
||||
// gerrit-extension-api/src/main/jcg/gerrit/extensions/client/DiffPreferencesInfo.java
|
||||
@@ -125,6 +130,10 @@
|
||||
tab_size: 8,
|
||||
theme: 'DEFAULT',
|
||||
};
|
||||
|
||||
this._preferences = {
|
||||
changes_per_page: 25,
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
|
@@ -86,13 +86,17 @@
|
||||
return this._fetchSharedCacheURL('/accounts/self/detail');
|
||||
},
|
||||
|
||||
getPreferences: function() {
|
||||
return this._fetchSharedCacheURL('/accounts/self/preferences');
|
||||
},
|
||||
|
||||
_fetchSharedCacheURL: function(url) {
|
||||
if (this._sharedFetchPromises[url]) {
|
||||
return this._sharedFetchPromises[url];
|
||||
}
|
||||
// TODO(andybons): Periodic cache invalidation.
|
||||
if (this._cache[url] !== undefined) {
|
||||
return this._cache[url];
|
||||
return Promise.resolve(this._cache[url]);
|
||||
}
|
||||
this._sharedFetchPromises[url] = this.fetchJSON(url).then(
|
||||
function(response) {
|
||||
|
@@ -65,7 +65,19 @@ limitations under the License.
|
||||
|
||||
Promise.all(promises).then(function(results) {
|
||||
assert.deepEqual(results, [1, 1, 1]);
|
||||
fetchJSONStub.restore();
|
||||
element._fetchSharedCacheURL('/foo').then(function(foo) {
|
||||
assert.equal(foo, 1);
|
||||
fetchJSONStub.restore();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('cached promise', function(done) {
|
||||
var promise = Promise.reject('foo');
|
||||
element._cache['/foo'] = promise;
|
||||
element._fetchSharedCacheURL('/foo').catch(function(p) {
|
||||
assert.equal(p, 'foo');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
@@ -19,6 +19,7 @@ limitations under the License.
|
||||
--primary-text-color: #000;
|
||||
--search-border-color: #ddd;
|
||||
--secondary-color: #f1f2f3;
|
||||
--selection-background-color: #ebf5fb;
|
||||
--default-text-color: #000;
|
||||
--view-background-color: #fff;
|
||||
--default-horizontal-margin: 1.25rem;
|
||||
|
Reference in New Issue
Block a user