Add an account dropdown menu
So that the user can see which account they're using, switch accounts, and logout. Feature: Issue 3693 Change-Id: I08ff42653f78c4a2c496d1a329d3eb26318ca32d
This commit is contained in:
parent
d44f4af2f2
commit
b07c0d2d6d
121
lib/js/BUCK
121
lib/js/BUCK
@ -89,6 +89,30 @@ bower_component(
|
||||
sha1 = 'f94a3a3d847842c49def41e27da42c7c94f8d7c7',
|
||||
)
|
||||
|
||||
bower_component(
|
||||
name = 'iron-dropdown',
|
||||
package = 'polymerelements/iron-dropdown',
|
||||
version = '1.0.6',
|
||||
deps = [
|
||||
':neon-animation',
|
||||
':iron-behaviors',
|
||||
':iron-overlay-behavior',
|
||||
':iron-resizable-behavior',
|
||||
':polymer',
|
||||
],
|
||||
license = 'polymer',
|
||||
sha1 = 'b54ff404ce5535919979bb4488e4b6ae9146fc5a',
|
||||
)
|
||||
|
||||
bower_component(
|
||||
name = 'iron-resizable-behavior',
|
||||
package = 'polymerelements/iron-resizable-behavior',
|
||||
version = '1.0.2',
|
||||
deps = [':polymer'],
|
||||
license = 'polymer',
|
||||
sha1 = '954e82c70b5412d20e7b4d65195a844bb6dc9a07',
|
||||
)
|
||||
|
||||
bower_component(
|
||||
name = 'iron-input',
|
||||
package = 'polymerelements/iron-input',
|
||||
@ -101,6 +125,103 @@ bower_component(
|
||||
sha1 = '2d3eedf0a26046c0e828b1ce3d5b102ee1d0ab19',
|
||||
)
|
||||
|
||||
bower_component(
|
||||
name = 'iron-behaviors',
|
||||
package = 'polymerelements/iron-behaviors',
|
||||
version = '1.0.11',
|
||||
deps = [
|
||||
':iron-a11y-keys-behavior',
|
||||
':polymer',
|
||||
],
|
||||
license = 'polymer',
|
||||
sha1 = 'e0fcfcd8696381fc78ff62261ba333e5e133f39d',
|
||||
)
|
||||
|
||||
bower_component(
|
||||
name = 'iron-overlay-behavior',
|
||||
package = 'polymerelements/iron-overlay-behavior',
|
||||
version = '1.1.1',
|
||||
deps = [
|
||||
':iron-fit-behavior',
|
||||
':polymer',
|
||||
],
|
||||
license = 'polymer',
|
||||
sha1 = '98d80ea1cbee2631553d4fbc98da6cbb25748a4f',
|
||||
)
|
||||
|
||||
bower_component(
|
||||
name = 'iron-fit-behavior',
|
||||
package = 'polymerelements/iron-fit-behavior',
|
||||
version = '1.0.5',
|
||||
deps = [':polymer'],
|
||||
license = 'polymer',
|
||||
sha1 = 'c0273d22531451a1e64f447971ad16b357a7f7e0',
|
||||
)
|
||||
|
||||
bower_component(
|
||||
name = 'neon-animation',
|
||||
package = 'polymerelements/neon-animation',
|
||||
version = '1.0.8',
|
||||
deps = [
|
||||
':iron-meta',
|
||||
':iron-resizable-behavior',
|
||||
':iron-selector',
|
||||
':paper-styles',
|
||||
':web-animations-js',
|
||||
':polymer'
|
||||
],
|
||||
license = 'polymer',
|
||||
sha1 = 'c5f3700e9259554db14f9dfddb290a42c099d88a',
|
||||
)
|
||||
|
||||
bower_component(
|
||||
name = 'iron-selector',
|
||||
package = 'polymerelements/iron-selector',
|
||||
version = '1.0.8',
|
||||
deps = [':polymer'],
|
||||
license = 'polymer',
|
||||
sha1 = '7559560733882656bf479b620669a1d60c3bda21',
|
||||
)
|
||||
|
||||
bower_component(
|
||||
name = 'paper-styles',
|
||||
package = 'polymerelements/paper-styles',
|
||||
version = '1.0.13',
|
||||
deps = [
|
||||
':font-roboto',
|
||||
':iron-flex-layout',
|
||||
':polymer',
|
||||
],
|
||||
license = 'polymer',
|
||||
sha1 = 'e0bfdadfe10e070f39c16aa784de16734eed25a6',
|
||||
)
|
||||
|
||||
bower_component(
|
||||
name = 'font-roboto',
|
||||
package = 'polymerelements/font-roboto',
|
||||
version = '1.0.1',
|
||||
license = 'polymer',
|
||||
sha1 = '735676217f67221903d6be10cc2fb1b336bed13f',
|
||||
)
|
||||
|
||||
bower_component(
|
||||
name = 'iron-flex-layout',
|
||||
package = 'polymerelements/iron-flex-layout',
|
||||
version = '1.2.2',
|
||||
deps = [':polymer'],
|
||||
license = 'polymer',
|
||||
sha1 = '3ca2fbbf3b56d95677663f78304262dee68753c3',
|
||||
)
|
||||
|
||||
bower_component(
|
||||
name = 'web-animations-js',
|
||||
package = 'web-animations-js',
|
||||
version = '2.1.2',
|
||||
deps = [],
|
||||
license = 'Apache2.0',
|
||||
sha1 = '3e2f4648b770183f577cb5171785cfedcb3a960b',
|
||||
)
|
||||
|
||||
bower_component(
|
||||
name = 'iron-meta',
|
||||
package = 'polymerelements/iron-meta',
|
||||
|
@ -3,10 +3,11 @@ include_defs('//lib/js.defs')
|
||||
bower_components(
|
||||
name = 'polygerrit_components',
|
||||
deps = [
|
||||
'//lib/js:polymer',
|
||||
'//lib/js:page',
|
||||
'//lib/js:iron-ajax',
|
||||
'//lib/js:iron-a11y-keys-behavior',
|
||||
'//lib/js:iron-ajax',
|
||||
'//lib/js:iron-dropdown',
|
||||
'//lib/js:iron-input',
|
||||
'//lib/js:page',
|
||||
'//lib/js:polymer',
|
||||
],
|
||||
)
|
||||
|
@ -15,21 +15,68 @@ limitations under the License.
|
||||
-->
|
||||
|
||||
<link rel="import" href="../bower_components/polymer/polymer.html">
|
||||
<link rel="import" href="../bower_components/iron-dropdown/iron-dropdown.html">
|
||||
|
||||
<dom-module id="gr-account-dropdown">
|
||||
<style>
|
||||
:host {
|
||||
display: inline-block;
|
||||
}
|
||||
.dropdown-trigger {
|
||||
color: #00e;
|
||||
cursor: pointer;
|
||||
}
|
||||
.dropdown-content {
|
||||
background-color: #fff;
|
||||
box-shadow: 0 1px 5px rgba(0, 0, 0, .3);
|
||||
}
|
||||
button {
|
||||
background: none;
|
||||
border: none;
|
||||
font: inherit;
|
||||
padding: .3em 0;
|
||||
}
|
||||
ul {
|
||||
list-style: none;
|
||||
}
|
||||
ul .accountName {
|
||||
font-weight: bold;
|
||||
}
|
||||
li .accountInfo,
|
||||
li a {
|
||||
display: block;
|
||||
padding: .85em 1em;
|
||||
}
|
||||
li a:link,
|
||||
li a:visited {
|
||||
color: #00e;
|
||||
text-decoration: none;
|
||||
}
|
||||
li a:hover {
|
||||
background-color: #6B82D6;
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<style>
|
||||
:not(.loggedIn):not(.loggedOut) .loginButton,
|
||||
:not(.loggedIn):not(.loggedOut) .logoutButton,
|
||||
.loggedIn .loginButton,
|
||||
.loggedOut .logoutButton {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
<div class$="[[_computeContainerClass(account)]]">
|
||||
<a class="loginButton" href="/login" on-tap="_loginTapHandler">Login</a>
|
||||
<a class="logoutButton" href="/logout">Logout</a>
|
||||
</div>
|
||||
<button class="dropdown-trigger" id="trigger"
|
||||
on-tap="_showDropdownTapHandler">[[account.name]]</button>
|
||||
<iron-dropdown id="dropdown"
|
||||
vertical-align="top"
|
||||
vertical-offset="25"
|
||||
horizontal-align="right">
|
||||
<div class="dropdown-content">
|
||||
<ul>
|
||||
<li>
|
||||
<div class="accountInfo">
|
||||
<div class="accountName">[[account.name]]</div>
|
||||
<div>[[account.email]]</div>
|
||||
</div>
|
||||
</li>
|
||||
<li><a href="/switch-account">Switch account</a></li>
|
||||
<li><a href="/logout">Logout</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</iron-dropdown>
|
||||
</template>
|
||||
<script>
|
||||
(function() {
|
||||
@ -42,19 +89,9 @@ limitations under the License.
|
||||
account: Object,
|
||||
},
|
||||
|
||||
_loginTapHandler: function(e) {
|
||||
e.preventDefault();
|
||||
page.show('/login/' + encodeURIComponent(
|
||||
window.location.pathname + window.location.hash));
|
||||
_showDropdownTapHandler: function(e) {
|
||||
this.$.dropdown.open();
|
||||
},
|
||||
|
||||
_computeContainerClass: function(account) {
|
||||
if (Object.keys(account).length == 0) {
|
||||
return 'loggedOut';
|
||||
}
|
||||
return 'loggedIn';
|
||||
},
|
||||
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
@ -72,7 +72,13 @@ limitations under the License.
|
||||
gr-search-bar {
|
||||
width: 500px;
|
||||
}
|
||||
gr-account-dropdown {
|
||||
.accountContainer:not(.loggedIn):not(.loggedOut) .loginButton,
|
||||
.accountContainer:not(.loggedIn):not(.loggedOut) gr-account-dropdown,
|
||||
.accountContainer.loggedIn .loginButton,
|
||||
.accountContainer.loggedOut gr-account-dropdown {
|
||||
display: none;
|
||||
}
|
||||
.accountContainer {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
margin-left: var(--default-horizontal-margin);
|
||||
@ -84,7 +90,10 @@ limitations under the License.
|
||||
<a href="/" class="bigTitle">PolyGerrit</a>
|
||||
<div class="headerRightItems">
|
||||
<gr-search-bar value="{{params.query}}" role="search"></gr-search-bar>
|
||||
<gr-account-dropdown account="[[account]]"></gr-account-dropdown>
|
||||
<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>
|
||||
</header>
|
||||
<main>
|
||||
@ -158,6 +167,8 @@ limitations under the License.
|
||||
|
||||
_accountChanged: function() {
|
||||
this._resolveAccountReady();
|
||||
this.$.accountContainer.classList.toggle('loggedIn', this.loggedIn);
|
||||
this.$.accountContainer.classList.toggle('loggedOut', !this.loggedIn);
|
||||
},
|
||||
|
||||
_configChanged: function(config) {
|
||||
@ -172,6 +183,12 @@ limitations under the License.
|
||||
this.constrained = route == 'gr-change-view';
|
||||
},
|
||||
|
||||
_loginTapHandler: function(e) {
|
||||
e.preventDefault();
|
||||
page.show('/login/' + encodeURIComponent(
|
||||
window.location.pathname + window.location.hash));
|
||||
},
|
||||
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
48
polygerrit-ui/app/test/gr-account-dropdown-test.html
Normal file
48
polygerrit-ui/app/test/gr-account-dropdown-test.html
Normal file
@ -0,0 +1,48 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
Copyright (C) 2015 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-account-dropdown</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="../elements/gr-account-dropdown.html">
|
||||
|
||||
<test-fixture id="basic">
|
||||
<template>
|
||||
<gr-account-dropdown></gr-account-dropdown>
|
||||
</template>
|
||||
</test-fixture>
|
||||
|
||||
<script>
|
||||
suite('gr-account-dropdown tests', function() {
|
||||
var element;
|
||||
|
||||
setup(function() {
|
||||
element = fixture('basic');
|
||||
});
|
||||
|
||||
test('tap on trigger opens menu', function() {
|
||||
assert.isFalse(element.$.dropdown.opened);
|
||||
MockInteractions.tap(element.$.trigger);
|
||||
assert.isTrue(element.$.dropdown.opened);
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
@ -23,7 +23,8 @@ limitations under the License.
|
||||
<script>
|
||||
var testFiles = [];
|
||||
|
||||
[ 'gr-change-list-item-test.html',
|
||||
[ 'gr-account-dropdown-test.html',
|
||||
'gr-change-list-item-test.html',
|
||||
'gr-change-list-test.html',
|
||||
'gr-change-view-test.html',
|
||||
'gr-date-formatter-test.html',
|
||||
|
@ -8,7 +8,8 @@
|
||||
"page": "visionmedia/page.js#1.6.4",
|
||||
"iron-ajax": "PolymerElements/iron-ajax#1.1.0",
|
||||
"iron-input": "PolymerElements/iron-input#1.0.6",
|
||||
"iron-a11y-keys-behavior": "PolymerElements/iron-a11y-keys-behavior#1.1.0"
|
||||
"iron-a11y-keys-behavior": "PolymerElements/iron-a11y-keys-behavior#1.1.0",
|
||||
"iron-dropdown": "PolymerElements/iron-dropdown#1.0.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"web-component-tester": "*",
|
||||
|
@ -19,6 +19,7 @@ import (
|
||||
"compress/gzip"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
@ -32,6 +33,7 @@ var (
|
||||
restHost = flag.String("host", "gerrit-review.googlesource.com", "Host to proxy requests to")
|
||||
port = flag.String("port", ":8081", "Port to serve HTTP requests on")
|
||||
prod = flag.Bool("prod", false, "Serve production assets")
|
||||
loggedIn = flag.Bool("logged_in", false, "Return user info as if the user is logged in")
|
||||
)
|
||||
|
||||
func main() {
|
||||
@ -48,6 +50,7 @@ func main() {
|
||||
http.HandleFunc("/changes/", handleRESTProxy)
|
||||
http.HandleFunc("/accounts/", handleRESTProxy)
|
||||
http.HandleFunc("/config/", handleRESTProxy)
|
||||
http.HandleFunc("/accounts/self/detail", handleAccountDetail)
|
||||
log.Println("Serving on port", *port)
|
||||
log.Fatal(http.ListenAndServe(*port, &server{}))
|
||||
}
|
||||
@ -76,6 +79,28 @@ func handleRESTProxy(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
func handleAccountDetail(w http.ResponseWriter, r *http.Request) {
|
||||
if !*loggedIn {
|
||||
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
fmt.Fprint(w, accountInfo)
|
||||
}
|
||||
|
||||
const accountInfo = `)]}'
|
||||
{
|
||||
"registered_on": "2015-08-31 21:24:17.614000000",
|
||||
"_account_id": 1021482,
|
||||
"name": "Andrew Bonventre",
|
||||
"email": "andybons@chromium.org",
|
||||
"avatars": [
|
||||
{
|
||||
"url": "https://lh4.googleusercontent.com/-1EovlES413I/AAAAAAAAAAI/AAAAAAAAAAA/GQ5-31ULE1Q/s26-p/photo.jpg",
|
||||
"height": 26
|
||||
}
|
||||
]
|
||||
}`
|
||||
|
||||
type gzipResponseWriter struct {
|
||||
io.WriteCloser
|
||||
http.ResponseWriter
|
||||
|
Loading…
Reference in New Issue
Block a user