Display avatars according to the server config

This uses a similar pattern to
https://gerrit-review.googlesource.com/72659/ where a promise is
used for a global var that is retrieved asynchronously.

Change-Id: I99a4b589d368876becf4dd000a2ffde39b34eaa4
This commit is contained in:
Andrew Bonventre
2015-11-30 18:44:48 -05:00
parent 8bcaba7609
commit 8d1cde2a5d
5 changed files with 81 additions and 29 deletions

View File

@@ -16,26 +16,36 @@ limitations under the License.
<link rel="import" href="../bower_components/polymer/polymer.html"> <link rel="import" href="../bower_components/polymer/polymer.html">
<dom-module id="gr-account-manager"> <dom-module id="gr-ajax">
<template> <template>
<iron-ajax id="xhr" <iron-ajax id="xhr"
auto auto="{{auto}}"
url="/accounts/self/detail" url="{{url}}"
json-prefix=")]}'"></iron-ajax> params="{{params}}"
json-prefix=")]}'"
debounce-duration="300"></iron-ajax>
</template> </template>
<script> <script>
(function() { (function() {
'use strict'; 'use strict';
Polymer({ Polymer({
is: 'gr-account-manager', is: 'gr-ajax',
hostAttributes: { hostAttributes: {
hidden: true hidden: true
}, },
properties: { properties: {
account: { auto: Boolean,
url: String,
params: {
type: Object,
value: function() {
return {};
},
},
response: {
type: Object, type: Object,
notify: true, notify: true,
}, },
@@ -48,9 +58,9 @@ limitations under the License.
_handleResponse: function(e, req) { _handleResponse: function(e, req) {
if (req.status >= 200 && req.status < 300) { if (req.status >= 200 && req.status < 300) {
this.account = req.response; this.response = req.response;
} else { } else {
this.account = {}; this.response = {};
} }
}, },

View File

@@ -17,7 +17,7 @@ limitations under the License.
<link rel="import" href="../bower_components/polymer/polymer.html"> <link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="../styles/app-theme.html"> <link rel="import" href="../styles/app-theme.html">
<link rel="import" href="gr-account-dropdown.html"> <link rel="import" href="gr-account-dropdown.html">
<link rel="import" href="gr-account-manager.html"> <link rel="import" href="gr-ajax.html">
<link rel="import" href="gr-change-list-view.html"> <link rel="import" href="gr-change-list-view.html">
<link rel="import" href="gr-change-view.html"> <link rel="import" href="gr-change-view.html">
<link rel="import" href="gr-dashboard-view.html"> <link rel="import" href="gr-dashboard-view.html">
@@ -78,7 +78,8 @@ limitations under the License.
margin-left: var(--default-horizontal-margin); margin-left: var(--default-horizontal-margin);
} }
</style> </style>
<gr-account-manager account="{{account}}"></gr-account-manager> <gr-ajax auto url="/accounts/self/detail" response="{{account}}"></gr-ajax>
<gr-ajax auto url="/config/server/info" response="{{config}}"></gr-ajax>
<header role="banner"> <header role="banner">
<a href="/" class="bigTitle">PolyGerrit</a> <a href="/" class="bigTitle">PolyGerrit</a>
<div class="headerRightItems"> <div class="headerRightItems">
@@ -124,6 +125,20 @@ limitations under the License.
}.bind(this)); }.bind(this));
}, },
}, },
config: {
type: Object,
observer: '_configChanged',
},
configReady: {
type: Object,
readOnly: true,
notify: true,
value: function() {
return new Promise(function(resolve) {
this._resolveConfigReady = resolve;
}.bind(this));
},
},
constrained: { constrained: {
type: Boolean, type: Boolean,
value: false, value: false,
@@ -145,6 +160,10 @@ limitations under the License.
this._resolveAccountReady(); this._resolveAccountReady();
}, },
_configChanged: function(config) {
this._resolveConfigReady(config);
},
_routeChanged: function(route) { _routeChanged: function(route) {
this.set('_showChangeListView', route == 'gr-change-list-view'); this.set('_showChangeListView', route == 'gr-change-list-view');
this.set('_showDashboardView', route == 'gr-dashboard-view'); this.set('_showDashboardView', route == 'gr-dashboard-view');

View File

@@ -85,7 +85,9 @@ limitations under the License.
</td> </td>
<td>[[_computeChangeStatusString(change)]]</td> <td>[[_computeChangeStatusString(change)]]</td>
<td> <td>
<template is="dom-if" if="[[showAvatar]]">
<img class="avatarImage" src$="[[_computeAvatarURL(change.owner)]]"> <img class="avatarImage" src$="[[_computeAvatarURL(change.owner)]]">
</template>
<a href$="[[_computeOwnerLink(change.owner.email)]]" <a href$="[[_computeOwnerLink(change.owner.email)]]"
title$="[[_computeOwnerTitle(change.owner)]]">[[change.owner.name]]</a> title$="[[_computeOwnerTitle(change.owner)]]">[[change.owner.name]]</a>
</td> </td>
@@ -126,7 +128,14 @@ limitations under the License.
changeURL: { changeURL: {
type: String, type: String,
computed: '_computeChangeURL(change._number)', computed: '_computeChangeURL(change._number)',
} },
showAvatar: Boolean,
},
ready: function() {
app.configReady.then(function(cfg) {
this.showAvatar = cfg && cfg.plugin && cfg.plugin.has_avatars;
}.bind(this));
}, },
_computeChangeURL: function(changeNum) { _computeChangeURL: function(changeNum) {

View File

@@ -30,33 +30,36 @@ limitations under the License.
} }
.avatar { .avatar {
border-radius: 50%; border-radius: 50%;
position: absolute;
left: var(--default-horizontal-margin);
}
.hideAvatar .avatar {
display: none;
} }
.collapsed .contentContainer { .collapsed .contentContainer {
padding: 10px; color: #777;
padding-right: 60px;
white-space: nowrap; white-space: nowrap;
overflow-x: hidden; overflow-x: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.expanded .contentContainer { .showAvatar.expanded .contentContainer {
padding: 7px 0 10px; margin-left: calc(var(--default-horizontal-margin) + 2.5em);
padding: 10px 0;
} }
.expanded .contentContainer { .showAvatar.collapsed .contentContainer {
margin-left: calc(var(--default-horizontal-margin) + 25px); margin-left: calc(var(--default-horizontal-margin) + 1.75em);
padding: 10px 75px 10px 0;
} }
.collapsed .contentContainer { .hideAvatar.collapsed .contentContainer,
color: #777; .hideAvatar.expanded .contentContainer {
margin-left: calc(var(--default-horizontal-margin) + 15px); margin-left: 0;
} padding: 10px 75px 10px 0;
.avatar {
position: absolute;
left: var(--default-horizontal-margin);
} }
.collapsed .avatar { .collapsed .avatar {
top: 8px; top: 8px;
} }
.expanded .avatar { .expanded .avatar {
top: 10px; top: 12px;
} }
.collapsed .avatar { .collapsed .avatar {
height: 1.75em; height: 1.75em;
@@ -111,7 +114,7 @@ limitations under the License.
flex: 1; flex: 1;
} }
</style> </style>
<div class$="[[_computeClass(expanded)]]"> <div class$="[[_computeClass(expanded, showAvatar)]]">
<img class="avatar" src$="[[_computeAvatarURL(message.author)]]"> <img class="avatar" src$="[[_computeAvatarURL(message.author)]]">
<div class="contentContainer"> <div class="contentContainer">
<div class="name" id="name">[[message.author.name]]</div> <div class="name" id="name">[[message.author.name]]</div>
@@ -168,6 +171,13 @@ limitations under the License.
value: true, value: true,
reflectToAttribute: true, reflectToAttribute: true,
}, },
showAvatar: Boolean,
},
ready: function() {
app.configReady.then(function(cfg) {
this.showAvatar = cfg && cfg.plugin && cfg.plugin.has_avatars;
}.bind(this));
}, },
_commentsChanged: function(value) { _commentsChanged: function(value) {
@@ -202,8 +212,11 @@ limitations under the License.
this.expanded = false; this.expanded = false;
}, },
_computeClass: function(expanded) { _computeClass: function(expanded, showAvatar) {
return expanded ? 'expanded' : 'collapsed'; var classes = [];
classes.push(expanded ? 'expanded' : 'collapsed');
classes.push(showAvatar ? 'showAvatar' : 'hideAvatar');
return classes.join(' ');
}, },
_computeAvatarURL: function(author) { _computeAvatarURL: function(author) {

View File

@@ -47,6 +47,7 @@ func main() {
http.HandleFunc("/changes/", handleRESTProxy) http.HandleFunc("/changes/", handleRESTProxy)
http.HandleFunc("/accounts/", handleRESTProxy) http.HandleFunc("/accounts/", handleRESTProxy)
http.HandleFunc("/config/", handleRESTProxy)
log.Println("Serving on port", *port) log.Println("Serving on port", *port)
log.Fatal(http.ListenAndServe(*port, &server{})) log.Fatal(http.ListenAndServe(*port, &server{}))
} }