Add the skeleton of a new UI based on Polymer, PolyGerrit
This is the beginnings of an experimental new non-GWT web UI developed using a modern JS web framework, http://www.polymer-project.org/. It will coexist alongside the GWT UI until it is feature-complete. The functionality of this change is light years from complete, with a full laundry list of things that don't work. This change is simply meant to get the starting work in and continue iteration afterward. The contents of the polygerrit-ui directory started as the full tree of https://github.com/andybons/polygerrit at 219f531, plus a few more local changes since review started. In the future this directory will be pruned, rearranged, and integrated with the Buck build. Change-Id: Ifb6f5429e8031ee049225cdafa244ad1c21bf5b5
This commit is contained in:
parent
1a468f047a
commit
ba69835964
|
@ -0,0 +1 @@
|
|||
* text=auto
|
|
@ -0,0 +1,5 @@
|
|||
node_modules
|
||||
npm-debug.log
|
||||
dist
|
||||
bower_components
|
||||
.tmp
|
|
@ -0,0 +1,11 @@
|
|||
# PolyGerrit
|
||||
|
||||
For local testing against production data...
|
||||
|
||||
```sh
|
||||
npm install
|
||||
bower install
|
||||
go run server.go
|
||||
```
|
||||
|
||||
Then visit http://localhost:8081
|
|
@ -0,0 +1,116 @@
|
|||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<link rel="import" href="../bower_components/polymer/polymer.html">
|
||||
<link rel="import" href="./gr-change-list-view.html">
|
||||
<link rel="import" href="./gr-change-view.html">
|
||||
<link rel="import" href="./gr-diff-view.html">
|
||||
<link rel="import" href="./gr-search-bar.html">
|
||||
|
||||
<dom-module id="gr-app">
|
||||
<template>
|
||||
<style>
|
||||
:host {
|
||||
display: flex;
|
||||
min-height: 100vh;
|
||||
flex-direction: column;
|
||||
}
|
||||
:host[constrained] main {
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
max-width: 980px;
|
||||
}
|
||||
header,
|
||||
footer {
|
||||
background-color: #eee;
|
||||
padding: 20px;
|
||||
}
|
||||
header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
main {
|
||||
flex: 1;
|
||||
padding: 20px 0;
|
||||
}
|
||||
.bigTitle {
|
||||
color: #000;
|
||||
font-size: 24px;
|
||||
text-decoration: none;
|
||||
}
|
||||
.bigTitle:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.searchContainer {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
gr-search-bar {
|
||||
width: 500px;
|
||||
}
|
||||
</style>
|
||||
<header role="banner">
|
||||
<a href="/" class="bigTitle">PolyGerrit</a>
|
||||
<div class="searchContainer">
|
||||
<gr-search-bar value="[[params.query]]" role="search"></gr-search-bar>
|
||||
</div>
|
||||
</header>
|
||||
<main>
|
||||
<template is="dom-if" if="{{_showChangeList}}">
|
||||
<gr-change-list-view params="[[params]]"></gr-change-list-view>
|
||||
</template>
|
||||
<template is="dom-if" if="{{_showChangeView}}" restamp="true">
|
||||
<gr-change-view params="[[params]]"></gr-change-view>
|
||||
</template>
|
||||
<template is="dom-if" if="{{_showDiffView}}" restamp="true">
|
||||
<gr-diff-view params="[[params]]"></gr-diff-view>
|
||||
</template>
|
||||
</main>
|
||||
<footer role="contentinfo">Powered by PolyGerrit</footer>
|
||||
</template>
|
||||
<script>
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-app',
|
||||
|
||||
properties: {
|
||||
constrained: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
reflectToAttribute: true,
|
||||
},
|
||||
params: Object,
|
||||
route: {
|
||||
type: Object,
|
||||
value: {},
|
||||
observer: '_routeChanged',
|
||||
}
|
||||
},
|
||||
|
||||
_routeChanged: function(route) {
|
||||
this.set('_showChangeList', route == 'gr-change-list');
|
||||
this.set('_showChangeView', route == 'gr-change-view');
|
||||
this.set('_showDiffView', route == 'gr-diff-view');
|
||||
this.constrained = route == 'gr-change-view';
|
||||
},
|
||||
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</dom-module>
|
|
@ -0,0 +1,197 @@
|
|||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<link rel="import" href="../bower_components/polymer/polymer.html">
|
||||
<link rel="import" href="./gr-date-formatter.html">
|
||||
|
||||
<dom-module id="gr-change-list-item">
|
||||
<template>
|
||||
<style>
|
||||
:host {
|
||||
display: table-row;
|
||||
}
|
||||
th, td {
|
||||
border-bottom: 1px solid #eee;
|
||||
padding: 2px 5px;
|
||||
vertical-align: top;
|
||||
}
|
||||
th {
|
||||
background: #eee;
|
||||
text-align: left;
|
||||
}
|
||||
a {
|
||||
color: #000;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.positionIndicator {
|
||||
opacity: .1;
|
||||
visibility: hidden;
|
||||
}
|
||||
.avatarImage {
|
||||
border-radius: 50%;
|
||||
height: 16px;
|
||||
vertical-align: -3px;
|
||||
width: 16px;
|
||||
}
|
||||
.u-monospace {
|
||||
font-family: 'Source Code Pro';
|
||||
}
|
||||
.u-green {
|
||||
color: #388E3C;
|
||||
}
|
||||
.u-red {
|
||||
color: #D32F2F;
|
||||
}
|
||||
</style>
|
||||
<template is="dom-if" if="[[header]]">
|
||||
<th></th> <!-- keyboard position indicator -->
|
||||
<th>Subject</th>
|
||||
<th>Status</th>
|
||||
<th>Owner</th>
|
||||
<th>Project</th>
|
||||
<th>Branch</th>
|
||||
<th>Updated</th>
|
||||
<th>Size</th>
|
||||
<th title="Code-Review">CR</th>
|
||||
<th title="Verified">V</th>
|
||||
</template>
|
||||
<template is="dom-if" if="[[!header]]">
|
||||
<td>
|
||||
<span class="positionIndicator">▶</span>
|
||||
</td>
|
||||
<td>
|
||||
<a href$="[[changeURL()]]">[[change.subject]]</a>
|
||||
</td>
|
||||
<td>[[_computeChangeStatusString(change)]]</td>
|
||||
<td>
|
||||
<img class="avatarImage" src$="[[_computeAvatarURL(change.owner)]]">
|
||||
<a href$="[[_computeOwnerLink(change.owner.email)]]"
|
||||
title$="[[_computeOwnerTitle(change.owner)]]">[[change.owner.name]]</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href$="[[_computeProjectURL(change.project)]]">[[change.project]]</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href$="[[_computeProjectBranchURL(change.project, change.branch)]]">[[change.branch]]</a>
|
||||
</td>
|
||||
<td><gr-date-formatter date-str="[[change.updated]]"></gr-date-formatter></td>
|
||||
<td class="u-monospace">
|
||||
<span class="u-green"><span>+</span>[[change.insertions]]</span>,
|
||||
<span class="u-red"><span>-</span>[[change.deletions]]</span>
|
||||
</td>
|
||||
<td title="Code-Review"
|
||||
class$="[[_computeCodeReviewClass(change.labels.Code-Review)]]">[[_computeCodeReviewLabel(change.labels.Code-Review)]]</td>
|
||||
<td title="Verified" class="u-green">[[_computeVerifiedLabel(change.labels.Verified)]]</td>
|
||||
</template>
|
||||
</template>
|
||||
<script>
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-change-list-item',
|
||||
|
||||
properties: {
|
||||
header: {
|
||||
type: Boolean,
|
||||
reflectToAttribute: true,
|
||||
value: false,
|
||||
},
|
||||
selected: {
|
||||
type: Boolean,
|
||||
reflectToAttribute: true,
|
||||
},
|
||||
change: Object,
|
||||
},
|
||||
|
||||
changeURL: function() {
|
||||
if (!this.change) { return ''; }
|
||||
return '/c/' + this.change._number + '/';
|
||||
},
|
||||
|
||||
_computeChangeStatusString: function(change) {
|
||||
if (!change.mergeable) {
|
||||
return 'Merge Conflict';
|
||||
}
|
||||
return '';
|
||||
},
|
||||
|
||||
_computeCodeReviewClass: function(codeReview) {
|
||||
if (!codeReview) { return ''; }
|
||||
if (codeReview.approved) {
|
||||
return 'u-green';
|
||||
}
|
||||
if (codeReview.value == 1) {
|
||||
return 'u-monospace u-green';
|
||||
}
|
||||
if (codeReview.value == -1) {
|
||||
return 'u-monospace u-red';
|
||||
}
|
||||
return '';
|
||||
},
|
||||
|
||||
_computeCodeReviewLabel: function(codeReview) {
|
||||
if (!codeReview) { return ''; }
|
||||
if (codeReview.approved) {
|
||||
return '✓';
|
||||
}
|
||||
if (codeReview.value == 1) {
|
||||
return '+1';
|
||||
}
|
||||
if (codeReview.value == -1) {
|
||||
return '-1';
|
||||
}
|
||||
return '';
|
||||
},
|
||||
|
||||
_computeVerifiedLabel: function(verified) {
|
||||
if (verified && verified.approved) {
|
||||
return '✓';
|
||||
}
|
||||
return ''
|
||||
},
|
||||
|
||||
_computeAvatarURL: function(owner) {
|
||||
if (!owner) { return ''; }
|
||||
return '/accounts/' + owner.email + '/avatar?s=32'
|
||||
},
|
||||
|
||||
_computeOwnerLink: function(email) {
|
||||
if (!email) { return ''; }
|
||||
return '/q/owner:' + encodeURIComponent(email) + '+status:open';
|
||||
},
|
||||
|
||||
_computeOwnerTitle: function(owner) {
|
||||
if (!owner) { return ''; }
|
||||
// TODO: Is this safe from XSS attacks?
|
||||
return owner.name + ' <' + owner.email + '>';
|
||||
},
|
||||
|
||||
_computeProjectURL: function(project) {
|
||||
return '/projects/' + project + ',dashboards/default';
|
||||
},
|
||||
|
||||
_computeProjectBranchURL: function(project, branch) {
|
||||
return '/q/status:open+project:' + project + '+branch:' + branch;
|
||||
},
|
||||
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</dom-module>
|
|
@ -0,0 +1,127 @@
|
|||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<link rel="import" href="../bower_components/polymer/polymer.html">
|
||||
<link rel="import" href="../bower_components/iron-ajax/iron-ajax.html">
|
||||
<link rel="import" href="./gr-change-list.html">
|
||||
|
||||
<dom-module id="gr-change-list-view">
|
||||
<template>
|
||||
<style>
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
gr-change-list {
|
||||
margin: 0 20px;
|
||||
width: calc(100% - 40px);
|
||||
}
|
||||
nav {
|
||||
padding: 10px 0;
|
||||
text-align: center;
|
||||
}
|
||||
nav a {
|
||||
display: inline-block;
|
||||
}
|
||||
nav a:first-of-type {
|
||||
margin-right: 10px;
|
||||
}
|
||||
[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
</style>
|
||||
<iron-ajax
|
||||
auto
|
||||
url="/changes/"
|
||||
params="[[_computeQueryParams(query, offset)]]"
|
||||
json-prefix=")]}'"
|
||||
last-response="{{_changes}}"
|
||||
debounce-duration="300"></iron-ajax>
|
||||
<gr-change-list changes="{{_changes}}"></gr-change-list>
|
||||
<nav>
|
||||
<a href$="[[_computeNavLink(query, offset, -1)]]"
|
||||
hidden$="[[_hidePrevArrow(offset)]]">← Prev</a>
|
||||
<a href$="[[_computeNavLink(query, offset, 1)]]"
|
||||
hidden$="[[_hideNextArrow(_changes.length)]]">Next →</a>
|
||||
</nav>
|
||||
</template>
|
||||
<script>
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
var DEFAULT_NUM_CHANGES = 25;
|
||||
|
||||
Polymer({
|
||||
is: 'gr-change-list-view',
|
||||
|
||||
properties: {
|
||||
/**
|
||||
* URL params passed from the router.
|
||||
*/
|
||||
params: {
|
||||
type: Object,
|
||||
observer: '_paramsChanged',
|
||||
},
|
||||
|
||||
/**
|
||||
* Change objects loaded from the server.
|
||||
*/
|
||||
_changes: Array,
|
||||
},
|
||||
|
||||
_paramsChanged: function(value) {
|
||||
this.query = value.query;
|
||||
this.offset = value.offset || 0;
|
||||
},
|
||||
|
||||
_computeQueryParams: function(query, offset) {
|
||||
var options = Changes.listChangesOptionsToHex(
|
||||
Changes.ListChangesOption.LABELS,
|
||||
Changes.ListChangesOption.DETAILED_ACCOUNTS
|
||||
);
|
||||
var obj = {
|
||||
n: DEFAULT_NUM_CHANGES, // Number of results to return.
|
||||
O: options,
|
||||
S: offset || 0,
|
||||
};
|
||||
if (query && query.length > 0) {
|
||||
obj.q = query;
|
||||
}
|
||||
return obj;
|
||||
},
|
||||
|
||||
_computeNavLink: function(query, offset, direction) {
|
||||
// Offset could be a string when passed from the router.
|
||||
offset = +(offset || 0);
|
||||
var newOffset = Math.max(0, offset + (25 * direction));
|
||||
var href = '/q/' + query;
|
||||
if (newOffset > 0) {
|
||||
href += ',' + newOffset;
|
||||
}
|
||||
return href;
|
||||
},
|
||||
|
||||
_hidePrevArrow: function(offset) {
|
||||
return offset == 0;
|
||||
},
|
||||
|
||||
_hideNextArrow: function(changesLen) {
|
||||
return changesLen < DEFAULT_NUM_CHANGES;
|
||||
},
|
||||
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</dom-module>
|
|
@ -0,0 +1,126 @@
|
|||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<link rel="import" href="../bower_components/polymer/polymer.html">
|
||||
<link rel="import" href="../bower_components/iron-a11y-keys/iron-a11y-keys.html">
|
||||
<link rel="import" href="./gr-change-list-item.html">
|
||||
|
||||
<dom-module id="gr-change-list">
|
||||
<template>
|
||||
<style>
|
||||
:host {
|
||||
display: table;
|
||||
border: 1px solid #eee;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
:host:focus gr-change-list-item[selected]::shadow {
|
||||
background-color: #d8EdF9;
|
||||
}
|
||||
:host gr-change-list-item[selected]::shadow .positionIndicator {
|
||||
visibility: visible;
|
||||
}
|
||||
:host:focus gr-change-list-item[selected]::shadow .positionIndicator {
|
||||
opacity: 1;
|
||||
}
|
||||
</style>
|
||||
|
||||
<iron-a11y-keys
|
||||
target="[[keyTarget]]"
|
||||
keys="j k enter"
|
||||
on-keys-pressed="_handleKey"></iron-a11y-keys>
|
||||
|
||||
<gr-change-list-item header></gr-change-list-item>
|
||||
<template is="dom-repeat" items="{{changes}}" as="change">
|
||||
<gr-change-list-item change="[[change]]"
|
||||
selected="[[_isSelected(index)]]"></gr-change-list-item>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-change-list',
|
||||
|
||||
hostAttributes: {
|
||||
tabindex: 0,
|
||||
},
|
||||
|
||||
properties: {
|
||||
/**
|
||||
* An array of ChangeInfo objects to render.
|
||||
* https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#change-info
|
||||
*/
|
||||
changes: Array,
|
||||
keyTarget: {
|
||||
type: Object,
|
||||
value: function() {
|
||||
return document.body;
|
||||
}
|
||||
},
|
||||
selectedIndex: {
|
||||
type: Number,
|
||||
value: 0,
|
||||
observer: '_selectedIndexChanged',
|
||||
},
|
||||
},
|
||||
|
||||
_isSelected: function(index) {
|
||||
return index == this.selectedIndex;
|
||||
},
|
||||
|
||||
_selectedIndexChanged: function(value) {
|
||||
// Don’t re-render the entire list.
|
||||
var changeEls = this._getNonHeaderListItems();
|
||||
for (var i = 0; i < changeEls.length; i++) {
|
||||
changeEls[i].toggleAttribute('selected', i == value);
|
||||
}
|
||||
},
|
||||
|
||||
_handleKey: function(e) {
|
||||
var len = (this.changes && this.changes.length) || 0;
|
||||
switch(e.detail.combo) {
|
||||
case 'j':
|
||||
if (this.selectedIndex == len - 1) { return; }
|
||||
this.selectedIndex += 1;
|
||||
break;
|
||||
case 'k':
|
||||
if (this.selectedIndex == 0) { return; }
|
||||
this.selectedIndex -= 1;
|
||||
break;
|
||||
case 'enter':
|
||||
page(this._changeURLForIndex(this.selectedIndex));
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_changeURLForIndex: function(index) {
|
||||
var changeEls = this._getNonHeaderListItems();
|
||||
if (index < changeEls.length && changeEls[index]) {
|
||||
return changeEls[index].changeURL();
|
||||
}
|
||||
return '';
|
||||
},
|
||||
|
||||
_getNonHeaderListItems: function() {
|
||||
return this.querySelectorAll('gr-change-list-item:not([header])');
|
||||
},
|
||||
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</dom-module>
|
|
@ -0,0 +1,195 @@
|
|||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<link rel="import" href="../bower_components/polymer/polymer.html">
|
||||
<link rel="import" href="../bower_components/iron-ajax/iron-ajax.html">
|
||||
<link rel="import" href="./gr-date-formatter.html">
|
||||
<link rel="import" href="./gr-file-list.html">
|
||||
<link rel="import" href="./gr-messages-list.html">
|
||||
|
||||
<dom-module id="gr-change-view">
|
||||
<template>
|
||||
<style>
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
.container {
|
||||
margin: 0 20px;
|
||||
}
|
||||
.changeInfo,
|
||||
.summary {
|
||||
margin: 10px 0;
|
||||
padding: 10px 0;
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
td {
|
||||
padding: 2px 5px;
|
||||
vertical-align: top;
|
||||
}
|
||||
.changeInfo-label {
|
||||
font-weight: bold;
|
||||
text-align: right;
|
||||
}
|
||||
.summary {
|
||||
font-family: 'Source Code Pro', Menlo, 'Lucida Console', Monaco, monospace;
|
||||
margin: 10px 0;
|
||||
overflow-x: auto;
|
||||
padding: 10px 0;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
.summary {
|
||||
border-top: 1px solid #ddd;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
</style>
|
||||
<iron-ajax id="detailXHR"
|
||||
url="[[_computeDetailPath(changeNum)]]"
|
||||
params="[[_computeDetailQueryParams()]]"
|
||||
json-prefix=")]}'"
|
||||
last-response="{{change}}"
|
||||
debounce-duration="300"></iron-ajax>
|
||||
<iron-ajax id="commentsXHR"
|
||||
url="[[_computeCommentsPath(changeNum)]]"
|
||||
json-prefix=")]}'"
|
||||
last-response="{{comments}}"
|
||||
debounce-duration="300"></iron-ajax>
|
||||
|
||||
<div class="container">
|
||||
<h2>[[change.subject]]</h2>
|
||||
<div class="changeInfo">
|
||||
<table>
|
||||
<tr>
|
||||
<td class="changeInfo-label">Owner</td>
|
||||
<td>[[change.owner.name]]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="changeInfo-label">Reviewers</td>
|
||||
<td>
|
||||
<template is="dom-repeat"
|
||||
items="[[_computeReviewers(change.labels.Code-Review.all, change.owner)]]"
|
||||
as="reviewer">
|
||||
<div>[[reviewer.name]]</div>
|
||||
</template>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="changeInfo-label">Project</td>
|
||||
<td>[[change.project]]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="changeInfo-label">Branch</td>
|
||||
<td>[[change.branch]]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="changeInfo-label">Topic</td>
|
||||
<td>[[change.topic]]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="changeInfo-label">Strategy</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="changeInfo-label">Updated</td>
|
||||
<td>
|
||||
<gr-date-formatter
|
||||
date-str="[[change.updated]]"></gr-date-formatter>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="summary">[[_computeCurrentRevisionMessage(change)]]</div>
|
||||
<gr-file-list change-num="[[changeNum]]"
|
||||
patch-num="[[_computePatchNum(change.current_revision)]]"
|
||||
revision="[[change.current_revision]]"
|
||||
comments="[[comments]]"></gr-file-list>
|
||||
<gr-messages-list change-num="[[changeNum]]"
|
||||
messages="[[change.messages]]"
|
||||
comments="[[comments]]"></gr-messages-list>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-change-view',
|
||||
|
||||
properties: {
|
||||
/**
|
||||
* URL params passed from the router.
|
||||
*/
|
||||
params: {
|
||||
type: Object,
|
||||
observer: '_paramsChanged',
|
||||
},
|
||||
|
||||
changeNum: Number,
|
||||
},
|
||||
|
||||
_paramsChanged: function(value) {
|
||||
this.changeNum = value.changeNum;
|
||||
if (!this.changeNum) {
|
||||
this.change = null;
|
||||
this.comments = null;
|
||||
return;
|
||||
}
|
||||
this.$.detailXHR.generateRequest();
|
||||
this.$.commentsXHR.generateRequest();
|
||||
},
|
||||
|
||||
_computeDetailPath: function(changeNum) {
|
||||
return '/changes/' + changeNum + '/detail';
|
||||
},
|
||||
|
||||
_computeCommitInfoPath: function(changeNum, commitHash) {
|
||||
return '/changes/' + changeNum + '/revisions/' + commitHash + '/commit';
|
||||
},
|
||||
|
||||
_computeCommentsPath: function(changeNum) {
|
||||
return '/changes/' + changeNum + '/comments';
|
||||
},
|
||||
|
||||
_computePatchNum: function(revision) {
|
||||
return this.change && this.change.revisions[revision]._number;
|
||||
},
|
||||
|
||||
_computeDetailQueryParams: function() {
|
||||
var options = Changes.listChangesOptionsToHex(
|
||||
Changes.ListChangesOption.CURRENT_REVISION,
|
||||
Changes.ListChangesOption.CURRENT_COMMIT,
|
||||
Changes.ListChangesOption.CHANGE_ACTIONS
|
||||
);
|
||||
return { O: options };
|
||||
},
|
||||
|
||||
_computeCurrentRevisionMessage: function(change) {
|
||||
return change &&
|
||||
change.revisions[change.current_revision].commit.message;
|
||||
},
|
||||
|
||||
_computeReviewers: function(reviewers, owner) {
|
||||
if (reviewers.length == 1) { return reviewers; }
|
||||
return reviewers.filter(function(reviewer) {
|
||||
return reviewer._account_id != owner._account_id;
|
||||
});
|
||||
},
|
||||
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</dom-module>
|
|
@ -0,0 +1,90 @@
|
|||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<link rel="import" href="../bower_components/polymer/polymer.html">
|
||||
|
||||
<dom-module id="gr-date-formatter">
|
||||
<template>
|
||||
<style>
|
||||
:host {
|
||||
display: inline;
|
||||
}
|
||||
</style>
|
||||
<span>[[_computeDateStr(dateStr)]]</span>
|
||||
</template>
|
||||
<script>
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
var Duration = {
|
||||
HOUR: 1000 * 60 * 60,
|
||||
DAY: 1000 * 60 * 60 * 24,
|
||||
};
|
||||
|
||||
var ShortMonthNames = [
|
||||
'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct',
|
||||
'Nov', 'Dec'
|
||||
];
|
||||
|
||||
Polymer({
|
||||
is: 'gr-date-formatter',
|
||||
|
||||
properties: {
|
||||
dateStr: {
|
||||
type: String,
|
||||
value: null,
|
||||
notify: true
|
||||
}
|
||||
},
|
||||
|
||||
_computeDateStr: function(dateStr) {
|
||||
return this._dateStr(this._parseDateStr(dateStr), new Date());
|
||||
},
|
||||
|
||||
_parseDateStr: function(dateStr) {
|
||||
if (!dateStr) { return null; }
|
||||
return util.parseDate(dateStr);
|
||||
},
|
||||
|
||||
_dateStr: function(t, now) {
|
||||
if (!t) { return ''; }
|
||||
var diff = now.getTime() - t.getTime();
|
||||
if (diff < Duration.DAY && t.getDay() == now.getDay()) {
|
||||
// Within 24 hours and on the same day:
|
||||
// '2:14 AM'
|
||||
var pm = t.getHours() >= 12;
|
||||
var hours = t.getHours() === 0 ? 12 :
|
||||
pm ? t.getHours() - 12 : t.getHours();
|
||||
var minutes = t.getMinutes() < 10 ? '0' + t.getMinutes() :
|
||||
t.getMinutes();
|
||||
return hours + ':' + minutes + (pm ? ' PM' : ' AM');
|
||||
} else if ((t.getDay() != now.getDay() || diff >= Duration.DAY) &&
|
||||
diff < 180 * Duration.DAY) {
|
||||
// From one to six months:
|
||||
// 'Aug 29'
|
||||
return ShortMonthNames[t.getMonth()] + ' ' + t.getDate();
|
||||
} else if (diff >= 180 * Duration.DAY) {
|
||||
// More than six months:
|
||||
// 'Aug 29, 1997'
|
||||
return ShortMonthNames[t.getMonth()] + ' ' + t.getDate() + ', ' +
|
||||
t.getFullYear();
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</dom-module>
|
|
@ -0,0 +1,273 @@
|
|||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<link rel="import" href="../bower_components/polymer/polymer.html">
|
||||
|
||||
<dom-module id="gr-diff-view">
|
||||
<template>
|
||||
<style>
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
.diffContainer {
|
||||
display: flex;
|
||||
font-family: 'Source Code Pro', monospace;
|
||||
white-space: pre;
|
||||
}
|
||||
.diffNumbers {
|
||||
border-right: 1px solid #eee;
|
||||
color: #aaa;
|
||||
padding: 0 10px;
|
||||
text-align: right;
|
||||
}
|
||||
.diffContent {
|
||||
padding-left: 2px;
|
||||
}
|
||||
.lineNum {
|
||||
cursor: pointer;
|
||||
}
|
||||
.lineNum:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.lightRed {
|
||||
background-color: #fee;
|
||||
}
|
||||
.darkRed,
|
||||
.delete span {
|
||||
background-color: #faa;
|
||||
}
|
||||
.lightGreen {
|
||||
background-color: #efe;
|
||||
}
|
||||
.darkGreen,
|
||||
.insert span {
|
||||
background-color: #9f9;
|
||||
}
|
||||
</style>
|
||||
<iron-ajax id="changeDetailXHR"
|
||||
auto
|
||||
url="[[_computeChangeDetailPath(_changeNum)]]"
|
||||
params="[[_computeChangeDetailQueryParams()]]"
|
||||
json-prefix=")]}'"
|
||||
last-response="{{_change}}"
|
||||
debounce-duration="300"></iron-ajax>
|
||||
<iron-ajax
|
||||
id="diffXHR"
|
||||
url="[[_computeDiffPath(_changeNum, _patchNum, _path)]]"
|
||||
json-prefix=")]}'"
|
||||
on-response="_handleDiffResponse"
|
||||
debounce-duration="300"></iron-ajax>
|
||||
<div class="diffContainer" id="diffContainer">
|
||||
<div class="diffNumbers" id="leftDiffNumbers"></div>
|
||||
<div class="diffContent" id="leftDiffContent"></div>
|
||||
<div class="diffNumbers" id="rightDiffNumbers"></div>
|
||||
<div class="diffContent" id="rightDiffContent"></div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-diff-view',
|
||||
|
||||
properties: {
|
||||
/**
|
||||
* URL params passed from the router.
|
||||
*/
|
||||
params: {
|
||||
type: Object,
|
||||
observer: '_paramsChanged',
|
||||
},
|
||||
_change: Object,
|
||||
_changeNum: String,
|
||||
_basePatchNum: String,
|
||||
_patchNum: String,
|
||||
_path: String,
|
||||
},
|
||||
|
||||
_paramsChanged: function(value) {
|
||||
console.log(value)
|
||||
this._changeNum = value.changeNum;
|
||||
this._patchNum = value.patchNum;
|
||||
this._basePatchNum = value.basePatchNum;
|
||||
this._path = value.path;
|
||||
console.log(this._basePatchNum);
|
||||
if (!this._changeNum) {
|
||||
this._change = null;
|
||||
this._basePatchNum = null;
|
||||
this._patchNum = null;
|
||||
this._path = null;
|
||||
return;
|
||||
}
|
||||
// Assign the params here since a computed binding relying on
|
||||
// `_basePatchNum` won’t fire in the case where it’s not defined.
|
||||
this.$.diffXHR.params = this._diffQueryParams();
|
||||
this.$.diffXHR.generateRequest();
|
||||
},
|
||||
|
||||
_computeChangeDetailPath: function(changeNum) {
|
||||
return '/changes/' + changeNum + '/detail';
|
||||
},
|
||||
|
||||
_computeChangeDetailQueryParams: function() {
|
||||
var options = Changes.listChangesOptionsToHex(
|
||||
Changes.ListChangesOption.ALL_REVISIONS
|
||||
);
|
||||
return { O: options };
|
||||
},
|
||||
|
||||
_computeDiffPath: function(changeNum, patchNum, path) {
|
||||
return '/changes/' + changeNum + '/revisions/' + patchNum + '/files/' +
|
||||
encodeURIComponent(path) + '/diff';
|
||||
},
|
||||
|
||||
_diffQueryParams: function(basePatchNum) {
|
||||
var params = {
|
||||
context: 'ALL',
|
||||
intraline: null
|
||||
};
|
||||
if (!!basePatchNum) {
|
||||
params.base = basePatchNum;
|
||||
}
|
||||
return params;
|
||||
},
|
||||
|
||||
_handleDiffResponse: function(e, req) {
|
||||
var diff = e.detail.response;
|
||||
this._constructDOM(diff);
|
||||
},
|
||||
|
||||
_constructDOM: function(diff) {
|
||||
if (!diff.content) { return; }
|
||||
|
||||
var leftLineNum = 0 + (diff.content.skip || 0);
|
||||
var rightLineNum = leftLineNum;
|
||||
for (var i = 0; i < diff.content.length; i++) {
|
||||
var diffChunk = diff.content[i];
|
||||
if (diffChunk.ab) {
|
||||
for (var j = 0; j < diffChunk.ab.length; j++) {
|
||||
this._addRow(++leftLineNum, ++rightLineNum, diffChunk.ab[j],
|
||||
diffChunk.ab[j]);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (diffChunk.a || diffChunk.b) {
|
||||
var aLen = (diffChunk.a && diffChunk.a.length) || 0;
|
||||
var bLen = (diffChunk.b && diffChunk.b.length) || 0;
|
||||
var maxLen = Math.max(aLen, bLen);
|
||||
for (var j = 0; j < maxLen; j++) {
|
||||
var leftContent;
|
||||
if (diffChunk.a && j < diffChunk.a.length) {
|
||||
leftContent = diffChunk.a[j];
|
||||
leftLineNum++;
|
||||
}
|
||||
var rightContent;
|
||||
if (diffChunk.b && j < diffChunk.b.length) {
|
||||
rightContent = diffChunk.b[j];
|
||||
rightLineNum++;
|
||||
}
|
||||
var leftHighlight;
|
||||
if (diffChunk.edit_a && j < diffChunk.edit_a.length) {
|
||||
leftHighlight = diffChunk.edit_a[j];
|
||||
}
|
||||
var rightHighlight;
|
||||
if (diffChunk.edit_b && j < diffChunk.edit_b.length) {
|
||||
rightHighlight = diffChunk.edit_b[j];
|
||||
}
|
||||
this._addRow(leftLineNum,
|
||||
rightLineNum,
|
||||
leftContent,
|
||||
rightContent,
|
||||
leftHighlight,
|
||||
rightHighlight);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_addRow: function(leftLineNum,
|
||||
rightLineNum,
|
||||
leftContent,
|
||||
rightContent,
|
||||
leftHighlight,
|
||||
rightHighlight) {
|
||||
var leftLineNumEl = document.createElement('div');
|
||||
var rightLineNumEl = document.createElement('div');
|
||||
var leftColEl = document.createElement('div');
|
||||
// These classes are added to account for Polymer’s polyfill behavior.
|
||||
// In order to guarantee sufficient specificity within the CSS rules,
|
||||
// these are added to every element. Since the Polymer DOM utility
|
||||
// functions (which would do this automatically) are not being used for
|
||||
// performance reasons, this is done manually.
|
||||
leftColEl.className = 'style-scope gr-diff-view';
|
||||
var rightColEl = document.createElement('div');
|
||||
rightColEl.className = 'style-scope gr-diff-view';
|
||||
leftLineNumEl.className = 'style-scope gr-diff-view lineNum';
|
||||
rightLineNumEl.className = 'style-scope gr-diff-view lineNum';
|
||||
|
||||
// Ensure that all elements have content so they render at the correct
|
||||
// height.
|
||||
leftLineNumEl.textContent =
|
||||
leftContent != undefined ? leftLineNum : '\n';
|
||||
rightLineNumEl.textContent =
|
||||
rightContent != undefined ? rightLineNum : '\n';
|
||||
leftContent = leftContent || '\n';
|
||||
rightContent = rightContent || '\n';
|
||||
|
||||
var leftHTML;
|
||||
var rightHTML;
|
||||
if (leftContent == rightContent) {
|
||||
leftHTML = leftContent;
|
||||
rightHTML = rightContent;
|
||||
} else {
|
||||
leftHTML = this._highlightedHTML(leftContent, leftHighlight);
|
||||
rightHTML = this._highlightedHTML(rightContent, rightHighlight);
|
||||
}
|
||||
|
||||
// If the html is just the text then it didn't get highlighted.
|
||||
// Use textContent which is faster than innerHTML.
|
||||
if (leftContent == leftHTML) {
|
||||
leftColEl.textContent = leftContent;
|
||||
} else {
|
||||
leftColEl.innerHTML = leftHTML;
|
||||
}
|
||||
if (rightContent == rightHTML) {
|
||||
rightColEl.textContent = rightContent;
|
||||
} else {
|
||||
rightColEl.innerHTML = rightHTML;
|
||||
}
|
||||
|
||||
if (leftContent != rightContent) {
|
||||
leftColEl.classList.add('delete');
|
||||
rightColEl.classList.add('insert');
|
||||
leftColEl.classList.add(leftHighlight ? 'lightRed' : 'darkRed');
|
||||
rightColEl.classList.add(rightHighlight ? 'lightGreen' : 'darkGreen');
|
||||
}
|
||||
this.$.leftDiffNumbers.appendChild(leftLineNumEl);
|
||||
this.$.leftDiffContent.appendChild(leftColEl);
|
||||
this.$.rightDiffNumbers.appendChild(rightLineNumEl);
|
||||
this.$.rightDiffContent.appendChild(rightColEl);
|
||||
},
|
||||
|
||||
_highlightedHTML: function(content, range) {
|
||||
return content;
|
||||
},
|
||||
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</dom-module>
|
|
@ -0,0 +1,129 @@
|
|||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<link rel="import" href="../bower_components/polymer/polymer.html">
|
||||
|
||||
<dom-module id="gr-file-list">
|
||||
<template>
|
||||
<style>
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
.tableContainer {
|
||||
overflow-x: auto;
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
}
|
||||
table a {
|
||||
display: block;
|
||||
}
|
||||
td {
|
||||
padding: 2px 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
th {
|
||||
text-align: left;
|
||||
}
|
||||
.status {
|
||||
width: 20px;
|
||||
}
|
||||
</style>
|
||||
<iron-ajax id="xhr"
|
||||
url="[[_computeFilesURL(changeNum, revision)]]"
|
||||
json-prefix=")]}'"
|
||||
on-response="_handleResponse"
|
||||
debounce-duration="300"></iron-ajax>
|
||||
<div class="tableContainer">
|
||||
<table>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th>Path</th>
|
||||
<th>Stats</th>
|
||||
</tr>
|
||||
<template is="dom-repeat" items="{{files}}" as="file">
|
||||
<tr>
|
||||
<td></td>
|
||||
<td class="status">[[file.status]]</td>
|
||||
<td class="path">
|
||||
<a class="file"
|
||||
href$="[[_computeDiffURL(changeNum, patchNum, file.__path)]]">[[file.__path]]</a>
|
||||
</td>
|
||||
<td>
|
||||
+<span>[[file.lines_inserted]]</span> lines,
|
||||
-<span>[[file.lines_deleted]]</span> lines
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-file-list',
|
||||
|
||||
properties: {
|
||||
patchNum: Number,
|
||||
changeNum: {
|
||||
type: Number,
|
||||
observer: '_changeNumOrRevisionChanged',
|
||||
},
|
||||
revision: {
|
||||
type: String,
|
||||
observer: '_changeNumOrRevisionChanged',
|
||||
},
|
||||
comments: {
|
||||
type: Array,
|
||||
value: [],
|
||||
},
|
||||
},
|
||||
|
||||
_changeNumOrRevisionChanged: function() {
|
||||
if (!!this.changeNum && !!this.revision) {
|
||||
this.$.xhr.generateRequest();
|
||||
}
|
||||
},
|
||||
|
||||
_computeFilesURL: function(changeNum, revision) {
|
||||
return '/changes/' + changeNum + '/revisions/' + revision + '/files';
|
||||
},
|
||||
|
||||
_handleResponse: function(e, req) {
|
||||
var result = e.detail.response;
|
||||
var paths = Object.keys(result).sort();
|
||||
var files = [];
|
||||
for (var i = 0; i < paths.length; i++) {
|
||||
var info = result[paths[i]];
|
||||
info.__path = paths[i];
|
||||
info.lines_inserted = info.lines_inserted || 0;
|
||||
info.lines_deleted = info.lines_deleted || 0;
|
||||
files.push(info)
|
||||
}
|
||||
this.files = files;
|
||||
},
|
||||
|
||||
_computeDiffURL: function(changeNum, patchNum, path) {
|
||||
return '/c/' + changeNum + '/' + patchNum + '/' + path;
|
||||
},
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</dom-module>
|
|
@ -0,0 +1,217 @@
|
|||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<link rel="import" href="../bower_components/polymer/polymer.html">
|
||||
<link rel="import" href="./gr-date-formatter.html">
|
||||
|
||||
<dom-module id="gr-message">
|
||||
<template>
|
||||
<style>
|
||||
:host {
|
||||
border-top: 1px solid #ddd;
|
||||
display: block;
|
||||
position: relative;
|
||||
}
|
||||
:host:not([expanded]) {
|
||||
cursor: pointer;
|
||||
}
|
||||
.avatar {
|
||||
border-radius: 50%;
|
||||
}
|
||||
.collapsed .contentContainer {
|
||||
padding: 10px;
|
||||
padding-right: 60px;
|
||||
white-space: nowrap;
|
||||
overflow-x: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.expanded .contentContainer {
|
||||
padding: 7px 0 10px;
|
||||
}
|
||||
.expanded .contentContainer {
|
||||
margin-left: 45px;
|
||||
}
|
||||
.collapsed .contentContainer {
|
||||
color: #777;
|
||||
margin-left: 35px;
|
||||
}
|
||||
.avatar {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
}
|
||||
.collapsed .avatar {
|
||||
top: 8px;
|
||||
}
|
||||
.expanded .avatar {
|
||||
top: 10px;
|
||||
}
|
||||
.collapsed .avatar {
|
||||
height: 25px;
|
||||
width: 25px;
|
||||
}
|
||||
.expanded .avatar {
|
||||
height: 35px;
|
||||
width: 35px;
|
||||
}
|
||||
.name {
|
||||
font-weight: bold;
|
||||
}
|
||||
.collapsed .name,
|
||||
.collapsed .content,
|
||||
.collapsed .message {
|
||||
display: inline;
|
||||
}
|
||||
.collapsed .comments {
|
||||
display: none;
|
||||
}
|
||||
.collapsed .name,
|
||||
.collapsed gr-date-formatter {
|
||||
color: #000;
|
||||
}
|
||||
.expanded .name {
|
||||
cursor: pointer;
|
||||
}
|
||||
.expanded .message,
|
||||
.expanded .commentMessage {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
gr-date-formatter {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 10px;
|
||||
}
|
||||
.file {
|
||||
border-top: 1px solid #ddd;
|
||||
font-weight: bold;
|
||||
margin: 10px 0 3px;
|
||||
padding: 10px 0 5px;
|
||||
}
|
||||
.commentContainer {
|
||||
display: flex;
|
||||
margin: 5px 0;
|
||||
}
|
||||
.lineNum {
|
||||
margin-right: 10px;
|
||||
min-width: 75px;
|
||||
}
|
||||
.commentMessage {
|
||||
flex: 1;
|
||||
}
|
||||
</style>
|
||||
<div class$="[[_computeClass(expanded)]]">
|
||||
<img class="avatar" src$="[[_computeAvatarURL(message.author)]]">
|
||||
<div class="contentContainer">
|
||||
<div class="name" id="name">[[message.author.name]]</div>
|
||||
<div class="content">
|
||||
<div class="message">[[message.message]]</div>
|
||||
<div class="comments">
|
||||
<template is="dom-repeat" items="{{files}}" as="file">
|
||||
<div class="file">
|
||||
<a href$="[[_computeFileDiffURL(file, changeNum, message._revision_number)]]">[[file]]</a>:
|
||||
</div>
|
||||
<template is="dom-repeat"
|
||||
items="[[_computeCommentsForFile(file)]]" as="comment">
|
||||
<div class="commentContainer">
|
||||
<a class="lineNum"
|
||||
href$="[[_computeDiffLineURL(file, changeNum, message._revision_number, comment)]]">
|
||||
<template is="dom-if" if="[[comment.line]]">
|
||||
Line <span>[[comment.line]]</span>:
|
||||
</template>
|
||||
<template is="dom-if" if="[[!comment.line]]">
|
||||
File comment:
|
||||
</template>
|
||||
</a>
|
||||
<div class="commentMessage">[[comment.message]]</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<gr-date-formatter date-str="[[message.date]]"></gr-date-formatter>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-message',
|
||||
|
||||
listeners: {
|
||||
'tap': '_tapHandler',
|
||||
'name.tap': '_collapseHandler',
|
||||
},
|
||||
|
||||
properties: {
|
||||
changeNum: Number,
|
||||
message: Object,
|
||||
comments: {
|
||||
type: Object,
|
||||
observer: '_commentsChanged',
|
||||
},
|
||||
expanded: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
reflectToAttribute: true,
|
||||
},
|
||||
},
|
||||
|
||||
_commentsChanged: function(value) {
|
||||
this.files = Object.keys(value || {}).sort();
|
||||
this.expanded = this.files.length > 0;
|
||||
},
|
||||
|
||||
_computeFileDiffURL: function(file, changeNum, patchNum) {
|
||||
return '/c/' + changeNum + '/' + patchNum + '/' + file;
|
||||
},
|
||||
|
||||
_computeDiffLineURL: function(file, changeNum, patchNum, comment) {
|
||||
var diffURL = this._computeFileDiffURL(file, changeNum, patchNum);
|
||||
if (comment.line) {
|
||||
diffURL += '#' + comment.line;
|
||||
}
|
||||
return diffURL;
|
||||
},
|
||||
|
||||
_computeCommentsForFile: function(file) {
|
||||
return this.comments[file];
|
||||
},
|
||||
|
||||
_tapHandler: function(e) {
|
||||
if (this.expanded) { return; }
|
||||
this.expanded = true;
|
||||
},
|
||||
|
||||
_collapseHandler: function(e) {
|
||||
if (!this.expanded) { return; }
|
||||
e.stopPropagation();
|
||||
this.expanded = false;
|
||||
},
|
||||
|
||||
_computeClass: function(expanded) {
|
||||
return expanded ? 'expanded' : 'collapsed';
|
||||
},
|
||||
|
||||
_computeAvatarURL: function(author) {
|
||||
if (!author) { return '' }
|
||||
return '/accounts/' + author.email + '/avatar?s=100';
|
||||
},
|
||||
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</dom-module>
|
|
@ -0,0 +1,81 @@
|
|||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<link rel="import" href="../bower_components/polymer/polymer.html">
|
||||
<link rel="import" href="./gr-message.html">
|
||||
|
||||
<dom-module id="gr-messages-list">
|
||||
<template>
|
||||
<style>
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
h3 {
|
||||
margin: 20px 0 5px;
|
||||
}
|
||||
</style>
|
||||
<h3>Messages</h3>
|
||||
<template is="dom-repeat" items="{{messages}}" as="message">
|
||||
<gr-message change-num="[[changeNum]]"
|
||||
message="[[message]]"
|
||||
comments="[[_computeCommentsForMessage(comments, message, index)]]"></gr-message>
|
||||
</template>
|
||||
</template>
|
||||
<script>
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-messages-list',
|
||||
|
||||
properties: {
|
||||
changeNum: Number,
|
||||
messages: {
|
||||
type: Array,
|
||||
value: [],
|
||||
},
|
||||
comments: Object,
|
||||
},
|
||||
|
||||
_computeCommentsForMessage: function(comments, message, index) {
|
||||
var comments = comments || {};
|
||||
var messages = this.messages || [];
|
||||
var msgComments = {};
|
||||
var mDate = util.parseDate(message.date);
|
||||
var nextMDate;
|
||||
if (index < messages.length - 1) {
|
||||
nextMDate = util.parseDate(messages[index + 1].date);
|
||||
}
|
||||
for (var file in comments) {
|
||||
var fileComments = comments[file];
|
||||
for (var i = 0; i < fileComments.length; i++) {
|
||||
var cDate = util.parseDate(fileComments[i].updated);
|
||||
if (cDate >= mDate) {
|
||||
if (nextMDate && cDate >= nextMDate) {
|
||||
continue;
|
||||
}
|
||||
msgComments[file] = msgComments[file] || [];
|
||||
msgComments[file].push(fileComments[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return msgComments;
|
||||
},
|
||||
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</dom-module>
|
|
@ -0,0 +1,92 @@
|
|||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<link rel="import" href="../bower_components/polymer/polymer.html">
|
||||
<link rel="import" href="../bower_components/iron-input/iron-input.html">
|
||||
|
||||
<dom-module id="gr-search-bar">
|
||||
<template>
|
||||
<style>
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
form {
|
||||
display: flex;
|
||||
}
|
||||
input,
|
||||
button {
|
||||
border: 1px solid #aaa;
|
||||
font-family: inherit;
|
||||
font-size: 14px;
|
||||
padding: 2px 5px;
|
||||
}
|
||||
input {
|
||||
flex: 1;
|
||||
border-radius: 2px 0 0 2px;
|
||||
}
|
||||
button {
|
||||
background-color: #f1f2f3;
|
||||
border-radius: 0 2px 2px 0;
|
||||
border-left-width: 0;
|
||||
}
|
||||
</style>
|
||||
<form>
|
||||
<input is="iron-input" id="searchInput" bind-value="{{inputVal}}">
|
||||
<button type="submit" id="searchButton">Search</button>
|
||||
</form>
|
||||
</template>
|
||||
<script>
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-search-bar',
|
||||
|
||||
listeners: {
|
||||
'value-changed': '_valueChangedHandler',
|
||||
'searchInput.keydown': '_inputKeyDownHandler',
|
||||
'searchButton.tap': '_preventDefaultAndNavigateToInputVal',
|
||||
},
|
||||
|
||||
properties: {
|
||||
value: {
|
||||
type: String,
|
||||
value: '',
|
||||
notify: true,
|
||||
}
|
||||
},
|
||||
|
||||
_valueChangedHandler: function(e) {
|
||||
this.inputVal = e.detail.value;
|
||||
},
|
||||
|
||||
_inputKeyDownHandler: function(e) {
|
||||
if (e.keyCode == 13) {
|
||||
// Enter was pressed.
|
||||
this._preventDefaultAndNavigateToInputVal(e);
|
||||
}
|
||||
},
|
||||
|
||||
_preventDefaultAndNavigateToInputVal: function(e) {
|
||||
e.preventDefault();
|
||||
page.show('/q/' + this.inputVal);
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
})();
|
||||
</script>
|
||||
</dom-module>
|
Binary file not shown.
After Width: | Height: | Size: 318 B |
|
@ -0,0 +1,54 @@
|
|||
<!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.
|
||||
-->
|
||||
|
||||
<html lang="en">
|
||||
<meta charset="utf-8">
|
||||
<meta name="description" content="Gerrit Code Review">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>PolyGerrit</title>
|
||||
|
||||
<!-- build:css /styles/main.css -->
|
||||
<link rel="stylesheet" href="/styles/main.css">
|
||||
<!-- endbuild-->
|
||||
|
||||
<!-- build:js /bower_components/webcomponentsjs/webcomponents-lite.min.js -->
|
||||
<script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
|
||||
<!-- endbuild -->
|
||||
|
||||
<!-- Use Shadow DOM where supported.
|
||||
https://www.polymer-project.org/1.0/docs/devguide/settings.html -->
|
||||
<!--<script>
|
||||
window.Polymer = window.Polymer || {};
|
||||
window.Polymer.dom = 'shadow';
|
||||
</script>-->
|
||||
|
||||
<!-- will be replaced with elements/gr-app.vulcanized.html -->
|
||||
<link rel="import" href="/elements/gr-app.html">
|
||||
<!-- endreplace-->
|
||||
|
||||
<body unresolved>
|
||||
<template is="dom-bind" id="app">
|
||||
<gr-app params="{{params}}" route="{{route}}"></gr-app>
|
||||
</template>
|
||||
|
||||
<!-- build:js /scripts/app.js -->
|
||||
<script src="/bower_components/page/page.js"></script>
|
||||
<script src="/scripts/app.js"></script>
|
||||
<script src="/scripts/changes.js"></script>
|
||||
<script src="/scripts/util.js"></script>
|
||||
|
||||
<!-- endbuild-->
|
|
@ -0,0 +1,2 @@
|
|||
User-agent: *
|
||||
Disallow:
|
|
@ -0,0 +1,66 @@
|
|||
// 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.
|
||||
|
||||
(function(document) {
|
||||
'use strict';
|
||||
|
||||
// See https://github.com/Polymer/polymer/issues/1381
|
||||
window.addEventListener('WebComponentsReady', function() {
|
||||
// Middleware
|
||||
function scrollToTop(ctx, next) {
|
||||
document.body.scrollTop = 0;
|
||||
next();
|
||||
}
|
||||
|
||||
// Routes.
|
||||
page('/', function() {
|
||||
page.redirect('/q/status:open');
|
||||
});
|
||||
|
||||
function queryHandler(data) {
|
||||
app.route = 'gr-change-list';
|
||||
app.params = data.params;
|
||||
}
|
||||
|
||||
page('/q/:query,:offset', scrollToTop, queryHandler);
|
||||
page('/q/:query', scrollToTop, queryHandler);
|
||||
|
||||
page(/^\/(\d+)\/?/, scrollToTop, function(ctx) {
|
||||
page.redirect('/c/' + ctx.params[0]);
|
||||
});
|
||||
|
||||
page('/c/:changeNum', scrollToTop, function(data) {
|
||||
app.route = 'gr-change-view';
|
||||
app.params = data.params;
|
||||
});
|
||||
|
||||
page(/^\/c\/(\d+)\/((\d+)(\.\.(\d+))?)\/(.+)/, scrollToTop, function(ctx) {
|
||||
app.route = 'gr-diff-view';
|
||||
var params = {
|
||||
changeNum: ctx.params[0],
|
||||
basePatchNum: ctx.params[2],
|
||||
patchNum: ctx.params[4],
|
||||
path: ctx.params[5]
|
||||
};
|
||||
if (!params.patchNum) {
|
||||
params.patchNum = params.basePatchNum;
|
||||
delete(params.basePatchNum);
|
||||
}
|
||||
app.params = params;
|
||||
});
|
||||
|
||||
page.start();
|
||||
});
|
||||
|
||||
})(document);
|
|
@ -0,0 +1,73 @@
|
|||
// 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.
|
||||
|
||||
'use strict';
|
||||
|
||||
var Changes = Changes || {};
|
||||
|
||||
// Must be kept in sync with the ListChangesOption enum and protobuf.
|
||||
Changes.ListChangesOption = {
|
||||
LABELS: 0,
|
||||
DETAILED_LABELS: 8,
|
||||
|
||||
// Return information on the current patch set of the change.
|
||||
CURRENT_REVISION: 1,
|
||||
ALL_REVISIONS: 2,
|
||||
|
||||
// If revisions are included, parse the commit object.
|
||||
CURRENT_COMMIT: 3,
|
||||
ALL_COMMITS: 4,
|
||||
|
||||
// If a patch set is included, include the files of the patch set.
|
||||
CURRENT_FILES: 5,
|
||||
ALL_FILES: 6,
|
||||
|
||||
// If accounts are included, include detailed account info.
|
||||
DETAILED_ACCOUNTS: 7,
|
||||
|
||||
// Include messages associated with the change.
|
||||
MESSAGES: 9,
|
||||
|
||||
// Include allowed actions client could perform.
|
||||
CURRENT_ACTIONS: 10,
|
||||
|
||||
// Set the reviewed boolean for the caller.
|
||||
REVIEWED: 11,
|
||||
|
||||
// Include download commands for the caller.
|
||||
DOWNLOAD_COMMANDS: 13,
|
||||
|
||||
// Include patch set weblinks.
|
||||
WEB_LINKS: 14,
|
||||
|
||||
// Include consistency check results.
|
||||
CHECK: 15,
|
||||
|
||||
// Include allowed change actions client could perform.
|
||||
CHANGE_ACTIONS: 16,
|
||||
|
||||
// Include a copy of commit messages including review footers.
|
||||
COMMIT_FOOTERS: 17,
|
||||
|
||||
// Include push certificate information along with any patch sets.
|
||||
PUSH_CERTIFICATES: 18
|
||||
};
|
||||
|
||||
Changes.listChangesOptionsToHex = function() {
|
||||
var v = 0;
|
||||
for (var i = 0; i < arguments.length; i++) {
|
||||
v |= 1 << arguments[i];
|
||||
}
|
||||
return v.toString(16);
|
||||
};
|
|
@ -0,0 +1,25 @@
|
|||
// 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.
|
||||
|
||||
'use strict';
|
||||
|
||||
var util = util || {};
|
||||
|
||||
util.parseDate = function(dateStr) {
|
||||
// Timestamps are given in UTC and have the format
|
||||
// "'yyyy-mm-dd hh:mm:ss.fffffffff'" where "'ffffffffff'" represents
|
||||
// nanoseconds.
|
||||
// Munge the date into an ISO 8061 format and parse that.
|
||||
return new Date(dateStr.replace(' ', 'T') + 'Z');
|
||||
};
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
@import "//fonts.googleapis.com/css?family=Open+Sans:400,700";
|
||||
@import "//fonts.googleapis.com/css?family=Source+Code+Pro";
|
||||
|
||||
*,
|
||||
*::after,
|
||||
*::before {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
transition: none; /* Override the default Polymer fade-in. */
|
||||
}
|
||||
body {
|
||||
font: 14px 'Open Sans', sans-serif;
|
||||
}
|
|
@ -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-app</title>
|
||||
|
||||
<script src="../../bower_components/webcomponentsjs/webcomponents.min.js"></script>
|
||||
<script src="../../bower_components/web-component-tester/browser.js"></script>
|
||||
<script src="../../bower_components/test-fixture/test-fixture-mocha.js"></script>
|
||||
<link rel="import" href="../../bower_components/test-fixture/test-fixture.html">
|
||||
|
||||
<!-- Step 1: import the element to test -->
|
||||
<link rel="import" href="../elements/gr-app.html">
|
||||
|
||||
<test-fixture id="basic">
|
||||
<template>
|
||||
<gr-app></gr-app>
|
||||
</template>
|
||||
</test-fixture>
|
||||
|
||||
<script>
|
||||
suite('gr-app tests', function() {
|
||||
var element;
|
||||
|
||||
setup(function() {
|
||||
element = fixture('basic');
|
||||
});
|
||||
|
||||
test('', function() {
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,89 @@
|
|||
<!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-change-list-item</title>
|
||||
|
||||
<script src="../../bower_components/webcomponentsjs/webcomponents.min.js"></script>
|
||||
<script src="../../bower_components/web-component-tester/browser.js"></script>
|
||||
<script src="../../bower_components/test-fixture/test-fixture-mocha.js"></script>
|
||||
<link rel="import" href="../../bower_components/test-fixture/test-fixture.html">
|
||||
|
||||
<link rel="import" href="../elements/gr-change-list-item.html">
|
||||
|
||||
<test-fixture id="basic">
|
||||
<template>
|
||||
<gr-change-list-item></gr-change-list-item>
|
||||
</template>
|
||||
</test-fixture>
|
||||
|
||||
<script>
|
||||
suite('gr-change-list-item tests', function() {
|
||||
var element;
|
||||
|
||||
setup(function() {
|
||||
element = fixture('basic');
|
||||
});
|
||||
|
||||
test('computed fields', function() {
|
||||
assert.equal(element._computeChangeStatusString({mergeable: true}), '');
|
||||
assert.equal(element._computeChangeStatusString({mergeable: false}),
|
||||
'Merge Conflict');
|
||||
|
||||
assert.equal(element._computeCodeReviewClass(), '');
|
||||
assert.equal(element._computeCodeReviewClass({}), '');
|
||||
assert.equal(element._computeCodeReviewClass({approved: true, value: 1}),
|
||||
'u-green');
|
||||
assert.equal(element._computeCodeReviewClass({value: 1}),
|
||||
'u-monospace u-green');
|
||||
assert.equal(element._computeCodeReviewClass({value: -1}),
|
||||
'u-monospace u-red');
|
||||
|
||||
assert.equal(element._computeCodeReviewLabel(), '');
|
||||
assert.equal(element._computeCodeReviewLabel({}), '');
|
||||
assert.equal(element._computeCodeReviewLabel({approved: true, value: 1}),
|
||||
'✓');
|
||||
assert.equal(element._computeCodeReviewLabel({value: 1}), '+1');
|
||||
assert.equal(element._computeCodeReviewLabel({value: -1}), '-1');
|
||||
|
||||
assert.equal(element._computeVerifiedLabel(), '');
|
||||
assert.equal(element._computeVerifiedLabel({}), '');
|
||||
assert.equal(element._computeVerifiedLabel({approved: true}), '✓');
|
||||
|
||||
|
||||
assert.equal(element._computeOwnerLink('andybons+gerrit@gmail.com'),
|
||||
'/q/owner:andybons%2Bgerrit%40gmail.com+status:open');
|
||||
|
||||
assert.equal(element._computeOwnerTitle(
|
||||
{
|
||||
name: 'Andrew Bonventre',
|
||||
email: 'andybons+gerrit@gmail.com'
|
||||
}),
|
||||
'Andrew Bonventre <andybons+gerrit@gmail.com>');
|
||||
|
||||
// TODO(andybons): _computeProjectURL once it's not a constant.
|
||||
|
||||
assert.equal(element._computeProjectBranchURL(
|
||||
'combustible-stuff', 'lemons'),
|
||||
'/q/status:open+project:combustible-stuff+branch:lemons');
|
||||
|
||||
element.change = { _number: 42 };
|
||||
assert.equal(element.changeURL(), '/c/42/');
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,74 @@
|
|||
<!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-change-list</title>
|
||||
|
||||
<script src="../../bower_components/webcomponentsjs/webcomponents.min.js"></script>
|
||||
<script src="../../bower_components/web-component-tester/browser.js"></script>
|
||||
<script src="../../bower_components/test-fixture/test-fixture-mocha.js"></script>
|
||||
|
||||
<link rel="import" href="../../bower_components/iron-test-helpers/iron-test-helpers.html">
|
||||
<link rel="import" href="../../bower_components/test-fixture/test-fixture.html">
|
||||
<link rel="import" href="../elements/gr-change-list.html">
|
||||
|
||||
<test-fixture id="basic">
|
||||
<template>
|
||||
<gr-change-list></gr-change-list>
|
||||
</template>
|
||||
</test-fixture>
|
||||
|
||||
<script>
|
||||
suite('gr-change-list tests', function() {
|
||||
var changeList;
|
||||
|
||||
setup(function() {
|
||||
changeList = fixture('basic');
|
||||
});
|
||||
|
||||
test('keyboard shortcuts', function() {
|
||||
changeList.changes = [
|
||||
{_number: 0},
|
||||
{_number: 1},
|
||||
{_number: 2},
|
||||
];
|
||||
flushAsynchronousOperations();
|
||||
var changeListItems =
|
||||
changeList.querySelectorAll('gr-change-list-item:not([header])');
|
||||
assert.equal(changeListItems.length, 3);
|
||||
assert.equal(changeList.selectedIndex, 0);
|
||||
|
||||
MockInteractions.pressAndReleaseKeyOn(changeList, 74); // 'j'
|
||||
flushAsynchronousOperations();
|
||||
assert.equal(changeList.selectedIndex, 1);
|
||||
MockInteractions.pressAndReleaseKeyOn(changeList, 74); // 'j'
|
||||
flushAsynchronousOperations();
|
||||
assert.equal(changeList.selectedIndex, 2);
|
||||
MockInteractions.pressAndReleaseKeyOn(changeList, 75); // 'k'
|
||||
flushAsynchronousOperations();
|
||||
assert.equal(changeList.selectedIndex, 1);
|
||||
MockInteractions.pressAndReleaseKeyOn(changeList, 75); // 'k'
|
||||
flushAsynchronousOperations();
|
||||
MockInteractions.pressAndReleaseKeyOn(changeList, 75); // 'k'
|
||||
flushAsynchronousOperations();
|
||||
MockInteractions.pressAndReleaseKeyOn(changeList, 75); // 'k'
|
||||
flushAsynchronousOperations();
|
||||
assert.equal(changeList.selectedIndex, 0);
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
|
@ -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-change-list-view</title>
|
||||
|
||||
<script src="../../bower_components/webcomponentsjs/webcomponents.min.js"></script>
|
||||
<script src="../../bower_components/web-component-tester/browser.js"></script>
|
||||
<script src="../../bower_components/test-fixture/test-fixture-mocha.js"></script>
|
||||
<link rel="import" href="../../bower_components/test-fixture/test-fixture.html">
|
||||
|
||||
<!-- Step 1: import the element to test -->
|
||||
<link rel="import" href="../elements/gr-change-list-view.html">
|
||||
|
||||
<test-fixture id="basic">
|
||||
<template>
|
||||
<gr-change-list-view></gr-change-list-view>
|
||||
</template>
|
||||
</test-fixture>
|
||||
|
||||
<script>
|
||||
suite('gr-change-list-view tests', function() {
|
||||
var element;
|
||||
|
||||
setup(function() {
|
||||
element = fixture('basic');
|
||||
});
|
||||
|
||||
test('', function() {
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,49 @@
|
|||
<!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-change-view</title>
|
||||
|
||||
<script src="../../bower_components/webcomponentsjs/webcomponents.min.js"></script>
|
||||
<script src="../../bower_components/web-component-tester/browser.js"></script>
|
||||
<script src="../../bower_components/test-fixture/test-fixture-mocha.js"></script>
|
||||
<script src="../scripts/changes.js"></script>
|
||||
<link rel="import" href="../../bower_components/test-fixture/test-fixture.html">
|
||||
|
||||
<!-- Step 1: import the element to test -->
|
||||
<link rel="import" href="../elements/gr-change-view.html">
|
||||
|
||||
<test-fixture id="basic">
|
||||
<template>
|
||||
<gr-change-view></gr-change-view>
|
||||
</template>
|
||||
</test-fixture>
|
||||
|
||||
<script>
|
||||
suite('gr-change-view tests', function() {
|
||||
var element;
|
||||
|
||||
setup(function() {
|
||||
element = fixture('basic');
|
||||
});
|
||||
|
||||
test('', function() {
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,83 @@
|
|||
<!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-date-formatter</title>
|
||||
|
||||
<script src="../../bower_components/webcomponentsjs/webcomponents.min.js"></script>
|
||||
<script src="../../bower_components/web-component-tester/browser.js"></script>
|
||||
<script src="../../bower_components/test-fixture/test-fixture-mocha.js"></script>
|
||||
<script src="../scripts/util.js"></script>
|
||||
<link rel="import" href="../../bower_components/test-fixture/test-fixture.html">
|
||||
|
||||
<link rel="import" href="../elements/gr-date-formatter.html">
|
||||
|
||||
<test-fixture id="basic">
|
||||
<template>
|
||||
<gr-date-formatter date-str="2015-09-24 23:30:17.033000000"></gr-date-formatter>
|
||||
</template>
|
||||
</test-fixture>
|
||||
|
||||
<script>
|
||||
suite('gr-date-formatter tests', function() {
|
||||
var element;
|
||||
|
||||
setup(function() {
|
||||
element = fixture('basic');
|
||||
});
|
||||
|
||||
test('date is parsed correctly', function() {
|
||||
assert.notOk((new Date('foo')).valueOf());
|
||||
var d = element._parseDateStr(element.getAttribute('date-str'));
|
||||
assert.isAbove(d.valueOf(), 0);
|
||||
});
|
||||
|
||||
function normalizedDate(dateStr) {
|
||||
var d = new Date(dateStr);
|
||||
d.setMinutes(d.getMinutes() + d.getTimezoneOffset());
|
||||
return d;
|
||||
}
|
||||
|
||||
function testDates(nowStr, dateStr, expected) {
|
||||
var now = normalizedDate(nowStr);
|
||||
var t = normalizedDate(dateStr);
|
||||
assert.equal(element._dateStr(t, now), expected);
|
||||
}
|
||||
|
||||
test('dates strings are correct', function() {
|
||||
// Within 24 hours on same day.
|
||||
testDates('2015-07-29T20:34:00.000Z',
|
||||
'2015-07-29T15:34:00.000Z',
|
||||
'3:34 PM');
|
||||
|
||||
// Within 24 hours on different days.
|
||||
testDates('2015-07-29T03:34:00.000Z',
|
||||
'2015-07-28T20:25:00.000Z',
|
||||
'Jul 28');
|
||||
|
||||
// More than 24 hours. Less than six months.
|
||||
testDates('2015-07-29T20:34:00.000Z',
|
||||
'2015-06-15T03:25:00.000Z',
|
||||
'Jun 15');
|
||||
|
||||
// More than six months.
|
||||
testDates('2015-09-15T20:34:00.000Z',
|
||||
'2015-01-15T03:25:00.000Z',
|
||||
'Jan 15, 2015');
|
||||
});
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,47 @@
|
|||
<!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-diff</title>
|
||||
|
||||
<script src="../../bower_components/webcomponentsjs/webcomponents.min.js"></script>
|
||||
<script src="../../bower_components/web-component-tester/browser.js"></script>
|
||||
<script src="../../bower_components/test-fixture/test-fixture-mocha.js"></script>
|
||||
<link rel="import" href="../../bower_components/test-fixture/test-fixture.html">
|
||||
|
||||
<link rel="import" href="../elements/gr-diff-view.html">
|
||||
|
||||
<test-fixture id="basic">
|
||||
<template>
|
||||
<gr-diff></gr-diff>
|
||||
</template>
|
||||
</test-fixture>
|
||||
|
||||
<script>
|
||||
suite('gr-diff-view tests', function() {
|
||||
var element;
|
||||
|
||||
setup(function() {
|
||||
element = fixture('basic');
|
||||
});
|
||||
|
||||
test('', function() {
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,47 @@
|
|||
<!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-file-list</title>
|
||||
|
||||
<script src="../../bower_components/webcomponentsjs/webcomponents.min.js"></script>
|
||||
<script src="../../bower_components/web-component-tester/browser.js"></script>
|
||||
<script src="../../bower_components/test-fixture/test-fixture-mocha.js"></script>
|
||||
<link rel="import" href="../../bower_components/test-fixture/test-fixture.html">
|
||||
|
||||
<link rel="import" href="../elements/gr-file-list.html">
|
||||
|
||||
<test-fixture id="basic">
|
||||
<template>
|
||||
<gr-file-list></gr-file-list>
|
||||
</template>
|
||||
</test-fixture>
|
||||
|
||||
<script>
|
||||
suite('gr-file-list tests', function() {
|
||||
var element;
|
||||
|
||||
setup(function() {
|
||||
element = fixture('basic');
|
||||
});
|
||||
|
||||
test('', function() {
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
|
@ -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-message</title>
|
||||
|
||||
<script src="../../bower_components/webcomponentsjs/webcomponents.min.js"></script>
|
||||
<script src="../../bower_components/web-component-tester/browser.js"></script>
|
||||
<script src="../../bower_components/test-fixture/test-fixture-mocha.js"></script>
|
||||
<link rel="import" href="../../bower_components/test-fixture/test-fixture.html">
|
||||
|
||||
<!-- Step 1: import the element to test -->
|
||||
<link rel="import" href="../elements/gr-message.html">
|
||||
|
||||
<test-fixture id="basic">
|
||||
<template>
|
||||
<gr-message></gr-message>
|
||||
</template>
|
||||
</test-fixture>
|
||||
|
||||
<script>
|
||||
suite('gr-message tests', function() {
|
||||
var element;
|
||||
|
||||
setup(function() {
|
||||
element = fixture('basic');
|
||||
});
|
||||
|
||||
test('', function() {
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
|
@ -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-messages-list</title>
|
||||
|
||||
<script src="../../bower_components/webcomponentsjs/webcomponents.min.js"></script>
|
||||
<script src="../../bower_components/web-component-tester/browser.js"></script>
|
||||
<script src="../../bower_components/test-fixture/test-fixture-mocha.js"></script>
|
||||
<link rel="import" href="../../bower_components/test-fixture/test-fixture.html">
|
||||
|
||||
<!-- Step 1: import the element to test -->
|
||||
<link rel="import" href="../elements/gr-messages-list.html">
|
||||
|
||||
<test-fixture id="basic">
|
||||
<template>
|
||||
<gr-messages-list></gr-messages-list>
|
||||
</template>
|
||||
</test-fixture>
|
||||
|
||||
<script>
|
||||
suite('gr-messages-list tests', function() {
|
||||
var element;
|
||||
|
||||
setup(function() {
|
||||
element = fixture('basic');
|
||||
});
|
||||
|
||||
test('', function() {
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,47 @@
|
|||
<!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-search-bar</title>
|
||||
|
||||
<script src="../../bower_components/webcomponentsjs/webcomponents.min.js"></script>
|
||||
<script src="../../bower_components/web-component-tester/browser.js"></script>
|
||||
<script src="../../bower_components/test-fixture/test-fixture-mocha.js"></script>
|
||||
<link rel="import" href="../../bower_components/test-fixture/test-fixture.html">
|
||||
|
||||
<link rel="import" href="../elements/gr-search-bar.html">
|
||||
|
||||
<test-fixture id="basic">
|
||||
<template>
|
||||
<search-bar></search-bar>
|
||||
</template>
|
||||
</test-fixture>
|
||||
|
||||
<script>
|
||||
suite('gr-search-bar tests', function() {
|
||||
var element;
|
||||
|
||||
setup(function() {
|
||||
element = fixture('basic');
|
||||
});
|
||||
|
||||
test('', function() {
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,36 @@
|
|||
<!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>Elements Test Runner</title>
|
||||
<meta charset="utf-8">
|
||||
<script src="../../bower_components/webcomponentsjs/webcomponents.min.js"></script>
|
||||
<script src="../../bower_components/web-component-tester/browser.js"></script>
|
||||
<script>
|
||||
WCT.loadSuites([
|
||||
'gr-change-list-test.html',
|
||||
'gr-search-bar-test.html',
|
||||
'gr-date-formatter-test.html',
|
||||
'gr-diff-view-test.html',
|
||||
'gr-app-test.html',
|
||||
'gr-change-view-test.html',
|
||||
'gr-change-list-item-test.html',
|
||||
'gr-change-list-view-test.html',
|
||||
'gr-file-list-test.html',
|
||||
'gr-messages-list-test.html',
|
||||
'gr-message-test.html']);
|
||||
</script>
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"name": "polygerrit",
|
||||
"version": "0.0.0",
|
||||
"authors": [
|
||||
"Andrew Bonventre <andybons@google.com>"
|
||||
],
|
||||
"description": "Gerrit UI in Polymer",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"polymer": "Polymer/polymer#^1.1",
|
||||
"page": "visionmedia/page.js#~1.6",
|
||||
"iron-ajax": "PolymerElements/iron-ajax#~1.0",
|
||||
"iron-a11y-keys": "PolymerElements/iron-a11y-keys#~1.0",
|
||||
"iron-input": "PolymerElements/iron-input#~1.0",
|
||||
"iron-test-helpers": "PolymerElements/iron-test-helpers#~1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"web-component-tester": "*",
|
||||
"test-fixture": "PolymerElements/test-fixture#^1.0.0"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,174 @@
|
|||
// 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.
|
||||
|
||||
'use strict';
|
||||
|
||||
// Include Gulp & tools we'll use
|
||||
var gulp = require('gulp');
|
||||
var $ = require('gulp-load-plugins')();
|
||||
var del = require('del');
|
||||
var runSequence = require('run-sequence');
|
||||
var merge = require('merge-stream');
|
||||
var path = require('path');
|
||||
var historyApiFallback = require('connect-history-api-fallback');
|
||||
|
||||
var AUTOPREFIXER_BROWSERS = [
|
||||
'ie >= 10',
|
||||
'ie_mob >= 10',
|
||||
'ff >= 30',
|
||||
'chrome >= 34',
|
||||
'safari >= 7',
|
||||
'opera >= 23',
|
||||
'ios >= 7',
|
||||
'android >= 4.4',
|
||||
'bb >= 10'
|
||||
];
|
||||
|
||||
var styleTask = function (stylesPath, srcs) {
|
||||
return gulp.src(srcs.map(function(src) {
|
||||
return path.join('app', stylesPath, src);
|
||||
}))
|
||||
.pipe($.changed(stylesPath, {extension: '.css'}))
|
||||
.pipe($.autoprefixer(AUTOPREFIXER_BROWSERS))
|
||||
.pipe(gulp.dest('.tmp/' + stylesPath))
|
||||
.pipe($.cssmin())
|
||||
.pipe(gulp.dest('dist/' + stylesPath))
|
||||
.pipe($.size({title: stylesPath}));
|
||||
};
|
||||
|
||||
var imageOptimizeTask = function (src, dest) {
|
||||
return gulp.src(src)
|
||||
.pipe($.cache($.imagemin({
|
||||
progressive: true,
|
||||
interlaced: true
|
||||
})))
|
||||
.pipe(gulp.dest(dest))
|
||||
.pipe($.size({title: 'images'}));
|
||||
};
|
||||
|
||||
var optimizeHtmlTask = function (src, dest) {
|
||||
var assets = $.useref.assets({searchPath: ['.tmp', 'app', 'dist']});
|
||||
|
||||
return gulp.src(src)
|
||||
// Replace path for vulcanized assets
|
||||
.pipe($.if('*.html', $.replace('elements/gr-app.html', 'elements/gr-app.vulcanized.html')))
|
||||
.pipe(assets)
|
||||
// Concatenate and minify JavaScript
|
||||
.pipe($.if('*.js', $.uglify({preserveComments: 'some'})))
|
||||
// Concatenate and minify styles
|
||||
// In case you are still using useref build blocks
|
||||
.pipe($.if('*.css', $.cssmin()))
|
||||
.pipe(assets.restore())
|
||||
.pipe($.useref())
|
||||
// Minify any HTML
|
||||
.pipe($.if('*.html', $.minifyHtml({
|
||||
quotes: true,
|
||||
empty: true,
|
||||
spare: true
|
||||
})))
|
||||
// Output files
|
||||
.pipe(gulp.dest(dest))
|
||||
.pipe($.size({title: 'html'}));
|
||||
};
|
||||
|
||||
// Compile and automatically prefix stylesheets
|
||||
gulp.task('styles', function () {
|
||||
return styleTask('styles', ['**/*.css']);
|
||||
});
|
||||
|
||||
gulp.task('elements', function () {
|
||||
return styleTask('elements', ['**/*.css']);
|
||||
});
|
||||
|
||||
// Optimize images
|
||||
gulp.task('images', function () {
|
||||
return imageOptimizeTask('app/images/**/*', 'dist/images');
|
||||
});
|
||||
|
||||
// Copy all files at the root level (app)
|
||||
gulp.task('copy', function () {
|
||||
var app = gulp.src([
|
||||
'app/*',
|
||||
'!app/test'
|
||||
], {
|
||||
dot: true
|
||||
}).pipe(gulp.dest('dist'));
|
||||
|
||||
var bower = gulp.src([
|
||||
'bower_components/**/*'
|
||||
]).pipe(gulp.dest('dist/bower_components'));
|
||||
|
||||
var elements = gulp.src(['app/elements/**/*.html',
|
||||
'app/elements/**/*.css',
|
||||
'app/elements/**/*.js'])
|
||||
.pipe(gulp.dest('dist/elements'));
|
||||
|
||||
var vulcanized = gulp.src(['app/elements/gr-app.html'])
|
||||
.pipe($.rename('gr-app.vulcanized.html'))
|
||||
.pipe(gulp.dest('dist/elements'));
|
||||
|
||||
return merge(app, bower, elements, vulcanized)
|
||||
.pipe($.size({title: 'copy'}));
|
||||
});
|
||||
|
||||
// Copy web fonts to dist
|
||||
gulp.task('fonts', function () {
|
||||
return gulp.src(['app/fonts/**'])
|
||||
.pipe(gulp.dest('dist/fonts'))
|
||||
.pipe($.size({title: 'fonts'}));
|
||||
});
|
||||
|
||||
// Scan your HTML for assets & optimize them
|
||||
gulp.task('html', function () {
|
||||
return optimizeHtmlTask(
|
||||
['app/**/*.html', '!app/{elements,test}/**/*.html'],
|
||||
'dist');
|
||||
});
|
||||
|
||||
// Vulcanize granular configuration.
|
||||
gulp.task('vulcanize', function () {
|
||||
var DEST_DIR = 'dist/elements';
|
||||
return gulp.src('dist/elements/gr-app.vulcanized.html')
|
||||
.pipe($.vulcanize({
|
||||
stripComments: true,
|
||||
inlineCss: true,
|
||||
inlineScripts: true
|
||||
}))
|
||||
.pipe(gulp.dest(DEST_DIR))
|
||||
.pipe($.size({title: 'vulcanize'}));
|
||||
});
|
||||
|
||||
// Clean output directory
|
||||
gulp.task('clean', function (cb) {
|
||||
del(['.tmp', 'dist'], cb);
|
||||
});
|
||||
|
||||
|
||||
// Build production files, the default task
|
||||
gulp.task('default', ['clean'], function (cb) {
|
||||
// Uncomment 'cache-config' if you are going to use service workers.
|
||||
runSequence(
|
||||
['copy', 'styles'],
|
||||
'elements',
|
||||
['images', 'fonts', 'html'],
|
||||
'vulcanize', // 'cache-config',
|
||||
cb);
|
||||
});
|
||||
|
||||
// Load tasks for web-component-tester
|
||||
// Adds tasks for `gulp test:local` and `gulp test:remote`
|
||||
require('web-component-tester').gulp.init(gulp);
|
||||
|
||||
// Load custom tasks from the `tasks` directory
|
||||
try { require('require-dir')('tasks'); } catch (err) {}
|
|
@ -0,0 +1,39 @@
|
|||
{
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"browser-sync": "^2.7.7",
|
||||
"connect-history-api-fallback": "^1.1.0",
|
||||
"del": "^1.1.1",
|
||||
"gulp": "^3.8.5",
|
||||
"gulp-autoprefixer": "^2.1.0",
|
||||
"gulp-cache": "^0.2.8",
|
||||
"gulp-changed": "^1.0.0",
|
||||
"gulp-cssmin": "^0.1.7",
|
||||
"gulp-flatten": "0.0.4",
|
||||
"gulp-if": "^1.2.1",
|
||||
"gulp-imagemin": "^2.2.1",
|
||||
"gulp-jshint": "^1.6.3",
|
||||
"gulp-load-plugins": "^0.10.0",
|
||||
"gulp-minify-html": "^1.0.2",
|
||||
"gulp-rename": "^1.2.0",
|
||||
"gulp-replace": "^0.5.3",
|
||||
"gulp-size": "^1.0.0",
|
||||
"gulp-uglify": "^1.2.0",
|
||||
"gulp-useref": "^1.1.2",
|
||||
"gulp-vulcanize": "^6.0.0",
|
||||
"jshint-stylish": "^2.0.0",
|
||||
"merge-stream": "^0.1.7",
|
||||
"opn": "^1.0.0",
|
||||
"require-dir": "^0.3.0",
|
||||
"run-sequence": "^1.0.2",
|
||||
"vulcanize": ">= 1.4.2",
|
||||
"web-component-tester": "^3.1.3"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "gulp test:local",
|
||||
"start": "gulp serve"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"compress/gzip"
|
||||
"errors"
|
||||
"flag"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
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")
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
if *prod {
|
||||
http.Handle("/", http.FileServer(http.Dir("dist")))
|
||||
} else {
|
||||
http.Handle("/bower_components/",
|
||||
http.StripPrefix("/bower_components/", http.FileServer(http.Dir("bower_components"))))
|
||||
http.Handle("/", http.FileServer(http.Dir("app")))
|
||||
}
|
||||
|
||||
http.HandleFunc("/changes/", handleRESTProxy)
|
||||
http.HandleFunc("/accounts/", handleRESTProxy)
|
||||
log.Println("Serving on port", *port)
|
||||
log.Fatal(http.ListenAndServe(*port, &server{}))
|
||||
}
|
||||
|
||||
func handleRESTProxy(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
req := &http.Request{
|
||||
Method: "GET",
|
||||
URL: &url.URL{
|
||||
Scheme: "https",
|
||||
Host: *restHost,
|
||||
Opaque: r.URL.EscapedPath(),
|
||||
RawQuery: r.URL.RawQuery,
|
||||
},
|
||||
}
|
||||
res, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer res.Body.Close()
|
||||
if _, err := io.Copy(w, res.Body); err != nil {
|
||||
log.Println("Error copying response to ResponseWriter:", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
type gzipResponseWriter struct {
|
||||
io.WriteCloser
|
||||
http.ResponseWriter
|
||||
}
|
||||
|
||||
func newGzipResponseWriter(w http.ResponseWriter) *gzipResponseWriter {
|
||||
gz := gzip.NewWriter(w)
|
||||
return &gzipResponseWriter{WriteCloser: gz, ResponseWriter: w}
|
||||
}
|
||||
|
||||
func (w gzipResponseWriter) Write(b []byte) (int, error) {
|
||||
return w.WriteCloser.Write(b)
|
||||
}
|
||||
|
||||
func (w gzipResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
h, ok := w.ResponseWriter.(http.Hijacker)
|
||||
if !ok {
|
||||
return nil, nil, errors.New("gzipResponseWriter: ResponseWriter does not satisfy http.Hijacker interface")
|
||||
}
|
||||
return h.Hijack()
|
||||
}
|
||||
|
||||
type server struct{}
|
||||
|
||||
// Any path prefixes that should resolve to index.html.
|
||||
var (
|
||||
fePaths = []string{"/q/", "/c/"}
|
||||
issueNumRE = regexp.MustCompile(`^\/\d+\/?$`)
|
||||
)
|
||||
|
||||
func (_ *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
log.Printf("%s %s %s %s\n", r.Proto, r.Method, r.RemoteAddr, r.URL)
|
||||
for _, prefix := range fePaths {
|
||||
if strings.HasPrefix(r.URL.Path, prefix) {
|
||||
r.URL.Path = "/"
|
||||
log.Println("Redirecting to /")
|
||||
break
|
||||
} else if match := issueNumRE.Find([]byte(r.URL.Path)); match != nil {
|
||||
r.URL.Path = "/"
|
||||
log.Println("Redirecting to /")
|
||||
break
|
||||
}
|
||||
}
|
||||
if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
|
||||
http.DefaultServeMux.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Encoding", "gzip")
|
||||
gzw := newGzipResponseWriter(w)
|
||||
defer gzw.Close()
|
||||
http.DefaultServeMux.ServeHTTP(gzw, r)
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
var path = require('path');
|
||||
|
||||
var ret = {
|
||||
suites: ['app/test'],
|
||||
webserver: {
|
||||
pathMappings: []
|
||||
}
|
||||
};
|
||||
|
||||
var mapping = {};
|
||||
var rootPath = (__dirname).split(path.sep).slice(-1)[0];
|
||||
|
||||
mapping['/components/' + rootPath + '/app/bower_components'] = 'bower_components';
|
||||
|
||||
ret.webserver.pathMappings.push(mapping);
|
||||
|
||||
module.exports = ret;
|
Loading…
Reference in New Issue