Convert legacy Polyemer elements to class-based
This commit converts almost all Polymer elements from Polymer-function based components to class-based components. There are few files which should be converted manually after this commit. Change-Id: I9e597e79053e0a6b5d5c0f1b54676d11b9d81db7
This commit is contained in:
@@ -36,61 +36,69 @@
|
||||
const ON_BEHALF_OF = '(On Behalf Of)';
|
||||
const LABEL = 'Label';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-access-section',
|
||||
|
||||
properties: {
|
||||
capabilities: Object,
|
||||
/** @type {?} */
|
||||
section: {
|
||||
type: Object,
|
||||
notify: true,
|
||||
observer: '_updateSection',
|
||||
},
|
||||
groups: Object,
|
||||
labels: Object,
|
||||
editing: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
observer: '_handleEditingChanged',
|
||||
},
|
||||
canUpload: Boolean,
|
||||
ownerOf: Array,
|
||||
_originalId: String,
|
||||
_editingRef: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_deleted: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_permissions: Array,
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
Gerrit.AccessBehavior,
|
||||
/**
|
||||
/**
|
||||
* @appliesMixin Gerrit.AccessMixin
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
*/
|
||||
class GrAccessSection extends Polymer.mixinBehaviors( [
|
||||
Gerrit.AccessBehavior,
|
||||
/**
|
||||
* Unused in this element, but called by other elements in tests
|
||||
* e.g gr-repo-access_test.
|
||||
*/
|
||||
Gerrit.FireBehavior,
|
||||
],
|
||||
Gerrit.FireBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-access-section'; }
|
||||
|
||||
listeners: {
|
||||
'access-saved': '_handleAccessSaved',
|
||||
},
|
||||
static get properties() {
|
||||
return {
|
||||
capabilities: Object,
|
||||
/** @type {?} */
|
||||
section: {
|
||||
type: Object,
|
||||
notify: true,
|
||||
observer: '_updateSection',
|
||||
},
|
||||
groups: Object,
|
||||
labels: Object,
|
||||
editing: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
observer: '_handleEditingChanged',
|
||||
},
|
||||
canUpload: Boolean,
|
||||
ownerOf: Array,
|
||||
_originalId: String,
|
||||
_editingRef: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_deleted: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_permissions: Array,
|
||||
};
|
||||
}
|
||||
|
||||
created() {
|
||||
super.created();
|
||||
this.addEventListener('access-saved',
|
||||
() => this._handleAccessSaved());
|
||||
}
|
||||
|
||||
_updateSection(section) {
|
||||
this._permissions = this.toSortedArray(section.value.permissions);
|
||||
this._originalId = section.id;
|
||||
},
|
||||
}
|
||||
|
||||
_handleAccessSaved() {
|
||||
// Set a new 'original' value to keep track of after the value has been
|
||||
// saved.
|
||||
this._updateSection(this.section);
|
||||
},
|
||||
}
|
||||
|
||||
_handleValueChange() {
|
||||
if (!this.section.value.added) {
|
||||
@@ -103,7 +111,7 @@
|
||||
'access-modified', {bubbles: true, composed: true}));
|
||||
}
|
||||
this.section.value.updatedId = this.section.id;
|
||||
},
|
||||
}
|
||||
|
||||
_handleEditingChanged(editing, editingOld) {
|
||||
// Ignore when editing gets set initially.
|
||||
@@ -123,7 +131,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_computePermissions(name, capabilities, labels) {
|
||||
let allPermissions;
|
||||
@@ -140,17 +148,17 @@
|
||||
return allPermissions.filter(permission => {
|
||||
return !this.section.value.permissions[permission.id];
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_computeHideEditClass(section) {
|
||||
return section.id === 'GLOBAL_CAPABILITIES' ? 'hide' : '';
|
||||
},
|
||||
}
|
||||
|
||||
_handleAddedPermissionRemoved(e) {
|
||||
const index = e.model.index;
|
||||
this._permissions = this._permissions.slice(0, index).concat(
|
||||
this._permissions.slice(index + 1, this._permissions.length));
|
||||
},
|
||||
}
|
||||
|
||||
_computeLabelOptions(labels) {
|
||||
const labelOptions = [];
|
||||
@@ -172,7 +180,7 @@
|
||||
});
|
||||
}
|
||||
return labelOptions;
|
||||
},
|
||||
}
|
||||
|
||||
_computePermissionName(name, permission, permissionValues, capabilities) {
|
||||
if (name === GLOBAL_NAME) {
|
||||
@@ -186,7 +194,7 @@
|
||||
}
|
||||
return `${LABEL} ${permission.value.label}${behalfOf}`;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_computeSectionName(name) {
|
||||
// When a new section is created, it doesn't yet have a ref. Set into
|
||||
@@ -204,7 +212,7 @@
|
||||
return `Reference: ${name}`;
|
||||
}
|
||||
return name;
|
||||
},
|
||||
}
|
||||
|
||||
_handleRemoveReference() {
|
||||
if (this.section.value.added) {
|
||||
@@ -215,27 +223,27 @@
|
||||
this.section.value.deleted = true;
|
||||
this.dispatchEvent(
|
||||
new CustomEvent('access-modified', {bubbles: true, composed: true}));
|
||||
},
|
||||
}
|
||||
|
||||
_handleUndoRemove() {
|
||||
this._deleted = false;
|
||||
delete this.section.value.deleted;
|
||||
},
|
||||
}
|
||||
|
||||
editRefInput() {
|
||||
return Polymer.dom(this.root).querySelector(Polymer.Element ?
|
||||
'iron-input.editRefInput' :
|
||||
'input[is=iron-input].editRefInput');
|
||||
},
|
||||
}
|
||||
|
||||
editReference() {
|
||||
this._editingRef = true;
|
||||
this.editRefInput().focus();
|
||||
},
|
||||
}
|
||||
|
||||
_isEditEnabled(canUpload, ownerOf, sectionId) {
|
||||
return canUpload || (ownerOf && ownerOf.indexOf(sectionId) >= 0);
|
||||
},
|
||||
}
|
||||
|
||||
_computeSectionClass(editing, canUpload, ownerOf, editingRef, deleted) {
|
||||
const classList = [];
|
||||
@@ -249,11 +257,11 @@
|
||||
classList.push('deleted');
|
||||
}
|
||||
return classList.join(' ');
|
||||
},
|
||||
}
|
||||
|
||||
_computeEditBtnClass(name) {
|
||||
return name === GLOBAL_NAME ? 'global' : '';
|
||||
},
|
||||
}
|
||||
|
||||
_handleAddPermission() {
|
||||
const value = this.$.permissionSelect.value;
|
||||
@@ -286,6 +294,8 @@
|
||||
this.push('_permissions', permission);
|
||||
this.set(['section.value.permissions', permission.id],
|
||||
permission.value);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrAccessSection.is, GrAccessSection);
|
||||
})();
|
||||
|
||||
@@ -17,65 +17,72 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-admin-group-list',
|
||||
/**
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
* @appliesMixin Gerrit.ListViewMixin
|
||||
*/
|
||||
class GrAdminGroupList extends Polymer.mixinBehaviors( [
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.ListViewBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-admin-group-list'; }
|
||||
|
||||
properties: {
|
||||
static get properties() {
|
||||
return {
|
||||
/**
|
||||
* URL params passed from the router.
|
||||
*/
|
||||
params: {
|
||||
type: Object,
|
||||
observer: '_paramsChanged',
|
||||
},
|
||||
params: {
|
||||
type: Object,
|
||||
observer: '_paramsChanged',
|
||||
},
|
||||
|
||||
/**
|
||||
/**
|
||||
* Offset of currently visible query results.
|
||||
*/
|
||||
_offset: Number,
|
||||
_path: {
|
||||
type: String,
|
||||
readOnly: true,
|
||||
value: '/admin/groups',
|
||||
},
|
||||
_hasNewGroupName: Boolean,
|
||||
_createNewCapability: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_groups: Array,
|
||||
_offset: Number,
|
||||
_path: {
|
||||
type: String,
|
||||
readOnly: true,
|
||||
value: '/admin/groups',
|
||||
},
|
||||
_hasNewGroupName: Boolean,
|
||||
_createNewCapability: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_groups: Array,
|
||||
|
||||
/**
|
||||
/**
|
||||
* Because we request one more than the groupsPerPage, _shownGroups
|
||||
* may be one less than _groups.
|
||||
* */
|
||||
_shownGroups: {
|
||||
type: Array,
|
||||
computed: 'computeShownItems(_groups)',
|
||||
},
|
||||
_shownGroups: {
|
||||
type: Array,
|
||||
computed: 'computeShownItems(_groups)',
|
||||
},
|
||||
|
||||
_groupsPerPage: {
|
||||
type: Number,
|
||||
value: 25,
|
||||
},
|
||||
_groupsPerPage: {
|
||||
type: Number,
|
||||
value: 25,
|
||||
},
|
||||
|
||||
_loading: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
_filter: String,
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.ListViewBehavior,
|
||||
],
|
||||
_loading: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
_filter: String,
|
||||
};
|
||||
}
|
||||
|
||||
attached() {
|
||||
super.attached();
|
||||
this._getCreateGroupCapability();
|
||||
this.fire('title-change', {title: 'Groups'});
|
||||
this._maybeOpenCreateOverlay(this.params);
|
||||
},
|
||||
}
|
||||
|
||||
_paramsChanged(params) {
|
||||
this._loading = true;
|
||||
@@ -84,7 +91,7 @@
|
||||
|
||||
return this._getGroups(this._filter, this._groupsPerPage,
|
||||
this._offset);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the create overlay if the route has a hash 'create'
|
||||
@@ -94,11 +101,11 @@
|
||||
if (params && params.openCreateModal) {
|
||||
this.$.createOverlay.open();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_computeGroupUrl(id) {
|
||||
return Gerrit.Nav.getUrlForGroup(id);
|
||||
},
|
||||
}
|
||||
|
||||
_getCreateGroupCapability() {
|
||||
return this.$.restAPI.getAccount().then(account => {
|
||||
@@ -110,7 +117,7 @@
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_getGroups(filter, groupsPerPage, offset) {
|
||||
this._groups = [];
|
||||
@@ -127,30 +134,32 @@
|
||||
});
|
||||
this._loading = false;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_refreshGroupsList() {
|
||||
this.$.restAPI.invalidateGroupsCache();
|
||||
return this._getGroups(this._filter, this._groupsPerPage,
|
||||
this._offset);
|
||||
},
|
||||
}
|
||||
|
||||
_handleCreateGroup() {
|
||||
this.$.createNewModal.handleCreateGroup().then(() => {
|
||||
this._refreshGroupsList();
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleCloseCreate() {
|
||||
this.$.createOverlay.close();
|
||||
},
|
||||
}
|
||||
|
||||
_handleCreateClicked() {
|
||||
this.$.createOverlay.open();
|
||||
},
|
||||
}
|
||||
|
||||
_visibleToAll(item) {
|
||||
return item.options.visible_to_all === true ? 'Y' : 'N';
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrAdminGroupList.is, GrAdminGroupList);
|
||||
})();
|
||||
|
||||
@@ -19,63 +19,73 @@
|
||||
|
||||
const INTERNAL_GROUP_REGEX = /^[\da-f]{40}$/;
|
||||
|
||||
Polymer({
|
||||
is: 'gr-admin-view',
|
||||
/**
|
||||
* @appliesMixin Gerrit.AdminNavMixin
|
||||
* @appliesMixin Gerrit.BaseUrlMixin
|
||||
* @appliesMixin Gerrit.URLEncodingMixin
|
||||
*/
|
||||
class GrAdminView extends Polymer.mixinBehaviors( [
|
||||
Gerrit.AdminNavBehavior,
|
||||
Gerrit.BaseUrlBehavior,
|
||||
Gerrit.URLEncodingBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-admin-view'; }
|
||||
|
||||
properties: {
|
||||
static get properties() {
|
||||
return {
|
||||
/** @type {?} */
|
||||
params: Object,
|
||||
path: String,
|
||||
adminView: String,
|
||||
params: Object,
|
||||
path: String,
|
||||
adminView: String,
|
||||
|
||||
_breadcrumbParentName: String,
|
||||
_repoName: String,
|
||||
_groupId: {
|
||||
type: Number,
|
||||
observer: '_computeGroupName',
|
||||
},
|
||||
_groupIsInternal: Boolean,
|
||||
_groupName: String,
|
||||
_groupOwner: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_subsectionLinks: Array,
|
||||
_filteredLinks: Array,
|
||||
_showDownload: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_isAdmin: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_showGroup: Boolean,
|
||||
_showGroupAuditLog: Boolean,
|
||||
_showGroupList: Boolean,
|
||||
_showGroupMembers: Boolean,
|
||||
_showRepoAccess: Boolean,
|
||||
_showRepoCommands: Boolean,
|
||||
_showRepoDashboards: Boolean,
|
||||
_showRepoDetailList: Boolean,
|
||||
_showRepoMain: Boolean,
|
||||
_showRepoList: Boolean,
|
||||
_showPluginList: Boolean,
|
||||
},
|
||||
_breadcrumbParentName: String,
|
||||
_repoName: String,
|
||||
_groupId: {
|
||||
type: Number,
|
||||
observer: '_computeGroupName',
|
||||
},
|
||||
_groupIsInternal: Boolean,
|
||||
_groupName: String,
|
||||
_groupOwner: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_subsectionLinks: Array,
|
||||
_filteredLinks: Array,
|
||||
_showDownload: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_isAdmin: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_showGroup: Boolean,
|
||||
_showGroupAuditLog: Boolean,
|
||||
_showGroupList: Boolean,
|
||||
_showGroupMembers: Boolean,
|
||||
_showRepoAccess: Boolean,
|
||||
_showRepoCommands: Boolean,
|
||||
_showRepoDashboards: Boolean,
|
||||
_showRepoDetailList: Boolean,
|
||||
_showRepoMain: Boolean,
|
||||
_showRepoList: Boolean,
|
||||
_showPluginList: Boolean,
|
||||
};
|
||||
}
|
||||
|
||||
behaviors: [
|
||||
Gerrit.AdminNavBehavior,
|
||||
Gerrit.BaseUrlBehavior,
|
||||
Gerrit.URLEncodingBehavior,
|
||||
],
|
||||
|
||||
observers: [
|
||||
'_paramsChanged(params)',
|
||||
],
|
||||
static get observers() {
|
||||
return [
|
||||
'_paramsChanged(params)',
|
||||
];
|
||||
}
|
||||
|
||||
attached() {
|
||||
super.attached();
|
||||
this.reload();
|
||||
},
|
||||
}
|
||||
|
||||
reload() {
|
||||
const promises = [
|
||||
@@ -123,18 +133,18 @@
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_computeSelectValue(params) {
|
||||
if (!params || !params.view) { return; }
|
||||
return params.view + (params.detail || '');
|
||||
},
|
||||
}
|
||||
|
||||
_selectedIsCurrentPage(selected) {
|
||||
return (selected.parent === (this._repoName || this._groupId) &&
|
||||
selected.view === this.params.view &&
|
||||
selected.detailType === this.params.detail);
|
||||
},
|
||||
}
|
||||
|
||||
_handleSubsectionChange(e) {
|
||||
const selected = this._subsectionLinks
|
||||
@@ -145,7 +155,7 @@
|
||||
return;
|
||||
}
|
||||
Gerrit.Nav.navigateToRelativeUrl(selected.url);
|
||||
},
|
||||
}
|
||||
|
||||
_paramsChanged(params) {
|
||||
const isGroupView = params.view === Gerrit.Nav.View.GROUP;
|
||||
@@ -194,19 +204,19 @@
|
||||
}
|
||||
if (!needsReload) { return; }
|
||||
this.reload();
|
||||
},
|
||||
}
|
||||
|
||||
// TODO (beckysiegel): Update these functions after router abstraction is
|
||||
// updated. They are currently copied from gr-dropdown (and should be
|
||||
// updated there as well once complete).
|
||||
_computeURLHelper(host, path) {
|
||||
return '//' + host + this.getBaseUrl() + path;
|
||||
},
|
||||
}
|
||||
|
||||
_computeRelativeURL(path) {
|
||||
const host = window.location.host;
|
||||
return this._computeURLHelper(host, path);
|
||||
},
|
||||
}
|
||||
|
||||
_computeLinkURL(link) {
|
||||
if (!link || typeof link.url === 'undefined') { return ''; }
|
||||
@@ -214,7 +224,7 @@
|
||||
return link.url;
|
||||
}
|
||||
return this._computeRelativeURL(link.url);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} itemView
|
||||
@@ -244,7 +254,7 @@
|
||||
return '';
|
||||
}
|
||||
return itemView === params.adminView ? 'selected' : '';
|
||||
},
|
||||
}
|
||||
|
||||
_computeGroupName(groupId) {
|
||||
if (!groupId) { return ''; }
|
||||
@@ -270,11 +280,13 @@
|
||||
this.reload();
|
||||
});
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_updateGroupName(e) {
|
||||
this._groupName = e.detail.name;
|
||||
this.reload();
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrAdminView.is, GrAdminView);
|
||||
})();
|
||||
|
||||
@@ -23,9 +23,15 @@
|
||||
TAGS: 'tags',
|
||||
};
|
||||
|
||||
Polymer({
|
||||
is: 'gr-confirm-delete-item-dialog',
|
||||
|
||||
/**
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
*/
|
||||
class GrConfirmDeleteItemDialog extends Polymer.mixinBehaviors( [
|
||||
Gerrit.FireBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-confirm-delete-item-dialog'; }
|
||||
/**
|
||||
* Fired when the confirm button is pressed.
|
||||
*
|
||||
@@ -38,26 +44,24 @@
|
||||
* @event cancel
|
||||
*/
|
||||
|
||||
properties: {
|
||||
item: String,
|
||||
itemType: String,
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
Gerrit.FireBehavior,
|
||||
],
|
||||
static get properties() {
|
||||
return {
|
||||
item: String,
|
||||
itemType: String,
|
||||
};
|
||||
}
|
||||
|
||||
_handleConfirmTap(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.fire('confirm', null, {bubbles: false});
|
||||
},
|
||||
}
|
||||
|
||||
_handleCancelTap(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.fire('cancel', null, {bubbles: false});
|
||||
},
|
||||
}
|
||||
|
||||
_computeItemName(detailType) {
|
||||
if (detailType === DETAIL_TYPES.BRANCHES) {
|
||||
@@ -67,6 +71,9 @@
|
||||
} else if (detailType === DETAIL_TYPES.ID) {
|
||||
return 'ID';
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrConfirmDeleteItemDialog.is,
|
||||
GrConfirmDeleteItemDialog);
|
||||
})();
|
||||
|
||||
@@ -20,44 +20,52 @@
|
||||
const SUGGESTIONS_LIMIT = 15;
|
||||
const REF_PREFIX = 'refs/heads/';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-create-change-dialog',
|
||||
|
||||
properties: {
|
||||
repoName: String,
|
||||
branch: String,
|
||||
/** @type {?} */
|
||||
_repoConfig: Object,
|
||||
subject: String,
|
||||
topic: String,
|
||||
_query: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._getRepoBranchesSuggestions.bind(this);
|
||||
},
|
||||
},
|
||||
baseChange: String,
|
||||
baseCommit: String,
|
||||
privateByDefault: String,
|
||||
canCreate: {
|
||||
type: Boolean,
|
||||
notify: true,
|
||||
value: false,
|
||||
},
|
||||
_privateChangesEnabled: Boolean,
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
Gerrit.BaseUrlBehavior,
|
||||
/**
|
||||
/**
|
||||
* @appliesMixin Gerrit.BaseUrlMixin
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
* @appliesMixin Gerrit.URLEncodingMixin
|
||||
*/
|
||||
class GrCreateChangeDialog extends Polymer.mixinBehaviors( [
|
||||
Gerrit.BaseUrlBehavior,
|
||||
/**
|
||||
* Unused in this element, but called by other elements in tests
|
||||
* e.g gr-repo-commands_test.
|
||||
*/
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.URLEncodingBehavior,
|
||||
],
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.URLEncodingBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-create-change-dialog'; }
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
repoName: String,
|
||||
branch: String,
|
||||
/** @type {?} */
|
||||
_repoConfig: Object,
|
||||
subject: String,
|
||||
topic: String,
|
||||
_query: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._getRepoBranchesSuggestions.bind(this);
|
||||
},
|
||||
},
|
||||
baseChange: String,
|
||||
baseCommit: String,
|
||||
privateByDefault: String,
|
||||
canCreate: {
|
||||
type: Boolean,
|
||||
notify: true,
|
||||
value: false,
|
||||
},
|
||||
_privateChangesEnabled: Boolean,
|
||||
};
|
||||
}
|
||||
|
||||
attached() {
|
||||
super.attached();
|
||||
if (!this.repoName) { return Promise.resolve(); }
|
||||
|
||||
const promises = [];
|
||||
@@ -75,19 +83,21 @@
|
||||
}));
|
||||
|
||||
return Promise.all(promises);
|
||||
},
|
||||
}
|
||||
|
||||
observers: [
|
||||
'_allowCreate(branch, subject)',
|
||||
],
|
||||
static get observers() {
|
||||
return [
|
||||
'_allowCreate(branch, subject)',
|
||||
];
|
||||
}
|
||||
|
||||
_computeBranchClass(baseChange) {
|
||||
return baseChange ? 'hide' : '';
|
||||
},
|
||||
}
|
||||
|
||||
_allowCreate(branch, subject) {
|
||||
this.canCreate = !!branch && !!subject;
|
||||
},
|
||||
}
|
||||
|
||||
handleCreateChange() {
|
||||
const isPrivate = this.$.privateChangeCheckBox.checked;
|
||||
@@ -99,7 +109,7 @@
|
||||
if (!changeCreated) { return; }
|
||||
Gerrit.Nav.navigateToChange(changeCreated);
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_getRepoBranchesSuggestions(input) {
|
||||
if (input.startsWith(REF_PREFIX)) {
|
||||
@@ -122,7 +132,7 @@
|
||||
}
|
||||
return branches;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_formatBooleanString(config) {
|
||||
if (config && config.configured_value === 'TRUE') {
|
||||
@@ -138,10 +148,12 @@
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_computePrivateSectionClass(config) {
|
||||
return config ? 'hide' : '';
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrCreateChangeDialog.is, GrCreateChangeDialog);
|
||||
})();
|
||||
|
||||
@@ -17,40 +17,48 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-create-group-dialog',
|
||||
/**
|
||||
* @appliesMixin Gerrit.BaseUrlMixin
|
||||
* @appliesMixin Gerrit.URLEncodingMixin
|
||||
*/
|
||||
class GrCreateGroupDialog extends Polymer.mixinBehaviors( [
|
||||
Gerrit.BaseUrlBehavior,
|
||||
Gerrit.URLEncodingBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-create-group-dialog'; }
|
||||
|
||||
properties: {
|
||||
params: Object,
|
||||
hasNewGroupName: {
|
||||
type: Boolean,
|
||||
notify: true,
|
||||
value: false,
|
||||
},
|
||||
_name: Object,
|
||||
_groupCreated: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
},
|
||||
static get properties() {
|
||||
return {
|
||||
params: Object,
|
||||
hasNewGroupName: {
|
||||
type: Boolean,
|
||||
notify: true,
|
||||
value: false,
|
||||
},
|
||||
_name: Object,
|
||||
_groupCreated: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
observers: [
|
||||
'_updateGroupName(_name)',
|
||||
],
|
||||
|
||||
behaviors: [
|
||||
Gerrit.BaseUrlBehavior,
|
||||
Gerrit.URLEncodingBehavior,
|
||||
],
|
||||
static get observers() {
|
||||
return [
|
||||
'_updateGroupName(_name)',
|
||||
];
|
||||
}
|
||||
|
||||
_computeGroupUrl(groupId) {
|
||||
return this.getBaseUrl() + '/admin/groups/' +
|
||||
this.encodeURL(groupId, true);
|
||||
},
|
||||
}
|
||||
|
||||
_updateGroupName(name) {
|
||||
this.hasNewGroupName = !!name;
|
||||
},
|
||||
}
|
||||
|
||||
handleCreateGroup() {
|
||||
return this.$.restAPI.createGroup({name: this._name})
|
||||
@@ -62,6 +70,8 @@
|
||||
page.show(this._computeGroupUrl(group.group_id));
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrCreateGroupDialog.is, GrCreateGroupDialog);
|
||||
})();
|
||||
|
||||
@@ -22,35 +22,43 @@
|
||||
tags: 'tags',
|
||||
};
|
||||
|
||||
Polymer({
|
||||
is: 'gr-create-pointer-dialog',
|
||||
/**
|
||||
* @appliesMixin Gerrit.BaseUrlMixin
|
||||
* @appliesMixin Gerrit.URLEncodingMixin
|
||||
*/
|
||||
class GrCreatePointerDialog extends Polymer.mixinBehaviors( [
|
||||
Gerrit.BaseUrlBehavior,
|
||||
Gerrit.URLEncodingBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-create-pointer-dialog'; }
|
||||
|
||||
properties: {
|
||||
detailType: String,
|
||||
repoName: String,
|
||||
hasNewItemName: {
|
||||
type: Boolean,
|
||||
notify: true,
|
||||
value: false,
|
||||
},
|
||||
itemDetail: String,
|
||||
_itemName: String,
|
||||
_itemRevision: String,
|
||||
_itemAnnotation: String,
|
||||
},
|
||||
static get properties() {
|
||||
return {
|
||||
detailType: String,
|
||||
repoName: String,
|
||||
hasNewItemName: {
|
||||
type: Boolean,
|
||||
notify: true,
|
||||
value: false,
|
||||
},
|
||||
itemDetail: String,
|
||||
_itemName: String,
|
||||
_itemRevision: String,
|
||||
_itemAnnotation: String,
|
||||
};
|
||||
}
|
||||
|
||||
behaviors: [
|
||||
Gerrit.BaseUrlBehavior,
|
||||
Gerrit.URLEncodingBehavior,
|
||||
],
|
||||
|
||||
observers: [
|
||||
'_updateItemName(_itemName)',
|
||||
],
|
||||
static get observers() {
|
||||
return [
|
||||
'_updateItemName(_itemName)',
|
||||
];
|
||||
}
|
||||
|
||||
_updateItemName(name) {
|
||||
this.hasNewItemName = !!name;
|
||||
},
|
||||
}
|
||||
|
||||
_computeItemUrl(project) {
|
||||
if (this.itemDetail === DETAIL_TYPES.branches) {
|
||||
@@ -60,7 +68,7 @@
|
||||
return this.getBaseUrl() + '/admin/repos/' +
|
||||
this.encodeURL(this.repoName, true) + ',tags';
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
handleCreateItem() {
|
||||
const USE_HEAD = this._itemRevision ? this._itemRevision : 'HEAD';
|
||||
@@ -82,10 +90,12 @@
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_computeHideItemClass(type) {
|
||||
return type === DETAIL_TYPES.branches ? 'hideItem' : '';
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrCreatePointerDialog.is, GrCreatePointerDialog);
|
||||
})();
|
||||
|
||||
@@ -17,69 +17,77 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-create-repo-dialog',
|
||||
/**
|
||||
* @appliesMixin Gerrit.BaseUrlMixin
|
||||
* @appliesMixin Gerrit.URLEncodingMixin
|
||||
*/
|
||||
class GrCreateRepoDialog extends Polymer.mixinBehaviors( [
|
||||
Gerrit.BaseUrlBehavior,
|
||||
Gerrit.URLEncodingBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-create-repo-dialog'; }
|
||||
|
||||
properties: {
|
||||
params: Object,
|
||||
hasNewRepoName: {
|
||||
type: Boolean,
|
||||
notify: true,
|
||||
value: false,
|
||||
},
|
||||
static get properties() {
|
||||
return {
|
||||
params: Object,
|
||||
hasNewRepoName: {
|
||||
type: Boolean,
|
||||
notify: true,
|
||||
value: false,
|
||||
},
|
||||
|
||||
/** @type {?} */
|
||||
_repoConfig: {
|
||||
type: Object,
|
||||
value: () => {
|
||||
/** @type {?} */
|
||||
_repoConfig: {
|
||||
type: Object,
|
||||
value: () => {
|
||||
// Set default values for dropdowns.
|
||||
return {
|
||||
create_empty_commit: true,
|
||||
permissions_only: false,
|
||||
};
|
||||
return {
|
||||
create_empty_commit: true,
|
||||
permissions_only: false,
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
_repoCreated: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_repoOwner: String,
|
||||
_repoOwnerId: {
|
||||
type: String,
|
||||
observer: '_repoOwnerIdUpdate',
|
||||
},
|
||||
|
||||
_query: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._getRepoSuggestions.bind(this);
|
||||
_repoCreated: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
},
|
||||
_queryGroups: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._getGroupSuggestions.bind(this);
|
||||
_repoOwner: String,
|
||||
_repoOwnerId: {
|
||||
type: String,
|
||||
observer: '_repoOwnerIdUpdate',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
observers: [
|
||||
'_updateRepoName(_repoConfig.name)',
|
||||
],
|
||||
_query: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._getRepoSuggestions.bind(this);
|
||||
},
|
||||
},
|
||||
_queryGroups: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._getGroupSuggestions.bind(this);
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
behaviors: [
|
||||
Gerrit.BaseUrlBehavior,
|
||||
Gerrit.URLEncodingBehavior,
|
||||
],
|
||||
static get observers() {
|
||||
return [
|
||||
'_updateRepoName(_repoConfig.name)',
|
||||
];
|
||||
}
|
||||
|
||||
_computeRepoUrl(repoName) {
|
||||
return this.getBaseUrl() + '/admin/repos/' +
|
||||
this.encodeURL(repoName, true);
|
||||
},
|
||||
}
|
||||
|
||||
_updateRepoName(name) {
|
||||
this.hasNewRepoName = !!name;
|
||||
},
|
||||
}
|
||||
|
||||
_repoOwnerIdUpdate(id) {
|
||||
if (id) {
|
||||
@@ -87,7 +95,7 @@
|
||||
} else {
|
||||
this.set('_repoConfig.owners', undefined);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
handleCreateRepo() {
|
||||
return this.$.restAPI.createRepo(this._repoConfig)
|
||||
@@ -97,7 +105,7 @@
|
||||
page.show(this._computeRepoUrl(this._repoConfig.name));
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_getRepoSuggestions(input) {
|
||||
return this.$.restAPI.getSuggestedProjects(input)
|
||||
@@ -112,7 +120,7 @@
|
||||
}
|
||||
return repos;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_getGroupSuggestions(input) {
|
||||
return this.$.restAPI.getSuggestedGroups(input)
|
||||
@@ -127,6 +135,8 @@
|
||||
}
|
||||
return groups;
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrCreateRepoDialog.is, GrCreateRepoDialog);
|
||||
})();
|
||||
|
||||
@@ -19,30 +19,38 @@
|
||||
|
||||
const GROUP_EVENTS = ['ADD_GROUP', 'REMOVE_GROUP'];
|
||||
|
||||
Polymer({
|
||||
is: 'gr-group-audit-log',
|
||||
/**
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
* @appliesMixin Gerrit.ListViewMixin
|
||||
*/
|
||||
class GrGroupAuditLog extends Polymer.mixinBehaviors( [
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.ListViewBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-group-audit-log'; }
|
||||
|
||||
properties: {
|
||||
groupId: String,
|
||||
_auditLog: Array,
|
||||
_loading: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.ListViewBehavior,
|
||||
],
|
||||
static get properties() {
|
||||
return {
|
||||
groupId: String,
|
||||
_auditLog: Array,
|
||||
_loading: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
attached() {
|
||||
super.attached();
|
||||
this.fire('title-change', {title: 'Audit Log'});
|
||||
},
|
||||
}
|
||||
|
||||
ready() {
|
||||
super.ready();
|
||||
this._getAuditLogs();
|
||||
},
|
||||
}
|
||||
|
||||
_getAuditLogs() {
|
||||
if (!this.groupId) { return ''; }
|
||||
@@ -60,11 +68,11 @@
|
||||
this._auditLog = auditLog;
|
||||
this._loading = false;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_status(item) {
|
||||
return item.disabled ? 'Disabled' : 'Enabled';
|
||||
},
|
||||
}
|
||||
|
||||
itemType(type) {
|
||||
let item;
|
||||
@@ -81,11 +89,11 @@
|
||||
item = '';
|
||||
}
|
||||
return item;
|
||||
},
|
||||
}
|
||||
|
||||
_isGroupEvent(type) {
|
||||
return GROUP_EVENTS.indexOf(type) !== -1;
|
||||
},
|
||||
}
|
||||
|
||||
_computeGroupUrl(group) {
|
||||
if (group && group.url && group.id) {
|
||||
@@ -93,11 +101,11 @@
|
||||
}
|
||||
|
||||
return '';
|
||||
},
|
||||
}
|
||||
|
||||
_getIdForUser(account) {
|
||||
return account._account_id ? ' (' + account._account_id + ')' : '';
|
||||
},
|
||||
}
|
||||
|
||||
_getNameForGroup(group) {
|
||||
if (group && group.name) {
|
||||
@@ -108,6 +116,8 @@
|
||||
}
|
||||
|
||||
return '';
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrGroupAuditLog.is, GrGroupAuditLog);
|
||||
})();
|
||||
|
||||
@@ -23,57 +23,65 @@
|
||||
|
||||
const URL_REGEX = '^(?:[a-z]+:)?//';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-group-members',
|
||||
/**
|
||||
* @appliesMixin Gerrit.BaseUrlMixin
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
* @appliesMixin Gerrit.URLEncodingMixin
|
||||
*/
|
||||
class GrGroupMembers extends Polymer.mixinBehaviors( [
|
||||
Gerrit.BaseUrlBehavior,
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.URLEncodingBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-group-members'; }
|
||||
|
||||
properties: {
|
||||
groupId: Number,
|
||||
_groupMemberSearchId: String,
|
||||
_groupMemberSearchName: String,
|
||||
_includedGroupSearchId: String,
|
||||
_includedGroupSearchName: String,
|
||||
_loading: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
_groupName: String,
|
||||
_groupMembers: Object,
|
||||
_includedGroups: Object,
|
||||
_itemName: String,
|
||||
_itemType: String,
|
||||
_queryMembers: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._getAccountSuggestions.bind(this);
|
||||
static get properties() {
|
||||
return {
|
||||
groupId: Number,
|
||||
_groupMemberSearchId: String,
|
||||
_groupMemberSearchName: String,
|
||||
_includedGroupSearchId: String,
|
||||
_includedGroupSearchName: String,
|
||||
_loading: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
},
|
||||
_queryIncludedGroup: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._getGroupSuggestions.bind(this);
|
||||
_groupName: String,
|
||||
_groupMembers: Object,
|
||||
_includedGroups: Object,
|
||||
_itemName: String,
|
||||
_itemType: String,
|
||||
_queryMembers: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._getAccountSuggestions.bind(this);
|
||||
},
|
||||
},
|
||||
},
|
||||
_groupOwner: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_isAdmin: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
Gerrit.BaseUrlBehavior,
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.URLEncodingBehavior,
|
||||
],
|
||||
_queryIncludedGroup: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._getGroupSuggestions.bind(this);
|
||||
},
|
||||
},
|
||||
_groupOwner: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_isAdmin: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
attached() {
|
||||
super.attached();
|
||||
this._loadGroupDetails();
|
||||
|
||||
this.fire('title-change', {title: 'Members'});
|
||||
},
|
||||
}
|
||||
|
||||
_loadGroupDetails() {
|
||||
if (!this.groupId) { return; }
|
||||
@@ -113,15 +121,15 @@
|
||||
this._loading = false;
|
||||
});
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_computeLoadingClass(loading) {
|
||||
return loading ? 'loading' : '';
|
||||
},
|
||||
}
|
||||
|
||||
_isLoading() {
|
||||
return this._loading || this._loading === undefined;
|
||||
},
|
||||
}
|
||||
|
||||
_computeGroupUrl(url) {
|
||||
if (!url) { return; }
|
||||
@@ -136,7 +144,7 @@
|
||||
return this.getBaseUrl() + url.slice(1);
|
||||
}
|
||||
return this.getBaseUrl() + url;
|
||||
},
|
||||
}
|
||||
|
||||
_handleSavingGroupMember() {
|
||||
return this.$.restAPI.saveGroupMembers(this._groupName,
|
||||
@@ -150,7 +158,7 @@
|
||||
this._groupMemberSearchName = '';
|
||||
this._groupMemberSearchId = '';
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleDeleteConfirm() {
|
||||
this.$.overlay.close();
|
||||
@@ -177,11 +185,11 @@
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_handleConfirmDialogCancel() {
|
||||
this.$.overlay.close();
|
||||
},
|
||||
}
|
||||
|
||||
_handleDeleteMember(e) {
|
||||
const id = e.model.get('item._account_id');
|
||||
@@ -196,7 +204,7 @@
|
||||
this._itemId = id;
|
||||
this._itemType = 'member';
|
||||
this.$.overlay.open();
|
||||
},
|
||||
}
|
||||
|
||||
_handleSavingIncludedGroups() {
|
||||
return this.$.restAPI.saveIncludedGroup(this._groupName,
|
||||
@@ -222,7 +230,7 @@
|
||||
this._includedGroupSearchName = '';
|
||||
this._includedGroupSearchId = '';
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleDeleteIncludedGroup(e) {
|
||||
const id = decodeURIComponent(e.model.get('item.id')).replace(/\+/g, ' ');
|
||||
@@ -233,7 +241,7 @@
|
||||
this._itemId = id;
|
||||
this._itemType = 'includedGroup';
|
||||
this.$.overlay.open();
|
||||
},
|
||||
}
|
||||
|
||||
_getAccountSuggestions(input) {
|
||||
if (input.length === 0) { return Promise.resolve([]); }
|
||||
@@ -257,7 +265,7 @@
|
||||
}
|
||||
return accountSuggestions;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_getGroupSuggestions(input) {
|
||||
return this.$.restAPI.getSuggestedGroups(input)
|
||||
@@ -272,10 +280,12 @@
|
||||
}
|
||||
return groups;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_computeHideItemClass(owner, admin) {
|
||||
return admin || owner ? '' : 'canModify';
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrGroupMembers.is, GrGroupMembers);
|
||||
})();
|
||||
|
||||
@@ -30,78 +30,85 @@
|
||||
},
|
||||
};
|
||||
|
||||
Polymer({
|
||||
is: 'gr-group',
|
||||
|
||||
/**
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
*/
|
||||
class GrGroup extends Polymer.mixinBehaviors( [
|
||||
Gerrit.FireBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-group'; }
|
||||
/**
|
||||
* Fired when the group name changes.
|
||||
*
|
||||
* @event name-changed
|
||||
*/
|
||||
|
||||
properties: {
|
||||
groupId: Number,
|
||||
_rename: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_groupIsInternal: Boolean,
|
||||
_description: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_owner: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_options: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_loading: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
/** @type {?} */
|
||||
_groupConfig: Object,
|
||||
_groupConfigOwner: String,
|
||||
_groupName: Object,
|
||||
_groupOwner: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_submitTypes: {
|
||||
type: Array,
|
||||
value() {
|
||||
return Object.values(OPTIONS);
|
||||
static get properties() {
|
||||
return {
|
||||
groupId: Number,
|
||||
_rename: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
},
|
||||
_query: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._getGroupSuggestions.bind(this);
|
||||
_groupIsInternal: Boolean,
|
||||
_description: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
},
|
||||
_isAdmin: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
},
|
||||
_owner: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_options: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_loading: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
/** @type {?} */
|
||||
_groupConfig: Object,
|
||||
_groupConfigOwner: String,
|
||||
_groupName: Object,
|
||||
_groupOwner: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_submitTypes: {
|
||||
type: Array,
|
||||
value() {
|
||||
return Object.values(OPTIONS);
|
||||
},
|
||||
},
|
||||
_query: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._getGroupSuggestions.bind(this);
|
||||
},
|
||||
},
|
||||
_isAdmin: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
behaviors: [
|
||||
Gerrit.FireBehavior,
|
||||
],
|
||||
|
||||
observers: [
|
||||
'_handleConfigName(_groupConfig.name)',
|
||||
'_handleConfigOwner(_groupConfig.owner, _groupConfigOwner)',
|
||||
'_handleConfigDescription(_groupConfig.description)',
|
||||
'_handleConfigOptions(_groupConfig.options.visible_to_all)',
|
||||
],
|
||||
static get observers() {
|
||||
return [
|
||||
'_handleConfigName(_groupConfig.name)',
|
||||
'_handleConfigOwner(_groupConfig.owner, _groupConfigOwner)',
|
||||
'_handleConfigDescription(_groupConfig.description)',
|
||||
'_handleConfigOptions(_groupConfig.options.visible_to_all)',
|
||||
];
|
||||
}
|
||||
|
||||
attached() {
|
||||
super.attached();
|
||||
this._loadGroup();
|
||||
},
|
||||
}
|
||||
|
||||
_loadGroup() {
|
||||
if (!this.groupId) { return; }
|
||||
@@ -143,15 +150,15 @@
|
||||
this._loading = false;
|
||||
});
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_computeLoadingClass(loading) {
|
||||
return loading ? 'loading' : '';
|
||||
},
|
||||
}
|
||||
|
||||
_isLoading() {
|
||||
return this._loading || this._loading === undefined;
|
||||
},
|
||||
}
|
||||
|
||||
_handleSaveName() {
|
||||
return this.$.restAPI.saveGroupName(this.groupId, this._groupConfig.name)
|
||||
@@ -163,7 +170,7 @@
|
||||
this._rename = false;
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleSaveOwner() {
|
||||
let owner = this._groupConfig.owner;
|
||||
@@ -174,14 +181,14 @@
|
||||
owner).then(config => {
|
||||
this._owner = false;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleSaveDescription() {
|
||||
return this.$.restAPI.saveGroupDescription(this.groupId,
|
||||
this._groupConfig.description).then(config => {
|
||||
this._description = false;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleSaveOptions() {
|
||||
const visible = this._groupConfig.options.visible_to_all;
|
||||
@@ -192,31 +199,31 @@
|
||||
options).then(config => {
|
||||
this._options = false;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleConfigName() {
|
||||
if (this._isLoading()) { return; }
|
||||
this._rename = true;
|
||||
},
|
||||
}
|
||||
|
||||
_handleConfigOwner() {
|
||||
if (this._isLoading()) { return; }
|
||||
this._owner = true;
|
||||
},
|
||||
}
|
||||
|
||||
_handleConfigDescription() {
|
||||
if (this._isLoading()) { return; }
|
||||
this._description = true;
|
||||
},
|
||||
}
|
||||
|
||||
_handleConfigOptions() {
|
||||
if (this._isLoading()) { return; }
|
||||
this._options = true;
|
||||
},
|
||||
}
|
||||
|
||||
_computeHeaderClass(configChanged) {
|
||||
return configChanged ? 'edited' : '';
|
||||
},
|
||||
}
|
||||
|
||||
_getGroupSuggestions(input) {
|
||||
return this.$.restAPI.getSuggestedGroups(input)
|
||||
@@ -231,10 +238,12 @@
|
||||
}
|
||||
return groups;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_computeGroupDisabled(owner, admin, groupIsInternal) {
|
||||
return groupIsInternal && (admin || owner) ? false : true;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrGroup.is, GrGroup);
|
||||
})();
|
||||
|
||||
@@ -24,92 +24,101 @@
|
||||
'BATCH CHANGES LIMIT',
|
||||
];
|
||||
|
||||
/**
|
||||
* @appliesMixin Gerrit.AccessMixin
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
*/
|
||||
/**
|
||||
* Fired when the permission has been modified or removed.
|
||||
*
|
||||
* @event access-modified
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fired when a permission that was previously added was removed.
|
||||
* @event added-permission-removed
|
||||
*/
|
||||
|
||||
Polymer({
|
||||
is: 'gr-permission',
|
||||
|
||||
properties: {
|
||||
labels: Object,
|
||||
name: String,
|
||||
/** @type {?} */
|
||||
permission: {
|
||||
type: Object,
|
||||
observer: '_sortPermission',
|
||||
notify: true,
|
||||
},
|
||||
groups: Object,
|
||||
section: String,
|
||||
editing: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
observer: '_handleEditingChanged',
|
||||
},
|
||||
_label: {
|
||||
type: Object,
|
||||
computed: '_computeLabel(permission, labels)',
|
||||
},
|
||||
_groupFilter: String,
|
||||
_query: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._getGroupSuggestions.bind(this);
|
||||
},
|
||||
},
|
||||
_rules: Array,
|
||||
_groupsWithRules: Object,
|
||||
_deleted: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_originalExclusiveValue: Boolean,
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
Gerrit.AccessBehavior,
|
||||
/**
|
||||
class GrPermission extends Polymer.mixinBehaviors( [
|
||||
Gerrit.AccessBehavior,
|
||||
/**
|
||||
* Unused in this element, but called by other elements in tests
|
||||
* e.g gr-access-section_test.
|
||||
*/
|
||||
Gerrit.FireBehavior,
|
||||
],
|
||||
Gerrit.FireBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-permission'; }
|
||||
|
||||
observers: [
|
||||
'_handleRulesChanged(_rules.splices)',
|
||||
],
|
||||
static get properties() {
|
||||
return {
|
||||
labels: Object,
|
||||
name: String,
|
||||
/** @type {?} */
|
||||
permission: {
|
||||
type: Object,
|
||||
observer: '_sortPermission',
|
||||
notify: true,
|
||||
},
|
||||
groups: Object,
|
||||
section: String,
|
||||
editing: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
observer: '_handleEditingChanged',
|
||||
},
|
||||
_label: {
|
||||
type: Object,
|
||||
computed: '_computeLabel(permission, labels)',
|
||||
},
|
||||
_groupFilter: String,
|
||||
_query: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._getGroupSuggestions.bind(this);
|
||||
},
|
||||
},
|
||||
_rules: Array,
|
||||
_groupsWithRules: Object,
|
||||
_deleted: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_originalExclusiveValue: Boolean,
|
||||
};
|
||||
}
|
||||
|
||||
listeners: {
|
||||
'access-saved': '_handleAccessSaved',
|
||||
},
|
||||
static get observers() {
|
||||
return [
|
||||
'_handleRulesChanged(_rules.splices)',
|
||||
];
|
||||
}
|
||||
|
||||
created() {
|
||||
super.created();
|
||||
this.addEventListener('access-saved',
|
||||
() => this._handleAccessSaved());
|
||||
}
|
||||
|
||||
ready() {
|
||||
super.ready();
|
||||
this._setupValues();
|
||||
},
|
||||
}
|
||||
|
||||
_setupValues() {
|
||||
if (!this.permission) { return; }
|
||||
this._originalExclusiveValue = !!this.permission.value.exclusive;
|
||||
Polymer.dom.flush();
|
||||
},
|
||||
}
|
||||
|
||||
_handleAccessSaved() {
|
||||
// Set a new 'original' value to keep track of after the value has been
|
||||
// saved.
|
||||
this._setupValues();
|
||||
},
|
||||
}
|
||||
|
||||
_permissionIsOwnerOrGlobal(permissionId, section) {
|
||||
return permissionId === 'owner' || section === 'GLOBAL_CAPABILITIES';
|
||||
},
|
||||
}
|
||||
|
||||
_handleEditingChanged(editing, editingOld) {
|
||||
// Ignore when editing gets set initially.
|
||||
@@ -130,20 +139,20 @@
|
||||
this.set(['permission', 'value', 'exclusive'],
|
||||
this._originalExclusiveValue);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_handleAddedRuleRemoved(e) {
|
||||
const index = e.model.index;
|
||||
this._rules = this._rules.slice(0, index)
|
||||
.concat(this._rules.slice(index + 1, this._rules.length));
|
||||
},
|
||||
}
|
||||
|
||||
_handleValueChange() {
|
||||
this.permission.value.modified = true;
|
||||
// Allows overall access page to know a change has been made.
|
||||
this.dispatchEvent(
|
||||
new CustomEvent('access-modified', {bubbles: true, composed: true}));
|
||||
},
|
||||
}
|
||||
|
||||
_handleRemovePermission() {
|
||||
if (this.permission.value.added) {
|
||||
@@ -154,16 +163,16 @@
|
||||
this.permission.value.deleted = true;
|
||||
this.dispatchEvent(
|
||||
new CustomEvent('access-modified', {bubbles: true, composed: true}));
|
||||
},
|
||||
}
|
||||
|
||||
_handleRulesChanged(changeRecord) {
|
||||
// Update the groups to exclude in the autocomplete.
|
||||
this._groupsWithRules = this._computeGroupsWithRules(this._rules);
|
||||
},
|
||||
}
|
||||
|
||||
_sortPermission(permission) {
|
||||
this._rules = this.toSortedArray(permission.value.rules);
|
||||
},
|
||||
}
|
||||
|
||||
_computeSectionClass(editing, deleted) {
|
||||
const classList = [];
|
||||
@@ -174,12 +183,12 @@
|
||||
classList.push('deleted');
|
||||
}
|
||||
return classList.join(' ');
|
||||
},
|
||||
}
|
||||
|
||||
_handleUndoRemove() {
|
||||
this._deleted = false;
|
||||
delete this.permission.value.deleted;
|
||||
},
|
||||
}
|
||||
|
||||
_computeLabel(permission, labels) {
|
||||
if (!labels || !permission ||
|
||||
@@ -195,7 +204,7 @@
|
||||
values: this._computeLabelValues(labels[labelName].values),
|
||||
};
|
||||
return label;
|
||||
},
|
||||
}
|
||||
|
||||
_computeLabelValues(values) {
|
||||
const valuesArr = [];
|
||||
@@ -211,7 +220,7 @@
|
||||
valuesArr.push({value: parseInt(key, 10), text});
|
||||
}
|
||||
return valuesArr;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Array} rules
|
||||
@@ -224,12 +233,12 @@
|
||||
groups[rule.id] = true;
|
||||
}
|
||||
return groups;
|
||||
},
|
||||
}
|
||||
|
||||
_computeGroupName(groups, groupId) {
|
||||
return groups && groups[groupId] && groups[groupId].name ?
|
||||
groups[groupId].name : groupId;
|
||||
},
|
||||
}
|
||||
|
||||
_getGroupSuggestions() {
|
||||
return this.$.restAPI.getSuggestedGroups(
|
||||
@@ -249,7 +258,7 @@
|
||||
return !this._groupsWithRules[group.value.id];
|
||||
});
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles adding a skeleton item to the dom-repeat.
|
||||
@@ -283,12 +292,14 @@
|
||||
this.set(['permission', 'value', 'rules', groupId], value);
|
||||
this.dispatchEvent(
|
||||
new CustomEvent('access-modified', {bubbles: true, composed: true}));
|
||||
},
|
||||
}
|
||||
|
||||
_computeHasRange(name) {
|
||||
if (!name) { return false; }
|
||||
|
||||
return RANGE_NAMES.includes(name.toUpperCase());
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrPermission.is, GrPermission);
|
||||
})();
|
||||
|
||||
@@ -17,39 +17,42 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-plugin-config-array-editor',
|
||||
|
||||
class GrPluginConfigArrayEditor extends Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element)) {
|
||||
static get is() { return 'gr-plugin-config-array-editor'; }
|
||||
/**
|
||||
* Fired when the plugin config option changes.
|
||||
*
|
||||
* @event plugin-config-option-changed
|
||||
*/
|
||||
|
||||
properties: {
|
||||
static get properties() {
|
||||
return {
|
||||
/** @type {?} */
|
||||
pluginOption: Object,
|
||||
/** @type {Boolean} */
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
computed: '_computeDisabled(pluginOption.*)',
|
||||
},
|
||||
/** @type {?} */
|
||||
_newValue: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
},
|
||||
pluginOption: Object,
|
||||
/** @type {Boolean} */
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
computed: '_computeDisabled(pluginOption.*)',
|
||||
},
|
||||
/** @type {?} */
|
||||
_newValue: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
_computeDisabled(record) {
|
||||
return !(record && record.base && record.base.info &&
|
||||
record.base.info.editable);
|
||||
},
|
||||
}
|
||||
|
||||
_handleAddTap(e) {
|
||||
e.preventDefault();
|
||||
this._handleAdd();
|
||||
},
|
||||
}
|
||||
|
||||
_handleInputKeydown(e) {
|
||||
// Enter.
|
||||
@@ -57,20 +60,20 @@
|
||||
e.preventDefault();
|
||||
this._handleAdd();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_handleAdd() {
|
||||
if (!this._newValue.length) { return; }
|
||||
this._dispatchChanged(
|
||||
this.pluginOption.info.values.concat([this._newValue]));
|
||||
this._newValue = '';
|
||||
},
|
||||
}
|
||||
|
||||
_handleDelete(e) {
|
||||
const value = Polymer.dom(e).localTarget.dataset.item;
|
||||
this._dispatchChanged(
|
||||
this.pluginOption.info.values.filter(str => str !== value));
|
||||
},
|
||||
}
|
||||
|
||||
_dispatchChanged(values) {
|
||||
const {_key, info} = this.pluginOption;
|
||||
@@ -81,10 +84,13 @@
|
||||
};
|
||||
this.dispatchEvent(
|
||||
new CustomEvent('plugin-config-option-changed', {detail}));
|
||||
},
|
||||
}
|
||||
|
||||
_computeShowInputRow(disabled) {
|
||||
return disabled ? 'hide' : '';
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrPluginConfigArrayEditor.is,
|
||||
GrPluginConfigArrayEditor);
|
||||
})();
|
||||
|
||||
@@ -17,60 +17,67 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-plugin-list',
|
||||
/**
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
* @appliesMixin Gerrit.ListViewMixin
|
||||
*/
|
||||
class GrPluginList extends Polymer.mixinBehaviors( [
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.ListViewBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-plugin-list'; }
|
||||
|
||||
properties: {
|
||||
static get properties() {
|
||||
return {
|
||||
/**
|
||||
* URL params passed from the router.
|
||||
*/
|
||||
params: {
|
||||
type: Object,
|
||||
observer: '_paramsChanged',
|
||||
},
|
||||
/**
|
||||
params: {
|
||||
type: Object,
|
||||
observer: '_paramsChanged',
|
||||
},
|
||||
/**
|
||||
* Offset of currently visible query results.
|
||||
*/
|
||||
_offset: {
|
||||
type: Number,
|
||||
value: 0,
|
||||
},
|
||||
_path: {
|
||||
type: String,
|
||||
readOnly: true,
|
||||
value: '/admin/plugins',
|
||||
},
|
||||
_plugins: Array,
|
||||
/**
|
||||
_offset: {
|
||||
type: Number,
|
||||
value: 0,
|
||||
},
|
||||
_path: {
|
||||
type: String,
|
||||
readOnly: true,
|
||||
value: '/admin/plugins',
|
||||
},
|
||||
_plugins: Array,
|
||||
/**
|
||||
* Because we request one more than the pluginsPerPage, _shownPlugins
|
||||
* maybe one less than _plugins.
|
||||
* */
|
||||
_shownPlugins: {
|
||||
type: Array,
|
||||
computed: 'computeShownItems(_plugins)',
|
||||
},
|
||||
_pluginsPerPage: {
|
||||
type: Number,
|
||||
value: 25,
|
||||
},
|
||||
_loading: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
_filter: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.ListViewBehavior,
|
||||
],
|
||||
_shownPlugins: {
|
||||
type: Array,
|
||||
computed: 'computeShownItems(_plugins)',
|
||||
},
|
||||
_pluginsPerPage: {
|
||||
type: Number,
|
||||
value: 25,
|
||||
},
|
||||
_loading: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
_filter: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
attached() {
|
||||
super.attached();
|
||||
this.fire('title-change', {title: 'Plugins'});
|
||||
},
|
||||
}
|
||||
|
||||
_paramsChanged(params) {
|
||||
this._loading = true;
|
||||
@@ -79,7 +86,7 @@
|
||||
|
||||
return this._getPlugins(this._filter, this._pluginsPerPage,
|
||||
this._offset);
|
||||
},
|
||||
}
|
||||
|
||||
_getPlugins(filter, pluginsPerPage, offset) {
|
||||
const errFn = response => {
|
||||
@@ -99,14 +106,16 @@
|
||||
});
|
||||
this._loading = false;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_status(item) {
|
||||
return item.disabled === true ? 'Disabled' : 'Enabled';
|
||||
},
|
||||
}
|
||||
|
||||
_computePluginUrl(id) {
|
||||
return this.getUrl('/', id);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrPluginList.is, GrPluginList);
|
||||
})();
|
||||
|
||||
@@ -67,66 +67,77 @@
|
||||
*/
|
||||
Defs.projectAccessInput;
|
||||
|
||||
Polymer({
|
||||
is: 'gr-repo-access',
|
||||
/**
|
||||
* @appliesMixin Gerrit.AccessMixin
|
||||
* @appliesMixin Gerrit.BaseUrlMixin
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
* @appliesMixin Gerrit.URLEncodingMixin
|
||||
*/
|
||||
class GrRepoAccess extends Polymer.mixinBehaviors( [
|
||||
Gerrit.AccessBehavior,
|
||||
Gerrit.BaseUrlBehavior,
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.URLEncodingBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-repo-access'; }
|
||||
|
||||
properties: {
|
||||
repo: {
|
||||
type: String,
|
||||
observer: '_repoChanged',
|
||||
},
|
||||
// The current path
|
||||
path: String,
|
||||
|
||||
_canUpload: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_inheritFromFilter: String,
|
||||
_query: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._getInheritFromSuggestions.bind(this);
|
||||
static get properties() {
|
||||
return {
|
||||
repo: {
|
||||
type: String,
|
||||
observer: '_repoChanged',
|
||||
},
|
||||
},
|
||||
_ownerOf: Array,
|
||||
_capabilities: Object,
|
||||
_groups: Object,
|
||||
/** @type {?} */
|
||||
_inheritsFrom: Object,
|
||||
_labels: Object,
|
||||
_local: Object,
|
||||
_editing: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
observer: '_handleEditingChanged',
|
||||
},
|
||||
_modified: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_sections: Array,
|
||||
_weblinks: Array,
|
||||
_loading: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
},
|
||||
// The current path
|
||||
path: String,
|
||||
|
||||
behaviors: [
|
||||
Gerrit.AccessBehavior,
|
||||
Gerrit.BaseUrlBehavior,
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.URLEncodingBehavior,
|
||||
],
|
||||
_canUpload: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_inheritFromFilter: String,
|
||||
_query: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._getInheritFromSuggestions.bind(this);
|
||||
},
|
||||
},
|
||||
_ownerOf: Array,
|
||||
_capabilities: Object,
|
||||
_groups: Object,
|
||||
/** @type {?} */
|
||||
_inheritsFrom: Object,
|
||||
_labels: Object,
|
||||
_local: Object,
|
||||
_editing: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
observer: '_handleEditingChanged',
|
||||
},
|
||||
_modified: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_sections: Array,
|
||||
_weblinks: Array,
|
||||
_loading: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
listeners: {
|
||||
'access-modified': '_handleAccessModified',
|
||||
},
|
||||
created() {
|
||||
super.created();
|
||||
this.addEventListener('access-modified',
|
||||
() =>
|
||||
this._handleAccessModified());
|
||||
}
|
||||
|
||||
_handleAccessModified() {
|
||||
this._modified = true;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} repo
|
||||
@@ -138,7 +149,7 @@
|
||||
if (!repo) { return Promise.resolve(); }
|
||||
|
||||
return this._reload(repo);
|
||||
},
|
||||
}
|
||||
|
||||
_reload(repo) {
|
||||
const promises = [];
|
||||
@@ -195,7 +206,7 @@
|
||||
this._sections = sections;
|
||||
this._loading = false;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleUpdateInheritFrom(e) {
|
||||
if (!this._inheritsFrom) {
|
||||
@@ -204,7 +215,7 @@
|
||||
this._inheritsFrom.id = e.detail.value;
|
||||
this._inheritsFrom.name = this._inheritFromFilter;
|
||||
this._handleAccessModified();
|
||||
},
|
||||
}
|
||||
|
||||
_getInheritFromSuggestions() {
|
||||
return this.$.restAPI.getRepos(
|
||||
@@ -221,33 +232,33 @@
|
||||
}
|
||||
return projects;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_computeLoadingClass(loading) {
|
||||
return loading ? 'loading' : '';
|
||||
},
|
||||
}
|
||||
|
||||
_handleEdit() {
|
||||
this._editing = !this._editing;
|
||||
},
|
||||
}
|
||||
|
||||
_editOrCancel(editing) {
|
||||
return editing ? 'Cancel' : 'Edit';
|
||||
},
|
||||
}
|
||||
|
||||
_computeWebLinkClass(weblinks) {
|
||||
return weblinks && weblinks.length ? 'show' : '';
|
||||
},
|
||||
}
|
||||
|
||||
_computeShowInherit(inheritsFrom) {
|
||||
return inheritsFrom ? 'show' : '';
|
||||
},
|
||||
}
|
||||
|
||||
_handleAddedSectionRemoved(e) {
|
||||
const index = e.model.index;
|
||||
this._sections = this._sections.slice(0, index)
|
||||
.concat(this._sections.slice(index + 1, this._sections.length));
|
||||
},
|
||||
}
|
||||
|
||||
_handleEditingChanged(editing, editingOld) {
|
||||
// Ignore when editing gets set initially.
|
||||
@@ -266,7 +277,7 @@
|
||||
delete this._local[key];
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Defs.projectAccessInput} addRemoveObj
|
||||
@@ -296,7 +307,7 @@
|
||||
curPos = curPos[item];
|
||||
}
|
||||
return addRemoveObj;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to recursively remove any objects with a 'deleted' bit.
|
||||
@@ -313,7 +324,7 @@
|
||||
this._recursivelyRemoveDeleted(obj[k]);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_recursivelyUpdateAddRemoveObj(obj, addRemoveObj, path = []) {
|
||||
for (const k in obj) {
|
||||
@@ -354,7 +365,7 @@
|
||||
path.concat(k));
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object formatted for saving or submitting access changes for
|
||||
@@ -388,7 +399,7 @@
|
||||
addRemoveObj.parent = inheritsFromId;
|
||||
}
|
||||
return addRemoveObj;
|
||||
},
|
||||
}
|
||||
|
||||
_handleCreateSection() {
|
||||
let newRef = 'refs/for/*';
|
||||
@@ -403,7 +414,7 @@
|
||||
Polymer.dom.flush();
|
||||
Polymer.dom(this.root).querySelector('gr-access-section:last-of-type')
|
||||
.editReference();
|
||||
},
|
||||
}
|
||||
|
||||
_getObjforSave() {
|
||||
const addRemoveObj = this._computeAddAndRemove();
|
||||
@@ -426,7 +437,7 @@
|
||||
obj.parent = addRemoveObj.parent;
|
||||
}
|
||||
return obj;
|
||||
},
|
||||
}
|
||||
|
||||
_handleSave() {
|
||||
const obj = this._getObjforSave();
|
||||
@@ -435,7 +446,7 @@
|
||||
.then(() => {
|
||||
this._reload(this.repo);
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleSaveForReview() {
|
||||
const obj = this._getObjforSave();
|
||||
@@ -444,15 +455,15 @@
|
||||
.then(change => {
|
||||
Gerrit.Nav.navigateToChange(change);
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_computeSaveReviewBtnClass(canUpload) {
|
||||
return !canUpload ? 'invisible' : '';
|
||||
},
|
||||
}
|
||||
|
||||
_computeSaveBtnClass(ownerOf) {
|
||||
return ownerOf && ownerOf.length === 0 ? 'invisible' : '';
|
||||
},
|
||||
}
|
||||
|
||||
_computeMainClass(ownerOf, canUpload, editing) {
|
||||
const classList = [];
|
||||
@@ -463,11 +474,13 @@
|
||||
classList.push('editing');
|
||||
}
|
||||
return classList.join(' ');
|
||||
},
|
||||
}
|
||||
|
||||
_computeParentHref(repoName) {
|
||||
return this.getBaseUrl() +
|
||||
`/admin/repos/${this.encodeURL(repoName, true)},access`;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrRepoAccess.is, GrRepoAccess);
|
||||
})();
|
||||
|
||||
@@ -17,14 +17,18 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-repo-command',
|
||||
class GrRepoCommand extends Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element)) {
|
||||
static get is() { return 'gr-repo-command'; }
|
||||
|
||||
properties: {
|
||||
title: String,
|
||||
disabled: Boolean,
|
||||
tooltip: String,
|
||||
},
|
||||
static get properties() {
|
||||
return {
|
||||
title: String,
|
||||
disabled: Boolean,
|
||||
tooltip: String,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired when command button is tapped.
|
||||
@@ -35,6 +39,8 @@
|
||||
_onCommandTap() {
|
||||
this.dispatchEvent(
|
||||
new CustomEvent('command-tap', {bubbles: true, composed: true}));
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrRepoCommand.is, GrRepoCommand);
|
||||
})();
|
||||
|
||||
@@ -26,30 +26,36 @@
|
||||
const CREATE_CHANGE_FAILED_MESSAGE = 'Failed to create change.';
|
||||
const CREATE_CHANGE_SUCCEEDED_MESSAGE = 'Navigating to change';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-repo-commands',
|
||||
/**
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
*/
|
||||
class GrRepoCommands extends Polymer.mixinBehaviors( [
|
||||
Gerrit.FireBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-repo-commands'; }
|
||||
|
||||
properties: {
|
||||
params: Object,
|
||||
repo: String,
|
||||
_loading: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
/** @type {?} */
|
||||
_repoConfig: Object,
|
||||
_canCreate: Boolean,
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
Gerrit.FireBehavior,
|
||||
],
|
||||
static get properties() {
|
||||
return {
|
||||
params: Object,
|
||||
repo: String,
|
||||
_loading: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
/** @type {?} */
|
||||
_repoConfig: Object,
|
||||
_canCreate: Boolean,
|
||||
};
|
||||
}
|
||||
|
||||
attached() {
|
||||
super.attached();
|
||||
this._loadRepo();
|
||||
|
||||
this.fire('title-change', {title: 'Repo Commands'});
|
||||
},
|
||||
}
|
||||
|
||||
_loadRepo() {
|
||||
if (!this.repo) { return Promise.resolve(); }
|
||||
@@ -65,15 +71,15 @@
|
||||
this._repoConfig = config;
|
||||
this._loading = false;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_computeLoadingClass(loading) {
|
||||
return loading ? 'loading' : '';
|
||||
},
|
||||
}
|
||||
|
||||
_isLoading() {
|
||||
return this._loading || this._loading === undefined;
|
||||
},
|
||||
}
|
||||
|
||||
_handleRunningGC() {
|
||||
return this.$.restAPI.runRepoGC(this.repo).then(response => {
|
||||
@@ -83,20 +89,20 @@
|
||||
{detail: {message: GC_MESSAGE}, bubbles: true, composed: true}));
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_createNewChange() {
|
||||
this.$.createChangeOverlay.open();
|
||||
},
|
||||
}
|
||||
|
||||
_handleCreateChange() {
|
||||
this.$.createNewChangeModal.handleCreateChange();
|
||||
this._handleCloseCreateChange();
|
||||
},
|
||||
}
|
||||
|
||||
_handleCloseCreateChange() {
|
||||
this.$.createChangeOverlay.close();
|
||||
},
|
||||
}
|
||||
|
||||
_handleEditRepoConfig() {
|
||||
return this.$.restAPI.createChange(this.repo, CONFIG_BRANCH,
|
||||
@@ -112,6 +118,8 @@
|
||||
Gerrit.Nav.navigateToRelativeUrl(Gerrit.Nav.getEditUrlForDiff(
|
||||
change, CONFIG_PATH, INITIAL_PATCHSET));
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrRepoCommands.is, GrRepoCommands);
|
||||
})();
|
||||
|
||||
@@ -17,24 +17,29 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-repo-dashboards',
|
||||
/**
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
*/
|
||||
class GrRepoDashboards extends Polymer.mixinBehaviors( [
|
||||
Gerrit.FireBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-repo-dashboards'; }
|
||||
|
||||
properties: {
|
||||
repo: {
|
||||
type: String,
|
||||
observer: '_repoChanged',
|
||||
},
|
||||
_loading: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
_dashboards: Array,
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
Gerrit.FireBehavior,
|
||||
],
|
||||
static get properties() {
|
||||
return {
|
||||
repo: {
|
||||
type: String,
|
||||
observer: '_repoChanged',
|
||||
},
|
||||
_loading: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
_dashboards: Array,
|
||||
};
|
||||
}
|
||||
|
||||
_repoChanged(repo) {
|
||||
this._loading = true;
|
||||
@@ -70,24 +75,26 @@
|
||||
this._loading = false;
|
||||
Polymer.dom.flush();
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_getUrl(project, id) {
|
||||
if (!project || !id) { return ''; }
|
||||
|
||||
return Gerrit.Nav.getUrlForRepoDashboard(project, id);
|
||||
},
|
||||
}
|
||||
|
||||
_computeLoadingClass(loading) {
|
||||
return loading ? 'loading' : '';
|
||||
},
|
||||
}
|
||||
|
||||
_computeInheritedFrom(project, definingProject) {
|
||||
return project === definingProject ? '' : definingProject;
|
||||
},
|
||||
}
|
||||
|
||||
_computeIsDefault(isDefault) {
|
||||
return isDefault ? '✓' : '';
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrRepoDashboards.is, GrRepoDashboards);
|
||||
})();
|
||||
|
||||
@@ -24,75 +24,82 @@
|
||||
|
||||
const PGP_START = '-----BEGIN PGP SIGNATURE-----';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-repo-detail-list',
|
||||
/**
|
||||
* @appliesMixin Gerrit.ListViewMixin
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
* @appliesMixin Gerrit.URLEncodingMixin
|
||||
*/
|
||||
class GrRepoDetailList extends Polymer.mixinBehaviors( [
|
||||
Gerrit.ListViewBehavior,
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.URLEncodingBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-repo-detail-list'; }
|
||||
|
||||
properties: {
|
||||
static get properties() {
|
||||
return {
|
||||
/**
|
||||
* URL params passed from the router.
|
||||
*/
|
||||
params: {
|
||||
type: Object,
|
||||
observer: '_paramsChanged',
|
||||
},
|
||||
/**
|
||||
params: {
|
||||
type: Object,
|
||||
observer: '_paramsChanged',
|
||||
},
|
||||
/**
|
||||
* The kind of detail we are displaying, possibilities are determined by
|
||||
* the const DETAIL_TYPES.
|
||||
*/
|
||||
detailType: String,
|
||||
detailType: String,
|
||||
|
||||
_editing: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_isOwner: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_loggedIn: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
/**
|
||||
_editing: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_isOwner: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_loggedIn: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
/**
|
||||
* Offset of currently visible query results.
|
||||
*/
|
||||
_offset: Number,
|
||||
_repo: Object,
|
||||
_items: Array,
|
||||
/**
|
||||
_offset: Number,
|
||||
_repo: Object,
|
||||
_items: Array,
|
||||
/**
|
||||
* Because we request one more than the projectsPerPage, _shownProjects
|
||||
* maybe one less than _projects.
|
||||
*/
|
||||
_shownItems: {
|
||||
type: Array,
|
||||
computed: 'computeShownItems(_items)',
|
||||
},
|
||||
_itemsPerPage: {
|
||||
type: Number,
|
||||
value: 25,
|
||||
},
|
||||
_loading: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
_filter: String,
|
||||
_refName: String,
|
||||
_hasNewItemName: Boolean,
|
||||
_isEditing: Boolean,
|
||||
_revisedRef: String,
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
Gerrit.ListViewBehavior,
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.URLEncodingBehavior,
|
||||
],
|
||||
_shownItems: {
|
||||
type: Array,
|
||||
computed: 'computeShownItems(_items)',
|
||||
},
|
||||
_itemsPerPage: {
|
||||
type: Number,
|
||||
value: 25,
|
||||
},
|
||||
_loading: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
_filter: String,
|
||||
_refName: String,
|
||||
_hasNewItemName: Boolean,
|
||||
_isEditing: Boolean,
|
||||
_revisedRef: String,
|
||||
};
|
||||
}
|
||||
|
||||
_determineIfOwner(repo) {
|
||||
return this.$.restAPI.getRepoAccess(repo)
|
||||
.then(access =>
|
||||
this._isOwner = access && !!access[repo].is_owner);
|
||||
},
|
||||
}
|
||||
|
||||
_paramsChanged(params) {
|
||||
if (!params || !params.repo) { return; }
|
||||
@@ -113,7 +120,7 @@
|
||||
|
||||
return this._getItems(this._filter, this._repo,
|
||||
this._itemsPerPage, this._offset, this.detailType);
|
||||
},
|
||||
}
|
||||
|
||||
_getItems(filter, repo, itemsPerPage, offset, detailType) {
|
||||
this._loading = true;
|
||||
@@ -137,24 +144,24 @@
|
||||
this._loading = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_getPath(repo) {
|
||||
return `/admin/repos/${this.encodeURL(repo, false)},` +
|
||||
`${this.detailType}`;
|
||||
},
|
||||
}
|
||||
|
||||
_computeWeblink(repo) {
|
||||
if (!repo.web_links) { return ''; }
|
||||
const webLinks = repo.web_links;
|
||||
return webLinks.length ? webLinks : null;
|
||||
},
|
||||
}
|
||||
|
||||
_computeMessage(message) {
|
||||
if (!message) { return; }
|
||||
// Strip PGP info.
|
||||
return message.split(PGP_START)[0];
|
||||
},
|
||||
}
|
||||
|
||||
_stripRefs(item, detailType) {
|
||||
if (detailType === DETAIL_TYPES.BRANCHES) {
|
||||
@@ -162,33 +169,33 @@
|
||||
} else if (detailType === DETAIL_TYPES.TAGS) {
|
||||
return item.replace('refs/tags/', '');
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_getLoggedIn() {
|
||||
return this.$.restAPI.getLoggedIn();
|
||||
},
|
||||
}
|
||||
|
||||
_computeEditingClass(isEditing) {
|
||||
return isEditing ? 'editing' : '';
|
||||
},
|
||||
}
|
||||
|
||||
_computeCanEditClass(ref, detailType, isOwner) {
|
||||
return isOwner && this._stripRefs(ref, detailType) === 'HEAD' ?
|
||||
'canEdit' : '';
|
||||
},
|
||||
}
|
||||
|
||||
_handleEditRevision(e) {
|
||||
this._revisedRef = e.model.get('item.revision');
|
||||
this._isEditing = true;
|
||||
},
|
||||
}
|
||||
|
||||
_handleCancelRevision() {
|
||||
this._isEditing = false;
|
||||
},
|
||||
}
|
||||
|
||||
_handleSaveRevision(e) {
|
||||
this._setRepoHead(this._repo, this._revisedRef, e);
|
||||
},
|
||||
}
|
||||
|
||||
_setRepoHead(repo, ref, e) {
|
||||
return this.$.restAPI.setRepoHead(repo, ref).then(res => {
|
||||
@@ -202,7 +209,7 @@
|
||||
this._offset, this.detailType);
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_computeItemName(detailType) {
|
||||
if (detailType === DETAIL_TYPES.BRANCHES) {
|
||||
@@ -210,7 +217,7 @@
|
||||
} else if (detailType === DETAIL_TYPES.TAGS) {
|
||||
return 'Tag';
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_handleDeleteItemConfirm() {
|
||||
this.$.overlay.close();
|
||||
@@ -233,18 +240,18 @@
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_handleConfirmDialogCancel() {
|
||||
this.$.overlay.close();
|
||||
},
|
||||
}
|
||||
|
||||
_handleDeleteItem(e) {
|
||||
const name = this._stripRefs(e.model.get('item.ref'), this.detailType);
|
||||
if (!name) { return; }
|
||||
this._refName = name;
|
||||
this.$.overlay.open();
|
||||
},
|
||||
}
|
||||
|
||||
_computeHideDeleteClass(owner, canDelete) {
|
||||
if (canDelete || owner) {
|
||||
@@ -252,20 +259,20 @@
|
||||
}
|
||||
|
||||
return '';
|
||||
},
|
||||
}
|
||||
|
||||
_handleCreateItem() {
|
||||
this.$.createNewModal.handleCreateItem();
|
||||
this._handleCloseCreate();
|
||||
},
|
||||
}
|
||||
|
||||
_handleCloseCreate() {
|
||||
this.$.createOverlay.close();
|
||||
},
|
||||
}
|
||||
|
||||
_handleCreateClicked() {
|
||||
this.$.createOverlay.open();
|
||||
},
|
||||
}
|
||||
|
||||
_hideIfBranch(type) {
|
||||
if (type === DETAIL_TYPES.BRANCHES) {
|
||||
@@ -273,10 +280,12 @@
|
||||
}
|
||||
|
||||
return '';
|
||||
},
|
||||
}
|
||||
|
||||
_computeHideTagger(tagger) {
|
||||
return tagger ? '' : 'hide';
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrRepoDetailList.is, GrRepoDetailList);
|
||||
})();
|
||||
|
||||
@@ -17,67 +17,73 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-repo-list',
|
||||
/**
|
||||
* @appliesMixin Gerrit.ListViewMixin
|
||||
*/
|
||||
class GrRepoList extends Polymer.mixinBehaviors( [
|
||||
Gerrit.ListViewBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-repo-list'; }
|
||||
|
||||
properties: {
|
||||
static get properties() {
|
||||
return {
|
||||
/**
|
||||
* URL params passed from the router.
|
||||
*/
|
||||
params: {
|
||||
type: Object,
|
||||
observer: '_paramsChanged',
|
||||
},
|
||||
params: {
|
||||
type: Object,
|
||||
observer: '_paramsChanged',
|
||||
},
|
||||
|
||||
/**
|
||||
/**
|
||||
* Offset of currently visible query results.
|
||||
*/
|
||||
_offset: Number,
|
||||
_path: {
|
||||
type: String,
|
||||
readOnly: true,
|
||||
value: '/admin/repos',
|
||||
},
|
||||
_hasNewRepoName: Boolean,
|
||||
_createNewCapability: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_repos: Array,
|
||||
_offset: Number,
|
||||
_path: {
|
||||
type: String,
|
||||
readOnly: true,
|
||||
value: '/admin/repos',
|
||||
},
|
||||
_hasNewRepoName: Boolean,
|
||||
_createNewCapability: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_repos: Array,
|
||||
|
||||
/**
|
||||
/**
|
||||
* Because we request one more than the projectsPerPage, _shownProjects
|
||||
* maybe one less than _projects.
|
||||
* */
|
||||
_shownRepos: {
|
||||
type: Array,
|
||||
computed: 'computeShownItems(_repos)',
|
||||
},
|
||||
_shownRepos: {
|
||||
type: Array,
|
||||
computed: 'computeShownItems(_repos)',
|
||||
},
|
||||
|
||||
_reposPerPage: {
|
||||
type: Number,
|
||||
value: 25,
|
||||
},
|
||||
_reposPerPage: {
|
||||
type: Number,
|
||||
value: 25,
|
||||
},
|
||||
|
||||
_loading: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
_filter: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
Gerrit.ListViewBehavior,
|
||||
],
|
||||
_loading: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
_filter: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
attached() {
|
||||
super.attached();
|
||||
this._getCreateRepoCapability();
|
||||
this.fire('title-change', {title: 'Repos'});
|
||||
this._maybeOpenCreateOverlay(this.params);
|
||||
},
|
||||
}
|
||||
|
||||
_paramsChanged(params) {
|
||||
this._loading = true;
|
||||
@@ -86,7 +92,7 @@
|
||||
|
||||
return this._getRepos(this._filter, this._reposPerPage,
|
||||
this._offset);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the create overlay if the route has a hash 'create'
|
||||
@@ -96,15 +102,15 @@
|
||||
if (params && params.openCreateModal) {
|
||||
this.$.createOverlay.open();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_computeRepoUrl(name) {
|
||||
return this.getUrl(this._path + '/', name);
|
||||
},
|
||||
}
|
||||
|
||||
_computeChangesLink(name) {
|
||||
return Gerrit.Nav.getUrlForProjectChanges(name);
|
||||
},
|
||||
}
|
||||
|
||||
_getCreateRepoCapability() {
|
||||
return this.$.restAPI.getAccount().then(account => {
|
||||
@@ -116,7 +122,7 @@
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_getRepos(filter, reposPerPage, offset) {
|
||||
this._repos = [];
|
||||
@@ -127,36 +133,38 @@
|
||||
this._repos = repos;
|
||||
this._loading = false;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_refreshReposList() {
|
||||
this.$.restAPI.invalidateReposCache();
|
||||
return this._getRepos(this._filter, this._reposPerPage,
|
||||
this._offset);
|
||||
},
|
||||
}
|
||||
|
||||
_handleCreateRepo() {
|
||||
this.$.createNewModal.handleCreateRepo().then(() => {
|
||||
this._refreshReposList();
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleCloseCreate() {
|
||||
this.$.createOverlay.close();
|
||||
},
|
||||
}
|
||||
|
||||
_handleCreateClicked() {
|
||||
this.$.createOverlay.open();
|
||||
},
|
||||
}
|
||||
|
||||
_readOnly(item) {
|
||||
return item.state === 'READ_ONLY' ? 'Y' : '';
|
||||
},
|
||||
}
|
||||
|
||||
_computeWeblink(repo) {
|
||||
if (!repo.web_links) { return ''; }
|
||||
const webLinks = repo.web_links;
|
||||
return webLinks.length ? webLinks : null;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrRepoList.is, GrRepoList);
|
||||
})();
|
||||
|
||||
@@ -17,28 +17,32 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-repo-plugin-config',
|
||||
|
||||
/**
|
||||
* @appliesMixin Gerrit.RepoPluginConfigMixin
|
||||
*/
|
||||
class GrRepoPluginConfig extends Polymer.mixinBehaviors( [
|
||||
Gerrit.RepoPluginConfig,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-repo-plugin-config'; }
|
||||
/**
|
||||
* Fired when the plugin config changes.
|
||||
*
|
||||
* @event plugin-config-changed
|
||||
*/
|
||||
|
||||
properties: {
|
||||
static get properties() {
|
||||
return {
|
||||
/** @type {?} */
|
||||
pluginData: Object,
|
||||
/** @type {Array} */
|
||||
_pluginConfigOptions: {
|
||||
type: Array,
|
||||
computed: '_computePluginConfigOptions(pluginData.*)',
|
||||
},
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
Gerrit.RepoPluginConfig,
|
||||
],
|
||||
pluginData: Object,
|
||||
/** @type {Array} */
|
||||
_pluginConfigOptions: {
|
||||
type: Array,
|
||||
computed: '_computePluginConfigOptions(pluginData.*)',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
_computePluginConfigOptions(dataRecord) {
|
||||
if (!dataRecord || !dataRecord.base || !dataRecord.base.config) {
|
||||
@@ -46,34 +50,34 @@
|
||||
}
|
||||
const {config} = dataRecord.base;
|
||||
return Object.keys(config).map(_key => ({_key, info: config[_key]}));
|
||||
},
|
||||
}
|
||||
|
||||
_isArray(type) {
|
||||
return type === this.ENTRY_TYPES.ARRAY;
|
||||
},
|
||||
}
|
||||
|
||||
_isBoolean(type) {
|
||||
return type === this.ENTRY_TYPES.BOOLEAN;
|
||||
},
|
||||
}
|
||||
|
||||
_isList(type) {
|
||||
return type === this.ENTRY_TYPES.LIST;
|
||||
},
|
||||
}
|
||||
|
||||
_isString(type) {
|
||||
// Treat numbers like strings for simplicity.
|
||||
return type === this.ENTRY_TYPES.STRING ||
|
||||
type === this.ENTRY_TYPES.INT ||
|
||||
type === this.ENTRY_TYPES.LONG;
|
||||
},
|
||||
}
|
||||
|
||||
_computeDisabled(editable) {
|
||||
return editable === 'false';
|
||||
},
|
||||
}
|
||||
|
||||
_computeChecked(value) {
|
||||
return JSON.parse(value);
|
||||
},
|
||||
}
|
||||
|
||||
_handleStringChange(e) {
|
||||
const el = Polymer.dom(e).localTarget;
|
||||
@@ -81,7 +85,7 @@
|
||||
const configChangeInfo =
|
||||
this._buildConfigChangeInfo(el.value, _key);
|
||||
this._handleChange(configChangeInfo);
|
||||
},
|
||||
}
|
||||
|
||||
_handleListChange(e) {
|
||||
const el = Polymer.dom(e).localTarget;
|
||||
@@ -89,7 +93,7 @@
|
||||
const configChangeInfo =
|
||||
this._buildConfigChangeInfo(el.value, _key);
|
||||
this._handleChange(configChangeInfo);
|
||||
},
|
||||
}
|
||||
|
||||
_handleBooleanChange(e) {
|
||||
const el = Polymer.dom(e).localTarget;
|
||||
@@ -97,7 +101,7 @@
|
||||
const configChangeInfo =
|
||||
this._buildConfigChangeInfo(JSON.stringify(el.checked), _key);
|
||||
this._handleChange(configChangeInfo);
|
||||
},
|
||||
}
|
||||
|
||||
_buildConfigChangeInfo(value, _key) {
|
||||
const info = this.pluginData.config[_key];
|
||||
@@ -107,11 +111,11 @@
|
||||
info,
|
||||
notifyPath: `${_key}.value`,
|
||||
};
|
||||
},
|
||||
}
|
||||
|
||||
_handleArrayChange({detail}) {
|
||||
this._handleChange(detail);
|
||||
},
|
||||
}
|
||||
|
||||
_handleChange({_key, info, notifyPath}) {
|
||||
const {name, config} = this.pluginData;
|
||||
@@ -125,6 +129,8 @@
|
||||
|
||||
this.dispatchEvent(new CustomEvent(
|
||||
this.PLUGIN_CONFIG_CHANGED, {detail, bubbles: true, composed: true}));
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrRepoPluginConfig.is, GrRepoPluginConfig);
|
||||
})();
|
||||
|
||||
@@ -51,76 +51,84 @@
|
||||
},
|
||||
};
|
||||
|
||||
Polymer({
|
||||
is: 'gr-repo',
|
||||
/**
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
*/
|
||||
class GrRepo extends Polymer.mixinBehaviors( [
|
||||
Gerrit.FireBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-repo'; }
|
||||
|
||||
properties: {
|
||||
params: Object,
|
||||
repo: String,
|
||||
static get properties() {
|
||||
return {
|
||||
params: Object,
|
||||
repo: String,
|
||||
|
||||
_configChanged: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_loading: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
_loggedIn: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
observer: '_loggedInChanged',
|
||||
},
|
||||
/** @type {?} */
|
||||
_repoConfig: Object,
|
||||
/** @type {?} */
|
||||
_pluginData: {
|
||||
type: Array,
|
||||
computed: '_computePluginData(_repoConfig.plugin_config.*)',
|
||||
},
|
||||
_readOnly: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
_states: {
|
||||
type: Array,
|
||||
value() {
|
||||
return Object.values(STATES);
|
||||
_configChanged: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
},
|
||||
_submitTypes: {
|
||||
type: Array,
|
||||
value() {
|
||||
return Object.values(SUBMIT_TYPES);
|
||||
_loading: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
},
|
||||
_schemes: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
computed: '_computeSchemes(_schemesObj)',
|
||||
observer: '_schemesChanged',
|
||||
},
|
||||
_selectedCommand: {
|
||||
type: String,
|
||||
value: 'Clone',
|
||||
},
|
||||
_selectedScheme: String,
|
||||
_schemesObj: Object,
|
||||
},
|
||||
_loggedIn: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
observer: '_loggedInChanged',
|
||||
},
|
||||
/** @type {?} */
|
||||
_repoConfig: Object,
|
||||
/** @type {?} */
|
||||
_pluginData: {
|
||||
type: Array,
|
||||
computed: '_computePluginData(_repoConfig.plugin_config.*)',
|
||||
},
|
||||
_readOnly: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
_states: {
|
||||
type: Array,
|
||||
value() {
|
||||
return Object.values(STATES);
|
||||
},
|
||||
},
|
||||
_submitTypes: {
|
||||
type: Array,
|
||||
value() {
|
||||
return Object.values(SUBMIT_TYPES);
|
||||
},
|
||||
},
|
||||
_schemes: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
computed: '_computeSchemes(_schemesObj)',
|
||||
observer: '_schemesChanged',
|
||||
},
|
||||
_selectedCommand: {
|
||||
type: String,
|
||||
value: 'Clone',
|
||||
},
|
||||
_selectedScheme: String,
|
||||
_schemesObj: Object,
|
||||
};
|
||||
}
|
||||
|
||||
behaviors: [
|
||||
Gerrit.FireBehavior,
|
||||
],
|
||||
|
||||
observers: [
|
||||
'_handleConfigChanged(_repoConfig.*)',
|
||||
],
|
||||
static get observers() {
|
||||
return [
|
||||
'_handleConfigChanged(_repoConfig.*)',
|
||||
];
|
||||
}
|
||||
|
||||
attached() {
|
||||
super.attached();
|
||||
this._loadRepo();
|
||||
|
||||
this.fire('title-change', {title: this.repo});
|
||||
},
|
||||
}
|
||||
|
||||
_computePluginData(configRecord) {
|
||||
if (!configRecord ||
|
||||
@@ -129,7 +137,7 @@
|
||||
const pluginConfig = configRecord.base;
|
||||
return Object.keys(pluginConfig)
|
||||
.map(name => ({name, config: pluginConfig[name]}));
|
||||
},
|
||||
}
|
||||
|
||||
_loadRepo() {
|
||||
if (!this.repo) { return Promise.resolve(); }
|
||||
@@ -179,15 +187,15 @@
|
||||
}));
|
||||
|
||||
return Promise.all(promises);
|
||||
},
|
||||
}
|
||||
|
||||
_computeLoadingClass(loading) {
|
||||
return loading ? 'loading' : '';
|
||||
},
|
||||
}
|
||||
|
||||
_computeHideClass(arr) {
|
||||
return !arr || !arr.length ? 'hide' : '';
|
||||
},
|
||||
}
|
||||
|
||||
_loggedInChanged(_loggedIn) {
|
||||
if (!_loggedIn) { return; }
|
||||
@@ -197,7 +205,7 @@
|
||||
this._selectedScheme = prefs.download_scheme.toLowerCase();
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_formatBooleanSelect(item) {
|
||||
if (!item) { return; }
|
||||
@@ -218,7 +226,7 @@
|
||||
value: 'FALSE',
|
||||
},
|
||||
];
|
||||
},
|
||||
}
|
||||
|
||||
_formatSubmitTypeSelect(projectConfig) {
|
||||
if (!projectConfig) { return; }
|
||||
@@ -248,15 +256,15 @@
|
||||
},
|
||||
...allValues,
|
||||
];
|
||||
},
|
||||
}
|
||||
|
||||
_isLoading() {
|
||||
return this._loading || this._loading === undefined;
|
||||
},
|
||||
}
|
||||
|
||||
_getLoggedIn() {
|
||||
return this.$.restAPI.getLoggedIn();
|
||||
},
|
||||
}
|
||||
|
||||
_formatRepoConfigForSave(repoConfig) {
|
||||
const configInputObj = {};
|
||||
@@ -278,38 +286,38 @@
|
||||
}
|
||||
}
|
||||
return configInputObj;
|
||||
},
|
||||
}
|
||||
|
||||
_handleSaveRepoConfig() {
|
||||
return this.$.restAPI.saveRepoConfig(this.repo,
|
||||
this._formatRepoConfigForSave(this._repoConfig)).then(() => {
|
||||
this._configChanged = false;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleConfigChanged() {
|
||||
if (this._isLoading()) { return; }
|
||||
this._configChanged = true;
|
||||
},
|
||||
}
|
||||
|
||||
_computeButtonDisabled(readOnly, configChanged) {
|
||||
return readOnly || !configChanged;
|
||||
},
|
||||
}
|
||||
|
||||
_computeHeaderClass(configChanged) {
|
||||
return configChanged ? 'edited' : '';
|
||||
},
|
||||
}
|
||||
|
||||
_computeSchemes(schemesObj) {
|
||||
return Object.keys(schemesObj);
|
||||
},
|
||||
}
|
||||
|
||||
_schemesChanged(schemes) {
|
||||
if (schemes.length === 0) { return; }
|
||||
if (!schemes.includes(this._selectedScheme)) {
|
||||
this._selectedScheme = schemes.sort()[0];
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_computeCommands(repo, schemesObj, _selectedScheme) {
|
||||
if (!schemesObj || !repo || !_selectedScheme) {
|
||||
@@ -331,19 +339,21 @@
|
||||
});
|
||||
}
|
||||
return commands;
|
||||
},
|
||||
}
|
||||
|
||||
_computeRepositoriesClass(config) {
|
||||
return config ? 'showConfig': '';
|
||||
},
|
||||
}
|
||||
|
||||
_computeChangesUrl(name) {
|
||||
return Gerrit.Nav.getUrlForProjectChanges(name);
|
||||
},
|
||||
}
|
||||
|
||||
_handlePluginConfigChanged({detail: {name, config, notifyPath}}) {
|
||||
this._repoConfig.plugin_config[name] = config;
|
||||
this.notifyPath('_repoConfig.plugin_config.' + notifyPath);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrRepo.is, GrRepo);
|
||||
})();
|
||||
|
||||
@@ -63,62 +63,76 @@
|
||||
},
|
||||
];
|
||||
|
||||
Polymer({
|
||||
is: 'gr-rule-editor',
|
||||
|
||||
properties: {
|
||||
hasRange: Boolean,
|
||||
/** @type {?} */
|
||||
label: Object,
|
||||
editing: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
observer: '_handleEditingChanged',
|
||||
},
|
||||
groupId: String,
|
||||
groupName: String,
|
||||
permission: String,
|
||||
/** @type {?} */
|
||||
rule: {
|
||||
type: Object,
|
||||
notify: true,
|
||||
},
|
||||
section: String,
|
||||
|
||||
_deleted: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_originalRuleValues: Object,
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
Gerrit.AccessBehavior,
|
||||
Gerrit.BaseUrlBehavior,
|
||||
/**
|
||||
/**
|
||||
* @appliesMixin Gerrit.AccessMixin
|
||||
* @appliesMixin Gerrit.BaseUrlMixin
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
* @appliesMixin Gerrit.URLEncodingMixin
|
||||
*/
|
||||
class GrRuleEditor extends Polymer.mixinBehaviors( [
|
||||
Gerrit.AccessBehavior,
|
||||
Gerrit.BaseUrlBehavior,
|
||||
/**
|
||||
* Unused in this element, but called by other elements in tests
|
||||
* e.g gr-permission_test.
|
||||
*/
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.URLEncodingBehavior,
|
||||
],
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.URLEncodingBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-rule-editor'; }
|
||||
|
||||
observers: [
|
||||
'_handleValueChange(rule.value.*)',
|
||||
],
|
||||
static get properties() {
|
||||
return {
|
||||
hasRange: Boolean,
|
||||
/** @type {?} */
|
||||
label: Object,
|
||||
editing: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
observer: '_handleEditingChanged',
|
||||
},
|
||||
groupId: String,
|
||||
groupName: String,
|
||||
permission: String,
|
||||
/** @type {?} */
|
||||
rule: {
|
||||
type: Object,
|
||||
notify: true,
|
||||
},
|
||||
section: String,
|
||||
|
||||
listeners: {
|
||||
'access-saved': '_handleAccessSaved',
|
||||
},
|
||||
_deleted: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_originalRuleValues: Object,
|
||||
};
|
||||
}
|
||||
|
||||
static get observers() {
|
||||
return [
|
||||
'_handleValueChange(rule.value.*)',
|
||||
];
|
||||
}
|
||||
|
||||
created() {
|
||||
super.created();
|
||||
this.addEventListener('access-saved',
|
||||
() => this._handleAccessSaved());
|
||||
}
|
||||
|
||||
ready() {
|
||||
super.ready();
|
||||
// Called on ready rather than the observer because when new rules are
|
||||
// added, the observer is triggered prior to being ready.
|
||||
if (!this.rule) { return; } // Check needed for test purposes.
|
||||
this._setupValues(this.rule);
|
||||
},
|
||||
}
|
||||
|
||||
attached() {
|
||||
super.attached();
|
||||
if (!this.rule) { return; } // Check needed for test purposes.
|
||||
if (!this._originalRuleValues) {
|
||||
// Observer _handleValueChange is called after the ready()
|
||||
@@ -126,13 +140,13 @@
|
||||
// avoid set .modified flag to true
|
||||
this._setOriginalRuleValues(this.rule.value);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_setupValues(rule) {
|
||||
if (!rule.value) {
|
||||
this._setDefaultRuleValues();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_computeForce(permission, action) {
|
||||
if (this.permissionValues.push.id === permission &&
|
||||
@@ -141,21 +155,21 @@
|
||||
}
|
||||
|
||||
return this.permissionValues.editTopicName.id === permission;
|
||||
},
|
||||
}
|
||||
|
||||
_computeForceClass(permission, action) {
|
||||
return this._computeForce(permission, action) ? 'force' : '';
|
||||
},
|
||||
}
|
||||
|
||||
_computeGroupPath(group) {
|
||||
return `${this.getBaseUrl()}/admin/groups/${this.encodeURL(group, true)}`;
|
||||
},
|
||||
}
|
||||
|
||||
_handleAccessSaved() {
|
||||
// Set a new 'original' value to keep track of after the value has been
|
||||
// saved.
|
||||
this._setOriginalRuleValues(this.rule.value);
|
||||
},
|
||||
}
|
||||
|
||||
_handleEditingChanged(editing, editingOld) {
|
||||
// Ignore when editing gets set initially.
|
||||
@@ -164,7 +178,7 @@
|
||||
if (!editing) {
|
||||
this._handleUndoChange();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_computeSectionClass(editing, deleted) {
|
||||
const classList = [];
|
||||
@@ -175,7 +189,7 @@
|
||||
classList.push('deleted');
|
||||
}
|
||||
return classList.join(' ');
|
||||
},
|
||||
}
|
||||
|
||||
_computeForceOptions(permission, action) {
|
||||
if (permission === this.permissionValues.push.id) {
|
||||
@@ -190,7 +204,7 @@
|
||||
return FORCE_EDIT_OPTIONS;
|
||||
}
|
||||
return [];
|
||||
},
|
||||
}
|
||||
|
||||
_getDefaultRuleValues(permission, label) {
|
||||
const ruleAction = Action.ALLOW;
|
||||
@@ -207,19 +221,19 @@
|
||||
}
|
||||
value.action = DROPDOWN_OPTIONS[0];
|
||||
return value;
|
||||
},
|
||||
}
|
||||
|
||||
_setDefaultRuleValues() {
|
||||
this.set('rule.value', this._getDefaultRuleValues(this.permission,
|
||||
this.label));
|
||||
},
|
||||
}
|
||||
|
||||
_computeOptions(permission) {
|
||||
if (permission === 'priority') {
|
||||
return PRIORITY_OPTIONS;
|
||||
}
|
||||
return DROPDOWN_OPTIONS;
|
||||
},
|
||||
}
|
||||
|
||||
_handleRemoveRule() {
|
||||
if (this.rule.value.added) {
|
||||
@@ -230,12 +244,12 @@
|
||||
this.rule.value.deleted = true;
|
||||
this.dispatchEvent(
|
||||
new CustomEvent('access-modified', {bubbles: true, composed: true}));
|
||||
},
|
||||
}
|
||||
|
||||
_handleUndoRemove() {
|
||||
this._deleted = false;
|
||||
delete this.rule.value.deleted;
|
||||
},
|
||||
}
|
||||
|
||||
_handleUndoChange() {
|
||||
// gr-permission will take care of removing rules that were added but
|
||||
@@ -245,7 +259,7 @@
|
||||
this._deleted = false;
|
||||
delete this.rule.value.deleted;
|
||||
delete this.rule.value.modified;
|
||||
},
|
||||
}
|
||||
|
||||
_handleValueChange() {
|
||||
if (!this._originalRuleValues) { return; }
|
||||
@@ -253,10 +267,12 @@
|
||||
// Allows overall access page to know a change has been made.
|
||||
this.dispatchEvent(
|
||||
new CustomEvent('access-modified', {bubbles: true, composed: true}));
|
||||
},
|
||||
}
|
||||
|
||||
_setOriginalRuleValues(value) {
|
||||
this._originalRuleValues = Object.assign({}, value);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrRuleEditor.is, GrRuleEditor);
|
||||
})();
|
||||
|
||||
@@ -24,57 +24,67 @@
|
||||
LARGE: 1000,
|
||||
};
|
||||
|
||||
Polymer({
|
||||
is: 'gr-change-list-item',
|
||||
/**
|
||||
* @appliesMixin Gerrit.BaseUrlMixin
|
||||
* @appliesMixin Gerrit.ChangeTableMixin
|
||||
* @appliesMixin Gerrit.PathListMixin
|
||||
* @appliesMixin Gerrit.RESTClientMixin
|
||||
* @appliesMixin Gerrit.URLEncodingMixin
|
||||
*/
|
||||
class GrChangeListItem extends Polymer.mixinBehaviors( [
|
||||
Gerrit.BaseUrlBehavior,
|
||||
Gerrit.ChangeTableBehavior,
|
||||
Gerrit.PathListBehavior,
|
||||
Gerrit.RESTClientBehavior,
|
||||
Gerrit.URLEncodingBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-change-list-item'; }
|
||||
|
||||
properties: {
|
||||
visibleChangeTableColumns: Array,
|
||||
labelNames: {
|
||||
type: Array,
|
||||
},
|
||||
static get properties() {
|
||||
return {
|
||||
visibleChangeTableColumns: Array,
|
||||
labelNames: {
|
||||
type: Array,
|
||||
},
|
||||
|
||||
/** @type {?} */
|
||||
change: Object,
|
||||
changeURL: {
|
||||
type: String,
|
||||
computed: '_computeChangeURL(change)',
|
||||
},
|
||||
statuses: {
|
||||
type: Array,
|
||||
computed: 'changeStatuses(change)',
|
||||
},
|
||||
showStar: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
showNumber: Boolean,
|
||||
_changeSize: {
|
||||
type: String,
|
||||
computed: '_computeChangeSize(change)',
|
||||
},
|
||||
_dynamicCellEndpoints: {
|
||||
type: Array,
|
||||
},
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
Gerrit.BaseUrlBehavior,
|
||||
Gerrit.ChangeTableBehavior,
|
||||
Gerrit.PathListBehavior,
|
||||
Gerrit.RESTClientBehavior,
|
||||
Gerrit.URLEncodingBehavior,
|
||||
],
|
||||
/** @type {?} */
|
||||
change: Object,
|
||||
changeURL: {
|
||||
type: String,
|
||||
computed: '_computeChangeURL(change)',
|
||||
},
|
||||
statuses: {
|
||||
type: Array,
|
||||
computed: 'changeStatuses(change)',
|
||||
},
|
||||
showStar: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
showNumber: Boolean,
|
||||
_changeSize: {
|
||||
type: String,
|
||||
computed: '_computeChangeSize(change)',
|
||||
},
|
||||
_dynamicCellEndpoints: {
|
||||
type: Array,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
attached() {
|
||||
super.attached();
|
||||
Gerrit.awaitPluginsLoaded().then(() => {
|
||||
this._dynamicCellEndpoints = Gerrit._endpoints.getDynamicEndpoints(
|
||||
'change-list-item-cell');
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_computeChangeURL(change) {
|
||||
return Gerrit.Nav.getUrlForChange(change);
|
||||
},
|
||||
}
|
||||
|
||||
_computeLabelTitle(change, labelName) {
|
||||
const label = change.labels[labelName];
|
||||
@@ -85,7 +95,7 @@
|
||||
return labelName + '\nby ' + significantLabel.name;
|
||||
}
|
||||
return labelName;
|
||||
},
|
||||
}
|
||||
|
||||
_computeLabelClass(change, labelName) {
|
||||
const label = change.labels[labelName];
|
||||
@@ -112,7 +122,7 @@
|
||||
classes['u-gray-background'] = true;
|
||||
}
|
||||
return Object.keys(classes).sort().join(' ');
|
||||
},
|
||||
}
|
||||
|
||||
_computeLabelValue(change, labelName) {
|
||||
const label = change.labels[labelName];
|
||||
@@ -130,22 +140,22 @@
|
||||
return label.value;
|
||||
}
|
||||
return '';
|
||||
},
|
||||
}
|
||||
|
||||
_computeRepoUrl(change) {
|
||||
return Gerrit.Nav.getUrlForProjectChanges(change.project, true,
|
||||
change.internalHost);
|
||||
},
|
||||
}
|
||||
|
||||
_computeRepoBranchURL(change) {
|
||||
return Gerrit.Nav.getUrlForBranch(change.branch, change.project, null,
|
||||
change.internalHost);
|
||||
},
|
||||
}
|
||||
|
||||
_computeTopicURL(change) {
|
||||
if (!change.topic) { return ''; }
|
||||
return Gerrit.Nav.getUrlForTopic(change.topic, change.internalHost);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the display string for the project column. If there is a host
|
||||
@@ -162,7 +172,7 @@
|
||||
if (change.internalHost) { str += change.internalHost + '/'; }
|
||||
str += truncate ? this.truncatePath(change.project, 2) : change.project;
|
||||
return str;
|
||||
},
|
||||
}
|
||||
|
||||
_computeSizeTooltip(change) {
|
||||
if (change.insertions + change.deletions === 0 ||
|
||||
@@ -171,7 +181,7 @@
|
||||
} else {
|
||||
return `+${change.insertions}, -${change.deletions}`;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* TShirt sizing is based on the following paper:
|
||||
@@ -193,7 +203,7 @@
|
||||
} else {
|
||||
return 'XL';
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
toggleReviewed() {
|
||||
const newVal = !this.change.reviewed;
|
||||
@@ -203,6 +213,8 @@
|
||||
composed: true,
|
||||
detail: {change: this.change, reviewed: newVal},
|
||||
}));
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrChangeListItem.is, GrChangeListItem);
|
||||
})();
|
||||
|
||||
@@ -29,44 +29,49 @@
|
||||
|
||||
const LIMIT_OPERATOR_PATTERN = /\blimit:(\d+)/i;
|
||||
|
||||
Polymer({
|
||||
is: 'gr-change-list-view',
|
||||
|
||||
/**
|
||||
* @appliesMixin Gerrit.BaseUrlMixin
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
* @appliesMixin Gerrit.URLEncodingMixin
|
||||
*/
|
||||
class GrChangeListView extends Polymer.mixinBehaviors( [
|
||||
Gerrit.BaseUrlBehavior,
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.URLEncodingBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-change-list-view'; }
|
||||
/**
|
||||
* Fired when the title of the page should change.
|
||||
*
|
||||
* @event title-change
|
||||
*/
|
||||
|
||||
behaviors: [
|
||||
Gerrit.BaseUrlBehavior,
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.URLEncodingBehavior,
|
||||
],
|
||||
|
||||
properties: {
|
||||
static get properties() {
|
||||
return {
|
||||
/**
|
||||
* URL params passed from the router.
|
||||
*/
|
||||
params: {
|
||||
type: Object,
|
||||
observer: '_paramsChanged',
|
||||
},
|
||||
params: {
|
||||
type: Object,
|
||||
observer: '_paramsChanged',
|
||||
},
|
||||
|
||||
/**
|
||||
/**
|
||||
* True when user is logged in.
|
||||
*/
|
||||
_loggedIn: {
|
||||
type: Boolean,
|
||||
computed: '_computeLoggedIn(account)',
|
||||
},
|
||||
_loggedIn: {
|
||||
type: Boolean,
|
||||
computed: '_computeLoggedIn(account)',
|
||||
},
|
||||
|
||||
account: {
|
||||
type: Object,
|
||||
value: null,
|
||||
},
|
||||
account: {
|
||||
type: Object,
|
||||
value: null,
|
||||
},
|
||||
|
||||
/**
|
||||
/**
|
||||
* State persisted across restamps of the element.
|
||||
*
|
||||
* Need sub-property declaration since it is used in template before
|
||||
@@ -74,66 +79,71 @@
|
||||
* @type {{ selectedChangeIndex: (number|undefined) }}
|
||||
*
|
||||
*/
|
||||
viewState: {
|
||||
type: Object,
|
||||
notify: true,
|
||||
value() { return {}; },
|
||||
},
|
||||
viewState: {
|
||||
type: Object,
|
||||
notify: true,
|
||||
value() { return {}; },
|
||||
},
|
||||
|
||||
preferences: Object,
|
||||
preferences: Object,
|
||||
|
||||
_changesPerPage: Number,
|
||||
_changesPerPage: Number,
|
||||
|
||||
/**
|
||||
/**
|
||||
* Currently active query.
|
||||
*/
|
||||
_query: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
_query: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
|
||||
/**
|
||||
/**
|
||||
* Offset of currently visible query results.
|
||||
*/
|
||||
_offset: Number,
|
||||
_offset: Number,
|
||||
|
||||
/**
|
||||
/**
|
||||
* Change objects loaded from the server.
|
||||
*/
|
||||
_changes: {
|
||||
type: Array,
|
||||
observer: '_changesChanged',
|
||||
},
|
||||
_changes: {
|
||||
type: Array,
|
||||
observer: '_changesChanged',
|
||||
},
|
||||
|
||||
/**
|
||||
/**
|
||||
* For showing a "loading..." string during ajax requests.
|
||||
*/
|
||||
_loading: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
_loading: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
|
||||
/** @type {?String} */
|
||||
_userId: {
|
||||
type: String,
|
||||
value: null,
|
||||
},
|
||||
/** @type {?String} */
|
||||
_userId: {
|
||||
type: String,
|
||||
value: null,
|
||||
},
|
||||
|
||||
/** @type {?String} */
|
||||
_repo: {
|
||||
type: String,
|
||||
value: null,
|
||||
},
|
||||
},
|
||||
/** @type {?String} */
|
||||
_repo: {
|
||||
type: String,
|
||||
value: null,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
listeners: {
|
||||
'next-page': '_handleNextPage',
|
||||
'previous-page': '_handlePreviousPage',
|
||||
},
|
||||
created() {
|
||||
super.created();
|
||||
this.addEventListener('next-page',
|
||||
() => this._handleNextPage());
|
||||
this.addEventListener('previous-page',
|
||||
() => this._handlePreviousPage());
|
||||
}
|
||||
|
||||
attached() {
|
||||
super.attached();
|
||||
this._loadPreferences();
|
||||
},
|
||||
}
|
||||
|
||||
_paramsChanged(value) {
|
||||
if (value.view !== Gerrit.Nav.View.SEARCH) { return; }
|
||||
@@ -170,7 +180,7 @@
|
||||
this._changes = changes;
|
||||
this._loading = false;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_loadPreferences() {
|
||||
return this.$.restAPI.getLoggedIn().then(loggedIn => {
|
||||
@@ -182,20 +192,20 @@
|
||||
this.preferences = {};
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_replaceCurrentLocation(url) {
|
||||
window.location.replace(url);
|
||||
},
|
||||
}
|
||||
|
||||
_getChanges() {
|
||||
return this.$.restAPI.getChanges(this._changesPerPage, this._query,
|
||||
this._offset);
|
||||
},
|
||||
}
|
||||
|
||||
_getPreferences() {
|
||||
return this.$.restAPI.getPreferences();
|
||||
},
|
||||
}
|
||||
|
||||
_limitFor(query, defaultLimit) {
|
||||
const match = query.match(LIMIT_OPERATOR_PATTERN);
|
||||
@@ -203,7 +213,7 @@
|
||||
return defaultLimit;
|
||||
}
|
||||
return parseInt(match[1], 10);
|
||||
},
|
||||
}
|
||||
|
||||
_computeNavLink(query, offset, direction, changesPerPage) {
|
||||
// Offset could be a string when passed from the router.
|
||||
@@ -211,32 +221,32 @@
|
||||
const limit = this._limitFor(query, changesPerPage);
|
||||
const newOffset = Math.max(0, offset + (limit * direction));
|
||||
return Gerrit.Nav.getUrlForSearchQuery(query, newOffset);
|
||||
},
|
||||
}
|
||||
|
||||
_computePrevArrowClass(offset) {
|
||||
return offset === 0 ? 'hide' : '';
|
||||
},
|
||||
}
|
||||
|
||||
_computeNextArrowClass(changes) {
|
||||
const more = changes.length && changes[changes.length - 1]._more_changes;
|
||||
return more ? '' : 'hide';
|
||||
},
|
||||
}
|
||||
|
||||
_computeNavClass(loading) {
|
||||
return loading || !this._changes || !this._changes.length ? 'hide' : '';
|
||||
},
|
||||
}
|
||||
|
||||
_handleNextPage() {
|
||||
if (this.$.nextArrow.hidden) { return; }
|
||||
page.show(this._computeNavLink(
|
||||
this._query, this._offset, 1, this._changesPerPage));
|
||||
},
|
||||
}
|
||||
|
||||
_handlePreviousPage() {
|
||||
if (this.$.prevArrow.hidden) { return; }
|
||||
page.show(this._computeNavLink(
|
||||
this._query, this._offset, -1, this._changesPerPage));
|
||||
},
|
||||
}
|
||||
|
||||
_changesChanged(changes) {
|
||||
this._userId = null;
|
||||
@@ -255,28 +265,30 @@
|
||||
if (REPO_QUERY_PATTERN.test(this._query)) {
|
||||
this._repo = changes[0].project;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_computeHeaderClass(id) {
|
||||
return id ? '' : 'hide';
|
||||
},
|
||||
}
|
||||
|
||||
_computePage(offset, changesPerPage) {
|
||||
return offset / changesPerPage + 1;
|
||||
},
|
||||
}
|
||||
|
||||
_computeLoggedIn(account) {
|
||||
return !!(account && Object.keys(account).length > 0);
|
||||
},
|
||||
}
|
||||
|
||||
_handleToggleStar(e) {
|
||||
this.$.restAPI.saveChangeStarred(e.detail.change._number,
|
||||
e.detail.starred);
|
||||
},
|
||||
}
|
||||
|
||||
_handleToggleReviewed(e) {
|
||||
this.$.restAPI.saveChangeReviewed(e.detail.change._number,
|
||||
e.detail.reviewed);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrChangeListView.is, GrChangeListView);
|
||||
})();
|
||||
|
||||
@@ -22,9 +22,25 @@
|
||||
const LABEL_PREFIX_INVALID_PROLOG = 'Invalid-Prolog-Rules-Label-Name--';
|
||||
const MAX_SHORTCUT_CHARS = 5;
|
||||
|
||||
Polymer({
|
||||
is: 'gr-change-list',
|
||||
|
||||
/**
|
||||
* @appliesMixin Gerrit.BaseUrlMixin
|
||||
* @appliesMixin Gerrit.ChangeTableMixin
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
* @appliesMixin Gerrit.KeyboardShortcutMixin
|
||||
* @appliesMixin Gerrit.RESTClientMixin
|
||||
* @appliesMixin Gerrit.URLEncodingMixin
|
||||
*/
|
||||
class GrChangeList extends Polymer.mixinBehaviors( [
|
||||
Gerrit.BaseUrlBehavior,
|
||||
Gerrit.ChangeTableBehavior,
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.KeyboardShortcutBehavior,
|
||||
Gerrit.RESTClientBehavior,
|
||||
Gerrit.URLEncodingBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-change-list'; }
|
||||
/**
|
||||
* Fired when next page key shortcut was pressed.
|
||||
*
|
||||
@@ -37,28 +53,25 @@
|
||||
* @event previous-page
|
||||
*/
|
||||
|
||||
hostAttributes: {
|
||||
tabindex: 0,
|
||||
},
|
||||
|
||||
properties: {
|
||||
static get properties() {
|
||||
return {
|
||||
/**
|
||||
* The logged-in user's account, or an empty object if no user is logged
|
||||
* in.
|
||||
*/
|
||||
account: {
|
||||
type: Object,
|
||||
value: null,
|
||||
},
|
||||
/**
|
||||
account: {
|
||||
type: Object,
|
||||
value: null,
|
||||
},
|
||||
/**
|
||||
* An array of ChangeInfo objects to render.
|
||||
* https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#change-info
|
||||
*/
|
||||
changes: {
|
||||
type: Array,
|
||||
observer: '_changesChanged',
|
||||
},
|
||||
/**
|
||||
changes: {
|
||||
type: Array,
|
||||
observer: '_changesChanged',
|
||||
},
|
||||
/**
|
||||
* ChangeInfo objects grouped into arrays. The sections and changes
|
||||
* properties should not be used together.
|
||||
*
|
||||
@@ -68,56 +81,46 @@
|
||||
* results: !Array<!Object>
|
||||
* }>}
|
||||
*/
|
||||
sections: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
labelNames: {
|
||||
type: Array,
|
||||
computed: '_computeLabelNames(sections)',
|
||||
},
|
||||
_dynamicHeaderEndpoints: {
|
||||
type: Array,
|
||||
},
|
||||
selectedIndex: {
|
||||
type: Number,
|
||||
notify: true,
|
||||
},
|
||||
showNumber: Boolean, // No default value to prevent flickering.
|
||||
showStar: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
showReviewedState: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
keyEventTarget: {
|
||||
type: Object,
|
||||
value() { return document.body; },
|
||||
},
|
||||
changeTableColumns: Array,
|
||||
visibleChangeTableColumns: Array,
|
||||
preferences: Object,
|
||||
},
|
||||
sections: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
labelNames: {
|
||||
type: Array,
|
||||
computed: '_computeLabelNames(sections)',
|
||||
},
|
||||
_dynamicHeaderEndpoints: {
|
||||
type: Array,
|
||||
},
|
||||
selectedIndex: {
|
||||
type: Number,
|
||||
notify: true,
|
||||
},
|
||||
showNumber: Boolean, // No default value to prevent flickering.
|
||||
showStar: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
showReviewedState: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
keyEventTarget: {
|
||||
type: Object,
|
||||
value() { return document.body; },
|
||||
},
|
||||
changeTableColumns: Array,
|
||||
visibleChangeTableColumns: Array,
|
||||
preferences: Object,
|
||||
};
|
||||
}
|
||||
|
||||
behaviors: [
|
||||
Gerrit.BaseUrlBehavior,
|
||||
Gerrit.ChangeTableBehavior,
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.KeyboardShortcutBehavior,
|
||||
Gerrit.RESTClientBehavior,
|
||||
Gerrit.URLEncodingBehavior,
|
||||
],
|
||||
|
||||
listeners: {
|
||||
keydown: '_scopedKeydownHandler',
|
||||
},
|
||||
|
||||
observers: [
|
||||
'_sectionsChanged(sections.*)',
|
||||
'_computePreferences(account, preferences)',
|
||||
],
|
||||
static get observers() {
|
||||
return [
|
||||
'_sectionsChanged(sections.*)',
|
||||
'_computePreferences(account, preferences)',
|
||||
];
|
||||
}
|
||||
|
||||
keyboardShortcuts() {
|
||||
return {
|
||||
@@ -130,14 +133,26 @@
|
||||
[this.Shortcut.TOGGLE_CHANGE_STAR]: '_toggleChangeStar',
|
||||
[this.Shortcut.REFRESH_CHANGE_LIST]: '_refreshChangeList',
|
||||
};
|
||||
},
|
||||
}
|
||||
|
||||
created() {
|
||||
super.created();
|
||||
this.addEventListener('keydown',
|
||||
e => this._scopedKeydownHandler(e));
|
||||
}
|
||||
|
||||
ready() {
|
||||
super.ready();
|
||||
this._ensureAttribute('tabindex', 0);
|
||||
}
|
||||
|
||||
attached() {
|
||||
super.attached();
|
||||
Gerrit.awaitPluginsLoaded().then(() => {
|
||||
this._dynamicHeaderEndpoints = Gerrit._endpoints.getDynamicEndpoints(
|
||||
'change-list-header');
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Iron-a11y-keys-behavior catches keyboard events globally. Some keyboard
|
||||
@@ -151,11 +166,11 @@
|
||||
// Enter.
|
||||
this._openChange(e);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_lowerCase(column) {
|
||||
return column.toLowerCase();
|
||||
},
|
||||
}
|
||||
|
||||
_computePreferences(account, preferences) {
|
||||
// Polymer 2: check for undefined
|
||||
@@ -175,13 +190,13 @@
|
||||
this.showNumber = false;
|
||||
this.visibleChangeTableColumns = this.columnNames;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_computeColspan(changeTableColumns, labelNames) {
|
||||
if (!changeTableColumns || !labelNames) return;
|
||||
return changeTableColumns.length + labelNames.length +
|
||||
NUMBER_FIXED_COLUMNS;
|
||||
},
|
||||
}
|
||||
|
||||
_computeLabelNames(sections) {
|
||||
if (!sections) { return []; }
|
||||
@@ -198,7 +213,7 @@
|
||||
}
|
||||
}
|
||||
return labels.sort();
|
||||
},
|
||||
}
|
||||
|
||||
_computeLabelShortcut(labelName) {
|
||||
if (labelName.startsWith(LABEL_PREFIX_INVALID_PROLOG)) {
|
||||
@@ -210,11 +225,11 @@
|
||||
return a + i[0].toUpperCase();
|
||||
}, '')
|
||||
.slice(0, MAX_SHORTCUT_CHARS);
|
||||
},
|
||||
}
|
||||
|
||||
_changesChanged(changes) {
|
||||
this.sections = changes ? [{results: changes}] : [];
|
||||
},
|
||||
}
|
||||
|
||||
_processQuery(query) {
|
||||
let tokens = query.split(' ');
|
||||
@@ -225,11 +240,11 @@
|
||||
});
|
||||
});
|
||||
return tokens.join(' ');
|
||||
},
|
||||
}
|
||||
|
||||
_sectionHref(query) {
|
||||
return Gerrit.Nav.getUrlForSearchQuery(this._processQuery(query));
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps an index local to a particular section to the absolute index
|
||||
@@ -245,19 +260,19 @@
|
||||
idx += this.sections[i].results.length;
|
||||
}
|
||||
return idx + localIndex;
|
||||
},
|
||||
}
|
||||
|
||||
_computeItemSelected(sectionIndex, index, selectedIndex) {
|
||||
const idx = this._computeItemAbsoluteIndex(sectionIndex, index);
|
||||
return idx == selectedIndex;
|
||||
},
|
||||
}
|
||||
|
||||
_computeItemNeedsReview(account, change, showReviewedState) {
|
||||
return showReviewedState && !change.reviewed &&
|
||||
!change.work_in_progress &&
|
||||
this.changeIsOpen(change) &&
|
||||
(!account || account._account_id != change.owner._account_id);
|
||||
},
|
||||
}
|
||||
|
||||
_computeItemHighlight(account, change) {
|
||||
// Do not show the assignee highlight if the change is not open.
|
||||
@@ -267,7 +282,7 @@
|
||||
return false;
|
||||
}
|
||||
return account._account_id === change.assignee._account_id;
|
||||
},
|
||||
}
|
||||
|
||||
_nextChange(e) {
|
||||
if (this.shouldSuppressKeyboardShortcut(e) ||
|
||||
@@ -275,7 +290,7 @@
|
||||
|
||||
e.preventDefault();
|
||||
this.$.cursor.next();
|
||||
},
|
||||
}
|
||||
|
||||
_prevChange(e) {
|
||||
if (this.shouldSuppressKeyboardShortcut(e) ||
|
||||
@@ -283,7 +298,7 @@
|
||||
|
||||
e.preventDefault();
|
||||
this.$.cursor.previous();
|
||||
},
|
||||
}
|
||||
|
||||
_openChange(e) {
|
||||
if (this.shouldSuppressKeyboardShortcut(e) ||
|
||||
@@ -291,7 +306,7 @@
|
||||
|
||||
e.preventDefault();
|
||||
Gerrit.Nav.navigateToChange(this._changeForIndex(this.selectedIndex));
|
||||
},
|
||||
}
|
||||
|
||||
_nextPage(e) {
|
||||
if (this.shouldSuppressKeyboardShortcut(e) ||
|
||||
@@ -301,7 +316,7 @@
|
||||
|
||||
e.preventDefault();
|
||||
this.fire('next-page');
|
||||
},
|
||||
}
|
||||
|
||||
_prevPage(e) {
|
||||
if (this.shouldSuppressKeyboardShortcut(e) ||
|
||||
@@ -311,7 +326,7 @@
|
||||
|
||||
e.preventDefault();
|
||||
this.fire('previous-page');
|
||||
},
|
||||
}
|
||||
|
||||
_toggleChangeReviewed(e) {
|
||||
if (this.shouldSuppressKeyboardShortcut(e) ||
|
||||
@@ -319,7 +334,7 @@
|
||||
|
||||
e.preventDefault();
|
||||
this._toggleReviewedForIndex(this.selectedIndex);
|
||||
},
|
||||
}
|
||||
|
||||
_toggleReviewedForIndex(index) {
|
||||
const changeEls = this._getListItems();
|
||||
@@ -329,18 +344,18 @@
|
||||
|
||||
const changeEl = changeEls[index];
|
||||
changeEl.toggleReviewed();
|
||||
},
|
||||
}
|
||||
|
||||
_refreshChangeList(e) {
|
||||
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||
|
||||
e.preventDefault();
|
||||
this._reloadWindow();
|
||||
},
|
||||
}
|
||||
|
||||
_reloadWindow() {
|
||||
window.location.reload();
|
||||
},
|
||||
}
|
||||
|
||||
_toggleChangeStar(e) {
|
||||
if (this.shouldSuppressKeyboardShortcut(e) ||
|
||||
@@ -348,7 +363,7 @@
|
||||
|
||||
e.preventDefault();
|
||||
this._toggleStarForIndex(this.selectedIndex);
|
||||
},
|
||||
}
|
||||
|
||||
_toggleStarForIndex(index) {
|
||||
const changeEls = this._getListItems();
|
||||
@@ -358,7 +373,7 @@
|
||||
|
||||
const changeEl = changeEls[index];
|
||||
changeEl.$$('gr-change-star').toggleStar();
|
||||
},
|
||||
}
|
||||
|
||||
_changeForIndex(index) {
|
||||
const changeEls = this._getListItems();
|
||||
@@ -366,12 +381,12 @@
|
||||
return changeEls[index].change;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
}
|
||||
|
||||
_getListItems() {
|
||||
return Array.from(
|
||||
Polymer.dom(this.root).querySelectorAll('gr-change-list-item'));
|
||||
},
|
||||
}
|
||||
|
||||
_sectionsChanged() {
|
||||
// Flush DOM operations so that the list item elements will be loaded.
|
||||
@@ -379,14 +394,16 @@
|
||||
this.$.cursor.stops = this._getListItems();
|
||||
this.$.cursor.moveToStart();
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_isOutgoing(section) {
|
||||
return !!section.isOutgoing;
|
||||
},
|
||||
}
|
||||
|
||||
_isEmpty(section) {
|
||||
return !section.results.length;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrChangeList.is, GrChangeList);
|
||||
})();
|
||||
|
||||
@@ -17,8 +17,10 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-create-change-help',
|
||||
class GrCreateChangeHelp extends Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element)) {
|
||||
static get is() { return 'gr-create-change-help'; }
|
||||
|
||||
/**
|
||||
* Fired when the "Create change" button is tapped.
|
||||
@@ -30,6 +32,8 @@
|
||||
e.preventDefault();
|
||||
this.dispatchEvent(
|
||||
new CustomEvent('create-tap', {bubbles: true, composed: true}));
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrCreateChangeHelp.is, GrCreateChangeHelp);
|
||||
})();
|
||||
|
||||
@@ -23,37 +23,43 @@
|
||||
PUSH_PREFIX: 'git push origin HEAD:refs/for/',
|
||||
};
|
||||
|
||||
Polymer({
|
||||
is: 'gr-create-commands-dialog',
|
||||
class GrCreateCommandsDialog extends Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element)) {
|
||||
static get is() { return 'gr-create-commands-dialog'; }
|
||||
|
||||
properties: {
|
||||
branch: String,
|
||||
_createNewCommitCommand: {
|
||||
type: String,
|
||||
readonly: true,
|
||||
value: Commands.CREATE,
|
||||
},
|
||||
_amendExistingCommitCommand: {
|
||||
type: String,
|
||||
readonly: true,
|
||||
value: Commands.AMEND,
|
||||
},
|
||||
_pushCommand: {
|
||||
type: String,
|
||||
computed: '_computePushCommand(branch)',
|
||||
},
|
||||
},
|
||||
static get properties() {
|
||||
return {
|
||||
branch: String,
|
||||
_createNewCommitCommand: {
|
||||
type: String,
|
||||
readonly: true,
|
||||
value: Commands.CREATE,
|
||||
},
|
||||
_amendExistingCommitCommand: {
|
||||
type: String,
|
||||
readonly: true,
|
||||
value: Commands.AMEND,
|
||||
},
|
||||
_pushCommand: {
|
||||
type: String,
|
||||
computed: '_computePushCommand(branch)',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
open() {
|
||||
this.$.commandsOverlay.open();
|
||||
},
|
||||
}
|
||||
|
||||
_handleClose() {
|
||||
this.$.commandsOverlay.close();
|
||||
},
|
||||
}
|
||||
|
||||
_computePushCommand(branch) {
|
||||
return Commands.PUSH_PREFIX + branch;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrCreateCommandsDialog.is, GrCreateCommandsDialog);
|
||||
})();
|
||||
|
||||
@@ -23,37 +23,44 @@
|
||||
*
|
||||
* @event confirm
|
||||
*/
|
||||
class GrCreateDestinationDialog extends Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element)) {
|
||||
static get is() { return 'gr-create-destination-dialog'; }
|
||||
|
||||
Polymer({
|
||||
is: 'gr-create-destination-dialog',
|
||||
static get properties() {
|
||||
return {
|
||||
_repo: String,
|
||||
_branch: String,
|
||||
_repoAndBranchSelected: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
computed: '_computeRepoAndBranchSelected(_repo, _branch)',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
properties: {
|
||||
_repo: String,
|
||||
_branch: String,
|
||||
_repoAndBranchSelected: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
computed: '_computeRepoAndBranchSelected(_repo, _branch)',
|
||||
},
|
||||
},
|
||||
open() {
|
||||
this._repo = '';
|
||||
this._branch = '';
|
||||
this.$.createOverlay.open();
|
||||
},
|
||||
}
|
||||
|
||||
_handleClose() {
|
||||
this.$.createOverlay.close();
|
||||
},
|
||||
}
|
||||
|
||||
_pickerConfirm() {
|
||||
this.$.createOverlay.close();
|
||||
const detail = {repo: this._repo, branch: this._branch};
|
||||
this.dispatchEvent(new CustomEvent('confirm', {detail, bubbles: false}));
|
||||
},
|
||||
}
|
||||
|
||||
_computeRepoAndBranchSelected(repo, branch) {
|
||||
return !!(repo && branch);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrCreateDestinationDialog.is,
|
||||
GrCreateDestinationDialog);
|
||||
})();
|
||||
|
||||
@@ -19,65 +19,72 @@
|
||||
|
||||
const PROJECT_PLACEHOLDER_PATTERN = /\$\{project\}/g;
|
||||
|
||||
Polymer({
|
||||
is: 'gr-dashboard-view',
|
||||
|
||||
/**
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
* @appliesMixin Gerrit.RESTClientMixin
|
||||
*/
|
||||
class GrDashboardView extends Polymer.mixinBehaviors( [
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.RESTClientBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-dashboard-view'; }
|
||||
/**
|
||||
* Fired when the title of the page should change.
|
||||
*
|
||||
* @event title-change
|
||||
*/
|
||||
|
||||
properties: {
|
||||
account: {
|
||||
type: Object,
|
||||
value: null,
|
||||
},
|
||||
preferences: Object,
|
||||
/** @type {{ selectedChangeIndex: number }} */
|
||||
viewState: Object,
|
||||
|
||||
/** @type {{ project: string, user: string }} */
|
||||
params: {
|
||||
type: Object,
|
||||
},
|
||||
|
||||
createChangeTap: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._createChangeTap.bind(this);
|
||||
static get properties() {
|
||||
return {
|
||||
account: {
|
||||
type: Object,
|
||||
value: null,
|
||||
},
|
||||
},
|
||||
preferences: Object,
|
||||
/** @type {{ selectedChangeIndex: number }} */
|
||||
viewState: Object,
|
||||
|
||||
_results: Array,
|
||||
/** @type {{ project: string, user: string }} */
|
||||
params: {
|
||||
type: Object,
|
||||
},
|
||||
|
||||
/**
|
||||
createChangeTap: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._createChangeTap.bind(this);
|
||||
},
|
||||
},
|
||||
|
||||
_results: Array,
|
||||
|
||||
/**
|
||||
* For showing a "loading..." string during ajax requests.
|
||||
*/
|
||||
_loading: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
_loading: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
|
||||
_showDraftsBanner: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_showDraftsBanner: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
_showNewUserHelp: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
},
|
||||
_showNewUserHelp: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
observers: [
|
||||
'_paramsChanged(params.*)',
|
||||
],
|
||||
|
||||
behaviors: [
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.RESTClientBehavior,
|
||||
],
|
||||
static get observers() {
|
||||
return [
|
||||
'_paramsChanged(params.*)',
|
||||
];
|
||||
}
|
||||
|
||||
get options() {
|
||||
return this.listChangesOptionsToHex(
|
||||
@@ -85,11 +92,12 @@
|
||||
this.ListChangesOption.DETAILED_ACCOUNTS,
|
||||
this.ListChangesOption.REVIEWED
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
attached() {
|
||||
super.attached();
|
||||
this._loadPreferences();
|
||||
},
|
||||
}
|
||||
|
||||
_loadPreferences() {
|
||||
return this.$.restAPI.getLoggedIn().then(loggedIn => {
|
||||
@@ -101,7 +109,7 @@
|
||||
this.preferences = {};
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_getProjectDashboard(project, dashboard) {
|
||||
const errFn = response => {
|
||||
@@ -124,18 +132,18 @@
|
||||
}),
|
||||
};
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_computeTitle(user) {
|
||||
if (!user || user === 'self') {
|
||||
return 'My Reviews';
|
||||
}
|
||||
return 'Dashboard for ' + user;
|
||||
},
|
||||
}
|
||||
|
||||
_isViewActive(params) {
|
||||
return params.view === Gerrit.Nav.View.DASHBOARD;
|
||||
},
|
||||
}
|
||||
|
||||
_paramsChanged(paramsChangeRecord) {
|
||||
const params = paramsChangeRecord.base;
|
||||
@@ -145,7 +153,7 @@
|
||||
}
|
||||
|
||||
return this._reload();
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads the element.
|
||||
@@ -179,7 +187,7 @@
|
||||
});
|
||||
console.warn(err);
|
||||
}).then(() => { this._loading = false; });
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the changes for each dashboard section and sets this._results
|
||||
@@ -218,7 +226,7 @@
|
||||
!res.sections[i].hideIfEmpty ||
|
||||
section.results.length));
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_computeSectionCountLabel(changes) {
|
||||
if (!changes || !changes.length || changes.length == 0) {
|
||||
@@ -228,7 +236,7 @@
|
||||
const numChanges = changes.length;
|
||||
const andMore = more ? ' and more' : '';
|
||||
return `(${numChanges}${andMore})`;
|
||||
},
|
||||
}
|
||||
|
||||
_computeUserHeaderClass(params) {
|
||||
if (!params || !!params.project || !params.user
|
||||
@@ -236,17 +244,17 @@
|
||||
return 'hide';
|
||||
}
|
||||
return '';
|
||||
},
|
||||
}
|
||||
|
||||
_handleToggleStar(e) {
|
||||
this.$.restAPI.saveChangeStarred(e.detail.change._number,
|
||||
e.detail.starred);
|
||||
},
|
||||
}
|
||||
|
||||
_handleToggleReviewed(e) {
|
||||
this.$.restAPI.saveChangeReviewed(e.detail.change._number,
|
||||
e.detail.reviewed);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Banner is shown if a user is on their own dashboard and they have draft
|
||||
@@ -265,15 +273,15 @@
|
||||
if (!closedChanges.length) { return; }
|
||||
|
||||
this._showDraftsBanner = true;
|
||||
},
|
||||
}
|
||||
|
||||
_computeBannerClass(show) {
|
||||
return show ? '' : 'hide';
|
||||
},
|
||||
}
|
||||
|
||||
_handleOpenDeleteDialog() {
|
||||
this.$.confirmDeleteOverlay.open();
|
||||
},
|
||||
}
|
||||
|
||||
_handleConfirmDelete() {
|
||||
this.$.confirmDeleteDialog.disabled = true;
|
||||
@@ -281,23 +289,25 @@
|
||||
this._closeConfirmDeleteOverlay();
|
||||
this._reload();
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_closeConfirmDeleteOverlay() {
|
||||
this.$.confirmDeleteOverlay.close();
|
||||
},
|
||||
}
|
||||
|
||||
_computeDraftsLink() {
|
||||
return Gerrit.Nav.getUrlForSearchQuery('has:draft -is:open');
|
||||
},
|
||||
}
|
||||
|
||||
_createChangeTap(e) {
|
||||
this.$.destinationDialog.open();
|
||||
},
|
||||
}
|
||||
|
||||
_handleDestinationConfirm(e) {
|
||||
this.$.commandsDialog.branch = e.detail.branch;
|
||||
this.$.commandsDialog.open();
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrDashboardView.is, GrDashboardView);
|
||||
})();
|
||||
|
||||
@@ -17,14 +17,20 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-embed-dashboard',
|
||||
class GrEmbedDashboard extends Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element)) {
|
||||
static get is() { return 'gr-embed-dashboard'; }
|
||||
|
||||
properties: {
|
||||
account: Object,
|
||||
sections: Array,
|
||||
preferences: Object,
|
||||
showNewUserHelp: Boolean,
|
||||
},
|
||||
});
|
||||
static get properties() {
|
||||
return {
|
||||
account: Object,
|
||||
sections: Array,
|
||||
preferences: Object,
|
||||
showNewUserHelp: Boolean,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrEmbedDashboard.is, GrEmbedDashboard);
|
||||
})();
|
||||
|
||||
@@ -17,18 +17,22 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-repo-header',
|
||||
class GrRepoHeader extends Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element)) {
|
||||
static get is() { return 'gr-repo-header'; }
|
||||
|
||||
properties: {
|
||||
static get properties() {
|
||||
return {
|
||||
/** @type {?String} */
|
||||
repo: {
|
||||
type: String,
|
||||
observer: '_repoChanged',
|
||||
},
|
||||
/** @type {String|null} */
|
||||
_repoUrl: String,
|
||||
},
|
||||
repo: {
|
||||
type: String,
|
||||
observer: '_repoChanged',
|
||||
},
|
||||
/** @type {String|null} */
|
||||
_repoUrl: String,
|
||||
};
|
||||
}
|
||||
|
||||
_repoChanged(repoName) {
|
||||
if (!repoName) {
|
||||
@@ -36,6 +40,8 @@
|
||||
return;
|
||||
}
|
||||
this._repoUrl = Gerrit.Nav.getUrlForRepo(repoName);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrRepoHeader.is, GrRepoHeader);
|
||||
})();
|
||||
|
||||
@@ -17,40 +17,44 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-user-header',
|
||||
class GrUserHeader extends Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element)) {
|
||||
static get is() { return 'gr-user-header'; }
|
||||
|
||||
properties: {
|
||||
static get properties() {
|
||||
return {
|
||||
/** @type {?String} */
|
||||
userId: {
|
||||
type: String,
|
||||
observer: '_accountChanged',
|
||||
},
|
||||
userId: {
|
||||
type: String,
|
||||
observer: '_accountChanged',
|
||||
},
|
||||
|
||||
showDashboardLink: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
showDashboardLink: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
loggedIn: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
loggedIn: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
/**
|
||||
/**
|
||||
* @type {?{name: ?, email: ?, registered_on: ?}}
|
||||
*/
|
||||
_accountDetails: {
|
||||
type: Object,
|
||||
value: null,
|
||||
},
|
||||
_accountDetails: {
|
||||
type: Object,
|
||||
value: null,
|
||||
},
|
||||
|
||||
/** @type {?String} */
|
||||
_status: {
|
||||
type: String,
|
||||
value: null,
|
||||
},
|
||||
},
|
||||
/** @type {?String} */
|
||||
_status: {
|
||||
type: String,
|
||||
value: null,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
_accountChanged(userId) {
|
||||
if (!userId) {
|
||||
@@ -65,19 +69,19 @@
|
||||
this.$.restAPI.getAccountStatus(userId).then(status => {
|
||||
this._status = status;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_computeDisplayClass(status) {
|
||||
return status ? ' ' : 'hide';
|
||||
},
|
||||
}
|
||||
|
||||
_computeDetail(accountDetails, name) {
|
||||
return accountDetails ? accountDetails[name] : '';
|
||||
},
|
||||
}
|
||||
|
||||
_computeStatusClass(accountDetails) {
|
||||
return this._computeDetail(accountDetails, 'status') ? '' : 'hide';
|
||||
},
|
||||
}
|
||||
|
||||
_computeDashboardUrl(accountDetails) {
|
||||
if (!accountDetails) { return null; }
|
||||
@@ -85,11 +89,13 @@
|
||||
const email = accountDetails.email;
|
||||
if (!id && !email ) { return null; }
|
||||
return Gerrit.Nav.getUrlForUserDashboard(id ? id : email);
|
||||
},
|
||||
}
|
||||
|
||||
_computeDashboardLinkClass(showDashboardLink, loggedIn) {
|
||||
return showDashboardLink && loggedIn ?
|
||||
'dashboardLink' : 'dashboardLink hide';
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrUserHeader.is, GrUserHeader);
|
||||
})();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -48,105 +48,111 @@
|
||||
TRUSTED: 'TRUSTED',
|
||||
};
|
||||
|
||||
Polymer({
|
||||
is: 'gr-change-metadata',
|
||||
|
||||
/**
|
||||
* @appliesMixin Gerrit.RESTClientMixin
|
||||
*/
|
||||
class GrChangeMetadata extends Polymer.mixinBehaviors( [
|
||||
Gerrit.RESTClientBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-change-metadata'; }
|
||||
/**
|
||||
* Fired when the change topic is changed.
|
||||
*
|
||||
* @event topic-changed
|
||||
*/
|
||||
|
||||
properties: {
|
||||
static get properties() {
|
||||
return {
|
||||
/** @type {?} */
|
||||
change: Object,
|
||||
labels: {
|
||||
type: Object,
|
||||
notify: true,
|
||||
},
|
||||
account: Object,
|
||||
/** @type {?} */
|
||||
revision: Object,
|
||||
commitInfo: Object,
|
||||
_mutable: {
|
||||
type: Boolean,
|
||||
computed: '_computeIsMutable(account)',
|
||||
},
|
||||
/** @type {?} */
|
||||
serverConfig: Object,
|
||||
parentIsCurrent: Boolean,
|
||||
_notCurrentMessage: {
|
||||
type: String,
|
||||
value: NOT_CURRENT_MESSAGE,
|
||||
readOnly: true,
|
||||
},
|
||||
_topicReadOnly: {
|
||||
type: Boolean,
|
||||
computed: '_computeTopicReadOnly(_mutable, change)',
|
||||
},
|
||||
_hashtagReadOnly: {
|
||||
type: Boolean,
|
||||
computed: '_computeHashtagReadOnly(_mutable, change)',
|
||||
},
|
||||
/**
|
||||
change: Object,
|
||||
labels: {
|
||||
type: Object,
|
||||
notify: true,
|
||||
},
|
||||
account: Object,
|
||||
/** @type {?} */
|
||||
revision: Object,
|
||||
commitInfo: Object,
|
||||
_mutable: {
|
||||
type: Boolean,
|
||||
computed: '_computeIsMutable(account)',
|
||||
},
|
||||
/** @type {?} */
|
||||
serverConfig: Object,
|
||||
parentIsCurrent: Boolean,
|
||||
_notCurrentMessage: {
|
||||
type: String,
|
||||
value: NOT_CURRENT_MESSAGE,
|
||||
readOnly: true,
|
||||
},
|
||||
_topicReadOnly: {
|
||||
type: Boolean,
|
||||
computed: '_computeTopicReadOnly(_mutable, change)',
|
||||
},
|
||||
_hashtagReadOnly: {
|
||||
type: Boolean,
|
||||
computed: '_computeHashtagReadOnly(_mutable, change)',
|
||||
},
|
||||
/**
|
||||
* @type {Gerrit.PushCertificateValidation}
|
||||
*/
|
||||
_pushCertificateValidation: {
|
||||
type: Object,
|
||||
computed: '_computePushCertificateValidation(serverConfig, change)',
|
||||
},
|
||||
_showRequirements: {
|
||||
type: Boolean,
|
||||
computed: '_computeShowRequirements(change)',
|
||||
},
|
||||
|
||||
_assignee: Array,
|
||||
_isWip: {
|
||||
type: Boolean,
|
||||
computed: '_computeIsWip(change)',
|
||||
},
|
||||
_newHashtag: String,
|
||||
|
||||
_settingTopic: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
_currentParents: {
|
||||
type: Array,
|
||||
computed: '_computeParents(change)',
|
||||
},
|
||||
|
||||
/** @type {?} */
|
||||
_CHANGE_ROLE: {
|
||||
type: Object,
|
||||
readOnly: true,
|
||||
value: {
|
||||
OWNER: 'owner',
|
||||
UPLOADER: 'uploader',
|
||||
AUTHOR: 'author',
|
||||
COMMITTER: 'committer',
|
||||
_pushCertificateValidation: {
|
||||
type: Object,
|
||||
computed: '_computePushCertificateValidation(serverConfig, change)',
|
||||
},
|
||||
_showRequirements: {
|
||||
type: Boolean,
|
||||
computed: '_computeShowRequirements(change)',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
Gerrit.RESTClientBehavior,
|
||||
],
|
||||
_assignee: Array,
|
||||
_isWip: {
|
||||
type: Boolean,
|
||||
computed: '_computeIsWip(change)',
|
||||
},
|
||||
_newHashtag: String,
|
||||
|
||||
observers: [
|
||||
'_changeChanged(change)',
|
||||
'_labelsChanged(change.labels)',
|
||||
'_assigneeChanged(_assignee.*)',
|
||||
],
|
||||
_settingTopic: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
_currentParents: {
|
||||
type: Array,
|
||||
computed: '_computeParents(change)',
|
||||
},
|
||||
|
||||
/** @type {?} */
|
||||
_CHANGE_ROLE: {
|
||||
type: Object,
|
||||
readOnly: true,
|
||||
value: {
|
||||
OWNER: 'owner',
|
||||
UPLOADER: 'uploader',
|
||||
AUTHOR: 'author',
|
||||
COMMITTER: 'committer',
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
static get observers() {
|
||||
return [
|
||||
'_changeChanged(change)',
|
||||
'_labelsChanged(change.labels)',
|
||||
'_assigneeChanged(_assignee.*)',
|
||||
];
|
||||
}
|
||||
|
||||
_labelsChanged(labels) {
|
||||
this.labels = Object.assign({}, labels) || null;
|
||||
},
|
||||
}
|
||||
|
||||
_changeChanged(change) {
|
||||
this._assignee = change.assignee ? [change.assignee] : [];
|
||||
},
|
||||
}
|
||||
|
||||
_assigneeChanged(assigneeRecord) {
|
||||
if (!this.change) { return; }
|
||||
@@ -162,11 +168,11 @@
|
||||
this.set(['change', 'assignee'], undefined);
|
||||
this.$.restAPI.deleteAssignee(this.change._number);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_computeHideStrategy(change) {
|
||||
return !this.changeIsOpen(change);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} commitInfo
|
||||
@@ -184,15 +190,15 @@
|
||||
config: serverConfig,
|
||||
});
|
||||
return weblinks.length ? weblinks : null;
|
||||
},
|
||||
}
|
||||
|
||||
_computeStrategy(change) {
|
||||
return SubmitTypeLabel[change.submit_type];
|
||||
},
|
||||
}
|
||||
|
||||
_computeLabelNames(labels) {
|
||||
return Object.keys(labels).sort();
|
||||
},
|
||||
}
|
||||
|
||||
_handleTopicChanged(e, topic) {
|
||||
const lastTopic = this.change.topic;
|
||||
@@ -207,19 +213,19 @@
|
||||
'topic-changed', {bubbles: true, composed: true}));
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_showAddTopic(changeRecord, settingTopic) {
|
||||
const hasTopic = !!changeRecord &&
|
||||
!!changeRecord.base && !!changeRecord.base.topic;
|
||||
return !hasTopic && !settingTopic;
|
||||
},
|
||||
}
|
||||
|
||||
_showTopicChip(changeRecord, settingTopic) {
|
||||
const hasTopic = !!changeRecord &&
|
||||
!!changeRecord.base && !!changeRecord.base.topic;
|
||||
return hasTopic && !settingTopic;
|
||||
},
|
||||
}
|
||||
|
||||
_handleHashtagChanged(e) {
|
||||
const lastHashtag = this.change.hashtag;
|
||||
@@ -234,7 +240,7 @@
|
||||
'hashtag-changed', {bubbles: true, composed: true}));
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_computeTopicReadOnly(mutable, change) {
|
||||
return !mutable ||
|
||||
@@ -242,7 +248,7 @@
|
||||
!change.actions ||
|
||||
!change.actions.topic ||
|
||||
!change.actions.topic.enabled;
|
||||
},
|
||||
}
|
||||
|
||||
_computeHashtagReadOnly(mutable, change) {
|
||||
return !mutable ||
|
||||
@@ -250,7 +256,7 @@
|
||||
!change.actions ||
|
||||
!change.actions.hashtags ||
|
||||
!change.actions.hashtags.enabled;
|
||||
},
|
||||
}
|
||||
|
||||
_computeAssigneeReadOnly(mutable, change) {
|
||||
return !mutable ||
|
||||
@@ -258,17 +264,17 @@
|
||||
!change.actions ||
|
||||
!change.actions.assignee ||
|
||||
!change.actions.assignee.enabled;
|
||||
},
|
||||
}
|
||||
|
||||
_computeTopicPlaceholder(_topicReadOnly) {
|
||||
// Action items in Material Design are uppercase -- placeholder label text
|
||||
// is sentence case.
|
||||
return _topicReadOnly ? 'No topic' : 'ADD TOPIC';
|
||||
},
|
||||
}
|
||||
|
||||
_computeHashtagPlaceholder(_hashtagReadOnly) {
|
||||
return _hashtagReadOnly ? '' : HASHTAG_ADD_MESSAGE;
|
||||
},
|
||||
}
|
||||
|
||||
_computeShowRequirements(change) {
|
||||
if (change.status !== this.ChangeStatus.NEW) {
|
||||
@@ -281,7 +287,7 @@
|
||||
const hasLabels = !!change.labels &&
|
||||
Object.keys(change.labels).length > 0;
|
||||
return hasRequirements || hasLabels || !!change.work_in_progress;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {?Gerrit.PushCertificateValidation} object representing data for
|
||||
@@ -326,7 +332,7 @@
|
||||
default:
|
||||
throw new Error(`unknown certificate status: ${key.status}`);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_problems(msg, key) {
|
||||
if (!key || !key.problems || key.problems.length === 0) {
|
||||
@@ -334,26 +340,26 @@
|
||||
}
|
||||
|
||||
return [msg + ':'].concat(key.problems).join('\n');
|
||||
},
|
||||
}
|
||||
|
||||
_computeProjectURL(project) {
|
||||
return Gerrit.Nav.getUrlForProjectChanges(project);
|
||||
},
|
||||
}
|
||||
|
||||
_computeBranchURL(project, branch) {
|
||||
if (!this.change || !this.change.status) return '';
|
||||
return Gerrit.Nav.getUrlForBranch(branch, project,
|
||||
this.change.status == this.ChangeStatus.NEW ? 'open' :
|
||||
this.change.status.toLowerCase());
|
||||
},
|
||||
}
|
||||
|
||||
_computeTopicURL(topic) {
|
||||
return Gerrit.Nav.getUrlForTopic(topic);
|
||||
},
|
||||
}
|
||||
|
||||
_computeHashtagURL(hashtag) {
|
||||
return Gerrit.Nav.getUrlForHashtag(hashtag);
|
||||
},
|
||||
}
|
||||
|
||||
_handleTopicRemoved(e) {
|
||||
const target = Polymer.dom(e).rootTarget;
|
||||
@@ -367,7 +373,7 @@
|
||||
target.disabled = false;
|
||||
return;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleHashtagRemoved(e) {
|
||||
e.preventDefault();
|
||||
@@ -382,15 +388,15 @@
|
||||
target.disabled = false;
|
||||
return;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_computeIsWip(change) {
|
||||
return !!change.work_in_progress;
|
||||
},
|
||||
}
|
||||
|
||||
_computeShowRoleClass(change, role) {
|
||||
return this._getNonOwnerRole(change, role) ? '' : 'hideDisplay';
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user with the specified role on the change. Returns null if the
|
||||
@@ -427,7 +433,7 @@
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
}
|
||||
|
||||
_computeParents(change) {
|
||||
if (!change || !change.current_revision ||
|
||||
@@ -436,11 +442,11 @@
|
||||
return undefined;
|
||||
}
|
||||
return change.revisions[change.current_revision].commit.parents;
|
||||
},
|
||||
}
|
||||
|
||||
_computeParentsLabel(parents) {
|
||||
return parents && parents.length > 1 ? 'Parents' : 'Parent';
|
||||
},
|
||||
}
|
||||
|
||||
_computeParentListClass(parents, parentIsCurrent) {
|
||||
// Undefined check for polymer 2
|
||||
@@ -453,24 +459,26 @@
|
||||
parents && parents.length > 1 ? 'merge' : 'nonMerge',
|
||||
parentIsCurrent ? 'current' : 'notCurrent',
|
||||
].join(' ');
|
||||
},
|
||||
}
|
||||
|
||||
_computeIsMutable(account) {
|
||||
return !!Object.keys(account).length;
|
||||
},
|
||||
}
|
||||
|
||||
editTopic() {
|
||||
if (this._topicReadOnly || this.change.topic) { return; }
|
||||
// Cannot use `this.$.ID` syntax because the element exists inside of a
|
||||
// dom-if.
|
||||
this.$$('.topicEditableLabel').open();
|
||||
},
|
||||
}
|
||||
|
||||
_getReviewerSuggestionsProvider(change) {
|
||||
const provider = GrReviewerSuggestionsProvider.create(this.$.restAPI,
|
||||
change._number, Gerrit.SUGGESTIONS_PROVIDERS_USERS_TYPES.ANY);
|
||||
provider.init();
|
||||
return provider;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrChangeMetadata.is, GrChangeMetadata);
|
||||
})();
|
||||
|
||||
@@ -17,47 +17,54 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-change-requirements',
|
||||
/**
|
||||
* @appliesMixin Gerrit.RESTClientMixin
|
||||
*/
|
||||
class GrChangeRequirements extends Polymer.mixinBehaviors( [
|
||||
Gerrit.RESTClientBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-change-requirements'; }
|
||||
|
||||
properties: {
|
||||
static get properties() {
|
||||
return {
|
||||
/** @type {?} */
|
||||
change: Object,
|
||||
account: Object,
|
||||
mutable: Boolean,
|
||||
_requirements: {
|
||||
type: Array,
|
||||
computed: '_computeRequirements(change)',
|
||||
},
|
||||
_requiredLabels: {
|
||||
type: Array,
|
||||
value: () => [],
|
||||
},
|
||||
_optionalLabels: {
|
||||
type: Array,
|
||||
value: () => [],
|
||||
},
|
||||
_showWip: {
|
||||
type: Boolean,
|
||||
computed: '_computeShowWip(change)',
|
||||
},
|
||||
_showOptionalLabels: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
},
|
||||
change: Object,
|
||||
account: Object,
|
||||
mutable: Boolean,
|
||||
_requirements: {
|
||||
type: Array,
|
||||
computed: '_computeRequirements(change)',
|
||||
},
|
||||
_requiredLabels: {
|
||||
type: Array,
|
||||
value: () => [],
|
||||
},
|
||||
_optionalLabels: {
|
||||
type: Array,
|
||||
value: () => [],
|
||||
},
|
||||
_showWip: {
|
||||
type: Boolean,
|
||||
computed: '_computeShowWip(change)',
|
||||
},
|
||||
_showOptionalLabels: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
behaviors: [
|
||||
Gerrit.RESTClientBehavior,
|
||||
],
|
||||
|
||||
observers: [
|
||||
'_computeLabels(change.labels.*)',
|
||||
],
|
||||
static get observers() {
|
||||
return [
|
||||
'_computeLabels(change.labels.*)',
|
||||
];
|
||||
}
|
||||
|
||||
_computeShowWip(change) {
|
||||
return change.work_in_progress;
|
||||
},
|
||||
}
|
||||
|
||||
_computeRequirements(change) {
|
||||
const _requirements = [];
|
||||
@@ -78,15 +85,15 @@
|
||||
}
|
||||
|
||||
return _requirements;
|
||||
},
|
||||
}
|
||||
|
||||
_computeRequirementClass(requirementStatus) {
|
||||
return requirementStatus ? 'approved' : '';
|
||||
},
|
||||
}
|
||||
|
||||
_computeRequirementIcon(requirementStatus) {
|
||||
return requirementStatus ? 'gr-icons:check' : 'gr-icons:hourglass';
|
||||
},
|
||||
}
|
||||
|
||||
_computeLabels(labelsRecord) {
|
||||
const labels = labelsRecord.base;
|
||||
@@ -103,7 +110,7 @@
|
||||
|
||||
this.push(path, {label, icon, style, labelInfo});
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} labelInfo
|
||||
@@ -114,7 +121,7 @@
|
||||
if (labelInfo.approved) { return 'gr-icons:check'; }
|
||||
if (labelInfo.rejected) { return 'gr-icons:close'; }
|
||||
return 'gr-icons:hourglass';
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} labelInfo
|
||||
@@ -123,28 +130,30 @@
|
||||
if (labelInfo.approved) { return 'approved'; }
|
||||
if (labelInfo.rejected) { return 'rejected'; }
|
||||
return '';
|
||||
},
|
||||
}
|
||||
|
||||
_computeShowOptional(optionalFieldsRecord) {
|
||||
return optionalFieldsRecord.base.length ? '' : 'hidden';
|
||||
},
|
||||
}
|
||||
|
||||
_computeLabelValue(value) {
|
||||
return (value > 0 ? '+' : '') + value;
|
||||
},
|
||||
}
|
||||
|
||||
_computeShowHideIcon(showOptionalLabels) {
|
||||
return showOptionalLabels ?
|
||||
'gr-icons:expand-less' :
|
||||
'gr-icons:expand-more';
|
||||
},
|
||||
}
|
||||
|
||||
_computeSectionClass(show) {
|
||||
return show ? '' : 'hidden';
|
||||
},
|
||||
}
|
||||
|
||||
_handleShowHide(e) {
|
||||
this._showOptionalLabels = !this._showOptionalLabels;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrChangeRequirements.is, GrChangeRequirements);
|
||||
})();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,32 +16,40 @@
|
||||
*/
|
||||
(function() {
|
||||
'use strict';
|
||||
Polymer({
|
||||
is: 'gr-comment-list',
|
||||
|
||||
behaviors: [
|
||||
Gerrit.BaseUrlBehavior,
|
||||
Gerrit.PathListBehavior,
|
||||
Gerrit.URLEncodingBehavior,
|
||||
],
|
||||
/**
|
||||
* @appliesMixin Gerrit.BaseUrlMixin
|
||||
* @appliesMixin Gerrit.PathListMixin
|
||||
* @appliesMixin Gerrit.URLEncodingMixin
|
||||
*/
|
||||
class GrCommentList extends Polymer.mixinBehaviors( [
|
||||
Gerrit.BaseUrlBehavior,
|
||||
Gerrit.PathListBehavior,
|
||||
Gerrit.URLEncodingBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-comment-list'; }
|
||||
|
||||
properties: {
|
||||
changeNum: Number,
|
||||
comments: Object,
|
||||
patchNum: Number,
|
||||
projectName: String,
|
||||
/** @type {?} */
|
||||
projectConfig: Object,
|
||||
},
|
||||
static get properties() {
|
||||
return {
|
||||
changeNum: Number,
|
||||
comments: Object,
|
||||
patchNum: Number,
|
||||
projectName: String,
|
||||
/** @type {?} */
|
||||
projectConfig: Object,
|
||||
};
|
||||
}
|
||||
|
||||
_computeFilesFromComments(comments) {
|
||||
const arr = Object.keys(comments || {});
|
||||
return arr.sort(this.specialFilePathCompare);
|
||||
},
|
||||
}
|
||||
|
||||
_isOnParent(comment) {
|
||||
return comment.side === 'PARENT';
|
||||
},
|
||||
}
|
||||
|
||||
_computeDiffLineURL(file, changeNum, patchNum, comment) {
|
||||
const basePatchNum = comment.hasOwnProperty('parent') ?
|
||||
@@ -49,13 +57,13 @@
|
||||
return Gerrit.Nav.getUrlForDiffById(this.changeNum, this.projectName,
|
||||
file, patchNum, basePatchNum, comment.line,
|
||||
this._isOnParent(comment));
|
||||
},
|
||||
}
|
||||
|
||||
_computeCommentsForFile(comments, file) {
|
||||
// Changes are not picked up by the dom-repeat due to the array instance
|
||||
// identity not changing even when it has elements added/removed from it.
|
||||
return (comments[file] || []).slice();
|
||||
},
|
||||
}
|
||||
|
||||
_computePatchDisplayName(comment) {
|
||||
if (this._isOnParent(comment)) {
|
||||
@@ -65,6 +73,8 @@
|
||||
return `PS${comment.patch_set}, `;
|
||||
}
|
||||
return '';
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrCommentList.is, GrCommentList);
|
||||
})();
|
||||
|
||||
@@ -17,23 +17,27 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-commit-info',
|
||||
class GrCommitInfo extends Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element)) {
|
||||
static get is() { return 'gr-commit-info'; }
|
||||
|
||||
properties: {
|
||||
change: Object,
|
||||
/** @type {?} */
|
||||
commitInfo: Object,
|
||||
serverConfig: Object,
|
||||
_showWebLink: {
|
||||
type: Boolean,
|
||||
computed: '_computeShowWebLink(change, commitInfo, serverConfig)',
|
||||
},
|
||||
_webLink: {
|
||||
type: String,
|
||||
computed: '_computeWebLink(change, commitInfo, serverConfig)',
|
||||
},
|
||||
},
|
||||
static get properties() {
|
||||
return {
|
||||
change: Object,
|
||||
/** @type {?} */
|
||||
commitInfo: Object,
|
||||
serverConfig: Object,
|
||||
_showWebLink: {
|
||||
type: Boolean,
|
||||
computed: '_computeShowWebLink(change, commitInfo, serverConfig)',
|
||||
},
|
||||
_webLink: {
|
||||
type: String,
|
||||
computed: '_computeWebLink(change, commitInfo, serverConfig)',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
_getWeblink(change, commitInfo, config) {
|
||||
return Gerrit.Nav.getPatchSetWeblink(
|
||||
@@ -43,7 +47,7 @@
|
||||
weblinks: commitInfo.web_links,
|
||||
config,
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_computeShowWebLink(change, commitInfo, serverConfig) {
|
||||
// Polymer 2: check for undefined
|
||||
@@ -53,7 +57,7 @@
|
||||
|
||||
const weblink = this._getWeblink(change, commitInfo, serverConfig);
|
||||
return !!weblink && !!weblink.url;
|
||||
},
|
||||
}
|
||||
|
||||
_computeWebLink(change, commitInfo, serverConfig) {
|
||||
// Polymer 2: check for undefined
|
||||
@@ -63,12 +67,14 @@
|
||||
|
||||
const {url} = this._getWeblink(change, commitInfo, serverConfig) || {};
|
||||
return url;
|
||||
},
|
||||
}
|
||||
|
||||
_computeShortHash(commitInfo) {
|
||||
const {name} =
|
||||
this._getWeblink(this.change, commitInfo, this.serverConfig) || {};
|
||||
return name;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrCommitInfo.is, GrCommitInfo);
|
||||
})();
|
||||
|
||||
@@ -17,9 +17,17 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-confirm-abandon-dialog',
|
||||
|
||||
/**
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
* @appliesMixin Gerrit.KeyboardShortcutMixin
|
||||
*/
|
||||
class GrConfirmAbandonDialog extends Polymer.mixinBehaviors( [
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.KeyboardShortcutBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-confirm-abandon-dialog'; }
|
||||
/**
|
||||
* Fired when the confirm button is pressed.
|
||||
*
|
||||
@@ -32,41 +40,42 @@
|
||||
* @event cancel
|
||||
*/
|
||||
|
||||
properties: {
|
||||
message: String,
|
||||
},
|
||||
static get properties() {
|
||||
return {
|
||||
message: String,
|
||||
};
|
||||
}
|
||||
|
||||
behaviors: [
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.KeyboardShortcutBehavior,
|
||||
],
|
||||
|
||||
keyBindings: {
|
||||
'ctrl+enter meta+enter': '_handleEnterKey',
|
||||
},
|
||||
get keyBindings() {
|
||||
return {
|
||||
'ctrl+enter meta+enter': '_handleEnterKey',
|
||||
};
|
||||
}
|
||||
|
||||
resetFocus() {
|
||||
this.$.messageInput.textarea.focus();
|
||||
},
|
||||
}
|
||||
|
||||
_handleEnterKey(e) {
|
||||
this._confirm();
|
||||
},
|
||||
}
|
||||
|
||||
_handleConfirmTap(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this._confirm();
|
||||
},
|
||||
}
|
||||
|
||||
_confirm() {
|
||||
this.fire('confirm', {reason: this.message}, {bubbles: false});
|
||||
},
|
||||
}
|
||||
|
||||
_handleCancelTap(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.fire('cancel', null, {bubbles: false});
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrConfirmAbandonDialog.is, GrConfirmAbandonDialog);
|
||||
})();
|
||||
|
||||
@@ -17,12 +17,15 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-confirm-cherrypick-conflict-dialog',
|
||||
|
||||
behaviors: [
|
||||
Gerrit.FireBehavior,
|
||||
],
|
||||
/**
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
*/
|
||||
class GrConfirmCherrypickConflictDialog extends Polymer.mixinBehaviors( [
|
||||
Gerrit.FireBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-confirm-cherrypick-conflict-dialog'; }
|
||||
|
||||
/**
|
||||
* Fired when the confirm button is pressed.
|
||||
@@ -40,12 +43,15 @@
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.fire('confirm', null, {bubbles: false});
|
||||
},
|
||||
}
|
||||
|
||||
_handleCancelTap(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.fire('cancel', null, {bubbles: false});
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrConfirmCherrypickConflictDialog.is,
|
||||
GrConfirmCherrypickConflictDialog);
|
||||
})();
|
||||
|
||||
@@ -19,9 +19,15 @@
|
||||
|
||||
const SUGGESTIONS_LIMIT = 15;
|
||||
|
||||
Polymer({
|
||||
is: 'gr-confirm-cherrypick-dialog',
|
||||
|
||||
/**
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
*/
|
||||
class GrConfirmCherrypickDialog extends Polymer.mixinBehaviors( [
|
||||
Gerrit.FireBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-confirm-cherrypick-dialog'; }
|
||||
/**
|
||||
* Fired when the confirm button is pressed.
|
||||
*
|
||||
@@ -34,29 +40,29 @@
|
||||
* @event cancel
|
||||
*/
|
||||
|
||||
properties: {
|
||||
branch: String,
|
||||
baseCommit: String,
|
||||
changeStatus: String,
|
||||
commitMessage: String,
|
||||
commitNum: String,
|
||||
message: String,
|
||||
project: String,
|
||||
_query: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._getProjectBranchesSuggestions.bind(this);
|
||||
static get properties() {
|
||||
return {
|
||||
branch: String,
|
||||
baseCommit: String,
|
||||
changeStatus: String,
|
||||
commitMessage: String,
|
||||
commitNum: String,
|
||||
message: String,
|
||||
project: String,
|
||||
_query: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._getProjectBranchesSuggestions.bind(this);
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
behaviors: [
|
||||
Gerrit.FireBehavior,
|
||||
],
|
||||
|
||||
observers: [
|
||||
'_computeMessage(changeStatus, commitNum, commitMessage)',
|
||||
],
|
||||
static get observers() {
|
||||
return [
|
||||
'_computeMessage(changeStatus, commitNum, commitMessage)',
|
||||
];
|
||||
}
|
||||
|
||||
_computeMessage(changeStatus, commitNum, commitMessage) {
|
||||
// Polymer 2: check for undefined
|
||||
@@ -74,23 +80,23 @@
|
||||
newMessage += '(cherry picked from commit ' + commitNum + ')';
|
||||
}
|
||||
this.message = newMessage;
|
||||
},
|
||||
}
|
||||
|
||||
_handleConfirmTap(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.fire('confirm', null, {bubbles: false});
|
||||
},
|
||||
}
|
||||
|
||||
_handleCancelTap(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.fire('cancel', null, {bubbles: false});
|
||||
},
|
||||
}
|
||||
|
||||
resetFocus() {
|
||||
this.$.branchInput.focus();
|
||||
},
|
||||
}
|
||||
|
||||
_getProjectBranchesSuggestions(input) {
|
||||
if (input.startsWith('refs/heads/')) {
|
||||
@@ -113,6 +119,9 @@
|
||||
}
|
||||
return branches;
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrConfirmCherrypickDialog.is,
|
||||
GrConfirmCherrypickDialog);
|
||||
})();
|
||||
|
||||
@@ -19,9 +19,15 @@
|
||||
|
||||
const SUGGESTIONS_LIMIT = 15;
|
||||
|
||||
Polymer({
|
||||
is: 'gr-confirm-move-dialog',
|
||||
|
||||
/**
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
*/
|
||||
class GrConfirmMoveDialog extends Polymer.mixinBehaviors( [
|
||||
Gerrit.FireBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-confirm-move-dialog'; }
|
||||
/**
|
||||
* Fired when the confirm button is pressed.
|
||||
*
|
||||
@@ -34,33 +40,31 @@
|
||||
* @event cancel
|
||||
*/
|
||||
|
||||
properties: {
|
||||
branch: String,
|
||||
message: String,
|
||||
project: String,
|
||||
_query: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._getProjectBranchesSuggestions.bind(this);
|
||||
static get properties() {
|
||||
return {
|
||||
branch: String,
|
||||
message: String,
|
||||
project: String,
|
||||
_query: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._getProjectBranchesSuggestions.bind(this);
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
Gerrit.FireBehavior,
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
_handleConfirmTap(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.fire('confirm', null, {bubbles: false});
|
||||
},
|
||||
}
|
||||
|
||||
_handleCancelTap(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.fire('cancel', null, {bubbles: false});
|
||||
},
|
||||
}
|
||||
|
||||
_getProjectBranchesSuggestions(input) {
|
||||
if (input.startsWith('refs/heads/')) {
|
||||
@@ -83,6 +87,8 @@
|
||||
}
|
||||
return branches;
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrConfirmMoveDialog.is, GrConfirmMoveDialog);
|
||||
})();
|
||||
|
||||
@@ -17,9 +17,10 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-confirm-rebase-dialog',
|
||||
|
||||
class GrConfirmRebaseDialog extends Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element)) {
|
||||
static get is() { return 'gr-confirm-rebase-dialog'; }
|
||||
/**
|
||||
* Fired when the confirm button is pressed.
|
||||
*
|
||||
@@ -32,24 +33,28 @@
|
||||
* @event cancel
|
||||
*/
|
||||
|
||||
properties: {
|
||||
branch: String,
|
||||
changeNumber: Number,
|
||||
hasParent: Boolean,
|
||||
rebaseOnCurrent: Boolean,
|
||||
_text: String,
|
||||
_query: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._getChangeSuggestions.bind(this);
|
||||
static get properties() {
|
||||
return {
|
||||
branch: String,
|
||||
changeNumber: Number,
|
||||
hasParent: Boolean,
|
||||
rebaseOnCurrent: Boolean,
|
||||
_text: String,
|
||||
_query: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._getChangeSuggestions.bind(this);
|
||||
},
|
||||
},
|
||||
},
|
||||
_recentChanges: Array,
|
||||
},
|
||||
_recentChanges: Array,
|
||||
};
|
||||
}
|
||||
|
||||
observers: [
|
||||
'_updateSelectedOption(rebaseOnCurrent, hasParent)',
|
||||
],
|
||||
static get observers() {
|
||||
return [
|
||||
'_updateSelectedOption(rebaseOnCurrent, hasParent)',
|
||||
];
|
||||
}
|
||||
|
||||
// This is called by gr-change-actions every time the rebase dialog is
|
||||
// re-opened. Unlike other autocompletes that make a request with each
|
||||
@@ -71,36 +76,36 @@
|
||||
this._recentChanges = changes;
|
||||
return this._recentChanges;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_getRecentChanges() {
|
||||
if (this._recentChanges) {
|
||||
return Promise.resolve(this._recentChanges);
|
||||
}
|
||||
return this.fetchRecentChanges();
|
||||
},
|
||||
}
|
||||
|
||||
_getChangeSuggestions(input) {
|
||||
return this._getRecentChanges().then(changes =>
|
||||
this._filterChanges(input, changes));
|
||||
},
|
||||
}
|
||||
|
||||
_filterChanges(input, changes) {
|
||||
return changes.filter(change => change.name.includes(input) &&
|
||||
change.value !== this.changeNumber);
|
||||
},
|
||||
}
|
||||
|
||||
_displayParentOption(rebaseOnCurrent, hasParent) {
|
||||
return hasParent && rebaseOnCurrent;
|
||||
},
|
||||
}
|
||||
|
||||
_displayParentUpToDateMsg(rebaseOnCurrent, hasParent) {
|
||||
return hasParent && !rebaseOnCurrent;
|
||||
},
|
||||
}
|
||||
|
||||
_displayTipOption(rebaseOnCurrent, hasParent) {
|
||||
return !(!rebaseOnCurrent && !hasParent);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* There is a subtle but important difference between setting the base to an
|
||||
@@ -115,7 +120,7 @@
|
||||
// Change numbers will have their description appended by the
|
||||
// autocomplete.
|
||||
return this._text.split(':')[0];
|
||||
},
|
||||
}
|
||||
|
||||
_handleConfirmTap(e) {
|
||||
e.preventDefault();
|
||||
@@ -123,22 +128,22 @@
|
||||
this.dispatchEvent(new CustomEvent('confirm',
|
||||
{detail: {base: this._getSelectedBase()}}));
|
||||
this._text = '';
|
||||
},
|
||||
}
|
||||
|
||||
_handleCancelTap(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.dispatchEvent(new CustomEvent('cancel'));
|
||||
this._text = '';
|
||||
},
|
||||
}
|
||||
|
||||
_handleRebaseOnOther() {
|
||||
this.$.parentInput.focus();
|
||||
},
|
||||
}
|
||||
|
||||
_handleEnterChangeNumberClick() {
|
||||
this.$.rebaseOnOtherInput.checked = true;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default radio button based on the state of the app and
|
||||
@@ -157,6 +162,8 @@
|
||||
} else {
|
||||
this.$.rebaseOnOtherInput.checked = true;
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrConfirmRebaseDialog.is, GrConfirmRebaseDialog);
|
||||
})();
|
||||
|
||||
@@ -20,9 +20,15 @@
|
||||
const ERR_COMMIT_NOT_FOUND =
|
||||
'Unable to find the commit hash of this change.';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-confirm-revert-dialog',
|
||||
|
||||
/**
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
*/
|
||||
class GrConfirmRevertDialog extends Polymer.mixinBehaviors( [
|
||||
Gerrit.FireBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-confirm-revert-dialog'; }
|
||||
/**
|
||||
* Fired when the confirm button is pressed.
|
||||
*
|
||||
@@ -35,13 +41,11 @@
|
||||
* @event cancel
|
||||
*/
|
||||
|
||||
properties: {
|
||||
message: String,
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
Gerrit.FireBehavior,
|
||||
],
|
||||
static get properties() {
|
||||
return {
|
||||
message: String,
|
||||
};
|
||||
}
|
||||
|
||||
populateRevertMessage(message, commitHash) {
|
||||
// Figure out what the revert title should be.
|
||||
@@ -55,18 +59,20 @@
|
||||
|
||||
this.message = `${revertTitle}\n\n${revertCommitText}\n\n` +
|
||||
`Reason for revert: <INSERT REASONING HERE>\n`;
|
||||
},
|
||||
}
|
||||
|
||||
_handleConfirmTap(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.fire('confirm', null, {bubbles: false});
|
||||
},
|
||||
}
|
||||
|
||||
_handleCancelTap(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.fire('cancel', null, {bubbles: false});
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrConfirmRevertDialog.is, GrConfirmRevertDialog);
|
||||
})();
|
||||
|
||||
@@ -20,9 +20,15 @@
|
||||
const ERR_COMMIT_NOT_FOUND =
|
||||
'Unable to find the commit hash of this change.';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-confirm-revert-submission-dialog',
|
||||
|
||||
/**
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
*/
|
||||
class GrConfirmRevertSubmissionDialog extends Polymer.mixinBehaviors( [
|
||||
Gerrit.FireBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-confirm-revert-submission-dialog'; }
|
||||
/**
|
||||
* Fired when the confirm button is pressed.
|
||||
*
|
||||
@@ -35,13 +41,11 @@
|
||||
* @event cancel
|
||||
*/
|
||||
|
||||
properties: {
|
||||
message: String,
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
Gerrit.FireBehavior,
|
||||
],
|
||||
static get properties() {
|
||||
return {
|
||||
message: String,
|
||||
};
|
||||
}
|
||||
|
||||
populateRevertSubmissionMessage(message, commitHash) {
|
||||
// Follow the same convention of the revert
|
||||
@@ -52,18 +56,21 @@
|
||||
}
|
||||
this.message = `${revertTitle}\n\n` +
|
||||
`Reason for revert: <INSERT REASONING HERE>\n`;
|
||||
},
|
||||
}
|
||||
|
||||
_handleConfirmTap(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.fire('confirm', null, {bubbles: false});
|
||||
},
|
||||
}
|
||||
|
||||
_handleCancelTap(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.fire('cancel', null, {bubbles: false});
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrConfirmRevertSubmissionDialog.is,
|
||||
GrConfirmRevertSubmissionDialog);
|
||||
})();
|
||||
|
||||
@@ -17,9 +17,10 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-confirm-submit-dialog',
|
||||
|
||||
class GrConfirmSubmitDialog extends Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element)) {
|
||||
static get is() { return 'gr-confirm-submit-dialog'; }
|
||||
/**
|
||||
* Fired when the confirm button is pressed.
|
||||
*
|
||||
@@ -32,37 +33,41 @@
|
||||
* @event cancel
|
||||
*/
|
||||
|
||||
properties: {
|
||||
static get properties() {
|
||||
return {
|
||||
/**
|
||||
* @type {{
|
||||
* is_private: boolean,
|
||||
* subject: string,
|
||||
* }}
|
||||
*/
|
||||
change: Object,
|
||||
change: Object,
|
||||
|
||||
/**
|
||||
/**
|
||||
* @type {{
|
||||
* label: string,
|
||||
* }}
|
||||
*/
|
||||
action: Object,
|
||||
},
|
||||
action: Object,
|
||||
};
|
||||
}
|
||||
|
||||
resetFocus(e) {
|
||||
this.$.dialog.resetFocus();
|
||||
},
|
||||
}
|
||||
|
||||
_handleConfirmTap(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.dispatchEvent(new CustomEvent('confirm', {bubbles: false}));
|
||||
},
|
||||
}
|
||||
|
||||
_handleCancelTap(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.dispatchEvent(new CustomEvent('cancel', {bubbles: false}));
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrConfirmSubmitDialog.is, GrConfirmSubmitDialog);
|
||||
})();
|
||||
|
||||
@@ -17,40 +17,47 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-download-dialog',
|
||||
|
||||
/**
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
* @appliesMixin Gerrit.PatchSetMixin
|
||||
* @appliesMixin Gerrit.RESTClientMixin
|
||||
*/
|
||||
class GrDownloadDialog extends Polymer.mixinBehaviors( [
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.PatchSetBehavior,
|
||||
Gerrit.RESTClientBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-download-dialog'; }
|
||||
/**
|
||||
* Fired when the user presses the close button.
|
||||
*
|
||||
* @event close
|
||||
*/
|
||||
|
||||
properties: {
|
||||
static get properties() {
|
||||
return {
|
||||
/** @type {{ revisions: Array }} */
|
||||
change: Object,
|
||||
patchNum: String,
|
||||
/** @type {?} */
|
||||
config: Object,
|
||||
change: Object,
|
||||
patchNum: String,
|
||||
/** @type {?} */
|
||||
config: Object,
|
||||
|
||||
_schemes: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
computed: '_computeSchemes(change, patchNum)',
|
||||
observer: '_schemesChanged',
|
||||
},
|
||||
_selectedScheme: String,
|
||||
},
|
||||
_schemes: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
computed: '_computeSchemes(change, patchNum)',
|
||||
observer: '_schemesChanged',
|
||||
},
|
||||
_selectedScheme: String,
|
||||
};
|
||||
}
|
||||
|
||||
hostAttributes: {
|
||||
role: 'dialog',
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.PatchSetBehavior,
|
||||
Gerrit.RESTClientBehavior,
|
||||
],
|
||||
ready() {
|
||||
super.ready();
|
||||
this._ensureAttribute('role', 'dialog');
|
||||
}
|
||||
|
||||
focus() {
|
||||
if (this._schemes.length) {
|
||||
@@ -58,7 +65,7 @@
|
||||
} else {
|
||||
this.$.download.focus();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
getFocusStops() {
|
||||
const links = this.$$('#archives').querySelectorAll('a');
|
||||
@@ -66,7 +73,7 @@
|
||||
start: this.$.closeButton,
|
||||
end: links[links.length - 1],
|
||||
};
|
||||
},
|
||||
}
|
||||
|
||||
_computeDownloadCommands(change, patchNum, _selectedScheme) {
|
||||
let commandObj;
|
||||
@@ -87,7 +94,7 @@
|
||||
});
|
||||
}
|
||||
return commands;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Object} change
|
||||
@@ -97,7 +104,7 @@
|
||||
*/
|
||||
_computeZipDownloadLink(change, patchNum) {
|
||||
return this._computeDownloadLink(change, patchNum, true);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Object} change
|
||||
@@ -107,7 +114,7 @@
|
||||
*/
|
||||
_computeZipDownloadFilename(change, patchNum) {
|
||||
return this._computeDownloadFilename(change, patchNum, true);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Object} change
|
||||
@@ -123,7 +130,7 @@
|
||||
}
|
||||
return this.changeBaseURL(change.project, change._number, patchNum) +
|
||||
'/patch?' + (opt_zip ? 'zip' : 'download');
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Object} change
|
||||
@@ -146,7 +153,7 @@
|
||||
}
|
||||
}
|
||||
return shortRev + '.diff.' + (opt_zip ? 'zip' : 'base64');
|
||||
},
|
||||
}
|
||||
|
||||
_computeHidePatchFile(change, patchNum) {
|
||||
// Polymer 2: check for undefined
|
||||
@@ -161,7 +168,7 @@
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
}
|
||||
|
||||
_computeArchiveDownloadLink(change, patchNum, format) {
|
||||
// Polymer 2: check for undefined
|
||||
@@ -170,7 +177,7 @@
|
||||
}
|
||||
return this.changeBaseURL(change.project, change._number, patchNum) +
|
||||
'/archive?format=' + format;
|
||||
},
|
||||
}
|
||||
|
||||
_computeSchemes(change, patchNum) {
|
||||
// Polymer 2: check for undefined
|
||||
@@ -188,28 +195,30 @@
|
||||
}
|
||||
}
|
||||
return [];
|
||||
},
|
||||
}
|
||||
|
||||
_computePatchSetQuantity(revisions) {
|
||||
if (!revisions) { return 0; }
|
||||
return Object.keys(revisions).length;
|
||||
},
|
||||
}
|
||||
|
||||
_handleCloseTap(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.fire('close', null, {bubbles: false});
|
||||
},
|
||||
}
|
||||
|
||||
_schemesChanged(schemes) {
|
||||
if (schemes.length === 0) { return; }
|
||||
if (!schemes.includes(this._selectedScheme)) {
|
||||
this._selectedScheme = schemes.sort()[0];
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_computeShowDownloadCommands(schemes) {
|
||||
return schemes.length ? '' : 'hidden';
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrDownloadDialog.is, GrDownloadDialog);
|
||||
})();
|
||||
|
||||
@@ -21,9 +21,17 @@
|
||||
const PATCH_DESC_MAX_LENGTH = 500;
|
||||
const MERGED_STATUS = 'MERGED';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-file-list-header',
|
||||
|
||||
/**
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
* @appliesMixin Gerrit.PatchSetMixin
|
||||
*/
|
||||
class GrFileListHeader extends Polymer.mixinBehaviors( [
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.PatchSetBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-file-list-header'; }
|
||||
/**
|
||||
* @event expand-diffs
|
||||
*/
|
||||
@@ -48,72 +56,71 @@
|
||||
* @event open-upload-help-dialog
|
||||
*/
|
||||
|
||||
properties: {
|
||||
account: Object,
|
||||
allPatchSets: Array,
|
||||
/** @type {?} */
|
||||
change: Object,
|
||||
changeNum: String,
|
||||
changeUrl: String,
|
||||
changeComments: Object,
|
||||
commitInfo: Object,
|
||||
editMode: Boolean,
|
||||
loggedIn: Boolean,
|
||||
serverConfig: Object,
|
||||
shownFileCount: Number,
|
||||
diffPrefs: Object,
|
||||
diffPrefsDisabled: Boolean,
|
||||
diffViewMode: {
|
||||
type: String,
|
||||
notify: true,
|
||||
},
|
||||
patchNum: String,
|
||||
basePatchNum: String,
|
||||
filesExpanded: String,
|
||||
// Caps the number of files that can be shown and have the 'show diffs' /
|
||||
// 'hide diffs' buttons still be functional.
|
||||
_maxFilesForBulkActions: {
|
||||
type: Number,
|
||||
readOnly: true,
|
||||
value: 225,
|
||||
},
|
||||
_patchsetDescription: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
showTitle: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
_descriptionReadOnly: {
|
||||
type: Boolean,
|
||||
computed: '_computeDescriptionReadOnly(loggedIn, change, account)',
|
||||
},
|
||||
revisionInfo: Object,
|
||||
},
|
||||
static get properties() {
|
||||
return {
|
||||
account: Object,
|
||||
allPatchSets: Array,
|
||||
/** @type {?} */
|
||||
change: Object,
|
||||
changeNum: String,
|
||||
changeUrl: String,
|
||||
changeComments: Object,
|
||||
commitInfo: Object,
|
||||
editMode: Boolean,
|
||||
loggedIn: Boolean,
|
||||
serverConfig: Object,
|
||||
shownFileCount: Number,
|
||||
diffPrefs: Object,
|
||||
diffPrefsDisabled: Boolean,
|
||||
diffViewMode: {
|
||||
type: String,
|
||||
notify: true,
|
||||
},
|
||||
patchNum: String,
|
||||
basePatchNum: String,
|
||||
filesExpanded: String,
|
||||
// Caps the number of files that can be shown and have the 'show diffs' /
|
||||
// 'hide diffs' buttons still be functional.
|
||||
_maxFilesForBulkActions: {
|
||||
type: Number,
|
||||
readOnly: true,
|
||||
value: 225,
|
||||
},
|
||||
_patchsetDescription: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
showTitle: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
_descriptionReadOnly: {
|
||||
type: Boolean,
|
||||
computed: '_computeDescriptionReadOnly(loggedIn, change, account)',
|
||||
},
|
||||
revisionInfo: Object,
|
||||
};
|
||||
}
|
||||
|
||||
behaviors: [
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.PatchSetBehavior,
|
||||
],
|
||||
|
||||
observers: [
|
||||
'_computePatchSetDescription(change, patchNum)',
|
||||
],
|
||||
static get observers() {
|
||||
return [
|
||||
'_computePatchSetDescription(change, patchNum)',
|
||||
];
|
||||
}
|
||||
|
||||
setDiffViewMode(mode) {
|
||||
this.$.modeSelect.setMode(mode);
|
||||
},
|
||||
}
|
||||
|
||||
_expandAllDiffs() {
|
||||
this._expanded = true;
|
||||
this.fire('expand-diffs');
|
||||
},
|
||||
}
|
||||
|
||||
_collapseAllDiffs() {
|
||||
this._expanded = false;
|
||||
this.fire('collapse-diffs');
|
||||
},
|
||||
}
|
||||
|
||||
_computeExpandedClass(filesExpanded) {
|
||||
const classes = [];
|
||||
@@ -125,11 +132,11 @@
|
||||
classes.push('openFile');
|
||||
}
|
||||
return classes.join(' ');
|
||||
},
|
||||
}
|
||||
|
||||
_computeDescriptionPlaceholder(readOnly) {
|
||||
return (readOnly ? 'No' : 'Add') + ' patchset description';
|
||||
},
|
||||
}
|
||||
|
||||
_computeDescriptionReadOnly(loggedIn, change, account) {
|
||||
// Polymer 2: check for undefined
|
||||
@@ -138,7 +145,7 @@
|
||||
}
|
||||
|
||||
return !(loggedIn && (account._account_id === change.owner._account_id));
|
||||
},
|
||||
}
|
||||
|
||||
_computePatchSetDescription(change, patchNum) {
|
||||
// Polymer 2: check for undefined
|
||||
@@ -149,11 +156,11 @@
|
||||
const rev = this.getRevisionByPatchNum(change.revisions, patchNum);
|
||||
this._patchsetDescription = (rev && rev.description) ?
|
||||
rev.description.substring(0, PATCH_DESC_MAX_LENGTH) : '';
|
||||
},
|
||||
}
|
||||
|
||||
_handleDescriptionRemoved(e) {
|
||||
return this._updateDescription('', e);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Object} revisions The revisions object keyed by revision hashes
|
||||
@@ -167,12 +174,12 @@
|
||||
return rev;
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_handleDescriptionChanged(e) {
|
||||
const desc = e.detail.trim();
|
||||
this._updateDescription(desc, e);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the patchset description with the rest API.
|
||||
@@ -197,43 +204,43 @@
|
||||
if (target) { target.disabled = false; }
|
||||
return;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_computePrefsButtonHidden(prefs, diffPrefsDisabled) {
|
||||
return diffPrefsDisabled || !prefs;
|
||||
},
|
||||
}
|
||||
|
||||
_fileListActionsVisible(shownFileCount, maxFilesForBulkActions) {
|
||||
return shownFileCount <= maxFilesForBulkActions;
|
||||
},
|
||||
}
|
||||
|
||||
_handlePatchChange(e) {
|
||||
const {basePatchNum, patchNum} = e.detail;
|
||||
if (this.patchNumEquals(basePatchNum, this.basePatchNum) &&
|
||||
this.patchNumEquals(patchNum, this.patchNum)) { return; }
|
||||
Gerrit.Nav.navigateToChange(this.change, patchNum, basePatchNum);
|
||||
},
|
||||
}
|
||||
|
||||
_handlePrefsTap(e) {
|
||||
e.preventDefault();
|
||||
this.fire('open-diff-prefs');
|
||||
},
|
||||
}
|
||||
|
||||
_handleIncludedInTap(e) {
|
||||
e.preventDefault();
|
||||
this.fire('open-included-in-dialog');
|
||||
},
|
||||
}
|
||||
|
||||
_handleDownloadTap(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.dispatchEvent(
|
||||
new CustomEvent('open-download-dialog', {bubbles: false}));
|
||||
},
|
||||
}
|
||||
|
||||
_computeEditModeClass(editMode) {
|
||||
return editMode ? 'editMode' : '';
|
||||
},
|
||||
}
|
||||
|
||||
_computePatchInfoClass(patchNum, allPatchSets) {
|
||||
const latestNum = this.computeLatestPatchNum(allPatchSets);
|
||||
@@ -241,18 +248,18 @@
|
||||
return '';
|
||||
}
|
||||
return 'patchInfoOldPatchSet';
|
||||
},
|
||||
}
|
||||
|
||||
_hideIncludedIn(change) {
|
||||
return change && change.status === MERGED_STATUS ? '' : 'hide';
|
||||
},
|
||||
}
|
||||
|
||||
_handleUploadTap(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.dispatchEvent(
|
||||
new CustomEvent('open-upload-help-dialog', {bubbles: false}));
|
||||
},
|
||||
}
|
||||
|
||||
_computeUploadHelpContainerClass(change, account) {
|
||||
const changeIsMerged = change && change.status === MERGED_STATUS;
|
||||
@@ -262,6 +269,8 @@
|
||||
const userIsOwner = ownerId && userId && ownerId === userId;
|
||||
const hideContainer = !userIsOwner || changeIsMerged;
|
||||
return 'uploadContainer desktop' + (hideContainer ? ' hide' : '');
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrFileListHeader.is, GrFileListHeader);
|
||||
})();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,36 +17,40 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-included-in-dialog',
|
||||
|
||||
/**
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
*/
|
||||
class GrIncludedInDialog extends Polymer.mixinBehaviors( [
|
||||
Gerrit.FireBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-included-in-dialog'; }
|
||||
/**
|
||||
* Fired when the user presses the close button.
|
||||
*
|
||||
* @event close
|
||||
*/
|
||||
|
||||
properties: {
|
||||
static get properties() {
|
||||
return {
|
||||
/** @type {?} */
|
||||
changeNum: {
|
||||
type: Object,
|
||||
observer: '_resetData',
|
||||
},
|
||||
/** @type {?} */
|
||||
_includedIn: Object,
|
||||
_loaded: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_filterText: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
Gerrit.FireBehavior,
|
||||
],
|
||||
changeNum: {
|
||||
type: Object,
|
||||
observer: '_resetData',
|
||||
},
|
||||
/** @type {?} */
|
||||
_includedIn: Object,
|
||||
_loaded: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_filterText: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
loadData() {
|
||||
if (!this.changeNum) { return; }
|
||||
@@ -57,12 +61,12 @@
|
||||
this._includedIn = configs;
|
||||
this._loaded = true;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_resetData() {
|
||||
this._includedIn = null;
|
||||
this._loaded = false;
|
||||
},
|
||||
}
|
||||
|
||||
_computeGroups(includedIn, filterText) {
|
||||
if (!includedIn) { return []; }
|
||||
@@ -83,22 +87,24 @@
|
||||
}
|
||||
}
|
||||
return groups.filter(g => g.items.length);
|
||||
},
|
||||
}
|
||||
|
||||
_handleCloseTap(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.fire('close', null, {bubbles: false});
|
||||
},
|
||||
}
|
||||
|
||||
_computeLoadingClass(loaded) {
|
||||
return loaded ? 'loading loaded' : 'loading';
|
||||
},
|
||||
}
|
||||
|
||||
_onFilterChanged() {
|
||||
this.debounce('filter-change', () => {
|
||||
this._filterText = this.$.filterInput.bindValue;
|
||||
}, 100);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrIncludedInDialog.is, GrIncludedInDialog);
|
||||
})();
|
||||
|
||||
@@ -17,56 +17,59 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-label-score-row',
|
||||
|
||||
class GrLabelScoreRow extends Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element)) {
|
||||
static get is() { return 'gr-label-score-row'; }
|
||||
/**
|
||||
* Fired when any label is changed.
|
||||
*
|
||||
* @event labels-changed
|
||||
*/
|
||||
|
||||
properties: {
|
||||
static get properties() {
|
||||
return {
|
||||
/**
|
||||
* @type {{ name: string }}
|
||||
*/
|
||||
label: Object,
|
||||
labels: Object,
|
||||
name: {
|
||||
type: String,
|
||||
reflectToAttribute: true,
|
||||
},
|
||||
permittedLabels: Object,
|
||||
labelValues: Object,
|
||||
_selectedValueText: {
|
||||
type: String,
|
||||
value: 'No value selected',
|
||||
},
|
||||
_items: {
|
||||
type: Array,
|
||||
computed: '_computePermittedLabelValues(permittedLabels, label.name)',
|
||||
},
|
||||
},
|
||||
label: Object,
|
||||
labels: Object,
|
||||
name: {
|
||||
type: String,
|
||||
reflectToAttribute: true,
|
||||
},
|
||||
permittedLabels: Object,
|
||||
labelValues: Object,
|
||||
_selectedValueText: {
|
||||
type: String,
|
||||
value: 'No value selected',
|
||||
},
|
||||
_items: {
|
||||
type: Array,
|
||||
computed: '_computePermittedLabelValues(permittedLabels, label.name)',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
get selectedItem() {
|
||||
if (!this._ironSelector) { return undefined; }
|
||||
return this._ironSelector.selectedItem;
|
||||
},
|
||||
}
|
||||
|
||||
get selectedValue() {
|
||||
if (!this._ironSelector) { return undefined; }
|
||||
return this._ironSelector.selected;
|
||||
},
|
||||
}
|
||||
|
||||
setSelectedValue(value) {
|
||||
// The selector may not be present if it’s not at the latest patch set.
|
||||
if (!this._ironSelector) { return; }
|
||||
this._ironSelector.select(value);
|
||||
},
|
||||
}
|
||||
|
||||
get _ironSelector() {
|
||||
return this.$ && this.$.labelSelector;
|
||||
},
|
||||
}
|
||||
|
||||
_computeBlankItems(permittedLabels, label, side) {
|
||||
if (!permittedLabels || !permittedLabels[label] ||
|
||||
@@ -82,7 +85,7 @@
|
||||
const endPosition = this.labelValues[parseInt(
|
||||
permittedLabels[label][permittedLabels[label].length - 1], 10)];
|
||||
return new Array(Object.keys(this.labelValues).length - endPosition - 1);
|
||||
},
|
||||
}
|
||||
|
||||
_getLabelValue(labels, permittedLabels, label) {
|
||||
if (label.value) {
|
||||
@@ -93,7 +96,7 @@
|
||||
return permittedLabels[label.name].find(
|
||||
value => parseInt(value, 10) === labels[label.name].default_value);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_computeButtonClass(value, index, totalItems) {
|
||||
const classes = [];
|
||||
@@ -114,7 +117,7 @@
|
||||
}
|
||||
|
||||
return classes.join(' ');
|
||||
},
|
||||
}
|
||||
|
||||
_computeLabelValue(labels, permittedLabels, label) {
|
||||
if ([labels, permittedLabels, label].some(arg => arg === undefined)) {
|
||||
@@ -131,7 +134,7 @@
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
}
|
||||
|
||||
_setSelectedValueText(e) {
|
||||
// Needed because when the selected item changes, it first changes to
|
||||
@@ -145,17 +148,17 @@
|
||||
this.dispatchEvent(new CustomEvent(
|
||||
'labels-changed',
|
||||
{detail: {name, value}, bubbles: true, composed: true}));
|
||||
},
|
||||
}
|
||||
|
||||
_computeAnyPermittedLabelValues(permittedLabels, label) {
|
||||
return permittedLabels && permittedLabels.hasOwnProperty(label) &&
|
||||
permittedLabels[label].length;
|
||||
},
|
||||
}
|
||||
|
||||
_computeHiddenClass(permittedLabels, label) {
|
||||
return !this._computeAnyPermittedLabelValues(permittedLabels, label) ?
|
||||
'hidden' : '';
|
||||
},
|
||||
}
|
||||
|
||||
_computePermittedLabelValues(permittedLabels, label) {
|
||||
// Polymer 2: check for undefined
|
||||
@@ -164,12 +167,14 @@
|
||||
}
|
||||
|
||||
return permittedLabels[label];
|
||||
},
|
||||
}
|
||||
|
||||
_computeLabelValueTitle(labels, label, value) {
|
||||
return labels[label] &&
|
||||
labels[label].values &&
|
||||
labels[label].values[value];
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrLabelScoreRow.is, GrLabelScoreRow);
|
||||
})();
|
||||
|
||||
@@ -17,25 +17,29 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-label-scores',
|
||||
class GrLabelScores extends Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element)) {
|
||||
static get is() { return 'gr-label-scores'; }
|
||||
|
||||
properties: {
|
||||
_labels: {
|
||||
type: Array,
|
||||
computed: '_computeLabels(change.labels.*, account)',
|
||||
},
|
||||
permittedLabels: {
|
||||
type: Object,
|
||||
observer: '_computeColumns',
|
||||
},
|
||||
/** @type {?} */
|
||||
change: Object,
|
||||
/** @type {?} */
|
||||
account: Object,
|
||||
static get properties() {
|
||||
return {
|
||||
_labels: {
|
||||
type: Array,
|
||||
computed: '_computeLabels(change.labels.*, account)',
|
||||
},
|
||||
permittedLabels: {
|
||||
type: Object,
|
||||
observer: '_computeColumns',
|
||||
},
|
||||
/** @type {?} */
|
||||
change: Object,
|
||||
/** @type {?} */
|
||||
account: Object,
|
||||
|
||||
_labelValues: Object,
|
||||
},
|
||||
_labelValues: Object,
|
||||
};
|
||||
}
|
||||
|
||||
getLabelValues() {
|
||||
const labels = {};
|
||||
@@ -61,7 +65,7 @@
|
||||
}
|
||||
}
|
||||
return labels;
|
||||
},
|
||||
}
|
||||
|
||||
_getStringLabelValue(labels, labelName, numberValue) {
|
||||
for (const k in labels[labelName].values) {
|
||||
@@ -70,7 +74,7 @@
|
||||
}
|
||||
}
|
||||
return numberValue;
|
||||
},
|
||||
}
|
||||
|
||||
_getVoteForAccount(labels, labelName, account) {
|
||||
const votes = labels[labelName];
|
||||
@@ -83,7 +87,7 @@
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
}
|
||||
|
||||
_computeLabels(labelRecord, account) {
|
||||
// Polymer 2: check for undefined
|
||||
@@ -99,7 +103,7 @@
|
||||
value: this._getVoteForAccount(labelsObj, key, this.account),
|
||||
};
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_computeColumns(permittedLabels) {
|
||||
const labels = Object.keys(permittedLabels);
|
||||
@@ -118,11 +122,11 @@
|
||||
values[orderedValues[i]] = i;
|
||||
}
|
||||
this._labelValues = values;
|
||||
},
|
||||
}
|
||||
|
||||
_changeIsMerged(changeStatus) {
|
||||
return changeStatus === 'MERGED';
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param label {string|undefined}
|
||||
@@ -136,6 +140,8 @@
|
||||
|
||||
return permittedLabels.hasOwnProperty(label) &&
|
||||
permittedLabels[label].length ? 'access' : 'no-access';
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrLabelScores.is, GrLabelScores);
|
||||
})();
|
||||
|
||||
@@ -20,9 +20,15 @@
|
||||
const PATCH_SET_PREFIX_PATTERN = /^Patch Set \d+: /;
|
||||
const LABEL_TITLE_SCORE_PATTERN = /^([A-Za-z0-9-]+)([+-]\d+)$/;
|
||||
|
||||
Polymer({
|
||||
is: 'gr-message',
|
||||
|
||||
/**
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
*/
|
||||
class GrMessage extends Polymer.mixinBehaviors( [
|
||||
Gerrit.FireBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-message'; }
|
||||
/**
|
||||
* Fired when this message's reply link is tapped.
|
||||
*
|
||||
@@ -35,90 +41,93 @@
|
||||
* @event message-anchor-tap
|
||||
*/
|
||||
|
||||
listeners: {
|
||||
click: '_handleClick',
|
||||
},
|
||||
static get properties() {
|
||||
return {
|
||||
changeNum: Number,
|
||||
/** @type {?} */
|
||||
message: Object,
|
||||
author: {
|
||||
type: Object,
|
||||
computed: '_computeAuthor(message)',
|
||||
},
|
||||
comments: {
|
||||
type: Object,
|
||||
observer: '_commentsChanged',
|
||||
},
|
||||
config: Object,
|
||||
hideAutomated: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
hidden: {
|
||||
type: Boolean,
|
||||
computed: '_computeIsHidden(hideAutomated, isAutomated)',
|
||||
reflectToAttribute: true,
|
||||
},
|
||||
isAutomated: {
|
||||
type: Boolean,
|
||||
computed: '_computeIsAutomated(message)',
|
||||
},
|
||||
showAvatar: {
|
||||
type: Boolean,
|
||||
computed: '_computeShowAvatar(author, config)',
|
||||
},
|
||||
showOnBehalfOf: {
|
||||
type: Boolean,
|
||||
computed: '_computeShowOnBehalfOf(message)',
|
||||
},
|
||||
showReplyButton: {
|
||||
type: Boolean,
|
||||
computed: '_computeShowReplyButton(message, _loggedIn)',
|
||||
},
|
||||
projectName: {
|
||||
type: String,
|
||||
observer: '_projectNameChanged',
|
||||
},
|
||||
|
||||
properties: {
|
||||
changeNum: Number,
|
||||
/** @type {?} */
|
||||
message: Object,
|
||||
author: {
|
||||
type: Object,
|
||||
computed: '_computeAuthor(message)',
|
||||
},
|
||||
comments: {
|
||||
type: Object,
|
||||
observer: '_commentsChanged',
|
||||
},
|
||||
config: Object,
|
||||
hideAutomated: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
hidden: {
|
||||
type: Boolean,
|
||||
computed: '_computeIsHidden(hideAutomated, isAutomated)',
|
||||
reflectToAttribute: true,
|
||||
},
|
||||
isAutomated: {
|
||||
type: Boolean,
|
||||
computed: '_computeIsAutomated(message)',
|
||||
},
|
||||
showAvatar: {
|
||||
type: Boolean,
|
||||
computed: '_computeShowAvatar(author, config)',
|
||||
},
|
||||
showOnBehalfOf: {
|
||||
type: Boolean,
|
||||
computed: '_computeShowOnBehalfOf(message)',
|
||||
},
|
||||
showReplyButton: {
|
||||
type: Boolean,
|
||||
computed: '_computeShowReplyButton(message, _loggedIn)',
|
||||
},
|
||||
projectName: {
|
||||
type: String,
|
||||
observer: '_projectNameChanged',
|
||||
},
|
||||
|
||||
/**
|
||||
/**
|
||||
* A mapping from label names to objects representing the minimum and
|
||||
* maximum possible values for that label.
|
||||
*/
|
||||
labelExtremes: Object,
|
||||
labelExtremes: Object,
|
||||
|
||||
/**
|
||||
/**
|
||||
* @type {{ commentlinks: Array }}
|
||||
*/
|
||||
_projectConfig: Object,
|
||||
// Computed property needed to trigger Polymer value observing.
|
||||
_expanded: {
|
||||
type: Object,
|
||||
computed: '_computeExpanded(message.expanded)',
|
||||
},
|
||||
_loggedIn: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
},
|
||||
_projectConfig: Object,
|
||||
// Computed property needed to trigger Polymer value observing.
|
||||
_expanded: {
|
||||
type: Object,
|
||||
computed: '_computeExpanded(message.expanded)',
|
||||
},
|
||||
_loggedIn: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
behaviors: [
|
||||
Gerrit.FireBehavior,
|
||||
],
|
||||
static get observers() {
|
||||
return [
|
||||
'_updateExpandedClass(message.expanded)',
|
||||
];
|
||||
}
|
||||
|
||||
observers: [
|
||||
'_updateExpandedClass(message.expanded)',
|
||||
],
|
||||
created() {
|
||||
super.created();
|
||||
this.addEventListener('click',
|
||||
e => this._handleClick(e));
|
||||
}
|
||||
|
||||
ready() {
|
||||
super.ready();
|
||||
this.$.restAPI.getConfig().then(config => {
|
||||
this.config = config;
|
||||
});
|
||||
this.$.restAPI.getLoggedIn().then(loggedIn => {
|
||||
this._loggedIn = loggedIn;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_updateExpandedClass(expanded) {
|
||||
if (expanded) {
|
||||
@@ -126,30 +135,30 @@
|
||||
} else {
|
||||
this.classList.remove('expanded');
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_computeAuthor(message) {
|
||||
return message.author || message.updated_by;
|
||||
},
|
||||
}
|
||||
|
||||
_computeShowAvatar(author, config) {
|
||||
return !!(author && config && config.plugin && config.plugin.has_avatars);
|
||||
},
|
||||
}
|
||||
|
||||
_computeShowOnBehalfOf(message) {
|
||||
const author = message.author || message.updated_by;
|
||||
return !!(author && message.real_author &&
|
||||
author._account_id != message.real_author._account_id);
|
||||
},
|
||||
}
|
||||
|
||||
_computeShowReplyButton(message, loggedIn) {
|
||||
return message && !!message.message && loggedIn &&
|
||||
!this._computeIsAutomated(message);
|
||||
},
|
||||
}
|
||||
|
||||
_computeExpanded(expanded) {
|
||||
return expanded;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* If there is no value set on the message object as to whether _expanded
|
||||
@@ -160,33 +169,33 @@
|
||||
if (this.message && this.message.expanded === undefined) {
|
||||
this.set('message.expanded', Object.keys(value || {}).length > 0);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_handleClick(e) {
|
||||
if (this.message.expanded) { return; }
|
||||
e.stopPropagation();
|
||||
this.set('message.expanded', true);
|
||||
},
|
||||
}
|
||||
|
||||
_handleAuthorClick(e) {
|
||||
if (!this.message.expanded) { return; }
|
||||
e.stopPropagation();
|
||||
this.set('message.expanded', false);
|
||||
},
|
||||
}
|
||||
|
||||
_computeIsAutomated(message) {
|
||||
return !!(message.reviewer ||
|
||||
this._computeIsReviewerUpdate(message) ||
|
||||
(message.tag && message.tag.startsWith('autogenerated')));
|
||||
},
|
||||
}
|
||||
|
||||
_computeIsHidden(hideAutomated, isAutomated) {
|
||||
return hideAutomated && isAutomated;
|
||||
},
|
||||
}
|
||||
|
||||
_computeIsReviewerUpdate(event) {
|
||||
return event.type === 'REVIEWER_UPDATE';
|
||||
},
|
||||
}
|
||||
|
||||
_getScores(message) {
|
||||
if (!message.message) { return []; }
|
||||
@@ -199,7 +208,7 @@
|
||||
.map(s => s.match(LABEL_TITLE_SCORE_PATTERN))
|
||||
.filter(ms => ms && ms.length === 3)
|
||||
.map(ms => ({label: ms[1], value: ms[2]}));
|
||||
},
|
||||
}
|
||||
|
||||
_computeScoreClass(score, labelExtremes) {
|
||||
// Polymer 2: check for undefined
|
||||
@@ -222,14 +231,14 @@
|
||||
}
|
||||
}
|
||||
return classes.join(' ');
|
||||
},
|
||||
}
|
||||
|
||||
_computeClass(expanded, showAvatar, message) {
|
||||
const classes = [];
|
||||
classes.push(expanded ? 'expanded' : 'collapsed');
|
||||
classes.push(showAvatar ? 'showAvatar' : 'hideAvatar');
|
||||
return classes.join(' ');
|
||||
},
|
||||
}
|
||||
|
||||
_handleAnchorClick(e) {
|
||||
e.preventDefault();
|
||||
@@ -238,26 +247,28 @@
|
||||
composed: true,
|
||||
detail: {id: this.message.id},
|
||||
}));
|
||||
},
|
||||
}
|
||||
|
||||
_handleReplyTap(e) {
|
||||
e.preventDefault();
|
||||
this.fire('reply', {message: this.message});
|
||||
},
|
||||
}
|
||||
|
||||
_projectNameChanged(name) {
|
||||
this.$.restAPI.getProjectConfig(name).then(config => {
|
||||
this._projectConfig = config;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_computeExpandToggleIcon(expanded) {
|
||||
return expanded ? 'gr-icons:expand-less' : 'gr-icons:expand-more';
|
||||
},
|
||||
}
|
||||
|
||||
_toggleExpanded(e) {
|
||||
e.stopPropagation();
|
||||
this.set('message.expanded', !this.message.expanded);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrMessage.is, GrMessage);
|
||||
})();
|
||||
|
||||
@@ -25,57 +25,61 @@
|
||||
SHOW_MORE: 'show-more-messages',
|
||||
};
|
||||
|
||||
Polymer({
|
||||
is: 'gr-messages-list',
|
||||
class GrMessagesList extends Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element)) {
|
||||
static get is() { return 'gr-messages-list'; }
|
||||
|
||||
properties: {
|
||||
changeNum: Number,
|
||||
messages: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
reviewerUpdates: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
changeComments: Object,
|
||||
projectName: String,
|
||||
showReplyButtons: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
labels: Object,
|
||||
static get properties() {
|
||||
return {
|
||||
changeNum: Number,
|
||||
messages: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
reviewerUpdates: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
changeComments: Object,
|
||||
projectName: String,
|
||||
showReplyButtons: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
labels: Object,
|
||||
|
||||
_expanded: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
observer: '_expandedChanged',
|
||||
},
|
||||
_hideAutomated: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
/**
|
||||
_expanded: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
observer: '_expandedChanged',
|
||||
},
|
||||
_hideAutomated: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
/**
|
||||
* The messages after processing and including merged reviewer updates.
|
||||
*/
|
||||
_processedMessages: {
|
||||
type: Array,
|
||||
computed: '_computeItems(messages, reviewerUpdates)',
|
||||
observer: '_processedMessagesChanged',
|
||||
},
|
||||
/**
|
||||
_processedMessages: {
|
||||
type: Array,
|
||||
computed: '_computeItems(messages, reviewerUpdates)',
|
||||
observer: '_processedMessagesChanged',
|
||||
},
|
||||
/**
|
||||
* The subset of _processedMessages that is visible to the user.
|
||||
*/
|
||||
_visibleMessages: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
_visibleMessages: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
|
||||
_labelExtremes: {
|
||||
type: Object,
|
||||
computed: '_computeLabelExtremes(labels.*)',
|
||||
},
|
||||
},
|
||||
_labelExtremes: {
|
||||
type: Object,
|
||||
computed: '_computeLabelExtremes(labels.*)',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
scrollToMessage(messageID) {
|
||||
let el = this.$$('[data-message-id="' + messageID + '"]');
|
||||
@@ -108,12 +112,12 @@
|
||||
}
|
||||
window.scrollTo(0, top);
|
||||
this._highlightEl(el);
|
||||
},
|
||||
}
|
||||
|
||||
_isAutomated(message) {
|
||||
return !!(message.reviewer ||
|
||||
(message.tag && message.tag.startsWith('autogenerated')));
|
||||
},
|
||||
}
|
||||
|
||||
_computeItems(messages, reviewerUpdates) {
|
||||
// Polymer 2: check for undefined
|
||||
@@ -152,7 +156,7 @@
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
}
|
||||
|
||||
_expandedChanged(exp) {
|
||||
if (this._processedMessages) {
|
||||
@@ -169,7 +173,7 @@
|
||||
this.notifyPath(`_visibleMessages.${i}.expanded`);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_highlightEl(el) {
|
||||
const highlightedEls =
|
||||
@@ -183,23 +187,23 @@
|
||||
}
|
||||
el.addEventListener('animationend', handleAnimationEnd);
|
||||
el.classList.add('highlighted');
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean} expand
|
||||
*/
|
||||
handleExpandCollapse(expand) {
|
||||
this._expanded = expand;
|
||||
},
|
||||
}
|
||||
|
||||
_handleExpandCollapseTap(e) {
|
||||
e.preventDefault();
|
||||
this.handleExpandCollapse(!this._expanded);
|
||||
},
|
||||
}
|
||||
|
||||
_handleAnchorClick(e) {
|
||||
this.scrollToMessage(e.detail.id);
|
||||
},
|
||||
}
|
||||
|
||||
_hasAutomatedMessages(messages) {
|
||||
if (!messages) { return false; }
|
||||
@@ -209,11 +213,11 @@
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
}
|
||||
|
||||
_computeExpandCollapseMessage(expanded) {
|
||||
return expanded ? 'Collapse all' : 'Expand all';
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes message author's file comments for change's message.
|
||||
@@ -268,7 +272,7 @@
|
||||
}
|
||||
}
|
||||
return msgComments;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of messages to splice to the beginning of
|
||||
@@ -293,7 +297,7 @@
|
||||
delta = msgsRemaining - i;
|
||||
}
|
||||
return Math.min(msgsRemaining, delta);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of messages that would be visible, but do not currently
|
||||
@@ -309,20 +313,20 @@
|
||||
this._getHumanMessages(visibleMessages).length;
|
||||
}
|
||||
return messages.length - visibleMessages.length;
|
||||
},
|
||||
}
|
||||
|
||||
_computeIncrementText(visibleMessages, messages, hideAutomated) {
|
||||
let delta = this._getDelta(visibleMessages, messages, hideAutomated);
|
||||
delta = Math.min(
|
||||
this._numRemaining(visibleMessages, messages, hideAutomated), delta);
|
||||
return 'Show ' + Math.min(MESSAGES_INCREMENT, delta) + ' more';
|
||||
},
|
||||
}
|
||||
|
||||
_getHumanMessages(messages) {
|
||||
return messages.filter(msg => {
|
||||
return !this._isAutomated(msg);
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_computeShowHideTextHidden(visibleMessages, messages,
|
||||
hideAutomated) {
|
||||
@@ -335,12 +339,12 @@
|
||||
visibleMessages = this._getHumanMessages(visibleMessages);
|
||||
}
|
||||
return visibleMessages.length >= messages.length;
|
||||
},
|
||||
}
|
||||
|
||||
_handleShowAllTap() {
|
||||
this._visibleMessages = this._processedMessages;
|
||||
this.$.reporting.reportInteraction(ReportingEvent.SHOW_ALL);
|
||||
},
|
||||
}
|
||||
|
||||
_handleIncrementShownMessages() {
|
||||
const delta = this._getDelta(this._visibleMessages,
|
||||
@@ -350,27 +354,27 @@
|
||||
// Add newMessages to the beginning of _visibleMessages
|
||||
this.splice(...['_visibleMessages', 0, 0].concat(newMessages));
|
||||
this.$.reporting.reportInteraction(ReportingEvent.SHOW_MORE);
|
||||
},
|
||||
}
|
||||
|
||||
_processedMessagesChanged(messages) {
|
||||
if (messages) {
|
||||
this._visibleMessages = messages.slice(-MAX_INITIAL_SHOWN_MESSAGES);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_computeNumMessagesText(visibleMessages, messages,
|
||||
hideAutomated) {
|
||||
const total =
|
||||
this._numRemaining(visibleMessages, messages, hideAutomated);
|
||||
return total === 1 ? 'Show 1 message' : 'Show all ' + total + ' messages';
|
||||
},
|
||||
}
|
||||
|
||||
_computeIncrementHidden(visibleMessages, messages,
|
||||
hideAutomated) {
|
||||
const total =
|
||||
this._numRemaining(visibleMessages, messages, hideAutomated);
|
||||
return total <= this._getDelta(visibleMessages, messages, hideAutomated);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute a mapping from label name to objects representing the minimum and
|
||||
@@ -389,6 +393,8 @@
|
||||
extremes[key] = {min: values[0], max: values[values.length - 1]};
|
||||
}
|
||||
return extremes;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrMessagesList.is, GrMessagesList);
|
||||
})();
|
||||
|
||||
@@ -17,9 +17,19 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-related-changes-list',
|
||||
|
||||
/**
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
* @appliesMixin Gerrit.PatchSetMixin
|
||||
* @appliesMixin Gerrit.RESTClientMixin
|
||||
*/
|
||||
class GrRelatedChangesList extends Polymer.mixinBehaviors( [
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.PatchSetBehavior,
|
||||
Gerrit.RESTClientBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-related-changes-list'; }
|
||||
/**
|
||||
* Fired when a new section is loaded so that the change view can determine
|
||||
* a show more button is needed, sometimes before all the sections finish
|
||||
@@ -28,64 +38,62 @@
|
||||
* @event new-section-loaded
|
||||
*/
|
||||
|
||||
properties: {
|
||||
change: Object,
|
||||
hasParent: {
|
||||
type: Boolean,
|
||||
notify: true,
|
||||
value: false,
|
||||
},
|
||||
patchNum: String,
|
||||
parentChange: Object,
|
||||
hidden: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
reflectToAttribute: true,
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
notify: true,
|
||||
},
|
||||
mergeable: Boolean,
|
||||
_connectedRevisions: {
|
||||
type: Array,
|
||||
computed: '_computeConnectedRevisions(change, patchNum, ' +
|
||||
static get properties() {
|
||||
return {
|
||||
change: Object,
|
||||
hasParent: {
|
||||
type: Boolean,
|
||||
notify: true,
|
||||
value: false,
|
||||
},
|
||||
patchNum: String,
|
||||
parentChange: Object,
|
||||
hidden: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
reflectToAttribute: true,
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
notify: true,
|
||||
},
|
||||
mergeable: Boolean,
|
||||
_connectedRevisions: {
|
||||
type: Array,
|
||||
computed: '_computeConnectedRevisions(change, patchNum, ' +
|
||||
'_relatedResponse.changes)',
|
||||
},
|
||||
/** @type {?} */
|
||||
_relatedResponse: {
|
||||
type: Object,
|
||||
value() { return {changes: []}; },
|
||||
},
|
||||
/** @type {?} */
|
||||
_submittedTogether: {
|
||||
type: Object,
|
||||
value() { return {changes: []}; },
|
||||
},
|
||||
_conflicts: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
_cherryPicks: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
_sameTopic: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
},
|
||||
},
|
||||
/** @type {?} */
|
||||
_relatedResponse: {
|
||||
type: Object,
|
||||
value() { return {changes: []}; },
|
||||
},
|
||||
/** @type {?} */
|
||||
_submittedTogether: {
|
||||
type: Object,
|
||||
value() { return {changes: []}; },
|
||||
},
|
||||
_conflicts: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
_cherryPicks: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
_sameTopic: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
behaviors: [
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.PatchSetBehavior,
|
||||
Gerrit.RESTClientBehavior,
|
||||
],
|
||||
|
||||
observers: [
|
||||
'_resultsChanged(_relatedResponse, _submittedTogether, ' +
|
||||
static get observers() {
|
||||
return [
|
||||
'_resultsChanged(_relatedResponse, _submittedTogether, ' +
|
||||
'_conflicts, _cherryPicks, _sameTopic)',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.loading = true;
|
||||
@@ -96,7 +104,7 @@
|
||||
this._conflicts = [];
|
||||
this._cherryPicks = [];
|
||||
this._sameTopic = [];
|
||||
},
|
||||
}
|
||||
|
||||
reload() {
|
||||
if (!this.change || !this.patchNum) {
|
||||
@@ -144,7 +152,7 @@
|
||||
return Promise.all(promises).then(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_fireReloadEvent() {
|
||||
// The listener on the change computes height of the related changes
|
||||
@@ -152,7 +160,7 @@
|
||||
// that requires a flush.
|
||||
Polymer.dom.flush();
|
||||
this.dispatchEvent(new CustomEvent('new-section-loaded'));
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not the given change has a parent change. If there
|
||||
@@ -166,34 +174,34 @@
|
||||
return relatedChanges.length > 0 &&
|
||||
relatedChanges[relatedChanges.length - 1].change_id !==
|
||||
currentChangeId;
|
||||
},
|
||||
}
|
||||
|
||||
_getRelatedChanges() {
|
||||
return this.$.restAPI.getRelatedChanges(this.change._number,
|
||||
this.patchNum);
|
||||
},
|
||||
}
|
||||
|
||||
_getSubmittedTogether() {
|
||||
return this.$.restAPI.getChangesSubmittedTogether(this.change._number);
|
||||
},
|
||||
}
|
||||
|
||||
_getServerConfig() {
|
||||
return this.$.restAPI.getConfig();
|
||||
},
|
||||
}
|
||||
|
||||
_getConflicts() {
|
||||
return this.$.restAPI.getChangeConflicts(this.change._number);
|
||||
},
|
||||
}
|
||||
|
||||
_getCherryPicks() {
|
||||
return this.$.restAPI.getChangeCherryPicks(this.change.project,
|
||||
this.change.change_id, this.change._number);
|
||||
},
|
||||
}
|
||||
|
||||
_getChangesWithSameTopic() {
|
||||
return this.$.restAPI.getChangesWithSameTopic(this.change.topic,
|
||||
this.change._number);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} changeNum
|
||||
@@ -203,7 +211,7 @@
|
||||
*/
|
||||
_computeChangeURL(changeNum, project, opt_patchNum) {
|
||||
return Gerrit.Nav.getUrlForChangeById(changeNum, project, opt_patchNum);
|
||||
},
|
||||
}
|
||||
|
||||
_computeChangeContainerClass(currentChange, relatedChange) {
|
||||
const classes = ['changeContainer'];
|
||||
@@ -214,7 +222,7 @@
|
||||
classes.push('thisChange');
|
||||
}
|
||||
return classes.join(' ');
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the given objects describe the same change? Compares the changes by
|
||||
@@ -229,7 +237,7 @@
|
||||
const aNum = this._getChangeNumber(a);
|
||||
const bNum = this._getChangeNumber(b);
|
||||
return aNum === bNum;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the change number from either a ChangeInfo (such as those included in
|
||||
@@ -251,7 +259,7 @@
|
||||
return change._change_number;
|
||||
}
|
||||
return change._number;
|
||||
},
|
||||
}
|
||||
|
||||
_computeLinkClass(change) {
|
||||
const statuses = [];
|
||||
@@ -262,7 +270,7 @@
|
||||
statuses.push('submittable');
|
||||
}
|
||||
return statuses.join(' ');
|
||||
},
|
||||
}
|
||||
|
||||
_computeChangeStatusClass(change) {
|
||||
const classes = ['status'];
|
||||
@@ -276,7 +284,7 @@
|
||||
classes.push('hidden');
|
||||
}
|
||||
return classes.join(' ');
|
||||
},
|
||||
}
|
||||
|
||||
_computeChangeStatus(change) {
|
||||
switch (change.status) {
|
||||
@@ -293,7 +301,7 @@
|
||||
return 'Submittable';
|
||||
}
|
||||
return '';
|
||||
},
|
||||
}
|
||||
|
||||
_resultsChanged(related, submittedTogether, conflicts,
|
||||
cherryPicks, sameTopic) {
|
||||
@@ -323,11 +331,11 @@
|
||||
}
|
||||
}
|
||||
this.hidden = true;
|
||||
},
|
||||
}
|
||||
|
||||
_isIndirectAncestor(change) {
|
||||
return !this._connectedRevisions.includes(change.commit.commit);
|
||||
},
|
||||
}
|
||||
|
||||
_computeConnectedRevisions(change, patchNum, relatedChanges) {
|
||||
// Polymer 2: check for undefined
|
||||
@@ -364,7 +372,7 @@
|
||||
--pos;
|
||||
}
|
||||
return connected;
|
||||
},
|
||||
}
|
||||
|
||||
_computeSubmittedTogetherClass(submittedTogether) {
|
||||
if (!submittedTogether || (
|
||||
@@ -373,11 +381,13 @@
|
||||
return 'hidden';
|
||||
}
|
||||
return '';
|
||||
},
|
||||
}
|
||||
|
||||
_computeNonVisibleChangesNote(n) {
|
||||
const noun = n === 1 ? 'change' : 'changes';
|
||||
return `(+ ${n} non-visible ${noun})`;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrRelatedChangesList.is, GrRelatedChangesList);
|
||||
})();
|
||||
|
||||
@@ -52,9 +52,23 @@
|
||||
|
||||
const SEND_REPLY_TIMING_LABEL = 'SendReply';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-reply-dialog',
|
||||
|
||||
/**
|
||||
* @appliesMixin Gerrit.BaseUrlMixin
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
* @appliesMixin Gerrit.KeyboardShortcutMixin
|
||||
* @appliesMixin Gerrit.PatchSetMixin
|
||||
* @appliesMixin Gerrit.RESTClientMixin
|
||||
*/
|
||||
class GrReplyDialog extends Polymer.mixinBehaviors( [
|
||||
Gerrit.BaseUrlBehavior,
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.KeyboardShortcutBehavior,
|
||||
Gerrit.PatchSetBehavior,
|
||||
Gerrit.RESTClientBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-reply-dialog'; }
|
||||
/**
|
||||
* Fired when a reply is successfully sent.
|
||||
*
|
||||
@@ -93,156 +107,159 @@
|
||||
* @event send-disabled-changed
|
||||
*/
|
||||
|
||||
properties: {
|
||||
constructor() {
|
||||
super();
|
||||
this.FocusTarget = FocusTarget;
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
/**
|
||||
* @type {{ _number: number, removable_reviewers: Array }}
|
||||
*/
|
||||
change: Object,
|
||||
patchNum: String,
|
||||
canBeStarted: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
reflectToAttribute: true,
|
||||
},
|
||||
draft: {
|
||||
type: String,
|
||||
value: '',
|
||||
observer: '_draftChanged',
|
||||
},
|
||||
quote: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
diffDrafts: {
|
||||
type: Object,
|
||||
observer: '_handleHeightChanged',
|
||||
},
|
||||
/** @type {!Function} */
|
||||
filterReviewerSuggestion: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._filterReviewerSuggestionGenerator(false);
|
||||
change: Object,
|
||||
patchNum: String,
|
||||
canBeStarted: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
},
|
||||
/** @type {!Function} */
|
||||
filterCCSuggestion: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._filterReviewerSuggestionGenerator(true);
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
reflectToAttribute: true,
|
||||
},
|
||||
},
|
||||
permittedLabels: Object,
|
||||
/**
|
||||
draft: {
|
||||
type: String,
|
||||
value: '',
|
||||
observer: '_draftChanged',
|
||||
},
|
||||
quote: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
diffDrafts: {
|
||||
type: Object,
|
||||
observer: '_handleHeightChanged',
|
||||
},
|
||||
/** @type {!Function} */
|
||||
filterReviewerSuggestion: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._filterReviewerSuggestionGenerator(false);
|
||||
},
|
||||
},
|
||||
/** @type {!Function} */
|
||||
filterCCSuggestion: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._filterReviewerSuggestionGenerator(true);
|
||||
},
|
||||
},
|
||||
permittedLabels: Object,
|
||||
/**
|
||||
* @type {{ commentlinks: Array }}
|
||||
*/
|
||||
projectConfig: Object,
|
||||
knownLatestState: String,
|
||||
underReview: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
|
||||
_account: Object,
|
||||
_ccs: Array,
|
||||
/** @type {?Object} */
|
||||
_ccPendingConfirmation: {
|
||||
type: Object,
|
||||
observer: '_reviewerPendingConfirmationUpdated',
|
||||
},
|
||||
_messagePlaceholder: {
|
||||
type: String,
|
||||
computed: '_computeMessagePlaceholder(canBeStarted)',
|
||||
},
|
||||
_owner: Object,
|
||||
/** @type {?} */
|
||||
_pendingConfirmationDetails: Object,
|
||||
_includeComments: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
_reviewers: Array,
|
||||
/** @type {?Object} */
|
||||
_reviewerPendingConfirmation: {
|
||||
type: Object,
|
||||
observer: '_reviewerPendingConfirmationUpdated',
|
||||
},
|
||||
_previewFormatting: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
observer: '_handleHeightChanged',
|
||||
},
|
||||
_reviewersPendingRemove: {
|
||||
type: Object,
|
||||
value: {
|
||||
CC: [],
|
||||
REVIEWER: [],
|
||||
projectConfig: Object,
|
||||
knownLatestState: String,
|
||||
underReview: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
},
|
||||
_sendButtonLabel: {
|
||||
type: String,
|
||||
computed: '_computeSendButtonLabel(canBeStarted)',
|
||||
},
|
||||
_savingComments: Boolean,
|
||||
_reviewersMutated: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_labelsChanged: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_saveTooltip: {
|
||||
type: String,
|
||||
value: ButtonTooltips.SAVE,
|
||||
readOnly: true,
|
||||
},
|
||||
_pluginMessage: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
_sendDisabled: {
|
||||
type: Boolean,
|
||||
computed: '_computeSendButtonDisabled(_sendButtonLabel, ' +
|
||||
|
||||
_account: Object,
|
||||
_ccs: Array,
|
||||
/** @type {?Object} */
|
||||
_ccPendingConfirmation: {
|
||||
type: Object,
|
||||
observer: '_reviewerPendingConfirmationUpdated',
|
||||
},
|
||||
_messagePlaceholder: {
|
||||
type: String,
|
||||
computed: '_computeMessagePlaceholder(canBeStarted)',
|
||||
},
|
||||
_owner: Object,
|
||||
/** @type {?} */
|
||||
_pendingConfirmationDetails: Object,
|
||||
_includeComments: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
_reviewers: Array,
|
||||
/** @type {?Object} */
|
||||
_reviewerPendingConfirmation: {
|
||||
type: Object,
|
||||
observer: '_reviewerPendingConfirmationUpdated',
|
||||
},
|
||||
_previewFormatting: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
observer: '_handleHeightChanged',
|
||||
},
|
||||
_reviewersPendingRemove: {
|
||||
type: Object,
|
||||
value: {
|
||||
CC: [],
|
||||
REVIEWER: [],
|
||||
},
|
||||
},
|
||||
_sendButtonLabel: {
|
||||
type: String,
|
||||
computed: '_computeSendButtonLabel(canBeStarted)',
|
||||
},
|
||||
_savingComments: Boolean,
|
||||
_reviewersMutated: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_labelsChanged: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_saveTooltip: {
|
||||
type: String,
|
||||
value: ButtonTooltips.SAVE,
|
||||
readOnly: true,
|
||||
},
|
||||
_pluginMessage: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
_sendDisabled: {
|
||||
type: Boolean,
|
||||
computed: '_computeSendButtonDisabled(_sendButtonLabel, ' +
|
||||
'diffDrafts, draft, _reviewersMutated, _labelsChanged, ' +
|
||||
'_includeComments, disabled)',
|
||||
observer: '_sendDisabledChanged',
|
||||
},
|
||||
},
|
||||
observer: '_sendDisabledChanged',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
FocusTarget,
|
||||
get keyBindings() {
|
||||
return {
|
||||
'esc': '_handleEscKey',
|
||||
'ctrl+enter meta+enter': '_handleEnterKey',
|
||||
};
|
||||
}
|
||||
|
||||
behaviors: [
|
||||
Gerrit.BaseUrlBehavior,
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.KeyboardShortcutBehavior,
|
||||
Gerrit.PatchSetBehavior,
|
||||
Gerrit.RESTClientBehavior,
|
||||
],
|
||||
|
||||
keyBindings: {
|
||||
'esc': '_handleEscKey',
|
||||
'ctrl+enter meta+enter': '_handleEnterKey',
|
||||
},
|
||||
|
||||
observers: [
|
||||
'_changeUpdated(change.reviewers.*, change.owner)',
|
||||
'_ccsChanged(_ccs.splices)',
|
||||
'_reviewersChanged(_reviewers.splices)',
|
||||
],
|
||||
static get observers() {
|
||||
return [
|
||||
'_changeUpdated(change.reviewers.*, change.owner)',
|
||||
'_ccsChanged(_ccs.splices)',
|
||||
'_reviewersChanged(_reviewers.splices)',
|
||||
];
|
||||
}
|
||||
|
||||
attached() {
|
||||
super.attached();
|
||||
this._getAccount().then(account => {
|
||||
this._account = account || {};
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
ready() {
|
||||
super.ready();
|
||||
this.$.jsAPI.addElement(this.$.jsAPI.Element.REPLY_DIALOG, this);
|
||||
},
|
||||
}
|
||||
|
||||
open(opt_focusTarget) {
|
||||
this.knownLatestState = LatestPatchState.CHECKING;
|
||||
@@ -268,11 +285,11 @@
|
||||
this._savingComments = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
focus() {
|
||||
this._focusOn(FocusTarget.ANY);
|
||||
},
|
||||
}
|
||||
|
||||
getFocusStops() {
|
||||
const end = this._sendDisabled ? this.$.cancelButton : this.$.sendButton;
|
||||
@@ -280,14 +297,14 @@
|
||||
start: this.$.reviewers.focusStart,
|
||||
end,
|
||||
};
|
||||
},
|
||||
}
|
||||
|
||||
setLabelValue(label, value) {
|
||||
const selectorEl =
|
||||
this.$.labelScores.$$(`gr-label-score-row[name="${label}"]`);
|
||||
if (!selectorEl) { return; }
|
||||
selectorEl.setSelectedValue(value);
|
||||
},
|
||||
}
|
||||
|
||||
getLabelValue(label) {
|
||||
const selectorEl =
|
||||
@@ -295,23 +312,23 @@
|
||||
if (!selectorEl) { return null; }
|
||||
|
||||
return selectorEl.selectedValue;
|
||||
},
|
||||
}
|
||||
|
||||
_handleEscKey(e) {
|
||||
this.cancel();
|
||||
},
|
||||
}
|
||||
|
||||
_handleEnterKey(e) {
|
||||
this._submit();
|
||||
},
|
||||
}
|
||||
|
||||
_ccsChanged(splices) {
|
||||
this._reviewerTypeChanged(splices, ReviewerTypes.CC);
|
||||
},
|
||||
}
|
||||
|
||||
_reviewersChanged(splices) {
|
||||
this._reviewerTypeChanged(splices, ReviewerTypes.REVIEWER);
|
||||
},
|
||||
}
|
||||
|
||||
_reviewerTypeChanged(splices, reviewerType) {
|
||||
if (splices && splices.indexSplices) {
|
||||
@@ -342,7 +359,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_processReviewerChange(indexSplices, type) {
|
||||
for (const splice of indexSplices) {
|
||||
@@ -354,7 +371,7 @@
|
||||
this._reviewersPendingRemove[type].push(account);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the state of the _reviewersPendingRemove object, and removes
|
||||
@@ -380,7 +397,7 @@
|
||||
this._reviewersPendingRemove[type] = [];
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an account from the change, both on the backend and the client.
|
||||
@@ -404,7 +421,7 @@
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_mapReviewer(reviewer) {
|
||||
let reviewerId;
|
||||
@@ -416,7 +433,7 @@
|
||||
confirmed = reviewer.group.confirmed;
|
||||
}
|
||||
return {reviewer: reviewerId, confirmed};
|
||||
},
|
||||
}
|
||||
|
||||
send(includeComments, startReview) {
|
||||
this.$.reporting.time(SEND_REPLY_TIMING_LABEL);
|
||||
@@ -479,7 +496,7 @@
|
||||
this.disabled = false;
|
||||
throw err;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_focusOn(section) {
|
||||
// Safeguard- always want to focus on something.
|
||||
@@ -497,7 +514,7 @@
|
||||
const ccEntry = this.$.ccs.focusStart;
|
||||
ccEntry.async(ccEntry.focus);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_chooseFocusTarget() {
|
||||
// If we are the owner and the reviewers field is empty, focus on that.
|
||||
@@ -509,7 +526,7 @@
|
||||
|
||||
// Default to BODY.
|
||||
return FocusTarget.BODY;
|
||||
},
|
||||
}
|
||||
|
||||
_handle400Error(response) {
|
||||
// A call to _saveReview could fail with a server error if erroneous
|
||||
@@ -551,11 +568,11 @@
|
||||
this.fire('server-error', {response});
|
||||
return null; // Means that the error has been handled.
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_computeHideDraftList(drafts) {
|
||||
return Object.keys(drafts || {}).length == 0;
|
||||
},
|
||||
}
|
||||
|
||||
_computeDraftsTitle(drafts) {
|
||||
let total = 0;
|
||||
@@ -567,13 +584,13 @@
|
||||
if (total == 0) { return ''; }
|
||||
if (total == 1) { return '1 Draft'; }
|
||||
if (total > 1) { return total + ' Drafts'; }
|
||||
},
|
||||
}
|
||||
|
||||
_computeMessagePlaceholder(canBeStarted) {
|
||||
return canBeStarted ?
|
||||
'Add a note for your reviewers...' :
|
||||
'Say something nice...';
|
||||
},
|
||||
}
|
||||
|
||||
_changeUpdated(changeRecord, owner) {
|
||||
// Polymer 2: check for undefined
|
||||
@@ -582,7 +599,7 @@
|
||||
}
|
||||
|
||||
this._rebuildReviewerArrays(changeRecord.base, owner);
|
||||
},
|
||||
}
|
||||
|
||||
_rebuildReviewerArrays(change, owner) {
|
||||
this._owner = owner;
|
||||
@@ -614,11 +631,11 @@
|
||||
|
||||
this._ccs = ccs;
|
||||
this._reviewers = reviewers;
|
||||
},
|
||||
}
|
||||
|
||||
_accountOrGroupKey(entry) {
|
||||
return entry.id || entry._account_id;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a function to filter out reviewer/CC entries. When isCCs is
|
||||
@@ -650,23 +667,23 @@
|
||||
}
|
||||
return this._reviewers.find(finder) === undefined;
|
||||
};
|
||||
},
|
||||
}
|
||||
|
||||
_getAccount() {
|
||||
return this.$.restAPI.getAccount();
|
||||
},
|
||||
}
|
||||
|
||||
_cancelTapHandler(e) {
|
||||
e.preventDefault();
|
||||
this.cancel();
|
||||
},
|
||||
}
|
||||
|
||||
cancel() {
|
||||
this.fire('cancel', null, {bubbles: false});
|
||||
this.$.textarea.closeDropdown();
|
||||
this._purgeReviewersPendingRemove(true);
|
||||
this._rebuildReviewerArrays(this.change.reviewers, this._owner);
|
||||
},
|
||||
}
|
||||
|
||||
_saveTapHandler(e) {
|
||||
e.preventDefault();
|
||||
@@ -678,12 +695,12 @@
|
||||
this.send(this._includeComments, false).then(keepReviewers => {
|
||||
this._purgeReviewersPendingRemove(false, keepReviewers);
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_sendTapHandler(e) {
|
||||
e.preventDefault();
|
||||
this._submit();
|
||||
},
|
||||
}
|
||||
|
||||
_submit() {
|
||||
if (!this.$.ccs.submitEntryText()) {
|
||||
@@ -710,12 +727,12 @@
|
||||
detail: {message: `Error submitting review ${err}`},
|
||||
}));
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_saveReview(review, opt_errFn) {
|
||||
return this.$.restAPI.saveChangeReview(this.change._number, this.patchNum,
|
||||
review, opt_errFn);
|
||||
},
|
||||
}
|
||||
|
||||
_reviewerPendingConfirmationUpdated(reviewer) {
|
||||
if (reviewer === null) {
|
||||
@@ -725,7 +742,7 @@
|
||||
this._ccPendingConfirmation || this._reviewerPendingConfirmation;
|
||||
this.$.reviewerConfirmationOverlay.open();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_confirmPendingReviewer() {
|
||||
if (this._ccPendingConfirmation) {
|
||||
@@ -735,7 +752,7 @@
|
||||
this.$.reviewers.confirmGroup(this._reviewerPendingConfirmation.group);
|
||||
this._focusOn(FocusTarget.REVIEWERS);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_cancelPendingReviewer() {
|
||||
this._ccPendingConfirmation = null;
|
||||
@@ -744,7 +761,7 @@
|
||||
const target =
|
||||
this._ccPendingConfirmation ? FocusTarget.CCS : FocusTarget.REVIEWERS;
|
||||
this._focusOn(target);
|
||||
},
|
||||
}
|
||||
|
||||
_getStorageLocation() {
|
||||
// Tests trigger this method without setting change.
|
||||
@@ -754,12 +771,12 @@
|
||||
patchNum: '@change',
|
||||
path: '@change',
|
||||
};
|
||||
},
|
||||
}
|
||||
|
||||
_loadStoredDraft() {
|
||||
const draft = this.$.storage.getDraftComment(this._getStorageLocation());
|
||||
return draft ? draft.message : '';
|
||||
},
|
||||
}
|
||||
|
||||
_handleAccountTextEntry() {
|
||||
// When either of the account entries has input added to the autocomplete,
|
||||
@@ -767,7 +784,7 @@
|
||||
//
|
||||
// Note: if the text is removed, the save button will not get disabled.
|
||||
this._reviewersMutated = true;
|
||||
},
|
||||
}
|
||||
|
||||
_draftChanged(newDraft, oldDraft) {
|
||||
this.debounce('store', () => {
|
||||
@@ -780,37 +797,37 @@
|
||||
this.draft);
|
||||
}
|
||||
}, STORAGE_DEBOUNCE_INTERVAL_MS);
|
||||
},
|
||||
}
|
||||
|
||||
_handleHeightChanged(e) {
|
||||
this.fire('autogrow');
|
||||
},
|
||||
}
|
||||
|
||||
_handleLabelsChanged() {
|
||||
this._labelsChanged = Object.keys(
|
||||
this.$.labelScores.getLabelValues()).length !== 0;
|
||||
},
|
||||
}
|
||||
|
||||
_isState(knownLatestState, value) {
|
||||
return knownLatestState === value;
|
||||
},
|
||||
}
|
||||
|
||||
_reload() {
|
||||
// Load the current change without any patch range.
|
||||
location.href = this.getBaseUrl() + '/c/' + this.change._number;
|
||||
},
|
||||
}
|
||||
|
||||
_computeSendButtonLabel(canBeStarted) {
|
||||
return canBeStarted ? ButtonLabels.START_REVIEW : ButtonLabels.SEND;
|
||||
},
|
||||
}
|
||||
|
||||
_computeSendButtonTooltip(canBeStarted) {
|
||||
return canBeStarted ? ButtonTooltips.START_REVIEW : ButtonTooltips.SEND;
|
||||
},
|
||||
}
|
||||
|
||||
_computeSavingLabelClass(savingComments) {
|
||||
return savingComments ? 'saving' : '';
|
||||
},
|
||||
}
|
||||
|
||||
_computeSendButtonDisabled(buttonLabel, drafts, text, reviewersMutated,
|
||||
labelsChanged, includeComments, disabled) {
|
||||
@@ -831,7 +848,7 @@
|
||||
if (buttonLabel === ButtonLabels.START_REVIEW) { return false; }
|
||||
const hasDrafts = includeComments && Object.keys(drafts).length;
|
||||
return !hasDrafts && !text.length && !reviewersMutated && !labelsChanged;
|
||||
},
|
||||
}
|
||||
|
||||
_computePatchSetWarning(patchNum, labelsChanged) {
|
||||
let str = `Patch ${patchNum} is not latest.`;
|
||||
@@ -839,28 +856,30 @@
|
||||
str += ' Voting on a non-latest patch will have no effect.';
|
||||
}
|
||||
return str;
|
||||
},
|
||||
}
|
||||
|
||||
setPluginMessage(message) {
|
||||
this._pluginMessage = message;
|
||||
},
|
||||
}
|
||||
|
||||
_sendDisabledChanged(sendDisabled) {
|
||||
this.dispatchEvent(new CustomEvent('send-disabled-changed'));
|
||||
},
|
||||
}
|
||||
|
||||
_getReviewerSuggestionsProvider(change) {
|
||||
const provider = GrReviewerSuggestionsProvider.create(this.$.restAPI,
|
||||
change._number, Gerrit.SUGGESTIONS_PROVIDERS_USERS_TYPES.REVIEWER);
|
||||
provider.init();
|
||||
return provider;
|
||||
},
|
||||
}
|
||||
|
||||
_getCcSuggestionsProvider(change) {
|
||||
const provider = GrReviewerSuggestionsProvider.create(this.$.restAPI,
|
||||
change._number, Gerrit.SUGGESTIONS_PROVIDERS_USERS_TYPES.CC);
|
||||
provider.init();
|
||||
return provider;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrReplyDialog.is, GrReplyDialog);
|
||||
})();
|
||||
|
||||
@@ -17,69 +17,75 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-reviewer-list',
|
||||
|
||||
/**
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
*/
|
||||
class GrReviewerList extends Polymer.mixinBehaviors( [
|
||||
Gerrit.FireBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-reviewer-list'; }
|
||||
/**
|
||||
* Fired when the "Add reviewer..." button is tapped.
|
||||
*
|
||||
* @event show-reply-dialog
|
||||
*/
|
||||
|
||||
properties: {
|
||||
change: Object,
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
reflectToAttribute: true,
|
||||
},
|
||||
mutable: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
reviewersOnly: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
ccsOnly: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
maxReviewersDisplayed: Number,
|
||||
static get properties() {
|
||||
return {
|
||||
change: Object,
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
reflectToAttribute: true,
|
||||
},
|
||||
mutable: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
reviewersOnly: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
ccsOnly: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
maxReviewersDisplayed: Number,
|
||||
|
||||
_displayedReviewers: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
_reviewers: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
_showInput: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_addLabel: {
|
||||
type: String,
|
||||
computed: '_computeAddLabel(ccsOnly)',
|
||||
},
|
||||
_hiddenReviewerCount: {
|
||||
type: Number,
|
||||
computed: '_computeHiddenCount(_reviewers, _displayedReviewers)',
|
||||
},
|
||||
_displayedReviewers: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
_reviewers: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
_showInput: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_addLabel: {
|
||||
type: String,
|
||||
computed: '_computeAddLabel(ccsOnly)',
|
||||
},
|
||||
_hiddenReviewerCount: {
|
||||
type: Number,
|
||||
computed: '_computeHiddenCount(_reviewers, _displayedReviewers)',
|
||||
},
|
||||
|
||||
// Used for testing.
|
||||
_lastAutocompleteRequest: Object,
|
||||
_xhrPromise: Object,
|
||||
},
|
||||
// Used for testing.
|
||||
_lastAutocompleteRequest: Object,
|
||||
_xhrPromise: Object,
|
||||
};
|
||||
}
|
||||
|
||||
behaviors: [
|
||||
Gerrit.FireBehavior,
|
||||
],
|
||||
|
||||
observers: [
|
||||
'_reviewersChanged(change.reviewers.*, change.owner)',
|
||||
],
|
||||
static get observers() {
|
||||
return [
|
||||
'_reviewersChanged(change.reviewers.*, change.owner)',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts change.permitted_labels to an array of hashes of label keys to
|
||||
@@ -100,7 +106,7 @@
|
||||
label,
|
||||
scores: labels[label].map(v => parseInt(v, 10)),
|
||||
}));
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns hash of labels to max permitted score.
|
||||
@@ -114,7 +120,7 @@
|
||||
.map(v => parseInt(v, 10))
|
||||
.reduce((a, b) => Math.max(a, b))}))
|
||||
.reduce((acc, i) => Object.assign(acc, i), {});
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns max permitted score for reviewer.
|
||||
@@ -139,7 +145,7 @@
|
||||
return 0;
|
||||
}
|
||||
return NaN;
|
||||
},
|
||||
}
|
||||
|
||||
_computeReviewerTooltip(reviewer, change) {
|
||||
if (!change || !change.labels) { return ''; }
|
||||
@@ -160,7 +166,7 @@
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_reviewersChanged(changeRecord, owner) {
|
||||
// Polymer 2: check for undefined
|
||||
@@ -194,7 +200,7 @@
|
||||
} else {
|
||||
this._displayedReviewers = this._reviewers;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_computeHiddenCount(reviewers, displayedReviewers) {
|
||||
// Polymer 2: check for undefined
|
||||
@@ -203,7 +209,7 @@
|
||||
}
|
||||
|
||||
return reviewers.length - displayedReviewers.length;
|
||||
},
|
||||
}
|
||||
|
||||
_computeCanRemoveReviewer(reviewer, mutable) {
|
||||
if (!mutable) { return false; }
|
||||
@@ -217,7 +223,7 @@
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
}
|
||||
|
||||
_handleRemove(e) {
|
||||
e.preventDefault();
|
||||
@@ -245,7 +251,7 @@
|
||||
this.disabled = false;
|
||||
throw err;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleAddTap(e) {
|
||||
e.preventDefault();
|
||||
@@ -257,18 +263,20 @@
|
||||
value.ccsOnly = true;
|
||||
}
|
||||
this.fire('show-reply-dialog', {value});
|
||||
},
|
||||
}
|
||||
|
||||
_handleViewAll(e) {
|
||||
this._displayedReviewers = this._reviewers;
|
||||
},
|
||||
}
|
||||
|
||||
_removeReviewer(id) {
|
||||
return this.$.restAPI.removeChangeReviewer(this.change._number, id);
|
||||
},
|
||||
}
|
||||
|
||||
_computeAddLabel(ccsOnly) {
|
||||
return ccsOnly ? 'Add CC' : 'Add reviewer';
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrReviewerList.is, GrReviewerList);
|
||||
})();
|
||||
|
||||
@@ -22,39 +22,42 @@
|
||||
*
|
||||
* @event thread-list-modified
|
||||
*/
|
||||
class GrThreadList extends Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element)) {
|
||||
static get is() { return 'gr-thread-list'; }
|
||||
|
||||
Polymer({
|
||||
is: 'gr-thread-list',
|
||||
|
||||
properties: {
|
||||
static get properties() {
|
||||
return {
|
||||
/** @type {?} */
|
||||
change: Object,
|
||||
threads: Array,
|
||||
changeNum: String,
|
||||
loggedIn: Boolean,
|
||||
_sortedThreads: {
|
||||
type: Array,
|
||||
},
|
||||
_filteredThreads: {
|
||||
type: Array,
|
||||
computed: '_computeFilteredThreads(_sortedThreads, ' +
|
||||
change: Object,
|
||||
threads: Array,
|
||||
changeNum: String,
|
||||
loggedIn: Boolean,
|
||||
_sortedThreads: {
|
||||
type: Array,
|
||||
},
|
||||
_filteredThreads: {
|
||||
type: Array,
|
||||
computed: '_computeFilteredThreads(_sortedThreads, ' +
|
||||
'_unresolvedOnly, _draftsOnly)',
|
||||
},
|
||||
_unresolvedOnly: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_draftsOnly: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
_unresolvedOnly: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_draftsOnly: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
observers: ['_computeSortedThreads(threads.*)'],
|
||||
static get observers() { return ['_computeSortedThreads(threads.*)']; }
|
||||
|
||||
_computeShowDraftToggle(loggedIn) {
|
||||
return loggedIn ? 'show' : '';
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Order as follows:
|
||||
@@ -68,7 +71,7 @@
|
||||
const threads = changeRecord.base;
|
||||
if (!threads) { return []; }
|
||||
this._updateSortedThreads(threads);
|
||||
},
|
||||
}
|
||||
|
||||
_updateSortedThreads(threads) {
|
||||
this._sortedThreads =
|
||||
@@ -90,7 +93,7 @@
|
||||
}
|
||||
return dateCompare ? dateCompare : c1.id.localeCompare(c2.id);
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_computeFilteredThreads(sortedThreads, unresolvedOnly, draftsOnly) {
|
||||
// Polymer 2: check for undefined
|
||||
@@ -125,7 +128,7 @@
|
||||
return c;
|
||||
}
|
||||
}).map(threadInfo => threadInfo.thread);
|
||||
},
|
||||
}
|
||||
|
||||
_getThreadWithSortInfo(thread) {
|
||||
const lastComment = thread.comments[thread.comments.length - 1] || {};
|
||||
@@ -143,7 +146,7 @@
|
||||
hasDraft: !!lastComment.__draft,
|
||||
updated: lastComment.updated,
|
||||
};
|
||||
},
|
||||
}
|
||||
|
||||
removeThread(rootId) {
|
||||
for (let i = 0; i < this.threads.length; i++) {
|
||||
@@ -154,11 +157,11 @@
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_handleThreadDiscard(e) {
|
||||
this.removeThread(e.detail.rootId);
|
||||
},
|
||||
}
|
||||
|
||||
_handleCommentsChanged(e) {
|
||||
// Reset threads so thread computations occur on deep array changes to
|
||||
@@ -167,10 +170,12 @@
|
||||
|
||||
this.dispatchEvent(new CustomEvent('thread-list-modified',
|
||||
{detail: {rootId: e.detail.rootId, path: e.detail.path}}));
|
||||
},
|
||||
}
|
||||
|
||||
_isOnParent(side) {
|
||||
return !!side;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrThreadList.is, GrThreadList);
|
||||
})();
|
||||
|
||||
@@ -27,41 +27,46 @@
|
||||
'pull',
|
||||
];
|
||||
|
||||
Polymer({
|
||||
is: 'gr-upload-help-dialog',
|
||||
|
||||
/**
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
*/
|
||||
class GrUploadHelpDialog extends Polymer.mixinBehaviors( [
|
||||
Gerrit.FireBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-upload-help-dialog'; }
|
||||
/**
|
||||
* Fired when the user presses the close button.
|
||||
*
|
||||
* @event close
|
||||
*/
|
||||
|
||||
properties: {
|
||||
revision: Object,
|
||||
targetBranch: String,
|
||||
_commitCommand: {
|
||||
type: String,
|
||||
value: COMMIT_COMMAND,
|
||||
readOnly: true,
|
||||
},
|
||||
_fetchCommand: {
|
||||
type: String,
|
||||
computed: '_computeFetchCommand(revision, ' +
|
||||
static get properties() {
|
||||
return {
|
||||
revision: Object,
|
||||
targetBranch: String,
|
||||
_commitCommand: {
|
||||
type: String,
|
||||
value: COMMIT_COMMAND,
|
||||
readOnly: true,
|
||||
},
|
||||
_fetchCommand: {
|
||||
type: String,
|
||||
computed: '_computeFetchCommand(revision, ' +
|
||||
'_preferredDownloadCommand, _preferredDownloadScheme)',
|
||||
},
|
||||
_preferredDownloadCommand: String,
|
||||
_preferredDownloadScheme: String,
|
||||
_pushCommand: {
|
||||
type: String,
|
||||
computed: '_computePushCommand(targetBranch)',
|
||||
},
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
Gerrit.FireBehavior,
|
||||
],
|
||||
},
|
||||
_preferredDownloadCommand: String,
|
||||
_preferredDownloadScheme: String,
|
||||
_pushCommand: {
|
||||
type: String,
|
||||
computed: '_computePushCommand(targetBranch)',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
attached() {
|
||||
super.attached();
|
||||
this.$.restAPI.getLoggedIn().then(loggedIn => {
|
||||
if (loggedIn) {
|
||||
return this.$.restAPI.getPreferences();
|
||||
@@ -72,13 +77,13 @@
|
||||
this._preferredDownloadScheme = prefs.download_scheme;
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleCloseTap(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.fire('close', null, {bubbles: false});
|
||||
},
|
||||
}
|
||||
|
||||
_computeFetchCommand(revision, preferredDownloadCommand,
|
||||
preferredDownloadScheme) {
|
||||
@@ -126,10 +131,12 @@
|
||||
}
|
||||
|
||||
return undefined;
|
||||
},
|
||||
}
|
||||
|
||||
_computePushCommand(targetBranch) {
|
||||
return PUSH_COMMAND_PREFIX + targetBranch;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrUploadHelpDialog.is, GrUploadHelpDialog);
|
||||
})();
|
||||
|
||||
@@ -19,29 +19,39 @@
|
||||
|
||||
const INTERPOLATE_URL_PATTERN = /\$\{([\w]+)\}/g;
|
||||
|
||||
Polymer({
|
||||
is: 'gr-account-dropdown',
|
||||
/**
|
||||
* @appliesMixin Gerrit.DisplayNameMixin
|
||||
*/
|
||||
class GrAccountDropdown extends Polymer.mixinBehaviors( [
|
||||
Gerrit.DisplayNameBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-account-dropdown'; }
|
||||
|
||||
properties: {
|
||||
account: Object,
|
||||
config: Object,
|
||||
links: {
|
||||
type: Array,
|
||||
computed: '_getLinks(_switchAccountUrl, _path)',
|
||||
},
|
||||
topContent: {
|
||||
type: Array,
|
||||
computed: '_getTopContent(account)',
|
||||
},
|
||||
_path: {
|
||||
type: String,
|
||||
value: '/',
|
||||
},
|
||||
_hasAvatars: Boolean,
|
||||
_switchAccountUrl: String,
|
||||
},
|
||||
static get properties() {
|
||||
return {
|
||||
account: Object,
|
||||
config: Object,
|
||||
links: {
|
||||
type: Array,
|
||||
computed: '_getLinks(_switchAccountUrl, _path)',
|
||||
},
|
||||
topContent: {
|
||||
type: Array,
|
||||
computed: '_getTopContent(account)',
|
||||
},
|
||||
_path: {
|
||||
type: String,
|
||||
value: '/',
|
||||
},
|
||||
_hasAvatars: Boolean,
|
||||
_switchAccountUrl: String,
|
||||
};
|
||||
}
|
||||
|
||||
attached() {
|
||||
super.attached();
|
||||
this._handleLocationChange();
|
||||
this.listen(window, 'location-change', '_handleLocationChange');
|
||||
this.$.restAPI.getConfig().then(cfg => {
|
||||
@@ -54,15 +64,12 @@
|
||||
}
|
||||
this._hasAvatars = !!(cfg && cfg.plugin && cfg.plugin.has_avatars);
|
||||
});
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
Gerrit.DisplayNameBehavior,
|
||||
],
|
||||
}
|
||||
|
||||
detached() {
|
||||
super.detached();
|
||||
this.unlisten(window, 'location-change', '_handleLocationChange');
|
||||
},
|
||||
}
|
||||
|
||||
_getLinks(switchAccountUrl, path) {
|
||||
// Polymer 2: check for undefined
|
||||
@@ -78,30 +85,32 @@
|
||||
}
|
||||
links.push({name: 'Sign out', url: '/logout'});
|
||||
return links;
|
||||
},
|
||||
}
|
||||
|
||||
_getTopContent(account) {
|
||||
return [
|
||||
{text: this._accountName(account), bold: true},
|
||||
{text: account.email ? account.email : ''},
|
||||
];
|
||||
},
|
||||
}
|
||||
|
||||
_handleLocationChange() {
|
||||
this._path =
|
||||
window.location.pathname +
|
||||
window.location.search +
|
||||
window.location.hash;
|
||||
},
|
||||
}
|
||||
|
||||
_interpolateUrl(url, replacements) {
|
||||
return url.replace(INTERPOLATE_URL_PATTERN, (match, p1) => {
|
||||
return replacements[p1] || '';
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_accountName(account) {
|
||||
return this.getUserName(this.config, account, true);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrAccountDropdown.is, GrAccountDropdown);
|
||||
})();
|
||||
|
||||
@@ -17,21 +17,26 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-error-dialog',
|
||||
|
||||
class GrErrorDialog extends Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element)) {
|
||||
static get is() { return 'gr-error-dialog'; }
|
||||
/**
|
||||
* Fired when the dismiss button is pressed.
|
||||
*
|
||||
* @event dismiss
|
||||
*/
|
||||
|
||||
properties: {
|
||||
text: String,
|
||||
},
|
||||
static get properties() {
|
||||
return {
|
||||
text: String,
|
||||
};
|
||||
}
|
||||
|
||||
_handleConfirm() {
|
||||
this.dispatchEvent(new CustomEvent('dismiss'));
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrErrorDialog.is, GrErrorDialog);
|
||||
})();
|
||||
|
||||
@@ -25,40 +25,47 @@
|
||||
const TOO_MANY_FILES = 'too many files to find conflicts';
|
||||
const AUTHENTICATION_REQUIRED = 'Authentication required\n';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-error-manager',
|
||||
/**
|
||||
* @appliesMixin Gerrit.BaseUrlMixin
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
*/
|
||||
class GrErrorManager extends Polymer.mixinBehaviors( [
|
||||
Gerrit.BaseUrlBehavior,
|
||||
Gerrit.FireBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-error-manager'; }
|
||||
|
||||
behaviors: [
|
||||
Gerrit.BaseUrlBehavior,
|
||||
Gerrit.FireBehavior,
|
||||
],
|
||||
|
||||
properties: {
|
||||
static get properties() {
|
||||
return {
|
||||
/**
|
||||
* The ID of the account that was logged in when the app was launched. If
|
||||
* not set, then there was no account at launch.
|
||||
*/
|
||||
knownAccountId: Number,
|
||||
knownAccountId: Number,
|
||||
|
||||
/** @type {?Object} */
|
||||
_alertElement: Object,
|
||||
/** @type {?number} */
|
||||
_hideAlertHandle: Number,
|
||||
_refreshingCredentials: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
/** @type {?Object} */
|
||||
_alertElement: Object,
|
||||
/** @type {?number} */
|
||||
_hideAlertHandle: Number,
|
||||
_refreshingCredentials: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
/**
|
||||
/**
|
||||
* The time (in milliseconds) since the most recent credential check.
|
||||
*/
|
||||
_lastCredentialCheck: {
|
||||
type: Number,
|
||||
value() { return Date.now(); },
|
||||
},
|
||||
},
|
||||
_lastCredentialCheck: {
|
||||
type: Number,
|
||||
value() { return Date.now(); },
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
attached() {
|
||||
super.attached();
|
||||
this.listen(document, 'server-error', '_handleServerError');
|
||||
this.listen(document, 'network-error', '_handleNetworkError');
|
||||
this.listen(document, 'auth-error', '_handleAuthError');
|
||||
@@ -66,9 +73,10 @@
|
||||
this.listen(document, 'show-error', '_handleShowErrorDialog');
|
||||
this.listen(document, 'visibilitychange', '_handleVisibilityChange');
|
||||
this.listen(document, 'show-auth-required', '_handleAuthRequired');
|
||||
},
|
||||
}
|
||||
|
||||
detached() {
|
||||
super.detached();
|
||||
this._clearHideAlertHandle();
|
||||
this.unlisten(document, 'server-error', '_handleServerError');
|
||||
this.unlisten(document, 'network-error', '_handleNetworkError');
|
||||
@@ -76,20 +84,20 @@
|
||||
this.unlisten(document, 'show-auth-required', '_handleAuthRequired');
|
||||
this.unlisten(document, 'visibilitychange', '_handleVisibilityChange');
|
||||
this.unlisten(document, 'show-error', '_handleShowErrorDialog');
|
||||
},
|
||||
}
|
||||
|
||||
_shouldSuppressError(msg) {
|
||||
return msg.includes(TOO_MANY_FILES);
|
||||
},
|
||||
}
|
||||
|
||||
_handleAuthRequired() {
|
||||
this._showAuthErrorAlert(
|
||||
'Log in is required to perform that action.', 'Log in.');
|
||||
},
|
||||
}
|
||||
|
||||
_handleAuthError() {
|
||||
this._showAuthErrorAlert('Auth error', 'Refresh credentials.');
|
||||
},
|
||||
}
|
||||
|
||||
_handleServerError(e) {
|
||||
const {request, response} = e.detail;
|
||||
@@ -113,7 +121,7 @@
|
||||
}
|
||||
console.error(errorText);
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_constructServerErrorMsg({errorText, status, statusText, url}) {
|
||||
let err = `Error ${status}`;
|
||||
@@ -122,21 +130,21 @@
|
||||
if (errorText) { err += errorText; }
|
||||
if (url) { err += `\nEndpoint: ${url}`; }
|
||||
return err;
|
||||
},
|
||||
}
|
||||
|
||||
_handleShowAlert(e) {
|
||||
this._showAlert(e.detail.message, e.detail.action, e.detail.callback,
|
||||
e.detail.dismissOnNavigation);
|
||||
},
|
||||
}
|
||||
|
||||
_handleNetworkError(e) {
|
||||
this._showAlert('Server unavailable');
|
||||
console.error(e.detail.error.message);
|
||||
},
|
||||
}
|
||||
|
||||
_getLoggedIn() {
|
||||
return this.$.restAPI.getLoggedIn();
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} text
|
||||
@@ -161,7 +169,7 @@
|
||||
const el = this._createToastAlert();
|
||||
el.show(text, opt_actionText, opt_actionCallback);
|
||||
this._alertElement = el;
|
||||
},
|
||||
}
|
||||
|
||||
_hideAlert() {
|
||||
if (!this._alertElement) { return; }
|
||||
@@ -171,14 +179,14 @@
|
||||
|
||||
// Remove listener for page navigation, if it exists.
|
||||
this.unlisten(document, 'location-change', '_hideAlert');
|
||||
},
|
||||
}
|
||||
|
||||
_clearHideAlertHandle() {
|
||||
if (this._hideAlertHandle != null) {
|
||||
this.cancelAsync(this._hideAlertHandle);
|
||||
this._hideAlertHandle = null;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_showAuthErrorAlert(errorText, actionText) {
|
||||
// TODO(viktard): close alert if it's not for auth error.
|
||||
@@ -193,13 +201,13 @@
|
||||
if (!document.hidden) {
|
||||
this._handleVisibilityChange();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_createToastAlert() {
|
||||
const el = document.createElement('gr-alert');
|
||||
el.toast = true;
|
||||
return el;
|
||||
},
|
||||
}
|
||||
|
||||
_handleVisibilityChange() {
|
||||
// Ignore when the page is transitioning to hidden (or hidden is
|
||||
@@ -216,12 +224,12 @@
|
||||
this._lastCredentialCheck = Date.now();
|
||||
this.$.restAPI.checkCredentials();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_requestCheckLoggedIn() {
|
||||
this.debounce(
|
||||
'checkLoggedIn', this._checkSignedIn, CHECK_SIGN_IN_INTERVAL_MS);
|
||||
},
|
||||
}
|
||||
|
||||
_checkSignedIn() {
|
||||
this.$.restAPI.checkCredentials().then(account => {
|
||||
@@ -242,11 +250,11 @@
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_reloadPage() {
|
||||
window.location.reload();
|
||||
},
|
||||
}
|
||||
|
||||
_createLoginPopup() {
|
||||
const left = window.screenLeft +
|
||||
@@ -262,31 +270,33 @@
|
||||
window.open(this.getBaseUrl() +
|
||||
'/login/%3FcloseAfterLogin', '_blank', options.join(','));
|
||||
this.listen(window, 'focus', '_handleWindowFocus');
|
||||
},
|
||||
}
|
||||
|
||||
_handleCredentialRefreshed() {
|
||||
this.unlisten(window, 'focus', '_handleWindowFocus');
|
||||
this._refreshingCredentials = false;
|
||||
this._hideAlert();
|
||||
this._showAlert('Credentials refreshed.');
|
||||
},
|
||||
}
|
||||
|
||||
_handleWindowFocus() {
|
||||
this.flushDebouncer('checkLoggedIn');
|
||||
},
|
||||
}
|
||||
|
||||
_handleShowErrorDialog(e) {
|
||||
this._showErrorDialog(e.detail.message);
|
||||
},
|
||||
}
|
||||
|
||||
_handleDismissErrorDialog() {
|
||||
this.$.errorOverlay.close();
|
||||
},
|
||||
}
|
||||
|
||||
_showErrorDialog(message) {
|
||||
this.$.reporting.reportErrorDialog(message);
|
||||
this.$.errorDialog.text = message;
|
||||
this.$.errorOverlay.open();
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrErrorManager.is, GrErrorManager);
|
||||
})();
|
||||
|
||||
@@ -17,20 +17,26 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-key-binding-display',
|
||||
class GrKeyBindingDisplay extends Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element)) {
|
||||
static get is() { return 'gr-key-binding-display'; }
|
||||
|
||||
properties: {
|
||||
static get properties() {
|
||||
return {
|
||||
/** @type {Array<string>} */
|
||||
binding: Array,
|
||||
},
|
||||
binding: Array,
|
||||
};
|
||||
}
|
||||
|
||||
_computeModifiers(binding) {
|
||||
return binding.slice(0, binding.length - 1);
|
||||
},
|
||||
}
|
||||
|
||||
_computeKey(binding) {
|
||||
return binding[binding.length - 1];
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrKeyBindingDisplay.is, GrKeyBindingDisplay);
|
||||
})();
|
||||
|
||||
@@ -19,60 +19,68 @@
|
||||
|
||||
const {ShortcutSection} = window.Gerrit.KeyboardShortcutBinder;
|
||||
|
||||
Polymer({
|
||||
is: 'gr-keyboard-shortcuts-dialog',
|
||||
|
||||
/**
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
* @appliesMixin Gerrit.KeyboardShortcutMixin
|
||||
*/
|
||||
class GrKeyboardShortcutsDialog extends Polymer.mixinBehaviors( [
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.KeyboardShortcutBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-keyboard-shortcuts-dialog'; }
|
||||
/**
|
||||
* Fired when the user presses the close button.
|
||||
*
|
||||
* @event close
|
||||
*/
|
||||
|
||||
properties: {
|
||||
_left: Array,
|
||||
_right: Array,
|
||||
static get properties() {
|
||||
return {
|
||||
_left: Array,
|
||||
_right: Array,
|
||||
|
||||
_propertyBySection: {
|
||||
type: Object,
|
||||
value() {
|
||||
return {
|
||||
[ShortcutSection.EVERYWHERE]: '_everywhere',
|
||||
[ShortcutSection.NAVIGATION]: '_navigation',
|
||||
[ShortcutSection.DASHBOARD]: '_dashboard',
|
||||
[ShortcutSection.CHANGE_LIST]: '_changeList',
|
||||
[ShortcutSection.ACTIONS]: '_actions',
|
||||
[ShortcutSection.REPLY_DIALOG]: '_replyDialog',
|
||||
[ShortcutSection.FILE_LIST]: '_fileList',
|
||||
[ShortcutSection.DIFFS]: '_diffs',
|
||||
};
|
||||
_propertyBySection: {
|
||||
type: Object,
|
||||
value() {
|
||||
return {
|
||||
[ShortcutSection.EVERYWHERE]: '_everywhere',
|
||||
[ShortcutSection.NAVIGATION]: '_navigation',
|
||||
[ShortcutSection.DASHBOARD]: '_dashboard',
|
||||
[ShortcutSection.CHANGE_LIST]: '_changeList',
|
||||
[ShortcutSection.ACTIONS]: '_actions',
|
||||
[ShortcutSection.REPLY_DIALOG]: '_replyDialog',
|
||||
[ShortcutSection.FILE_LIST]: '_fileList',
|
||||
[ShortcutSection.DIFFS]: '_diffs',
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
behaviors: [
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.KeyboardShortcutBehavior,
|
||||
],
|
||||
|
||||
hostAttributes: {
|
||||
role: 'dialog',
|
||||
},
|
||||
ready() {
|
||||
super.ready();
|
||||
this._ensureAttribute('role', 'dialog');
|
||||
}
|
||||
|
||||
attached() {
|
||||
super.attached();
|
||||
this.addKeyboardShortcutDirectoryListener(
|
||||
this._onDirectoryUpdated.bind(this));
|
||||
},
|
||||
}
|
||||
|
||||
detached() {
|
||||
super.detached();
|
||||
this.removeKeyboardShortcutDirectoryListener(
|
||||
this._onDirectoryUpdated.bind(this));
|
||||
},
|
||||
}
|
||||
|
||||
_handleCloseTap(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.fire('close', null, {bubbles: false});
|
||||
},
|
||||
}
|
||||
|
||||
_onDirectoryUpdated(directory) {
|
||||
const left = [];
|
||||
@@ -122,6 +130,9 @@
|
||||
|
||||
this.set('_left', left);
|
||||
this.set('_right', right);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrKeyboardShortcutsDialog.is,
|
||||
GrKeyboardShortcutsDialog);
|
||||
})();
|
||||
|
||||
@@ -69,94 +69,107 @@
|
||||
'CUSTOM_EXTENSION',
|
||||
]);
|
||||
|
||||
Polymer({
|
||||
is: 'gr-main-header',
|
||||
/**
|
||||
* @appliesMixin Gerrit.AdminNavMixin
|
||||
* @appliesMixin Gerrit.BaseUrlMixin
|
||||
* @appliesMixin Gerrit.DocsUrlMixin
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
*/
|
||||
class GrMainHeader extends Polymer.mixinBehaviors( [
|
||||
Gerrit.AdminNavBehavior,
|
||||
Gerrit.BaseUrlBehavior,
|
||||
Gerrit.DocsUrlBehavior,
|
||||
Gerrit.FireBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-main-header'; }
|
||||
|
||||
hostAttributes: {
|
||||
role: 'banner',
|
||||
},
|
||||
|
||||
properties: {
|
||||
searchQuery: {
|
||||
type: String,
|
||||
notify: true,
|
||||
},
|
||||
loggedIn: {
|
||||
type: Boolean,
|
||||
reflectToAttribute: true,
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
reflectToAttribute: true,
|
||||
},
|
||||
|
||||
/** @type {?Object} */
|
||||
_account: Object,
|
||||
_adminLinks: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
_defaultLinks: {
|
||||
type: Array,
|
||||
value() {
|
||||
return DEFAULT_LINKS;
|
||||
static get properties() {
|
||||
return {
|
||||
searchQuery: {
|
||||
type: String,
|
||||
notify: true,
|
||||
},
|
||||
},
|
||||
_docBaseUrl: {
|
||||
type: String,
|
||||
value: null,
|
||||
},
|
||||
_links: {
|
||||
type: Array,
|
||||
computed: '_computeLinks(_defaultLinks, _userLinks, _adminLinks, ' +
|
||||
loggedIn: {
|
||||
type: Boolean,
|
||||
reflectToAttribute: true,
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
reflectToAttribute: true,
|
||||
},
|
||||
|
||||
/** @type {?Object} */
|
||||
_account: Object,
|
||||
_adminLinks: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
_defaultLinks: {
|
||||
type: Array,
|
||||
value() {
|
||||
return DEFAULT_LINKS;
|
||||
},
|
||||
},
|
||||
_docBaseUrl: {
|
||||
type: String,
|
||||
value: null,
|
||||
},
|
||||
_links: {
|
||||
type: Array,
|
||||
computed: '_computeLinks(_defaultLinks, _userLinks, _adminLinks, ' +
|
||||
'_topMenus, _docBaseUrl)',
|
||||
},
|
||||
_loginURL: {
|
||||
type: String,
|
||||
value: '/login',
|
||||
},
|
||||
_userLinks: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
_topMenus: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
_registerText: {
|
||||
type: String,
|
||||
value: 'Sign up',
|
||||
},
|
||||
_registerURL: {
|
||||
type: String,
|
||||
value: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
_loginURL: {
|
||||
type: String,
|
||||
value: '/login',
|
||||
},
|
||||
_userLinks: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
_topMenus: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
_registerText: {
|
||||
type: String,
|
||||
value: 'Sign up',
|
||||
},
|
||||
_registerURL: {
|
||||
type: String,
|
||||
value: null,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
behaviors: [
|
||||
Gerrit.AdminNavBehavior,
|
||||
Gerrit.BaseUrlBehavior,
|
||||
Gerrit.DocsUrlBehavior,
|
||||
Gerrit.FireBehavior,
|
||||
],
|
||||
static get observers() {
|
||||
return [
|
||||
'_accountLoaded(_account)',
|
||||
];
|
||||
}
|
||||
|
||||
observers: [
|
||||
'_accountLoaded(_account)',
|
||||
],
|
||||
ready() {
|
||||
super.ready();
|
||||
this._ensureAttribute('role', 'banner');
|
||||
}
|
||||
|
||||
attached() {
|
||||
super.attached();
|
||||
this._loadAccount();
|
||||
this._loadConfig();
|
||||
this.listen(window, 'location-change', '_handleLocationChange');
|
||||
},
|
||||
}
|
||||
|
||||
detached() {
|
||||
super.detached();
|
||||
this.unlisten(window, 'location-change', '_handleLocationChange');
|
||||
},
|
||||
}
|
||||
|
||||
reload() {
|
||||
this._loadAccount();
|
||||
},
|
||||
}
|
||||
|
||||
_handleLocationChange(e) {
|
||||
const baseUrl = this.getBaseUrl();
|
||||
@@ -173,11 +186,11 @@
|
||||
window.location.search +
|
||||
window.location.hash);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_computeRelativeURL(path) {
|
||||
return '//' + window.location.host + this.getBaseUrl() + path;
|
||||
},
|
||||
}
|
||||
|
||||
_computeLinks(defaultLinks, userLinks, adminLinks, topMenus, docBaseUrl) {
|
||||
// Polymer 2: check for undefined
|
||||
@@ -232,7 +245,7 @@
|
||||
}
|
||||
}
|
||||
return links;
|
||||
},
|
||||
}
|
||||
|
||||
_getDocLinks(docBaseUrl, docLinks) {
|
||||
if (!docBaseUrl || !docLinks) {
|
||||
@@ -249,7 +262,7 @@
|
||||
target: '_blank',
|
||||
};
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_loadAccount() {
|
||||
this.loading = true;
|
||||
@@ -273,7 +286,7 @@
|
||||
this._adminLinks = res.links;
|
||||
});
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_loadConfig() {
|
||||
this.$.restAPI.getConfig()
|
||||
@@ -282,7 +295,7 @@
|
||||
return this.getDocsBaseUrl(config, this.$.restAPI);
|
||||
})
|
||||
.then(docBaseUrl => { this._docBaseUrl = docBaseUrl; });
|
||||
},
|
||||
}
|
||||
|
||||
_accountLoaded(account) {
|
||||
if (!account) { return; }
|
||||
@@ -290,7 +303,7 @@
|
||||
this.$.restAPI.getPreferences().then(prefs => {
|
||||
this._userLinks = prefs.my.map(this._fixCustomMenuItem);
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_retrieveRegisterURL(config) {
|
||||
if (AUTH_TYPES_WITH_REGISTER_URL.has(config.auth.auth_type)) {
|
||||
@@ -299,11 +312,11 @@
|
||||
this._registerText = config.auth.register_text;
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_computeIsInvisible(registerURL) {
|
||||
return registerURL ? '' : 'invisible';
|
||||
},
|
||||
}
|
||||
|
||||
_fixCustomMenuItem(linkObj) {
|
||||
// Normalize all urls to PolyGerrit style.
|
||||
@@ -321,17 +334,17 @@
|
||||
delete linkObj.target;
|
||||
|
||||
return linkObj;
|
||||
},
|
||||
}
|
||||
|
||||
_generateSettingsLink() {
|
||||
return this.getBaseUrl() + '/settings/';
|
||||
},
|
||||
}
|
||||
|
||||
_onMobileSearchTap(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.fire('mobile-search', null, {bubbles: false});
|
||||
},
|
||||
}
|
||||
|
||||
_computeLinkGroupClass(linkGroup) {
|
||||
if (linkGroup && linkGroup.class) {
|
||||
@@ -339,6 +352,8 @@
|
||||
}
|
||||
|
||||
return '';
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrMainHeader.is, GrMainHeader);
|
||||
})();
|
||||
|
||||
@@ -207,38 +207,46 @@
|
||||
});
|
||||
})();
|
||||
|
||||
Polymer({
|
||||
is: 'gr-router',
|
||||
/**
|
||||
* @appliesMixin Gerrit.BaseUrlMixin
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
* @appliesMixin Gerrit.PatchSetMixin
|
||||
* @appliesMixin Gerrit.URLEncodingMixin
|
||||
*/
|
||||
class GrRouter extends Polymer.mixinBehaviors( [
|
||||
Gerrit.BaseUrlBehavior,
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.PatchSetBehavior,
|
||||
Gerrit.URLEncodingBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-router'; }
|
||||
|
||||
properties: {
|
||||
_app: {
|
||||
type: Object,
|
||||
value: app,
|
||||
},
|
||||
_isRedirecting: Boolean,
|
||||
// This variable is to differentiate between internal navigation (false)
|
||||
// and for first navigation in app after loaded from server (true).
|
||||
_isInitialLoad: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
Gerrit.BaseUrlBehavior,
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.PatchSetBehavior,
|
||||
Gerrit.URLEncodingBehavior,
|
||||
],
|
||||
static get properties() {
|
||||
return {
|
||||
_app: {
|
||||
type: Object,
|
||||
value: app,
|
||||
},
|
||||
_isRedirecting: Boolean,
|
||||
// This variable is to differentiate between internal navigation (false)
|
||||
// and for first navigation in app after loaded from server (true).
|
||||
_isInitialLoad: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
start() {
|
||||
if (!this._app) { return; }
|
||||
this._startRouter();
|
||||
},
|
||||
}
|
||||
|
||||
_setParams(params) {
|
||||
this._appElement().params = params;
|
||||
},
|
||||
}
|
||||
|
||||
_appElement() {
|
||||
// In Polymer2 you have to reach through the shadow root of the app
|
||||
@@ -248,12 +256,12 @@
|
||||
return document.getElementById('app-element') ||
|
||||
document.getElementById('app').shadowRoot.getElementById(
|
||||
'app-element');
|
||||
},
|
||||
}
|
||||
|
||||
_redirect(url) {
|
||||
this._isRedirecting = true;
|
||||
page.redirect(url);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Object} params
|
||||
@@ -285,7 +293,7 @@
|
||||
}
|
||||
|
||||
return base + url;
|
||||
},
|
||||
}
|
||||
|
||||
_generateWeblinks(params) {
|
||||
const type = params.type;
|
||||
@@ -299,7 +307,7 @@
|
||||
default:
|
||||
console.warn(`Unsupported weblink ${type}!`);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_getPatchSetWeblink(params) {
|
||||
const {commit, options} = params;
|
||||
@@ -311,7 +319,7 @@
|
||||
} else {
|
||||
return {name, url: weblink.url};
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_firstCodeBrowserWeblink(weblinks) {
|
||||
// This is an ordered whitelist of web link types that provide direct
|
||||
@@ -323,7 +331,7 @@
|
||||
if (weblink) { return weblink; }
|
||||
}
|
||||
return null;
|
||||
},
|
||||
}
|
||||
|
||||
_getBrowseCommitWeblink(weblinks, config) {
|
||||
if (!weblinks) { return null; }
|
||||
@@ -339,7 +347,7 @@
|
||||
}
|
||||
if (!weblink) { return null; }
|
||||
return weblink;
|
||||
},
|
||||
}
|
||||
|
||||
_getChangeWeblinks({repo, commit, options: {weblinks, config}}) {
|
||||
if (!weblinks || !weblinks.length) return [];
|
||||
@@ -348,11 +356,11 @@
|
||||
!commitWeblink ||
|
||||
!commitWeblink.name ||
|
||||
weblink.name !== commitWeblink.name);
|
||||
},
|
||||
}
|
||||
|
||||
_getFileWebLinks({repo, commit, file, options: {weblinks}}) {
|
||||
return weblinks;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Object} params
|
||||
@@ -399,7 +407,7 @@
|
||||
}
|
||||
|
||||
return '/q/' + operators.join('+') + offsetExpr;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Object} params
|
||||
@@ -423,7 +431,7 @@
|
||||
} else {
|
||||
return `/c/${params.changeNum}${suffix}`;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Object} params
|
||||
@@ -448,7 +456,7 @@
|
||||
// User dashboard.
|
||||
return `/dashboard/${params.user || 'self'}`;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Array<!{name: string, query: string}>} sections
|
||||
@@ -465,7 +473,7 @@
|
||||
return encodeURIComponent(section.name) + '=' +
|
||||
encodeURIComponent(query);
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Object} params
|
||||
@@ -491,7 +499,7 @@
|
||||
} else {
|
||||
return `/c/${params.changeNum}${suffix}`;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Object} params
|
||||
@@ -505,7 +513,7 @@
|
||||
url += ',audit-log';
|
||||
}
|
||||
return url;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Object} params
|
||||
@@ -525,7 +533,7 @@
|
||||
url += ',dashboards';
|
||||
}
|
||||
return url;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Object} params
|
||||
@@ -533,7 +541,7 @@
|
||||
*/
|
||||
_generateSettingsUrl(params) {
|
||||
return '/settings';
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an object of parameters, potentially including a `patchNum` or a
|
||||
@@ -547,7 +555,7 @@
|
||||
if (params.patchNum) { range = '' + params.patchNum; }
|
||||
if (params.basePatchNum) { range = params.basePatchNum + '..' + range; }
|
||||
return range;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a set of params without a project, gets the project from the rest
|
||||
@@ -571,7 +579,7 @@
|
||||
this._normalizePatchRangeParams(params);
|
||||
this._redirect(this._generateUrl(params));
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes the params object, and determines if the URL needs to be
|
||||
@@ -600,7 +608,7 @@
|
||||
params.basePatchNum = null;
|
||||
}
|
||||
return needsRedirect;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect the user to login using the given return-URL for redirection
|
||||
@@ -611,7 +619,7 @@
|
||||
const basePath = this.getBaseUrl() || '';
|
||||
page(
|
||||
'/login/' + encodeURIComponent(returnUrl.substring(basePath.length)));
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Hashes parsed by page.js exclude "inner" hashes, so a URL like "/a#b#c"
|
||||
@@ -622,7 +630,7 @@
|
||||
*/
|
||||
_getHashFromCanonicalPath(canonicalPath) {
|
||||
return canonicalPath.split('#').slice(1).join('#');
|
||||
},
|
||||
}
|
||||
|
||||
_parseLineAddress(hash) {
|
||||
const match = hash.match(LINE_ADDRESS_PATTERN);
|
||||
@@ -631,7 +639,7 @@
|
||||
leftSide: !!match[1],
|
||||
lineNum: parseInt(match[2], 10),
|
||||
};
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if the user is logged in and return a promise that only
|
||||
@@ -650,12 +658,12 @@
|
||||
return Promise.reject(new Error());
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
/** Page.js middleware that warms the REST API's logged-in cache line. */
|
||||
_loadUserMiddleware(ctx, next) {
|
||||
this.$.restAPI.getLoggedIn().then(() => { next(); });
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Map a route to a method on the router.
|
||||
@@ -682,7 +690,7 @@
|
||||
this._redirectIfNotLoggedIn(data) : Promise.resolve();
|
||||
promise.then(() => { this[handlerName](data); });
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_startRouter() {
|
||||
const base = this.getBaseUrl();
|
||||
@@ -878,7 +886,7 @@
|
||||
this._mapRoute(RoutePattern.DEFAULT, '_handleDefaultRoute');
|
||||
|
||||
page.start();
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Object} data
|
||||
@@ -919,7 +927,7 @@
|
||||
this._redirect('/q/status:open');
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode an application/x-www-form-urlencoded string.
|
||||
@@ -929,7 +937,7 @@
|
||||
*/
|
||||
_decodeQueryString(qs) {
|
||||
return decodeURIComponent(qs.replace(PLUS_PATTERN, ' '));
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a query string (e.g. window.location.search) into an array of
|
||||
@@ -961,7 +969,7 @@
|
||||
}
|
||||
});
|
||||
return params;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle dashboard routes. These may be user, or project dashboards.
|
||||
@@ -986,7 +994,7 @@
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle custom dashboard routes.
|
||||
@@ -1038,7 +1046,7 @@
|
||||
// Redirect /dashboard/ -> /dashboard/self.
|
||||
this._redirect('/dashboard/self');
|
||||
return Promise.resolve();
|
||||
},
|
||||
}
|
||||
|
||||
_handleProjectDashboardRoute(data) {
|
||||
const project = data.params[0];
|
||||
@@ -1048,22 +1056,22 @@
|
||||
dashboard: decodeURIComponent(data.params[1]),
|
||||
});
|
||||
this.$.reporting.setRepoName(project);
|
||||
},
|
||||
}
|
||||
|
||||
_handleGroupInfoRoute(data) {
|
||||
this._redirect('/admin/groups/' + encodeURIComponent(data.params[0]));
|
||||
},
|
||||
}
|
||||
|
||||
_handleGroupSelfRedirectRoute(data) {
|
||||
this._redirect('/settings/#Groups');
|
||||
},
|
||||
}
|
||||
|
||||
_handleGroupRoute(data) {
|
||||
this._setParams({
|
||||
view: Gerrit.Nav.View.GROUP,
|
||||
groupId: data.params[0],
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleGroupAuditLogRoute(data) {
|
||||
this._setParams({
|
||||
@@ -1071,7 +1079,7 @@
|
||||
detail: Gerrit.Nav.GroupDetailView.LOG,
|
||||
groupId: data.params[0],
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleGroupMembersRoute(data) {
|
||||
this._setParams({
|
||||
@@ -1079,7 +1087,7 @@
|
||||
detail: Gerrit.Nav.GroupDetailView.MEMBERS,
|
||||
groupId: data.params[0],
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleGroupListOffsetRoute(data) {
|
||||
this._setParams({
|
||||
@@ -1089,7 +1097,7 @@
|
||||
filter: null,
|
||||
openCreateModal: data.hash === 'create',
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleGroupListFilterOffsetRoute(data) {
|
||||
this._setParams({
|
||||
@@ -1098,7 +1106,7 @@
|
||||
offset: data.params.offset,
|
||||
filter: data.params.filter,
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleGroupListFilterRoute(data) {
|
||||
this._setParams({
|
||||
@@ -1106,7 +1114,7 @@
|
||||
adminView: 'gr-admin-group-list',
|
||||
filter: data.params.filter || null,
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleProjectsOldRoute(data) {
|
||||
let params = '';
|
||||
@@ -1119,7 +1127,7 @@
|
||||
}
|
||||
|
||||
this._redirect(`/admin/repos/${params}`);
|
||||
},
|
||||
}
|
||||
|
||||
_handleRepoCommandsRoute(data) {
|
||||
const repo = data.params[0];
|
||||
@@ -1129,7 +1137,7 @@
|
||||
repo,
|
||||
});
|
||||
this.$.reporting.setRepoName(repo);
|
||||
},
|
||||
}
|
||||
|
||||
_handleRepoAccessRoute(data) {
|
||||
const repo = data.params[0];
|
||||
@@ -1139,7 +1147,7 @@
|
||||
repo,
|
||||
});
|
||||
this.$.reporting.setRepoName(repo);
|
||||
},
|
||||
}
|
||||
|
||||
_handleRepoDashboardsRoute(data) {
|
||||
const repo = data.params[0];
|
||||
@@ -1149,7 +1157,7 @@
|
||||
repo,
|
||||
});
|
||||
this.$.reporting.setRepoName(repo);
|
||||
},
|
||||
}
|
||||
|
||||
_handleBranchListOffsetRoute(data) {
|
||||
this._setParams({
|
||||
@@ -1159,7 +1167,7 @@
|
||||
offset: data.params[2] || 0,
|
||||
filter: null,
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleBranchListFilterOffsetRoute(data) {
|
||||
this._setParams({
|
||||
@@ -1169,7 +1177,7 @@
|
||||
offset: data.params.offset,
|
||||
filter: data.params.filter,
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleBranchListFilterRoute(data) {
|
||||
this._setParams({
|
||||
@@ -1178,7 +1186,7 @@
|
||||
repo: data.params.repo,
|
||||
filter: data.params.filter || null,
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleTagListOffsetRoute(data) {
|
||||
this._setParams({
|
||||
@@ -1188,7 +1196,7 @@
|
||||
offset: data.params[2] || 0,
|
||||
filter: null,
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleTagListFilterOffsetRoute(data) {
|
||||
this._setParams({
|
||||
@@ -1198,7 +1206,7 @@
|
||||
offset: data.params.offset,
|
||||
filter: data.params.filter,
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleTagListFilterRoute(data) {
|
||||
this._setParams({
|
||||
@@ -1207,7 +1215,7 @@
|
||||
repo: data.params.repo,
|
||||
filter: data.params.filter || null,
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleRepoListOffsetRoute(data) {
|
||||
this._setParams({
|
||||
@@ -1217,7 +1225,7 @@
|
||||
filter: null,
|
||||
openCreateModal: data.hash === 'create',
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleRepoListFilterOffsetRoute(data) {
|
||||
this._setParams({
|
||||
@@ -1226,7 +1234,7 @@
|
||||
offset: data.params.offset,
|
||||
filter: data.params.filter,
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleRepoListFilterRoute(data) {
|
||||
this._setParams({
|
||||
@@ -1234,19 +1242,19 @@
|
||||
adminView: 'gr-repo-list',
|
||||
filter: data.params.filter || null,
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleCreateProjectRoute(data) {
|
||||
// Redirects the legacy route to the new route, which displays the project
|
||||
// list with a hash 'create'.
|
||||
this._redirect('/admin/repos#create');
|
||||
},
|
||||
}
|
||||
|
||||
_handleCreateGroupRoute(data) {
|
||||
// Redirects the legacy route to the new route, which displays the group
|
||||
// list with a hash 'create'.
|
||||
this._redirect('/admin/groups#create');
|
||||
},
|
||||
}
|
||||
|
||||
_handleRepoRoute(data) {
|
||||
const repo = data.params[0];
|
||||
@@ -1255,7 +1263,7 @@
|
||||
repo,
|
||||
});
|
||||
this.$.reporting.setRepoName(repo);
|
||||
},
|
||||
}
|
||||
|
||||
_handlePluginListOffsetRoute(data) {
|
||||
this._setParams({
|
||||
@@ -1264,7 +1272,7 @@
|
||||
offset: data.params[1] || 0,
|
||||
filter: null,
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handlePluginListFilterOffsetRoute(data) {
|
||||
this._setParams({
|
||||
@@ -1273,7 +1281,7 @@
|
||||
offset: data.params.offset,
|
||||
filter: data.params.filter,
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handlePluginListFilterRoute(data) {
|
||||
this._setParams({
|
||||
@@ -1281,14 +1289,14 @@
|
||||
adminView: 'gr-plugin-list',
|
||||
filter: data.params.filter || null,
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handlePluginListRoute(data) {
|
||||
this._setParams({
|
||||
view: Gerrit.Nav.View.ADMIN,
|
||||
adminView: 'gr-plugin-list',
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleQueryRoute(data) {
|
||||
this._setParams({
|
||||
@@ -1296,15 +1304,15 @@
|
||||
query: data.params[0],
|
||||
offset: data.params[2],
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleQueryLegacySuffixRoute(ctx) {
|
||||
this._redirect(ctx.path.replace(LEGACY_QUERY_SUFFIX_PATTERN, ''));
|
||||
},
|
||||
}
|
||||
|
||||
_handleChangeNumberLegacyRoute(ctx) {
|
||||
this._redirect('/c/' + encodeURIComponent(ctx.params[0]));
|
||||
},
|
||||
}
|
||||
|
||||
_handleChangeRoute(ctx) {
|
||||
// Parameter order is based on the regex group number matched.
|
||||
@@ -1318,7 +1326,7 @@
|
||||
|
||||
this.$.reporting.setRepoName(params.project);
|
||||
this._redirectOrNavigate(params);
|
||||
},
|
||||
}
|
||||
|
||||
_handleDiffRoute(ctx) {
|
||||
// Parameter order is based on the regex group number matched.
|
||||
@@ -1338,7 +1346,7 @@
|
||||
}
|
||||
this.$.reporting.setRepoName(params.project);
|
||||
this._redirectOrNavigate(params);
|
||||
},
|
||||
}
|
||||
|
||||
_handleChangeLegacyRoute(ctx) {
|
||||
// Parameter order is based on the regex group number matched.
|
||||
@@ -1351,11 +1359,11 @@
|
||||
};
|
||||
|
||||
this._normalizeLegacyRouteParams(params);
|
||||
},
|
||||
}
|
||||
|
||||
_handleLegacyLinenum(ctx) {
|
||||
this._redirect(ctx.path.replace(LEGACY_LINENUM_PATTERN, '#$1'));
|
||||
},
|
||||
}
|
||||
|
||||
_handleDiffLegacyRoute(ctx) {
|
||||
// Parameter order is based on the regex group number matched.
|
||||
@@ -1374,7 +1382,7 @@
|
||||
}
|
||||
|
||||
this._normalizeLegacyRouteParams(params);
|
||||
},
|
||||
}
|
||||
|
||||
_handleDiffEditRoute(ctx) {
|
||||
// Parameter order is based on the regex group number matched.
|
||||
@@ -1387,7 +1395,7 @@
|
||||
view: Gerrit.Nav.View.EDIT,
|
||||
});
|
||||
this.$.reporting.setRepoName(project);
|
||||
},
|
||||
}
|
||||
|
||||
_handleChangeEditRoute(ctx) {
|
||||
// Parameter order is based on the regex group number matched.
|
||||
@@ -1400,7 +1408,7 @@
|
||||
edit: true,
|
||||
});
|
||||
this.$.reporting.setRepoName(project);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize the patch range params for a the change or diff view and
|
||||
@@ -1413,16 +1421,16 @@
|
||||
} else {
|
||||
this._setParams(params);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_handleAgreementsRoute() {
|
||||
this._redirect('/settings/#Agreements');
|
||||
},
|
||||
}
|
||||
|
||||
_handleNewAgreementsRoute(data) {
|
||||
data.params.view = Gerrit.Nav.View.AGREEMENTS;
|
||||
this._setParams(data.params);
|
||||
},
|
||||
}
|
||||
|
||||
_handleSettingsLegacyRoute(data) {
|
||||
// email tokens may contain '+' but no space.
|
||||
@@ -1433,11 +1441,11 @@
|
||||
view: Gerrit.Nav.View.SETTINGS,
|
||||
emailToken: token,
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleSettingsRoute(data) {
|
||||
this._setParams({view: Gerrit.Nav.View.SETTINGS});
|
||||
},
|
||||
}
|
||||
|
||||
_handleRegisterRoute(ctx) {
|
||||
this._setParams({justRegistered: true});
|
||||
@@ -1448,7 +1456,7 @@
|
||||
|
||||
if (path[0] !== '/') { return; }
|
||||
this._redirect(this.getBaseUrl() + path);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for routes that should pass through the router and not be caught
|
||||
@@ -1456,7 +1464,7 @@
|
||||
*/
|
||||
_handlePassThroughRoute() {
|
||||
location.reload();
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* URL may sometimes have /+/ encoded to / /.
|
||||
@@ -1466,26 +1474,26 @@
|
||||
let hash = this._getHashFromCanonicalPath(ctx.canonicalPath);
|
||||
if (hash.length) { hash = '#' + hash; }
|
||||
this._redirect(`/c/${ctx.params[0]}/+/${ctx.params[1]}${hash}`);
|
||||
},
|
||||
}
|
||||
|
||||
_handlePluginScreen(ctx) {
|
||||
const view = Gerrit.Nav.View.PLUGIN_SCREEN;
|
||||
const plugin = ctx.params[0];
|
||||
const screen = ctx.params[1];
|
||||
this._setParams({view, plugin, screen});
|
||||
},
|
||||
}
|
||||
|
||||
_handleDocumentationSearchRoute(data) {
|
||||
this._setParams({
|
||||
view: Gerrit.Nav.View.DOCUMENTATION_SEARCH,
|
||||
filter: data.params.filter || null,
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleDocumentationSearchRedirectRoute(data) {
|
||||
this._redirect('/Documentation/q/filter:' +
|
||||
encodeURIComponent(data.params[0]));
|
||||
},
|
||||
}
|
||||
|
||||
_handleDocumentationRedirectRoute(data) {
|
||||
if (data.params[1]) {
|
||||
@@ -1494,7 +1502,7 @@
|
||||
// Redirect /Documentation to /Documentation/index.html
|
||||
this._redirect('/Documentation/index.html');
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Catchall route for when no other route is matched.
|
||||
@@ -1507,7 +1515,7 @@
|
||||
// Route can be recognized by server, so we pass it to server.
|
||||
this._handlePassThroughRoute();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_show404() {
|
||||
// Note: the app's 404 display is tightly-coupled with catching 404
|
||||
@@ -1515,6 +1523,8 @@
|
||||
// TODO: Decouple the gr-app error view from network responses.
|
||||
this._appElement().dispatchEvent(new CustomEvent('page-error',
|
||||
{detail: {response: {status: 404}}}));
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrRouter.is, GrRouter);
|
||||
})();
|
||||
|
||||
@@ -103,75 +103,80 @@
|
||||
|
||||
const TOKENIZE_REGEX = /(?:[^\s"]+|"[^"]*")+\s*/g;
|
||||
|
||||
Polymer({
|
||||
is: 'gr-search-bar',
|
||||
|
||||
/**
|
||||
* @appliesMixin Gerrit.KeyboardShortcutMixin
|
||||
* @appliesMixin Gerrit.URLEncodingMixin
|
||||
*/
|
||||
class GrSearchBar extends Polymer.mixinBehaviors( [
|
||||
Gerrit.KeyboardShortcutBehavior,
|
||||
Gerrit.URLEncodingBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-search-bar'; }
|
||||
/**
|
||||
* Fired when a search is committed
|
||||
*
|
||||
* @event handle-search
|
||||
*/
|
||||
|
||||
behaviors: [
|
||||
Gerrit.KeyboardShortcutBehavior,
|
||||
Gerrit.URLEncodingBehavior,
|
||||
],
|
||||
|
||||
properties: {
|
||||
value: {
|
||||
type: String,
|
||||
value: '',
|
||||
notify: true,
|
||||
observer: '_valueChanged',
|
||||
},
|
||||
keyEventTarget: {
|
||||
type: Object,
|
||||
value() { return document.body; },
|
||||
},
|
||||
query: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._getSearchSuggestions.bind(this);
|
||||
static get properties() {
|
||||
return {
|
||||
value: {
|
||||
type: String,
|
||||
value: '',
|
||||
notify: true,
|
||||
observer: '_valueChanged',
|
||||
},
|
||||
},
|
||||
projectSuggestions: {
|
||||
type: Function,
|
||||
value() {
|
||||
return () => Promise.resolve([]);
|
||||
keyEventTarget: {
|
||||
type: Object,
|
||||
value() { return document.body; },
|
||||
},
|
||||
},
|
||||
groupSuggestions: {
|
||||
type: Function,
|
||||
value() {
|
||||
return () => Promise.resolve([]);
|
||||
query: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._getSearchSuggestions.bind(this);
|
||||
},
|
||||
},
|
||||
},
|
||||
accountSuggestions: {
|
||||
type: Function,
|
||||
value() {
|
||||
return () => Promise.resolve([]);
|
||||
projectSuggestions: {
|
||||
type: Function,
|
||||
value() {
|
||||
return () => Promise.resolve([]);
|
||||
},
|
||||
},
|
||||
},
|
||||
_inputVal: String,
|
||||
_threshold: {
|
||||
type: Number,
|
||||
value: 1,
|
||||
},
|
||||
},
|
||||
groupSuggestions: {
|
||||
type: Function,
|
||||
value() {
|
||||
return () => Promise.resolve([]);
|
||||
},
|
||||
},
|
||||
accountSuggestions: {
|
||||
type: Function,
|
||||
value() {
|
||||
return () => Promise.resolve([]);
|
||||
},
|
||||
},
|
||||
_inputVal: String,
|
||||
_threshold: {
|
||||
type: Number,
|
||||
value: 1,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
keyboardShortcuts() {
|
||||
return {
|
||||
[this.Shortcut.SEARCH]: '_handleSearch',
|
||||
};
|
||||
},
|
||||
}
|
||||
|
||||
_valueChanged(value) {
|
||||
this._inputVal = value;
|
||||
},
|
||||
}
|
||||
|
||||
_handleInputCommit(e) {
|
||||
this._preventDefaultAndNavigateToInputVal(e);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called in a few different cases:
|
||||
@@ -205,7 +210,7 @@
|
||||
detail: {inputVal: this._inputVal},
|
||||
}));
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine what array of possible suggestions should be provided
|
||||
@@ -247,7 +252,7 @@
|
||||
.filter(operator => operator.includes(input))
|
||||
.map(operator => ({text: operator})));
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the sorted, pruned list of suggestions for the current search query.
|
||||
@@ -290,7 +295,7 @@
|
||||
};
|
||||
});
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleSearch(e) {
|
||||
const keyboardEvent = this.getKeyboardEvent(e);
|
||||
@@ -300,6 +305,8 @@
|
||||
e.preventDefault();
|
||||
this.$.searchInput.focus();
|
||||
this.$.searchInput.selectAll();
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrSearchBar.is, GrSearchBar);
|
||||
})();
|
||||
|
||||
@@ -21,52 +21,58 @@
|
||||
const SELF_EXPRESSION = 'self';
|
||||
const ME_EXPRESSION = 'me';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-smart-search',
|
||||
/**
|
||||
* @appliesMixin Gerrit.DisplayNameMixin
|
||||
*/
|
||||
class GrSmartSearch extends Polymer.mixinBehaviors( [
|
||||
Gerrit.DisplayNameBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-smart-search'; }
|
||||
|
||||
properties: {
|
||||
searchQuery: String,
|
||||
_config: Object,
|
||||
_projectSuggestions: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._fetchProjects.bind(this);
|
||||
static get properties() {
|
||||
return {
|
||||
searchQuery: String,
|
||||
_config: Object,
|
||||
_projectSuggestions: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._fetchProjects.bind(this);
|
||||
},
|
||||
},
|
||||
},
|
||||
_groupSuggestions: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._fetchGroups.bind(this);
|
||||
_groupSuggestions: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._fetchGroups.bind(this);
|
||||
},
|
||||
},
|
||||
},
|
||||
_accountSuggestions: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._fetchAccounts.bind(this);
|
||||
_accountSuggestions: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._fetchAccounts.bind(this);
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
Gerrit.DisplayNameBehavior,
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
attached() {
|
||||
super.attached();
|
||||
this.$.restAPI.getConfig().then(cfg => {
|
||||
this._config = cfg;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleSearch(e) {
|
||||
const input = e.detail.inputVal;
|
||||
if (input) {
|
||||
Gerrit.Nav.navigateToSearchQuery(input);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_accountOrAnon(name) {
|
||||
return this.getUserName(this._serverConfig, name, false);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch from the API the predicted projects.
|
||||
@@ -86,7 +92,7 @@
|
||||
const keys = Object.keys(projects);
|
||||
return keys.map(key => ({text: predicate + ':' + key}));
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch from the API the predicted groups.
|
||||
@@ -107,7 +113,7 @@
|
||||
const keys = Object.keys(groups);
|
||||
return keys.map(key => ({text: predicate + ':' + key}));
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch from the API the predicted accounts.
|
||||
@@ -138,7 +144,7 @@
|
||||
return accounts;
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_mapAccountsHelper(accounts, predicate) {
|
||||
return accounts.map(account => ({
|
||||
@@ -147,6 +153,8 @@
|
||||
`${predicate}:${account.email}` :
|
||||
`${predicate}:"${this._accountOrAnon(account)}"`,
|
||||
}));
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrSmartSearch.is, GrSmartSearch);
|
||||
})();
|
||||
|
||||
@@ -460,20 +460,27 @@
|
||||
this._isInRevisionOfPatchRange(comment, range);
|
||||
};
|
||||
|
||||
Polymer({
|
||||
is: 'gr-comment-api',
|
||||
/**
|
||||
* @appliesMixin Gerrit.PatchSetMixin
|
||||
*/
|
||||
class GrCommentApi extends Polymer.mixinBehaviors( [
|
||||
Gerrit.PatchSetBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-comment-api'; }
|
||||
|
||||
properties: {
|
||||
_changeComments: Object,
|
||||
},
|
||||
static get properties() {
|
||||
return {
|
||||
_changeComments: Object,
|
||||
};
|
||||
}
|
||||
|
||||
listeners: {
|
||||
'reload-drafts': 'reloadDrafts',
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
Gerrit.PatchSetBehavior,
|
||||
],
|
||||
created() {
|
||||
super.created();
|
||||
this.addEventListener('reload-drafts',
|
||||
changeNum => this.reloadDrafts(changeNum));
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all comments (with drafts and robot comments) for the given change
|
||||
@@ -494,7 +501,7 @@
|
||||
robotComments, drafts, changeNum);
|
||||
return this._changeComments;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-initialize _changeComments with a new ChangeComments object, that
|
||||
@@ -513,6 +520,8 @@
|
||||
this._changeComments.robotComments, drafts, changeNum);
|
||||
return this._changeComments;
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrCommentApi.is, GrCommentApi);
|
||||
})();
|
||||
|
||||
@@ -24,20 +24,23 @@
|
||||
[Gerrit.CoverageType.NOT_INSTRUMENTED, 'Not instrumented by any tests.'],
|
||||
]);
|
||||
|
||||
Polymer({
|
||||
is: 'gr-coverage-layer',
|
||||
class GrCoverageLayer extends Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element)) {
|
||||
static get is() { return 'gr-coverage-layer'; }
|
||||
|
||||
properties: {
|
||||
static get properties() {
|
||||
return {
|
||||
/**
|
||||
* Must be sorted by code_range.start_line.
|
||||
* Must only contain ranges that match the side.
|
||||
*
|
||||
* @type {!Array<!Gerrit.CoverageRange>}
|
||||
*/
|
||||
coverageRanges: Array,
|
||||
side: String,
|
||||
coverageRanges: Array,
|
||||
side: String,
|
||||
|
||||
/**
|
||||
/**
|
||||
* We keep track of the line number from the previous annotate() call,
|
||||
* and also of the index of the coverage range that had matched.
|
||||
* annotate() calls are coming in with increasing line numbers and
|
||||
@@ -45,15 +48,16 @@
|
||||
* and efficient way for finding the coverage range that matches a given
|
||||
* line number.
|
||||
*/
|
||||
_lineNumber: {
|
||||
type: Number,
|
||||
value: 0,
|
||||
},
|
||||
_index: {
|
||||
type: Number,
|
||||
value: 0,
|
||||
},
|
||||
},
|
||||
_lineNumber: {
|
||||
type: Number,
|
||||
value: 0,
|
||||
},
|
||||
_index: {
|
||||
type: Number,
|
||||
value: 0,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Layer method to add annotations to a line.
|
||||
@@ -102,6 +106,8 @@
|
||||
lineNumberEl.title = TOOLTIP_MAP.get(coverageRange.type);
|
||||
return;
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrCoverageLayer.is, GrCoverageLayer);
|
||||
})();
|
||||
|
||||
@@ -35,33 +35,36 @@
|
||||
const LEFT_SIDE_CLASS = 'target-side-left';
|
||||
const RIGHT_SIDE_CLASS = 'target-side-right';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-diff-cursor',
|
||||
class GrDiffCursor extends Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element)) {
|
||||
static get is() { return 'gr-diff-cursor'; }
|
||||
|
||||
properties: {
|
||||
static get properties() {
|
||||
return {
|
||||
/**
|
||||
* Either DiffSides.LEFT or DiffSides.RIGHT.
|
||||
*/
|
||||
side: {
|
||||
type: String,
|
||||
value: DiffSides.RIGHT,
|
||||
},
|
||||
/** @type {!HTMLElement|undefined} */
|
||||
diffRow: {
|
||||
type: Object,
|
||||
notify: true,
|
||||
observer: '_rowChanged',
|
||||
},
|
||||
side: {
|
||||
type: String,
|
||||
value: DiffSides.RIGHT,
|
||||
},
|
||||
/** @type {!HTMLElement|undefined} */
|
||||
diffRow: {
|
||||
type: Object,
|
||||
notify: true,
|
||||
observer: '_rowChanged',
|
||||
},
|
||||
|
||||
/**
|
||||
/**
|
||||
* The diff views to cursor through and listen to.
|
||||
*/
|
||||
diffs: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
diffs: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
|
||||
/**
|
||||
/**
|
||||
* If set, the cursor will attempt to move to the line number (instead of
|
||||
* the first chunk) the next time the diff renders. It is set back to null
|
||||
* when used. It should be only used if you want the line to be focused
|
||||
@@ -71,56 +74,61 @@
|
||||
*
|
||||
* @type (?number)
|
||||
*/
|
||||
initialLineNumber: {
|
||||
type: Number,
|
||||
value: null,
|
||||
},
|
||||
initialLineNumber: {
|
||||
type: Number,
|
||||
value: null,
|
||||
},
|
||||
|
||||
/**
|
||||
/**
|
||||
* The scroll behavior for the cursor. Values are 'never' and
|
||||
* 'keep-visible'. 'keep-visible' will only scroll if the cursor is beyond
|
||||
* the viewport.
|
||||
*/
|
||||
_scrollBehavior: {
|
||||
type: String,
|
||||
value: ScrollBehavior.KEEP_VISIBLE,
|
||||
},
|
||||
_scrollBehavior: {
|
||||
type: String,
|
||||
value: ScrollBehavior.KEEP_VISIBLE,
|
||||
},
|
||||
|
||||
_focusOnMove: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
_focusOnMove: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
|
||||
_listeningForScroll: Boolean,
|
||||
},
|
||||
_listeningForScroll: Boolean,
|
||||
};
|
||||
}
|
||||
|
||||
observers: [
|
||||
'_updateSideClass(side)',
|
||||
'_diffsChanged(diffs.splices)',
|
||||
],
|
||||
static get observers() {
|
||||
return [
|
||||
'_updateSideClass(side)',
|
||||
'_diffsChanged(diffs.splices)',
|
||||
];
|
||||
}
|
||||
|
||||
attached() {
|
||||
super.attached();
|
||||
// Catch when users are scrolling as the view loads.
|
||||
this.listen(window, 'scroll', '_handleWindowScroll');
|
||||
},
|
||||
}
|
||||
|
||||
detached() {
|
||||
super.detached();
|
||||
this.unlisten(window, 'scroll', '_handleWindowScroll');
|
||||
},
|
||||
}
|
||||
|
||||
moveLeft() {
|
||||
this.side = DiffSides.LEFT;
|
||||
if (this._isTargetBlank()) {
|
||||
this.moveUp();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
moveRight() {
|
||||
this.side = DiffSides.RIGHT;
|
||||
if (this._isTargetBlank()) {
|
||||
this.moveUp();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
moveDown() {
|
||||
if (this._getViewMode() === DiffViewMode.SIDE_BY_SIDE) {
|
||||
@@ -128,7 +136,7 @@
|
||||
} else {
|
||||
this.$.cursorManager.next();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
moveUp() {
|
||||
if (this._getViewMode() === DiffViewMode.SIDE_BY_SIDE) {
|
||||
@@ -136,7 +144,7 @@
|
||||
} else {
|
||||
this.$.cursorManager.previous();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
moveToNextChunk(opt_clipToTop) {
|
||||
this.$.cursorManager.next(this._isFirstRowOfChunk.bind(this),
|
||||
@@ -144,22 +152,22 @@
|
||||
return target.parentNode.scrollHeight;
|
||||
}, opt_clipToTop);
|
||||
this._fixSide();
|
||||
},
|
||||
}
|
||||
|
||||
moveToPreviousChunk() {
|
||||
this.$.cursorManager.previous(this._isFirstRowOfChunk.bind(this));
|
||||
this._fixSide();
|
||||
},
|
||||
}
|
||||
|
||||
moveToNextCommentThread() {
|
||||
this.$.cursorManager.next(this._rowHasThread.bind(this));
|
||||
this._fixSide();
|
||||
},
|
||||
}
|
||||
|
||||
moveToPreviousCommentThread() {
|
||||
this.$.cursorManager.previous(this._rowHasThread.bind(this));
|
||||
this._fixSide();
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} number
|
||||
@@ -172,7 +180,7 @@
|
||||
this.side = side;
|
||||
this.$.cursorManager.setCursor(row);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the line number element targeted by the cursor row and side.
|
||||
@@ -190,7 +198,7 @@
|
||||
}
|
||||
|
||||
return this.diffRow.querySelector(lineElSelector);
|
||||
},
|
||||
}
|
||||
|
||||
getTargetDiffElement() {
|
||||
if (!this.diffRow) return null;
|
||||
@@ -202,12 +210,12 @@
|
||||
return hostOwner.host;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
}
|
||||
|
||||
moveToFirstChunk() {
|
||||
this.$.cursorManager.moveToStart();
|
||||
this.moveToNextChunk(true);
|
||||
},
|
||||
}
|
||||
|
||||
reInitCursor() {
|
||||
this._updateStops();
|
||||
@@ -217,7 +225,7 @@
|
||||
} else {
|
||||
this.moveToFirstChunk();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_handleWindowScroll() {
|
||||
if (this._listeningForScroll) {
|
||||
@@ -225,7 +233,7 @@
|
||||
this._focusOnMove = false;
|
||||
this._listeningForScroll = false;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
handleDiffUpdate() {
|
||||
this._updateStops();
|
||||
@@ -240,11 +248,11 @@
|
||||
this._scrollBehavior = ScrollBehavior.KEEP_VISIBLE;
|
||||
this._focusOnMove = true;
|
||||
this._listeningForScroll = false;
|
||||
},
|
||||
}
|
||||
|
||||
_handleDiffRenderStart() {
|
||||
this._listeningForScroll = true;
|
||||
},
|
||||
}
|
||||
|
||||
createCommentInPlace() {
|
||||
const diffWithRangeSelected = this.diffs.find(diff => {
|
||||
@@ -258,7 +266,7 @@
|
||||
this.getTargetDiffElement().addDraftAtLine(line);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an object describing the location of the cursor. Such as
|
||||
@@ -290,7 +298,7 @@
|
||||
leftSide: cell.matches('.left'),
|
||||
number: parseInt(number, 10),
|
||||
};
|
||||
},
|
||||
}
|
||||
|
||||
_getViewMode() {
|
||||
if (!this.diffRow) {
|
||||
@@ -302,24 +310,24 @@
|
||||
} else {
|
||||
return DiffViewMode.UNIFIED;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_rowHasSide(row) {
|
||||
const selector = (this.side === DiffSides.LEFT ? '.left' : '.right') +
|
||||
' + .content';
|
||||
return !!row.querySelector(selector);
|
||||
},
|
||||
}
|
||||
|
||||
_isFirstRowOfChunk(row) {
|
||||
const parentClassList = row.parentNode.classList;
|
||||
return parentClassList.contains('section') &&
|
||||
parentClassList.contains('delta') &&
|
||||
!row.previousSibling;
|
||||
},
|
||||
}
|
||||
|
||||
_rowHasThread(row) {
|
||||
return row.querySelector('.thread-group');
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* If we jumped to a row where there is no content on the current side then
|
||||
@@ -331,7 +339,7 @@
|
||||
this.side = this.side === DiffSides.LEFT ?
|
||||
DiffSides.RIGHT : DiffSides.LEFT;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_isTargetBlank() {
|
||||
if (!this.diffRow) {
|
||||
@@ -341,14 +349,14 @@
|
||||
const actions = this._getActionsForRow();
|
||||
return (this.side === DiffSides.LEFT && !actions.left) ||
|
||||
(this.side === DiffSides.RIGHT && !actions.right);
|
||||
},
|
||||
}
|
||||
|
||||
_rowChanged(newRow, oldRow) {
|
||||
if (oldRow) {
|
||||
oldRow.classList.remove(LEFT_SIDE_CLASS, RIGHT_SIDE_CLASS);
|
||||
}
|
||||
this._updateSideClass();
|
||||
},
|
||||
}
|
||||
|
||||
_updateSideClass() {
|
||||
if (!this.diffRow) {
|
||||
@@ -358,11 +366,11 @@
|
||||
this.diffRow);
|
||||
this.toggleClass(RIGHT_SIDE_CLASS, this.side === DiffSides.RIGHT,
|
||||
this.diffRow);
|
||||
},
|
||||
}
|
||||
|
||||
_isActionType(type) {
|
||||
return type !== 'blank' && type !== 'contextControl';
|
||||
},
|
||||
}
|
||||
|
||||
_getActionsForRow() {
|
||||
const actions = {left: false, right: false};
|
||||
@@ -373,18 +381,18 @@
|
||||
this.diffRow.getAttribute('right-type'));
|
||||
}
|
||||
return actions;
|
||||
},
|
||||
}
|
||||
|
||||
_getStops() {
|
||||
return this.diffs.reduce(
|
||||
(stops, diff) => {
|
||||
return stops.concat(diff.getCursorStops());
|
||||
}, []);
|
||||
},
|
||||
}
|
||||
|
||||
_updateStops() {
|
||||
this.$.cursorManager.stops = this._getStops();
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup and tear down on-render listeners for any diffs that are added or
|
||||
@@ -420,7 +428,7 @@
|
||||
'render-content', 'handleDiffUpdate');
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_findRowByNumberAndFile(targetNumber, side, opt_path) {
|
||||
let stops;
|
||||
@@ -437,6 +445,8 @@
|
||||
return stops[i];
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrDiffCursor.is, GrDiffCursor);
|
||||
})();
|
||||
|
||||
@@ -17,24 +17,32 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-diff-highlight',
|
||||
/**
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
*/
|
||||
class GrDiffHighlight extends Polymer.mixinBehaviors( [
|
||||
Gerrit.FireBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-diff-highlight'; }
|
||||
|
||||
properties: {
|
||||
static get properties() {
|
||||
return {
|
||||
/** @type {!Array<!Gerrit.HoveredRange>} */
|
||||
commentRanges: {
|
||||
type: Array,
|
||||
notify: true,
|
||||
},
|
||||
loggedIn: Boolean,
|
||||
/**
|
||||
commentRanges: {
|
||||
type: Array,
|
||||
notify: true,
|
||||
},
|
||||
loggedIn: Boolean,
|
||||
/**
|
||||
* querySelector can return null, so needs to be nullable.
|
||||
*
|
||||
* @type {?HTMLElement}
|
||||
* */
|
||||
_cachedDiffBuilder: Object,
|
||||
_cachedDiffBuilder: Object,
|
||||
|
||||
/**
|
||||
/**
|
||||
* Which range is currently selected by the user.
|
||||
* Stored in order to add a range-based comment
|
||||
* later.
|
||||
@@ -42,21 +50,22 @@
|
||||
*
|
||||
* @type {{side: string, range: Gerrit.Range}|undefined}
|
||||
*/
|
||||
selectedRange: {
|
||||
type: Object,
|
||||
notify: true,
|
||||
},
|
||||
},
|
||||
selectedRange: {
|
||||
type: Object,
|
||||
notify: true,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
behaviors: [
|
||||
Gerrit.FireBehavior,
|
||||
],
|
||||
|
||||
listeners: {
|
||||
'comment-thread-mouseleave': '_handleCommentThreadMouseleave',
|
||||
'comment-thread-mouseenter': '_handleCommentThreadMouseenter',
|
||||
'create-comment-requested': '_handleRangeCommentRequest',
|
||||
},
|
||||
created() {
|
||||
super.created();
|
||||
this.addEventListener('comment-thread-mouseleave',
|
||||
e => this._handleCommentThreadMouseleave(e));
|
||||
this.addEventListener('comment-thread-mouseenter',
|
||||
e => this._handleCommentThreadMouseenter(e));
|
||||
this.addEventListener('create-comment-requested',
|
||||
e => this._handleRangeCommentRequest(e));
|
||||
}
|
||||
|
||||
get diffBuilder() {
|
||||
if (!this._cachedDiffBuilder) {
|
||||
@@ -64,7 +73,7 @@
|
||||
Polymer.dom(this).querySelector('gr-diff-builder');
|
||||
}
|
||||
return this._cachedDiffBuilder;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines side/line/range for a DOM selection and shows a tooltip.
|
||||
@@ -93,7 +102,7 @@
|
||||
this.debounce(
|
||||
'selectionChange', () => this._handleSelection(selection, isMouseUp),
|
||||
10);
|
||||
},
|
||||
}
|
||||
|
||||
_getThreadEl(e) {
|
||||
const path = Polymer.dom(e).path || [];
|
||||
@@ -101,7 +110,7 @@
|
||||
if (pathEl.classList.contains('comment-thread')) return pathEl;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
}
|
||||
|
||||
_handleCommentThreadMouseenter(e) {
|
||||
const threadEl = this._getThreadEl(e);
|
||||
@@ -110,7 +119,7 @@
|
||||
if (index !== undefined) {
|
||||
this.set(['commentRanges', index, 'hovering'], true);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_handleCommentThreadMouseleave(e) {
|
||||
const threadEl = this._getThreadEl(e);
|
||||
@@ -119,7 +128,7 @@
|
||||
if (index !== undefined) {
|
||||
this.set(['commentRanges', index, 'hovering'], false);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_indexForThreadEl(threadEl) {
|
||||
const side = threadEl.getAttribute('comment-side');
|
||||
@@ -128,7 +137,7 @@
|
||||
if (!range) return undefined;
|
||||
|
||||
return this._indexOfCommentRange(side, range);
|
||||
},
|
||||
}
|
||||
|
||||
_indexOfCommentRange(side, range) {
|
||||
function rangesEqual(a, b) {
|
||||
@@ -146,7 +155,7 @@
|
||||
|
||||
return this.commentRanges.findIndex(commentRange =>
|
||||
commentRange.side === side && rangesEqual(commentRange.range, range));
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current normalized selection.
|
||||
@@ -184,7 +193,7 @@
|
||||
end: endRange.end,
|
||||
};
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a specific DOM Range.
|
||||
@@ -198,7 +207,7 @@
|
||||
end: this._normalizeSelectionSide(
|
||||
range.endContainer, range.endOffset),
|
||||
}, domRange);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust triple click selection for the whole line.
|
||||
@@ -239,7 +248,7 @@
|
||||
};
|
||||
}
|
||||
return range;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert DOM Range selection to concrete numbers (line, column, side).
|
||||
@@ -296,7 +305,7 @@
|
||||
line,
|
||||
column,
|
||||
};
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* The only line in which add a comment tooltip is cut off is the first
|
||||
@@ -312,7 +321,7 @@
|
||||
}
|
||||
actionBox.positionBelow = true;
|
||||
actionBox.placeBelow(range);
|
||||
},
|
||||
}
|
||||
|
||||
_isRangeValid(range) {
|
||||
if (!range || !range.start || !range.end) {
|
||||
@@ -326,7 +335,7 @@
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
}
|
||||
|
||||
_handleSelection(selection, isMouseUp) {
|
||||
const normalizedRange = this._getNormalizedRange(selection);
|
||||
@@ -398,12 +407,12 @@
|
||||
} else {
|
||||
this._positionActionBox(actionBox, start.line, start.node);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_fireCreateRangeComment(side, range) {
|
||||
this.fire('create-range-comment', {side, range});
|
||||
this._removeActionBox();
|
||||
},
|
||||
}
|
||||
|
||||
_handleRangeCommentRequest(e) {
|
||||
e.stopPropagation();
|
||||
@@ -412,7 +421,7 @@
|
||||
}
|
||||
const {side, range} = this.selectedRange;
|
||||
this._fireCreateRangeComment(side, range);
|
||||
},
|
||||
}
|
||||
|
||||
_removeActionBox() {
|
||||
this.selectedRange = undefined;
|
||||
@@ -420,7 +429,7 @@
|
||||
if (actionBox) {
|
||||
Polymer.dom(this.root).removeChild(actionBox);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_convertOffsetToColumn(el, offset) {
|
||||
if (el instanceof Element && el.classList.contains('content')) {
|
||||
@@ -436,7 +445,7 @@
|
||||
}
|
||||
}
|
||||
return offset;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Traverse Element from right to left, call callback for each node.
|
||||
@@ -461,7 +470,7 @@
|
||||
}
|
||||
node = nextNode;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Get length of a node. If the node is a content node, then only give the
|
||||
@@ -476,6 +485,8 @@
|
||||
} else {
|
||||
return GrAnnotation.getLength(node);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrDiffHighlight.is, GrDiffHighlight);
|
||||
})();
|
||||
|
||||
@@ -68,15 +68,23 @@
|
||||
RIGHT: 'right',
|
||||
};
|
||||
|
||||
/**
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
* @appliesMixin Gerrit.PatchSetMixin
|
||||
*/
|
||||
/**
|
||||
* Wrapper around gr-diff.
|
||||
*
|
||||
* Webcomponent fetching diffs and related data from restAPI and passing them
|
||||
* to the presentational gr-diff for rendering.
|
||||
*/
|
||||
Polymer({
|
||||
is: 'gr-diff-host',
|
||||
|
||||
class GrDiffHost extends Polymer.mixinBehaviors( [
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.PatchSetBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-diff-host'; }
|
||||
/**
|
||||
* Fired when the user selects a line.
|
||||
* @event line-selected
|
||||
@@ -94,182 +102,191 @@
|
||||
* @event diff-comments-modified
|
||||
*/
|
||||
|
||||
properties: {
|
||||
changeNum: String,
|
||||
noAutoRender: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
/** @type {?} */
|
||||
patchRange: Object,
|
||||
path: String,
|
||||
prefs: {
|
||||
type: Object,
|
||||
},
|
||||
projectName: String,
|
||||
displayLine: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
isImageDiff: {
|
||||
type: Boolean,
|
||||
computed: '_computeIsImageDiff(diff)',
|
||||
notify: true,
|
||||
},
|
||||
commitRange: Object,
|
||||
filesWeblinks: {
|
||||
type: Object,
|
||||
value() {
|
||||
return {};
|
||||
static get properties() {
|
||||
return {
|
||||
changeNum: String,
|
||||
noAutoRender: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
/** @type {?} */
|
||||
patchRange: Object,
|
||||
path: String,
|
||||
prefs: {
|
||||
type: Object,
|
||||
},
|
||||
projectName: String,
|
||||
displayLine: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
isImageDiff: {
|
||||
type: Boolean,
|
||||
computed: '_computeIsImageDiff(diff)',
|
||||
notify: true,
|
||||
},
|
||||
commitRange: Object,
|
||||
filesWeblinks: {
|
||||
type: Object,
|
||||
value() {
|
||||
return {};
|
||||
},
|
||||
notify: true,
|
||||
},
|
||||
hidden: {
|
||||
type: Boolean,
|
||||
reflectToAttribute: true,
|
||||
},
|
||||
noRenderOnPrefsChange: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
comments: {
|
||||
type: Object,
|
||||
observer: '_commentsChanged',
|
||||
},
|
||||
lineWrapping: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
viewMode: {
|
||||
type: String,
|
||||
value: DiffViewMode.SIDE_BY_SIDE,
|
||||
},
|
||||
notify: true,
|
||||
},
|
||||
hidden: {
|
||||
type: Boolean,
|
||||
reflectToAttribute: true,
|
||||
},
|
||||
noRenderOnPrefsChange: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
comments: {
|
||||
type: Object,
|
||||
observer: '_commentsChanged',
|
||||
},
|
||||
lineWrapping: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
viewMode: {
|
||||
type: String,
|
||||
value: DiffViewMode.SIDE_BY_SIDE,
|
||||
},
|
||||
|
||||
/**
|
||||
/**
|
||||
* Special line number which should not be collapsed into a shared region.
|
||||
* @type {{
|
||||
* number: number,
|
||||
* leftSide: {boolean}
|
||||
* }|null}
|
||||
*/
|
||||
lineOfInterest: Object,
|
||||
lineOfInterest: Object,
|
||||
|
||||
/**
|
||||
/**
|
||||
* If the diff fails to load, show the failure message in the diff rather
|
||||
* than bubbling the error up to the whole page. This is useful for when
|
||||
* loading inline diffs because one diff failing need not mark the whole
|
||||
* page with a failure.
|
||||
*/
|
||||
showLoadFailure: Boolean,
|
||||
showLoadFailure: Boolean,
|
||||
|
||||
isBlameLoaded: {
|
||||
type: Boolean,
|
||||
notify: true,
|
||||
computed: '_computeIsBlameLoaded(_blame)',
|
||||
},
|
||||
isBlameLoaded: {
|
||||
type: Boolean,
|
||||
notify: true,
|
||||
computed: '_computeIsBlameLoaded(_blame)',
|
||||
},
|
||||
|
||||
_loggedIn: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_loggedIn: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
_loading: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_loading: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
/** @type {?string} */
|
||||
_errorMessage: {
|
||||
type: String,
|
||||
value: null,
|
||||
},
|
||||
/** @type {?string} */
|
||||
_errorMessage: {
|
||||
type: String,
|
||||
value: null,
|
||||
},
|
||||
|
||||
/** @type {?Object} */
|
||||
_baseImage: Object,
|
||||
/** @type {?Object} */
|
||||
_revisionImage: Object,
|
||||
/**
|
||||
/** @type {?Object} */
|
||||
_baseImage: Object,
|
||||
/** @type {?Object} */
|
||||
_revisionImage: Object,
|
||||
/**
|
||||
* This is a DiffInfo object.
|
||||
*/
|
||||
diff: {
|
||||
type: Object,
|
||||
notify: true,
|
||||
},
|
||||
diff: {
|
||||
type: Object,
|
||||
notify: true,
|
||||
},
|
||||
|
||||
/** @type {?Object} */
|
||||
_blame: {
|
||||
type: Object,
|
||||
value: null,
|
||||
},
|
||||
/** @type {?Object} */
|
||||
_blame: {
|
||||
type: Object,
|
||||
value: null,
|
||||
},
|
||||
|
||||
/**
|
||||
/**
|
||||
* @type {!Array<!Gerrit.CoverageRange>}
|
||||
*/
|
||||
_coverageRanges: {
|
||||
type: Array,
|
||||
value: () => [],
|
||||
},
|
||||
_coverageRanges: {
|
||||
type: Array,
|
||||
value: () => [],
|
||||
},
|
||||
|
||||
_loadedWhitespaceLevel: String,
|
||||
_loadedWhitespaceLevel: String,
|
||||
|
||||
_parentIndex: {
|
||||
type: Number,
|
||||
computed: '_computeParentIndex(patchRange.*)',
|
||||
},
|
||||
_parentIndex: {
|
||||
type: Number,
|
||||
computed: '_computeParentIndex(patchRange.*)',
|
||||
},
|
||||
|
||||
_syntaxHighlightingEnabled: {
|
||||
type: Boolean,
|
||||
computed:
|
||||
_syntaxHighlightingEnabled: {
|
||||
type: Boolean,
|
||||
computed:
|
||||
'_isSyntaxHighlightingEnabled(prefs.*, diff)',
|
||||
},
|
||||
},
|
||||
|
||||
_layers: {
|
||||
type: Array,
|
||||
value: [],
|
||||
},
|
||||
},
|
||||
_layers: {
|
||||
type: Array,
|
||||
value: [],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
behaviors: [
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.PatchSetBehavior,
|
||||
],
|
||||
|
||||
listeners: {
|
||||
// These are named inconsistently for a reason:
|
||||
// The create-comment event is fired to indicate that we should
|
||||
// create a comment.
|
||||
// The comment-* events are just notifying that the comments did already
|
||||
// change in some way, and that we should update any models we may want
|
||||
// to keep in sync.
|
||||
'create-comment': '_handleCreateComment',
|
||||
'comment-discard': '_handleCommentDiscard',
|
||||
'comment-update': '_handleCommentUpdate',
|
||||
'comment-save': '_handleCommentSave',
|
||||
|
||||
'render-start': '_handleRenderStart',
|
||||
'render-content': '_handleRenderContent',
|
||||
|
||||
'normalize-range': '_handleNormalizeRange',
|
||||
'diff-context-expanded': '_handleDiffContextExpanded',
|
||||
},
|
||||
|
||||
observers: [
|
||||
'_whitespaceChanged(prefs.ignore_whitespace, _loadedWhitespaceLevel,' +
|
||||
static get observers() {
|
||||
return [
|
||||
'_whitespaceChanged(prefs.ignore_whitespace, _loadedWhitespaceLevel,' +
|
||||
' noRenderOnPrefsChange)',
|
||||
'_syntaxHighlightingChanged(noRenderOnPrefsChange, prefs.*)',
|
||||
],
|
||||
'_syntaxHighlightingChanged(noRenderOnPrefsChange, prefs.*)',
|
||||
];
|
||||
}
|
||||
|
||||
created() {
|
||||
super.created();
|
||||
this.addEventListener(
|
||||
// These are named inconsistently for a reason:
|
||||
// The create-comment event is fired to indicate that we should
|
||||
// create a comment.
|
||||
// The comment-* events are just notifying that the comments did already
|
||||
// change in some way, and that we should update any models we may want
|
||||
// to keep in sync.
|
||||
'create-comment',
|
||||
e => this._handleCreateComment(e));
|
||||
this.addEventListener('comment-discard',
|
||||
e => this._handleCommentDiscard(e));
|
||||
this.addEventListener('comment-update',
|
||||
e => this._handleCommentUpdate(e));
|
||||
this.addEventListener('comment-save',
|
||||
e => this._handleCommentSave(e));
|
||||
this.addEventListener('render-start',
|
||||
() => this._handleRenderStart());
|
||||
this.addEventListener('render-content',
|
||||
() => this._handleRenderContent());
|
||||
this.addEventListener('normalize-range',
|
||||
event => this._handleNormalizeRange(event));
|
||||
this.addEventListener('diff-context-expanded',
|
||||
event => this._handleDiffContextExpanded(event));
|
||||
}
|
||||
|
||||
ready() {
|
||||
super.ready();
|
||||
if (this._canReload()) {
|
||||
this.reload();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
attached() {
|
||||
super.attached();
|
||||
this._getLoggedIn().then(loggedIn => {
|
||||
this._loggedIn = loggedIn;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean=} shouldReportMetric indicate a new Diff Page. This is a
|
||||
@@ -364,7 +381,7 @@
|
||||
console.warn('Error encountered loading diff:', err);
|
||||
})
|
||||
.then(() => { this._loading = false; });
|
||||
},
|
||||
}
|
||||
|
||||
_getFilesWeblinks(diff) {
|
||||
if (!this.commitRange) {
|
||||
@@ -378,30 +395,30 @@
|
||||
this.projectName, this.commitRange.commit, this.path,
|
||||
{weblinks: diff && diff.meta_b && diff.meta_b.web_links}),
|
||||
};
|
||||
},
|
||||
}
|
||||
|
||||
/** Cancel any remaining diff builder rendering work. */
|
||||
cancel() {
|
||||
this.$.diff.cancel();
|
||||
},
|
||||
}
|
||||
|
||||
/** @return {!Array<!HTMLElement>} */
|
||||
getCursorStops() {
|
||||
return this.$.diff.getCursorStops();
|
||||
},
|
||||
}
|
||||
|
||||
/** @return {boolean} */
|
||||
isRangeSelected() {
|
||||
return this.$.diff.isRangeSelected();
|
||||
},
|
||||
}
|
||||
|
||||
createRangeComment() {
|
||||
return this.$.diff.createRangeComment();
|
||||
},
|
||||
}
|
||||
|
||||
toggleLeftDiff() {
|
||||
this.$.diff.toggleLeftDiff();
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Load and display blame information for the base of the diff.
|
||||
@@ -418,12 +435,12 @@
|
||||
|
||||
this._blame = blame;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
/** Unload blame information for the diff. */
|
||||
clearBlame() {
|
||||
this._blame = null;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* The thread elements in this diff, in no particular order.
|
||||
@@ -432,31 +449,31 @@
|
||||
getThreadEls() {
|
||||
return Array.from(
|
||||
Polymer.dom(this.$.diff).querySelectorAll('.comment-thread'));
|
||||
},
|
||||
}
|
||||
|
||||
/** @param {HTMLElement} el */
|
||||
addDraftAtLine(el) {
|
||||
this.$.diff.addDraftAtLine(el);
|
||||
},
|
||||
}
|
||||
|
||||
clearDiffContent() {
|
||||
this.$.diff.clearDiffContent();
|
||||
},
|
||||
}
|
||||
|
||||
expandAllContext() {
|
||||
this.$.diff.expandAllContext();
|
||||
},
|
||||
}
|
||||
|
||||
/** @return {!Promise} */
|
||||
_getLoggedIn() {
|
||||
return this.$.restAPI.getLoggedIn();
|
||||
},
|
||||
}
|
||||
|
||||
/** @return {boolean}} */
|
||||
_canReload() {
|
||||
return !!this.changeNum && !!this.patchRange && !!this.path &&
|
||||
!this.noAutoRender;
|
||||
},
|
||||
}
|
||||
|
||||
/** @return {!Promise<!Object>} */
|
||||
_getDiff() {
|
||||
@@ -472,7 +489,7 @@
|
||||
reject)
|
||||
.then(resolve);
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleGetDiffError(response) {
|
||||
// Loading the diff may respond with 409 if the file is too large. In this
|
||||
@@ -492,7 +509,7 @@
|
||||
}
|
||||
|
||||
this.fire('page-error', {response});
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Report info about the diff response.
|
||||
@@ -533,7 +550,7 @@
|
||||
this.$.reporting.reportInteraction(EVENT_NONZERO_REBASE,
|
||||
percentRebaseDelta);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} diff
|
||||
@@ -550,7 +567,7 @@
|
||||
this._revisionImage = null;
|
||||
return Promise.resolve();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} diff
|
||||
@@ -558,7 +575,7 @@
|
||||
*/
|
||||
_computeIsImageDiff(diff) {
|
||||
return isImageDiff(diff);
|
||||
},
|
||||
}
|
||||
|
||||
_commentsChanged(newComments) {
|
||||
const allComments = [];
|
||||
@@ -579,7 +596,7 @@
|
||||
const threadEl = this._createThreadElement(thread);
|
||||
this._attachThreadElement(threadEl);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Array<!Object>} comments
|
||||
@@ -621,7 +638,7 @@
|
||||
threads.push(newThread);
|
||||
}
|
||||
return threads;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} blame
|
||||
@@ -629,7 +646,7 @@
|
||||
*/
|
||||
_computeIsBlameLoaded(blame) {
|
||||
return !!blame;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} diff
|
||||
@@ -638,7 +655,7 @@
|
||||
_getImages(diff) {
|
||||
return this.$.restAPI.getImagesForDiff(this.changeNum, diff,
|
||||
this.patchRange);
|
||||
},
|
||||
}
|
||||
|
||||
/** @param {CustomEvent} e */
|
||||
_handleCreateComment(e) {
|
||||
@@ -648,7 +665,7 @@
|
||||
threadEl.addOrEditDraft(lineNum, range);
|
||||
|
||||
this.$.reporting.recordDraftInteraction();
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets or creates a comment thread at a given location.
|
||||
@@ -675,18 +692,18 @@
|
||||
this._attachThreadElement(threadEl);
|
||||
}
|
||||
return threadEl;
|
||||
},
|
||||
}
|
||||
|
||||
_attachThreadElement(threadEl) {
|
||||
Polymer.dom(this.$.diff).appendChild(threadEl);
|
||||
},
|
||||
}
|
||||
|
||||
_clearThreads() {
|
||||
for (const threadEl of this.getThreadEls()) {
|
||||
const parent = Polymer.dom(threadEl).parentNode;
|
||||
Polymer.dom(parent).removeChild(threadEl);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_createThreadElement(thread) {
|
||||
const threadEl = document.createElement('gr-comment-thread');
|
||||
@@ -717,7 +734,7 @@
|
||||
};
|
||||
threadEl.addEventListener('thread-discard', threadDiscardListener);
|
||||
return threadEl;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a comment thread element at a given location.
|
||||
@@ -746,7 +763,7 @@
|
||||
const filteredThreadEls = this._filterThreadElsForLocation(
|
||||
this.getThreadEls(), line, commentSide).filter(matchesRange);
|
||||
return filteredThreadEls.length ? filteredThreadEls[0] : null;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Array<!HTMLElement>} threadEls
|
||||
@@ -791,14 +808,14 @@
|
||||
}
|
||||
return threadEls.filter(threadEl =>
|
||||
matchers.some(matcher => matcher(threadEl)));
|
||||
},
|
||||
}
|
||||
|
||||
_getIgnoreWhitespace() {
|
||||
if (!this.prefs || !this.prefs.ignore_whitespace) {
|
||||
return WHITESPACE_IGNORE_NONE;
|
||||
}
|
||||
return this.prefs.ignore_whitespace;
|
||||
},
|
||||
}
|
||||
|
||||
_whitespaceChanged(
|
||||
preferredWhitespaceLevel, loadedWhitespaceLevel,
|
||||
@@ -816,7 +833,7 @@
|
||||
!noRenderOnPrefsChange) {
|
||||
this.reload();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_syntaxHighlightingChanged(noRenderOnPrefsChange, prefsChangeRecord) {
|
||||
// Polymer 2: check for undefined
|
||||
@@ -834,7 +851,7 @@
|
||||
if (!noRenderOnPrefsChange) {
|
||||
this.reload();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} patchRangeRecord
|
||||
@@ -843,7 +860,7 @@
|
||||
_computeParentIndex(patchRangeRecord) {
|
||||
return this.isMergeParent(patchRangeRecord.base.basePatchNum) ?
|
||||
this.getParentIndex(patchRangeRecord.base.basePatchNum) : null;
|
||||
},
|
||||
}
|
||||
|
||||
_handleCommentSave(e) {
|
||||
const comment = e.detail.comment;
|
||||
@@ -851,13 +868,13 @@
|
||||
const idx = this._findDraftIndex(comment, side);
|
||||
this.set(['comments', side, idx], comment);
|
||||
this._handleCommentSaveOrDiscard();
|
||||
},
|
||||
}
|
||||
|
||||
_handleCommentDiscard(e) {
|
||||
const comment = e.detail.comment;
|
||||
this._removeComment(comment);
|
||||
this._handleCommentSaveOrDiscard();
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Closure annotation for Polymer.prototype.push is off. Submitted PR:
|
||||
@@ -878,17 +895,17 @@
|
||||
} else { // Create new draft.
|
||||
this.push(['comments', side], comment);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_handleCommentSaveOrDiscard() {
|
||||
this.dispatchEvent(new CustomEvent(
|
||||
'diff-comments-modified', {bubbles: true, composed: true}));
|
||||
},
|
||||
}
|
||||
|
||||
_removeComment(comment) {
|
||||
const side = comment.__commentSide;
|
||||
this._removeCommentFromSide(comment, side);
|
||||
},
|
||||
}
|
||||
|
||||
_removeCommentFromSide(comment, side) {
|
||||
let idx = this._findCommentIndex(comment, side);
|
||||
@@ -898,7 +915,7 @@
|
||||
if (idx !== -1) {
|
||||
this.splice('comments.' + side, idx, 1);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/** @return {number} */
|
||||
_findCommentIndex(comment, side) {
|
||||
@@ -906,7 +923,7 @@
|
||||
return -1;
|
||||
}
|
||||
return this.comments[side].findIndex(item => item.id === comment.id);
|
||||
},
|
||||
}
|
||||
|
||||
/** @return {number} */
|
||||
_findDraftIndex(comment, side) {
|
||||
@@ -915,7 +932,7 @@
|
||||
}
|
||||
return this.comments[side].findIndex(
|
||||
item => item.__draftID === comment.__draftID);
|
||||
},
|
||||
}
|
||||
|
||||
_isSyntaxHighlightingEnabled(preferenceChangeRecord, diff) {
|
||||
if (!preferenceChangeRecord ||
|
||||
@@ -926,7 +943,7 @@
|
||||
}
|
||||
return !this._anyLineTooLong(diff) &&
|
||||
this.$.diff.getDiffLength(diff) <= SYNTAX_MAX_DIFF_LENGTH;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {boolean} whether any of the lines in diff are longer
|
||||
@@ -940,7 +957,7 @@
|
||||
(section.a || []).concat(section.b || []);
|
||||
return lines.some(line => line.length >= SYNTAX_MAX_LINE_LENGTH);
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_listenToViewportRender() {
|
||||
const renderUpdateListener = start => {
|
||||
@@ -951,26 +968,28 @@
|
||||
};
|
||||
|
||||
this.$.syntaxLayer.addListener(renderUpdateListener);
|
||||
},
|
||||
}
|
||||
|
||||
_handleRenderStart() {
|
||||
this.$.reporting.time(TimingLabel.TOTAL);
|
||||
this.$.reporting.time(TimingLabel.CONTENT);
|
||||
},
|
||||
}
|
||||
|
||||
_handleRenderContent() {
|
||||
this.$.reporting.timeEnd(TimingLabel.CONTENT);
|
||||
},
|
||||
}
|
||||
|
||||
_handleNormalizeRange(event) {
|
||||
this.$.reporting.reportInteraction('normalize-range',
|
||||
`Modified invalid comment range on l. ${event.detail.lineNum}` +
|
||||
` of the ${event.detail.side} side`);
|
||||
},
|
||||
}
|
||||
|
||||
_handleDiffContextExpanded(event) {
|
||||
this.$.reporting.reportInteraction(
|
||||
'diff-context-expanded', event.detail.numLines);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrDiffHost.is, GrDiffHost);
|
||||
})();
|
||||
|
||||
@@ -17,34 +17,38 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-diff-mode-selector',
|
||||
class GrDiffModeSelector extends Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element)) {
|
||||
static get is() { return 'gr-diff-mode-selector'; }
|
||||
|
||||
properties: {
|
||||
mode: {
|
||||
type: String,
|
||||
notify: true,
|
||||
},
|
||||
static get properties() {
|
||||
return {
|
||||
mode: {
|
||||
type: String,
|
||||
notify: true,
|
||||
},
|
||||
|
||||
/**
|
||||
/**
|
||||
* If set to true, the user's preference will be updated every time a
|
||||
* button is tapped. Don't set to true if there is no user.
|
||||
*/
|
||||
saveOnChange: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
/** @type {?} */
|
||||
_VIEW_MODES: {
|
||||
type: Object,
|
||||
readOnly: true,
|
||||
value: {
|
||||
SIDE_BY_SIDE: 'SIDE_BY_SIDE',
|
||||
UNIFIED: 'UNIFIED_DIFF',
|
||||
saveOnChange: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
/** @type {?} */
|
||||
_VIEW_MODES: {
|
||||
type: Object,
|
||||
readOnly: true,
|
||||
value: {
|
||||
SIDE_BY_SIDE: 'SIDE_BY_SIDE',
|
||||
UNIFIED: 'UNIFIED_DIFF',
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the mode. If save on change is enabled also update the preference.
|
||||
@@ -54,18 +58,20 @@
|
||||
this.$.restAPI.savePreferences({diff_view: newMode});
|
||||
}
|
||||
this.mode = newMode;
|
||||
},
|
||||
}
|
||||
|
||||
_computeSelectedClass(diffViewMode, buttonViewMode) {
|
||||
return buttonViewMode === diffViewMode ? 'selected' : '';
|
||||
},
|
||||
}
|
||||
|
||||
_handleSideBySideTap() {
|
||||
this.setMode(this._VIEW_MODES.SIDE_BY_SIDE);
|
||||
},
|
||||
}
|
||||
|
||||
_handleUnifiedTap() {
|
||||
this.setMode(this._VIEW_MODES.UNIFIED);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrDiffModeSelector.is, GrDiffModeSelector);
|
||||
})();
|
||||
|
||||
@@ -17,39 +17,44 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-diff-preferences-dialog',
|
||||
/**
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
*/
|
||||
class GrDiffPreferencesDialog extends Polymer.mixinBehaviors( [
|
||||
Gerrit.FireBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-diff-preferences-dialog'; }
|
||||
|
||||
properties: {
|
||||
static get properties() {
|
||||
return {
|
||||
/** @type {?} */
|
||||
diffPrefs: Object,
|
||||
diffPrefs: Object,
|
||||
|
||||
_diffPrefsChanged: Boolean,
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
Gerrit.FireBehavior,
|
||||
],
|
||||
_diffPrefsChanged: Boolean,
|
||||
};
|
||||
}
|
||||
|
||||
getFocusStops() {
|
||||
return {
|
||||
start: this.$.diffPreferences.$.contextSelect,
|
||||
end: this.$.saveButton,
|
||||
};
|
||||
},
|
||||
}
|
||||
|
||||
resetFocus() {
|
||||
this.$.diffPreferences.$.contextSelect.focus();
|
||||
},
|
||||
}
|
||||
|
||||
_computeHeaderClass(changed) {
|
||||
return changed ? 'edited' : '';
|
||||
},
|
||||
}
|
||||
|
||||
_handleCancelDiff(e) {
|
||||
e.stopPropagation();
|
||||
this.$.diffPrefsOverlay.close();
|
||||
},
|
||||
}
|
||||
|
||||
open() {
|
||||
this.$.diffPrefsOverlay.open().then(() => {
|
||||
@@ -57,7 +62,7 @@
|
||||
this.$.diffPrefsOverlay.setFocusStops(focusStops);
|
||||
this.resetFocus();
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleSaveDiffPreferences() {
|
||||
this.$.diffPreferences.save().then(() => {
|
||||
@@ -65,6 +70,8 @@
|
||||
|
||||
this.$.diffPrefsOverlay.close();
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrDiffPreferencesDialog.is, GrDiffPreferencesDialog);
|
||||
})();
|
||||
|
||||
@@ -64,71 +64,77 @@
|
||||
* that the part that is within the context or has comments is shown, while
|
||||
* the rest is not.
|
||||
*/
|
||||
Polymer({
|
||||
is: 'gr-diff-processor',
|
||||
class GrDiffProcessor extends Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element)) {
|
||||
static get is() { return 'gr-diff-processor'; }
|
||||
|
||||
properties: {
|
||||
static get properties() {
|
||||
return {
|
||||
|
||||
/**
|
||||
/**
|
||||
* The amount of context around collapsed groups.
|
||||
*/
|
||||
context: Number,
|
||||
context: Number,
|
||||
|
||||
/**
|
||||
/**
|
||||
* The array of groups output by the processor.
|
||||
*/
|
||||
groups: {
|
||||
type: Array,
|
||||
notify: true,
|
||||
},
|
||||
groups: {
|
||||
type: Array,
|
||||
notify: true,
|
||||
},
|
||||
|
||||
/**
|
||||
/**
|
||||
* Locations that should not be collapsed, including the locations of
|
||||
* comments.
|
||||
*/
|
||||
keyLocations: {
|
||||
type: Object,
|
||||
value() { return {left: {}, right: {}}; },
|
||||
},
|
||||
keyLocations: {
|
||||
type: Object,
|
||||
value() { return {left: {}, right: {}}; },
|
||||
},
|
||||
|
||||
/**
|
||||
/**
|
||||
* The maximum number of lines to process synchronously.
|
||||
*/
|
||||
_asyncThreshold: {
|
||||
type: Number,
|
||||
value: 64,
|
||||
},
|
||||
_asyncThreshold: {
|
||||
type: Number,
|
||||
value: 64,
|
||||
},
|
||||
|
||||
/** @type {?number} */
|
||||
_nextStepHandle: Number,
|
||||
/**
|
||||
/** @type {?number} */
|
||||
_nextStepHandle: Number,
|
||||
/**
|
||||
* The promise last returned from `process()` while the asynchronous
|
||||
* processing is running - `null` otherwise. Provides a `cancel()`
|
||||
* method that rejects it with `{isCancelled: true}`.
|
||||
* @type {?Object}
|
||||
*/
|
||||
_processPromise: {
|
||||
type: Object,
|
||||
value: null,
|
||||
},
|
||||
_isScrolling: Boolean,
|
||||
},
|
||||
_processPromise: {
|
||||
type: Object,
|
||||
value: null,
|
||||
},
|
||||
_isScrolling: Boolean,
|
||||
};
|
||||
}
|
||||
|
||||
attached() {
|
||||
super.attached();
|
||||
this.listen(window, 'scroll', '_handleWindowScroll');
|
||||
},
|
||||
}
|
||||
|
||||
detached() {
|
||||
super.detached();
|
||||
this.cancel();
|
||||
this.unlisten(window, 'scroll', '_handleWindowScroll');
|
||||
},
|
||||
}
|
||||
|
||||
_handleWindowScroll() {
|
||||
this._isScrolling = true;
|
||||
this.debounce('resetIsScrolling', () => {
|
||||
this._isScrolling = false;
|
||||
}, 50);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously process the diff chunks into groups. As it processes, it
|
||||
@@ -196,7 +202,7 @@
|
||||
}));
|
||||
return this._processPromise
|
||||
.finally(() => { this._processPromise = null; });
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel any jobs that are running.
|
||||
@@ -209,7 +215,7 @@
|
||||
if (this._processPromise) {
|
||||
this._processPromise.cancel();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the next uncollapsible chunk, or the next collapsible chunks.
|
||||
@@ -236,15 +242,15 @@
|
||||
|
||||
return this._processCollapsibleChunks(
|
||||
state, chunks, firstUncollapsibleChunkIndex);
|
||||
},
|
||||
}
|
||||
|
||||
_linesLeft(chunk) {
|
||||
return chunk.ab || chunk.a || [];
|
||||
},
|
||||
}
|
||||
|
||||
_linesRight(chunk) {
|
||||
return chunk.ab || chunk.b || [];
|
||||
},
|
||||
}
|
||||
|
||||
_firstUncollapsibleChunkIndex(chunks, offset) {
|
||||
let chunkIndex = offset;
|
||||
@@ -253,11 +259,11 @@
|
||||
chunkIndex++;
|
||||
}
|
||||
return chunkIndex;
|
||||
},
|
||||
}
|
||||
|
||||
_isCollapsibleChunk(chunk) {
|
||||
return (chunk.ab || chunk.common) && !chunk.keyLocation;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a stretch of collapsible chunks.
|
||||
@@ -303,7 +309,7 @@
|
||||
groups,
|
||||
newChunkIndex: firstUncollapsibleChunkIndex,
|
||||
};
|
||||
},
|
||||
}
|
||||
|
||||
_commonChunkLength(chunk) {
|
||||
console.assert(chunk.ab || chunk.common);
|
||||
@@ -311,7 +317,7 @@
|
||||
!chunk.a || (chunk.b && chunk.a.length === chunk.b.length),
|
||||
`common chunk needs same number of a and b lines: `, chunk);
|
||||
return this._linesLeft(chunk).length;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Array<!Object>} chunks
|
||||
@@ -327,7 +333,7 @@
|
||||
offsetRight += chunkLength;
|
||||
return group;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Object} chunk
|
||||
@@ -343,7 +349,7 @@
|
||||
group.dueToRebase = chunk.due_to_rebase;
|
||||
group.ignoredWhitespaceOnly = chunk.common;
|
||||
return group;
|
||||
},
|
||||
}
|
||||
|
||||
_linesFromChunk(chunk, offsetLeft, offsetRight) {
|
||||
if (chunk.ab) {
|
||||
@@ -366,7 +372,7 @@
|
||||
chunk[DiffHighlights.ADDED]));
|
||||
}
|
||||
return lines;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} lineType (GrDiffLine.Type)
|
||||
@@ -380,7 +386,7 @@
|
||||
this._convertIntralineInfos(rows, opt_intralineInfos) : undefined;
|
||||
return rows.map((row, i) => this._lineFromRow(
|
||||
lineType, offset, offset, row, i, grDiffHighlights));
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} type (GrDiffLine.Type)
|
||||
@@ -403,14 +409,14 @@
|
||||
line.hasIntralineInfo = false;
|
||||
}
|
||||
return line;
|
||||
},
|
||||
}
|
||||
|
||||
_makeFileComments() {
|
||||
const line = new GrDiffLine(GrDiffLine.Type.BOTH);
|
||||
line.beforeNumber = GrDiffLine.FILE;
|
||||
line.afterNumber = GrDiffLine.FILE;
|
||||
return new GrDiffGroup(GrDiffGroup.Type.BOTH, [line]);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Split chunks into smaller chunks of the same kind.
|
||||
@@ -452,7 +458,7 @@
|
||||
}
|
||||
}
|
||||
return newChunks;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* In order to show key locations, such as comments, out of the bounds of
|
||||
@@ -503,7 +509,7 @@
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {!Array<{offset: number, keyLocation: boolean}>} Offsets of the
|
||||
@@ -534,7 +540,7 @@
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
}
|
||||
|
||||
_splitAtChunkEnds(lines, chunkEnds) {
|
||||
const result = [];
|
||||
@@ -545,7 +551,7 @@
|
||||
lastChunkEndOffset = offset;
|
||||
}
|
||||
return result;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts `IntralineInfo`s return by the API to `GrLineHighlights` used
|
||||
@@ -595,7 +601,7 @@
|
||||
normalized.push(lineHighlight);
|
||||
}
|
||||
return normalized;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* If a group is an addition or a removal, break it down into smaller groups
|
||||
@@ -625,7 +631,7 @@
|
||||
}
|
||||
return subChunk;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an array and a size, return an array of arrays where no inner array
|
||||
@@ -643,6 +649,8 @@
|
||||
const tail = array.slice(array.length - size);
|
||||
|
||||
return this._breakdown(head, size).concat([tail]);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrDiffProcessor.is, GrDiffProcessor);
|
||||
})();
|
||||
|
||||
@@ -30,35 +30,46 @@
|
||||
|
||||
const getNewCache = () => { return {left: null, right: null}; };
|
||||
|
||||
Polymer({
|
||||
is: 'gr-diff-selection',
|
||||
/**
|
||||
* @appliesMixin Gerrit.DomUtilMixin
|
||||
*/
|
||||
class GrDiffSelection extends Polymer.mixinBehaviors( [
|
||||
Gerrit.DomUtilBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-diff-selection'; }
|
||||
|
||||
properties: {
|
||||
diff: Object,
|
||||
/** @type {?Object} */
|
||||
_cachedDiffBuilder: Object,
|
||||
_linesCache: {
|
||||
type: Object,
|
||||
value: getNewCache(),
|
||||
},
|
||||
},
|
||||
static get properties() {
|
||||
return {
|
||||
diff: Object,
|
||||
/** @type {?Object} */
|
||||
_cachedDiffBuilder: Object,
|
||||
_linesCache: {
|
||||
type: Object,
|
||||
value: getNewCache(),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
observers: [
|
||||
'_diffChanged(diff)',
|
||||
],
|
||||
static get observers() {
|
||||
return [
|
||||
'_diffChanged(diff)',
|
||||
];
|
||||
}
|
||||
|
||||
listeners: {
|
||||
copy: '_handleCopy',
|
||||
down: '_handleDown',
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
Gerrit.DomUtilBehavior,
|
||||
],
|
||||
created() {
|
||||
super.created();
|
||||
this.addEventListener('copy',
|
||||
e => this._handleCopy(e));
|
||||
Polymer.Gestures.addListener(this, 'down',
|
||||
e => this._handleDown(e));
|
||||
}
|
||||
|
||||
attached() {
|
||||
super.attached();
|
||||
this.classList.add(SelectionClass.RIGHT);
|
||||
},
|
||||
}
|
||||
|
||||
get diffBuilder() {
|
||||
if (!this._cachedDiffBuilder) {
|
||||
@@ -66,11 +77,11 @@
|
||||
Polymer.dom(this).querySelector('gr-diff-builder');
|
||||
}
|
||||
return this._cachedDiffBuilder;
|
||||
},
|
||||
}
|
||||
|
||||
_diffChanged() {
|
||||
this._linesCache = getNewCache();
|
||||
},
|
||||
}
|
||||
|
||||
_handleDownOnRangeComment(node) {
|
||||
if (node &&
|
||||
@@ -85,7 +96,7 @@
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
}
|
||||
|
||||
_handleDown(e) {
|
||||
// Handle the down event on comment thread in Polymer 2
|
||||
@@ -115,7 +126,7 @@
|
||||
}
|
||||
|
||||
this._setClasses(targetClasses);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the provided list of classes on the element, to the exclusion of all
|
||||
@@ -138,11 +149,11 @@
|
||||
this.classList.add(_class);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_getCopyEventTarget(e) {
|
||||
return Polymer.dom(e).rootTarget;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function to determine whether an element is a descendant of
|
||||
@@ -155,7 +166,7 @@
|
||||
_elementDescendedFromClass(element, className) {
|
||||
return this.descendedFromClass(element, className,
|
||||
this.diffBuilder.diffElement);
|
||||
},
|
||||
}
|
||||
|
||||
_handleCopy(e) {
|
||||
let commentSelected = false;
|
||||
@@ -175,7 +186,7 @@
|
||||
e.clipboardData.setData('Text', text);
|
||||
e.preventDefault();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* For Polymer 2, use shadowRoot.getSelection instead.
|
||||
@@ -186,7 +197,7 @@
|
||||
diffHost.shadowRoot &&
|
||||
diffHost.shadowRoot.getSelection();
|
||||
return selection ? selection: window.getSelection();
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the text of the current selection. If commentSelected is
|
||||
@@ -225,7 +236,7 @@
|
||||
|
||||
return this._getRangeFromDiff(startLineNum, range.startOffset, endLineNum,
|
||||
range.endOffset, side);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the diff object for the selected lines.
|
||||
@@ -247,7 +258,7 @@
|
||||
lines[0] = lines[0].substring(startOffset);
|
||||
}
|
||||
return lines.join('\n');
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the diff object for the lines from a particular side.
|
||||
@@ -270,7 +281,7 @@
|
||||
}
|
||||
this._linesCache[side] = lines;
|
||||
return lines;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the diffElement for comments and check whether they lie inside the
|
||||
@@ -308,7 +319,7 @@
|
||||
}
|
||||
|
||||
return content.join('\n');
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a DOM node, a selection, and a selection range, recursively get all
|
||||
@@ -338,6 +349,8 @@
|
||||
}
|
||||
}
|
||||
return text;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrDiffSelection.is, GrDiffSelection);
|
||||
})();
|
||||
|
||||
@@ -33,9 +33,23 @@
|
||||
UNIFIED: 'UNIFIED_DIFF',
|
||||
};
|
||||
|
||||
Polymer({
|
||||
is: 'gr-diff-view',
|
||||
|
||||
/**
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
* @appliesMixin Gerrit.KeyboardShortcutMixin
|
||||
* @appliesMixin Gerrit.PatchSetMixin
|
||||
* @appliesMixin Gerrit.PathListMixin
|
||||
* @appliesMixin Gerrit.RESTClientMixin
|
||||
*/
|
||||
class GrDiffView extends Polymer.mixinBehaviors( [
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.KeyboardShortcutBehavior,
|
||||
Gerrit.PatchSetBehavior,
|
||||
Gerrit.PathListBehavior,
|
||||
Gerrit.RESTClientBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-diff-view'; }
|
||||
/**
|
||||
* Fired when the title of the page should change.
|
||||
*
|
||||
@@ -48,154 +62,152 @@
|
||||
* @event show-alert
|
||||
*/
|
||||
|
||||
properties: {
|
||||
static get properties() {
|
||||
return {
|
||||
/**
|
||||
* URL params passed from the router.
|
||||
*/
|
||||
params: {
|
||||
type: Object,
|
||||
observer: '_paramsChanged',
|
||||
},
|
||||
keyEventTarget: {
|
||||
type: Object,
|
||||
value() { return document.body; },
|
||||
},
|
||||
/**
|
||||
params: {
|
||||
type: Object,
|
||||
observer: '_paramsChanged',
|
||||
},
|
||||
keyEventTarget: {
|
||||
type: Object,
|
||||
value() { return document.body; },
|
||||
},
|
||||
/**
|
||||
* @type {{ diffMode: (string|undefined) }}
|
||||
*/
|
||||
changeViewState: {
|
||||
type: Object,
|
||||
notify: true,
|
||||
value() { return {}; },
|
||||
observer: '_changeViewStateChanged',
|
||||
},
|
||||
disableDiffPrefs: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_diffPrefsDisabled: {
|
||||
type: Boolean,
|
||||
computed: '_computeDiffPrefsDisabled(disableDiffPrefs, _loggedIn)',
|
||||
},
|
||||
/** @type {?} */
|
||||
_patchRange: Object,
|
||||
/** @type {?} */
|
||||
_commitRange: Object,
|
||||
/**
|
||||
changeViewState: {
|
||||
type: Object,
|
||||
notify: true,
|
||||
value() { return {}; },
|
||||
observer: '_changeViewStateChanged',
|
||||
},
|
||||
disableDiffPrefs: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_diffPrefsDisabled: {
|
||||
type: Boolean,
|
||||
computed: '_computeDiffPrefsDisabled(disableDiffPrefs, _loggedIn)',
|
||||
},
|
||||
/** @type {?} */
|
||||
_patchRange: Object,
|
||||
/** @type {?} */
|
||||
_commitRange: Object,
|
||||
/**
|
||||
* @type {{
|
||||
* subject: string,
|
||||
* project: string,
|
||||
* revisions: string,
|
||||
* }}
|
||||
*/
|
||||
_change: Object,
|
||||
/** @type {?} */
|
||||
_changeComments: Object,
|
||||
_changeNum: String,
|
||||
/**
|
||||
_change: Object,
|
||||
/** @type {?} */
|
||||
_changeComments: Object,
|
||||
_changeNum: String,
|
||||
/**
|
||||
* This is a DiffInfo object.
|
||||
* This is retrieved and owned by a child component.
|
||||
*/
|
||||
_diff: Object,
|
||||
// An array specifically formatted to be used in a gr-dropdown-list
|
||||
// element for selected a file to view.
|
||||
_formattedFiles: {
|
||||
type: Array,
|
||||
computed: '_formatFilesForDropdown(_fileList, ' +
|
||||
_diff: Object,
|
||||
// An array specifically formatted to be used in a gr-dropdown-list
|
||||
// element for selected a file to view.
|
||||
_formattedFiles: {
|
||||
type: Array,
|
||||
computed: '_formatFilesForDropdown(_fileList, ' +
|
||||
'_patchRange.patchNum, _changeComments)',
|
||||
},
|
||||
// An sorted array of files, as returned by the rest API.
|
||||
_fileList: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
_path: {
|
||||
type: String,
|
||||
observer: '_pathChanged',
|
||||
},
|
||||
_fileNum: {
|
||||
type: Number,
|
||||
computed: '_computeFileNum(_path, _formattedFiles)',
|
||||
},
|
||||
_loggedIn: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_loading: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
_prefs: Object,
|
||||
_localPrefs: Object,
|
||||
_projectConfig: Object,
|
||||
_userPrefs: Object,
|
||||
_diffMode: {
|
||||
type: String,
|
||||
computed: '_getDiffViewMode(changeViewState.diffMode, _userPrefs)',
|
||||
},
|
||||
_isImageDiff: Boolean,
|
||||
_filesWeblinks: Object,
|
||||
},
|
||||
// An sorted array of files, as returned by the rest API.
|
||||
_fileList: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
_path: {
|
||||
type: String,
|
||||
observer: '_pathChanged',
|
||||
},
|
||||
_fileNum: {
|
||||
type: Number,
|
||||
computed: '_computeFileNum(_path, _formattedFiles)',
|
||||
},
|
||||
_loggedIn: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_loading: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
_prefs: Object,
|
||||
_localPrefs: Object,
|
||||
_projectConfig: Object,
|
||||
_userPrefs: Object,
|
||||
_diffMode: {
|
||||
type: String,
|
||||
computed: '_getDiffViewMode(changeViewState.diffMode, _userPrefs)',
|
||||
},
|
||||
_isImageDiff: Boolean,
|
||||
_filesWeblinks: Object,
|
||||
|
||||
/**
|
||||
/**
|
||||
* Map of paths in the current change and patch range that have comments
|
||||
* or drafts or robot comments.
|
||||
*/
|
||||
_commentMap: Object,
|
||||
_commentMap: Object,
|
||||
|
||||
_commentsForDiff: Object,
|
||||
_commentsForDiff: Object,
|
||||
|
||||
/**
|
||||
/**
|
||||
* Object to contain the path of the next and previous file in the current
|
||||
* change and patch range that has comments.
|
||||
*/
|
||||
_commentSkips: {
|
||||
type: Object,
|
||||
computed: '_computeCommentSkips(_commentMap, _fileList, _path)',
|
||||
},
|
||||
_panelFloatingDisabled: {
|
||||
type: Boolean,
|
||||
value: () => { return window.PANEL_FLOATING_DISABLED; },
|
||||
},
|
||||
_editMode: {
|
||||
type: Boolean,
|
||||
computed: '_computeEditMode(_patchRange.*)',
|
||||
},
|
||||
_isBlameLoaded: Boolean,
|
||||
_isBlameLoading: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_allPatchSets: {
|
||||
type: Array,
|
||||
computed: 'computeAllPatchSets(_change, _change.revisions.*)',
|
||||
},
|
||||
_revisionInfo: {
|
||||
type: Object,
|
||||
computed: '_getRevisionInfo(_change)',
|
||||
},
|
||||
_reviewedFiles: {
|
||||
type: Object,
|
||||
value: () => new Set(),
|
||||
},
|
||||
},
|
||||
_commentSkips: {
|
||||
type: Object,
|
||||
computed: '_computeCommentSkips(_commentMap, _fileList, _path)',
|
||||
},
|
||||
_panelFloatingDisabled: {
|
||||
type: Boolean,
|
||||
value: () => { return window.PANEL_FLOATING_DISABLED; },
|
||||
},
|
||||
_editMode: {
|
||||
type: Boolean,
|
||||
computed: '_computeEditMode(_patchRange.*)',
|
||||
},
|
||||
_isBlameLoaded: Boolean,
|
||||
_isBlameLoading: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_allPatchSets: {
|
||||
type: Array,
|
||||
computed: 'computeAllPatchSets(_change, _change.revisions.*)',
|
||||
},
|
||||
_revisionInfo: {
|
||||
type: Object,
|
||||
computed: '_getRevisionInfo(_change)',
|
||||
},
|
||||
_reviewedFiles: {
|
||||
type: Object,
|
||||
value: () => new Set(),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
behaviors: [
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.KeyboardShortcutBehavior,
|
||||
Gerrit.PatchSetBehavior,
|
||||
Gerrit.PathListBehavior,
|
||||
Gerrit.RESTClientBehavior,
|
||||
],
|
||||
static get observers() {
|
||||
return [
|
||||
'_getProjectConfig(_change.project)',
|
||||
'_getFiles(_changeNum, _patchRange.*)',
|
||||
'_setReviewedObserver(_loggedIn, params.*, _prefs)',
|
||||
];
|
||||
}
|
||||
|
||||
observers: [
|
||||
'_getProjectConfig(_change.project)',
|
||||
'_getFiles(_changeNum, _patchRange.*)',
|
||||
'_setReviewedObserver(_loggedIn, params.*, _prefs)',
|
||||
],
|
||||
|
||||
keyBindings: {
|
||||
esc: '_handleEscKey',
|
||||
},
|
||||
get keyBindings() {
|
||||
return {
|
||||
esc: '_handleEscKey',
|
||||
};
|
||||
}
|
||||
|
||||
keyboardShortcuts() {
|
||||
return {
|
||||
@@ -230,37 +242,38 @@
|
||||
[this.Shortcut.EXPAND_ALL_COMMENT_THREADS]: null,
|
||||
[this.Shortcut.COLLAPSE_ALL_COMMENT_THREADS]: null,
|
||||
};
|
||||
},
|
||||
}
|
||||
|
||||
attached() {
|
||||
super.attached();
|
||||
this._getLoggedIn().then(loggedIn => {
|
||||
this._loggedIn = loggedIn;
|
||||
});
|
||||
|
||||
this.$.cursor.push('diffs', this.$.diffHost);
|
||||
},
|
||||
}
|
||||
|
||||
_getLoggedIn() {
|
||||
return this.$.restAPI.getLoggedIn();
|
||||
},
|
||||
}
|
||||
|
||||
_getProjectConfig(project) {
|
||||
return this.$.restAPI.getProjectConfig(project).then(
|
||||
config => {
|
||||
this._projectConfig = config;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_getChangeDetail(changeNum) {
|
||||
return this.$.restAPI.getDiffChangeDetail(changeNum).then(change => {
|
||||
this._change = change;
|
||||
return change;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_getChangeEdit(changeNum) {
|
||||
return this.$.restAPI.getChangeEdit(this._changeNum);
|
||||
},
|
||||
}
|
||||
|
||||
_getFiles(changeNum, patchRangeRecord) {
|
||||
// Polymer 2: check for undefined
|
||||
@@ -274,25 +287,25 @@
|
||||
changeNum, patchRange).then(files => {
|
||||
this._fileList = files;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_getDiffPreferences() {
|
||||
return this.$.restAPI.getDiffPreferences().then(prefs => {
|
||||
this._prefs = prefs;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_getPreferences() {
|
||||
return this.$.restAPI.getPreferences();
|
||||
},
|
||||
}
|
||||
|
||||
_getWindowWidth() {
|
||||
return window.innerWidth;
|
||||
},
|
||||
}
|
||||
|
||||
_handleReviewedChange(e) {
|
||||
this._setReviewed(Polymer.dom(e).rootTarget.checked);
|
||||
},
|
||||
}
|
||||
|
||||
_setReviewed(reviewed) {
|
||||
if (this._editMode) { return; }
|
||||
@@ -301,12 +314,12 @@
|
||||
this.fire('show-alert', {message: ERR_REVIEW_STATUS});
|
||||
throw err;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_saveReviewedState(reviewed) {
|
||||
return this.$.restAPI.saveFileReviewed(this._changeNum,
|
||||
this._patchRange.patchNum, this._path, reviewed);
|
||||
},
|
||||
}
|
||||
|
||||
_handleToggleFileReviewed(e) {
|
||||
if (this.shouldSuppressKeyboardShortcut(e) ||
|
||||
@@ -314,7 +327,7 @@
|
||||
|
||||
e.preventDefault();
|
||||
this._setReviewed(!this.$.reviewed.checked);
|
||||
},
|
||||
}
|
||||
|
||||
_handleEscKey(e) {
|
||||
if (this.shouldSuppressKeyboardShortcut(e) ||
|
||||
@@ -322,21 +335,21 @@
|
||||
|
||||
e.preventDefault();
|
||||
this.$.diffHost.displayLine = false;
|
||||
},
|
||||
}
|
||||
|
||||
_handleLeftPane(e) {
|
||||
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||
|
||||
e.preventDefault();
|
||||
this.$.cursor.moveLeft();
|
||||
},
|
||||
}
|
||||
|
||||
_handleRightPane(e) {
|
||||
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||
|
||||
e.preventDefault();
|
||||
this.$.cursor.moveRight();
|
||||
},
|
||||
}
|
||||
|
||||
_handlePrevLineOrFileWithComments(e) {
|
||||
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||
@@ -350,7 +363,7 @@
|
||||
e.preventDefault();
|
||||
this.$.diffHost.displayLine = true;
|
||||
this.$.cursor.moveUp();
|
||||
},
|
||||
}
|
||||
|
||||
_handleNextLineOrFileWithComments(e) {
|
||||
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||
@@ -364,7 +377,7 @@
|
||||
e.preventDefault();
|
||||
this.$.diffHost.displayLine = true;
|
||||
this.$.cursor.moveDown();
|
||||
},
|
||||
}
|
||||
|
||||
_moveToPreviousFileWithComment() {
|
||||
if (!this._commentSkips) { return; }
|
||||
@@ -378,7 +391,7 @@
|
||||
|
||||
Gerrit.Nav.navigateToDiff(this._change, this._commentSkips.previous,
|
||||
this._patchRange.patchNum, this._patchRange.basePatchNum);
|
||||
},
|
||||
}
|
||||
|
||||
_moveToNextFileWithComment() {
|
||||
if (!this._commentSkips) { return; }
|
||||
@@ -391,14 +404,14 @@
|
||||
|
||||
Gerrit.Nav.navigateToDiff(this._change, this._commentSkips.next,
|
||||
this._patchRange.patchNum, this._patchRange.basePatchNum);
|
||||
},
|
||||
}
|
||||
|
||||
_handleNewComment(e) {
|
||||
if (this.shouldSuppressKeyboardShortcut(e) ||
|
||||
this.modifierPressed(e)) { return; }
|
||||
e.preventDefault();
|
||||
this.$.cursor.createCommentInPlace();
|
||||
},
|
||||
}
|
||||
|
||||
_handlePrevFile(e) {
|
||||
// Check for meta key to avoid overriding native chrome shortcut.
|
||||
@@ -407,7 +420,7 @@
|
||||
|
||||
e.preventDefault();
|
||||
this._navToFile(this._path, this._fileList, -1);
|
||||
},
|
||||
}
|
||||
|
||||
_handleNextFile(e) {
|
||||
// Check for meta key to avoid overriding native chrome shortcut.
|
||||
@@ -416,7 +429,7 @@
|
||||
|
||||
e.preventDefault();
|
||||
this._navToFile(this._path, this._fileList, 1);
|
||||
},
|
||||
}
|
||||
|
||||
_handleNextChunkOrCommentThread(e) {
|
||||
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||
@@ -428,7 +441,7 @@
|
||||
if (this.modifierPressed(e)) { return; }
|
||||
this.$.cursor.moveToNextChunk();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_handlePrevChunkOrCommentThread(e) {
|
||||
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||
@@ -440,7 +453,7 @@
|
||||
if (this.modifierPressed(e)) { return; }
|
||||
this.$.cursor.moveToPreviousChunk();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_handleOpenReplyDialogOrToggleLeftPane(e) {
|
||||
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||
@@ -458,7 +471,7 @@
|
||||
this.set('changeViewState.showReplyDialog', true);
|
||||
e.preventDefault();
|
||||
this._navToChangeView();
|
||||
},
|
||||
}
|
||||
|
||||
_handleUpToChange(e) {
|
||||
if (this.shouldSuppressKeyboardShortcut(e) ||
|
||||
@@ -466,7 +479,7 @@
|
||||
|
||||
e.preventDefault();
|
||||
this._navToChangeView();
|
||||
},
|
||||
}
|
||||
|
||||
_handleCommaKey(e) {
|
||||
if (this.shouldSuppressKeyboardShortcut(e) ||
|
||||
@@ -475,7 +488,7 @@
|
||||
|
||||
e.preventDefault();
|
||||
this.$.diffPreferencesDialog.open();
|
||||
},
|
||||
}
|
||||
|
||||
_handleToggleDiffMode(e) {
|
||||
if (this.shouldSuppressKeyboardShortcut(e) ||
|
||||
@@ -487,7 +500,7 @@
|
||||
} else {
|
||||
this.$.modeSelect.setMode(DiffViewMode.SIDE_BY_SIDE);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_navToChangeView() {
|
||||
if (!this._changeNum || !this._patchRange.patchNum) { return; }
|
||||
@@ -495,7 +508,7 @@
|
||||
this._change,
|
||||
this._patchRange,
|
||||
this._change && this._change.revisions);
|
||||
},
|
||||
}
|
||||
|
||||
_navToFile(path, fileList, direction) {
|
||||
const newPath = this._getNavLinkPath(path, fileList, direction);
|
||||
@@ -511,7 +524,7 @@
|
||||
|
||||
Gerrit.Nav.navigateToDiff(this._change, newPath.path,
|
||||
this._patchRange.patchNum, this._patchRange.basePatchNum);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {?string} path The path of the current file being shown.
|
||||
@@ -535,7 +548,7 @@
|
||||
this._change && this._change.revisions);
|
||||
}
|
||||
return this._getDiffUrl(this._change, this._patchRange, newPath.path);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives an object representing the target of navigating either left or
|
||||
@@ -575,7 +588,7 @@
|
||||
}
|
||||
|
||||
return {path: fileList[idx]};
|
||||
},
|
||||
}
|
||||
|
||||
_getReviewedFiles(changeNum, patchNum) {
|
||||
return this.$.restAPI.getReviewedFiles(changeNum, patchNum)
|
||||
@@ -583,13 +596,13 @@
|
||||
this._reviewedFiles = new Set(files);
|
||||
return this._reviewedFiles;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_getReviewedStatus(editMode, changeNum, patchNum, path) {
|
||||
if (editMode) { return Promise.resolve(false); }
|
||||
return this._getReviewedFiles(changeNum, patchNum)
|
||||
.then(files => files.has(path));
|
||||
},
|
||||
}
|
||||
|
||||
_paramsChanged(value) {
|
||||
if (value.view !== Gerrit.Nav.View.DIFF) { return; }
|
||||
@@ -676,7 +689,7 @@
|
||||
// If diff view displayed has not ended yet, it ends here.
|
||||
this.$.reporting.diffViewDisplayed();
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_changeViewStateChanged(changeViewState) {
|
||||
if (changeViewState.diffMode === null) {
|
||||
@@ -685,7 +698,7 @@
|
||||
this.set('changeViewState.diffMode', prefs.default_diff_view);
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_setReviewedObserver(_loggedIn, paramsRecord, _prefs) {
|
||||
// Polymer 2: check for undefined
|
||||
@@ -709,7 +722,7 @@
|
||||
if (params.view === Gerrit.Nav.View.DIFF) {
|
||||
this._setReviewed(true);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* If the params specify a diff address then configure the diff cursor.
|
||||
@@ -722,14 +735,14 @@
|
||||
this.$.cursor.side = DiffSides.RIGHT;
|
||||
}
|
||||
this.$.cursor.initialLineNumber = params.lineNum;
|
||||
},
|
||||
}
|
||||
|
||||
_getLineOfInterest(params) {
|
||||
// If there is a line number specified, pass it along to the diff so that
|
||||
// it will not get collapsed.
|
||||
if (!params.lineNum) { return null; }
|
||||
return {number: params.lineNum, leftSide: params.leftSide};
|
||||
},
|
||||
}
|
||||
|
||||
_pathChanged(path) {
|
||||
if (path) {
|
||||
@@ -741,7 +754,7 @@
|
||||
|
||||
this.set('changeViewState.selectedFileIndex',
|
||||
this._fileList.indexOf(path));
|
||||
},
|
||||
}
|
||||
|
||||
_getDiffUrl(change, patchRange, path) {
|
||||
if ([change, patchRange, path].some(arg => arg === undefined)) {
|
||||
@@ -749,7 +762,7 @@
|
||||
}
|
||||
return Gerrit.Nav.getUrlForDiff(change, path, patchRange.patchNum,
|
||||
patchRange.basePatchNum);
|
||||
},
|
||||
}
|
||||
|
||||
_patchRangeStr(patchRange) {
|
||||
let patchStr = patchRange.patchNum;
|
||||
@@ -758,7 +771,7 @@
|
||||
patchStr = patchRange.basePatchNum + '..' + patchRange.patchNum;
|
||||
}
|
||||
return patchStr;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* When the latest patch of the change is selected (and there is no base
|
||||
@@ -782,7 +795,7 @@
|
||||
basePatchNum = patchRange.basePatchNum;
|
||||
}
|
||||
return {patchNum, basePatchNum};
|
||||
},
|
||||
}
|
||||
|
||||
_getChangePath(change, patchRange, revisions) {
|
||||
if ([change, patchRange].some(arg => arg === undefined)) {
|
||||
@@ -791,16 +804,16 @@
|
||||
const range = this._getChangeUrlRange(patchRange, revisions);
|
||||
return Gerrit.Nav.getUrlForChange(change, range.patchNum,
|
||||
range.basePatchNum);
|
||||
},
|
||||
}
|
||||
|
||||
_navigateToChange(change, patchRange, revisions) {
|
||||
const range = this._getChangeUrlRange(patchRange, revisions);
|
||||
Gerrit.Nav.navigateToChange(change, range.patchNum, range.basePatchNum);
|
||||
},
|
||||
}
|
||||
|
||||
_computeChangePath(change, patchRangeRecord, revisions) {
|
||||
return this._getChangePath(change, patchRangeRecord.base, revisions);
|
||||
},
|
||||
}
|
||||
|
||||
_formatFilesForDropdown(fileList, patchNum, changeComments) {
|
||||
// Polymer 2: check for undefined
|
||||
@@ -824,7 +837,7 @@
|
||||
});
|
||||
}
|
||||
return dropdownContent;
|
||||
},
|
||||
}
|
||||
|
||||
_computeCommentString(changeComments, patchNum, path) {
|
||||
const unresolvedCount = changeComments.computeUnresolvedNum(patchNum,
|
||||
@@ -840,11 +853,11 @@
|
||||
(commentString && unresolvedString ? ', ' : '') +
|
||||
// Add parentheses around unresolved if it exists.
|
||||
(unresolvedString ? `${unresolvedString}` : '');
|
||||
},
|
||||
}
|
||||
|
||||
_computePrefsButtonHidden(prefs, prefsDisabled) {
|
||||
return prefsDisabled || !prefs;
|
||||
},
|
||||
}
|
||||
|
||||
_handleFileChange(e) {
|
||||
// This is when it gets set initially.
|
||||
@@ -855,7 +868,7 @@
|
||||
|
||||
Gerrit.Nav.navigateToDiff(this._change, path, this._patchRange.patchNum,
|
||||
this._patchRange.basePatchNum);
|
||||
},
|
||||
}
|
||||
|
||||
_handleFileTap(e) {
|
||||
// async is needed so that that the click event is fired before the
|
||||
@@ -863,7 +876,7 @@
|
||||
this.async(() => {
|
||||
this.$.dropdown.close();
|
||||
}, 1);
|
||||
},
|
||||
}
|
||||
|
||||
_handlePatchChange(e) {
|
||||
const {basePatchNum, patchNum} = e.detail;
|
||||
@@ -871,12 +884,12 @@
|
||||
this.patchNumEquals(patchNum, this._patchRange.patchNum)) { return; }
|
||||
Gerrit.Nav.navigateToDiff(
|
||||
this._change, this._path, patchNum, basePatchNum);
|
||||
},
|
||||
}
|
||||
|
||||
_handlePrefsTap(e) {
|
||||
e.preventDefault();
|
||||
this.$.diffPreferencesDialog.open();
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* _getDiffViewMode: Get the diff view (side-by-side or unified) based on
|
||||
@@ -901,11 +914,11 @@
|
||||
} else {
|
||||
return 'SIDE_BY_SIDE';
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_computeModeSelectHideClass(isImageDiff) {
|
||||
return isImageDiff ? 'hide' : '';
|
||||
},
|
||||
}
|
||||
|
||||
_onLineSelected(e, detail) {
|
||||
this.$.cursor.moveToLineNumber(detail.number, detail.side);
|
||||
@@ -917,7 +930,7 @@
|
||||
this._change.project, this._path, this._patchRange.patchNum,
|
||||
this._patchRange.basePatchNum, number, leftSide);
|
||||
history.replaceState(null, '', url);
|
||||
},
|
||||
}
|
||||
|
||||
_computeDownloadDropdownLinks(
|
||||
project, changeNum, patchRange, path, diff) {
|
||||
@@ -956,7 +969,7 @@
|
||||
}
|
||||
|
||||
return links;
|
||||
},
|
||||
}
|
||||
|
||||
_computeDownloadFileLink(
|
||||
project, changeNum, patchRange, path, isBase) {
|
||||
@@ -976,13 +989,13 @@
|
||||
}
|
||||
|
||||
return url;
|
||||
},
|
||||
}
|
||||
|
||||
_computeDownloadPatchLink(project, changeNum, patchRange, path) {
|
||||
let url = this.changeBaseURL(project, changeNum, patchRange.patchNum);
|
||||
url += '/patch?zip&path=' + encodeURIComponent(path);
|
||||
return url;
|
||||
},
|
||||
}
|
||||
|
||||
_loadComments() {
|
||||
return this.$.commentAPI.loadAll(this._changeNum).then(comments => {
|
||||
@@ -992,20 +1005,20 @@
|
||||
this._commentsForDiff = this._getCommentsForPath(this._path,
|
||||
this._patchRange, this._projectConfig);
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_getPaths(patchRange) {
|
||||
return this._changeComments.getPaths(patchRange);
|
||||
},
|
||||
}
|
||||
|
||||
_getCommentsForPath(path, patchRange, projectConfig) {
|
||||
return this._changeComments.getCommentsBySideForPath(path, patchRange,
|
||||
projectConfig);
|
||||
},
|
||||
}
|
||||
|
||||
_getDiffDrafts() {
|
||||
return this.$.restAPI.getDiffDrafts(this._changeNum);
|
||||
},
|
||||
}
|
||||
|
||||
_computeCommentSkips(commentMap, fileList, path) {
|
||||
// Polymer 2: check for undefined
|
||||
@@ -1038,13 +1051,13 @@
|
||||
}
|
||||
|
||||
return skips;
|
||||
},
|
||||
}
|
||||
|
||||
_computeDiffClass(panelFloatingDisabled) {
|
||||
if (panelFloatingDisabled) {
|
||||
return 'noOverflow';
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Object} patchRangeRecord
|
||||
@@ -1052,19 +1065,19 @@
|
||||
_computeEditMode(patchRangeRecord) {
|
||||
const patchRange = patchRangeRecord.base || {};
|
||||
return this.patchNumEquals(patchRange.patchNum, this.EDIT_NAME);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean} editMode
|
||||
*/
|
||||
_computeContainerClass(editMode) {
|
||||
return editMode ? 'editMode' : '';
|
||||
},
|
||||
}
|
||||
|
||||
_computeBlameToggleLabel(loaded, loading) {
|
||||
if (loaded) { return 'Hide blame'; }
|
||||
return 'Show blame';
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Load and display blame information if it has not already been loaded.
|
||||
@@ -1086,15 +1099,15 @@
|
||||
.catch(() => {
|
||||
this._isBlameLoading = false;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_computeBlameLoaderClass(isImageDiff) {
|
||||
return !isImageDiff ? 'show' : '';
|
||||
},
|
||||
}
|
||||
|
||||
_getRevisionInfo(change) {
|
||||
return new Gerrit.RevisionInfo(change);
|
||||
},
|
||||
}
|
||||
|
||||
_computeFileNum(file, files) {
|
||||
// Polymer 2: check for undefined
|
||||
@@ -1103,7 +1116,7 @@
|
||||
}
|
||||
|
||||
return files.findIndex(({value}) => value === file) + 1;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} fileNum
|
||||
@@ -1115,16 +1128,16 @@
|
||||
return 'show';
|
||||
}
|
||||
return '';
|
||||
},
|
||||
}
|
||||
|
||||
_handleExpandAllDiffContext(e) {
|
||||
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||
this.$.diffHost.expandAllContext();
|
||||
},
|
||||
}
|
||||
|
||||
_computeDiffPrefsDisabled(disableDiffPrefs, loggedIn) {
|
||||
return disableDiffPrefs || !loggedIn;
|
||||
},
|
||||
}
|
||||
|
||||
_handleNextUnreviewedFile(e) {
|
||||
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||
@@ -1135,10 +1148,12 @@
|
||||
.filter(file =>
|
||||
(file === this._path || !this._reviewedFiles.has(file)));
|
||||
this._navToFile(this._path, unreviewedFiles, 1);
|
||||
},
|
||||
}
|
||||
|
||||
_handleReloadingDiffPreference() {
|
||||
this._getDiffPreferences();
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrDiffView.is, GrDiffView);
|
||||
})();
|
||||
|
||||
@@ -91,9 +91,17 @@
|
||||
|
||||
const RENDER_DIFF_TABLE_DEBOUNCE_NAME = 'renderDiffTable';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-diff',
|
||||
|
||||
/**
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
* @appliesMixin Gerrit.PatchSetMixin
|
||||
*/
|
||||
class GrDiff extends Polymer.mixinBehaviors( [
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.PatchSetBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-diff'; }
|
||||
/**
|
||||
* Fired when the user selects a line.
|
||||
* @event line-selected
|
||||
@@ -126,89 +134,90 @@
|
||||
* @event diff-context-expanded
|
||||
*/
|
||||
|
||||
properties: {
|
||||
changeNum: String,
|
||||
noAutoRender: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
/** @type {?} */
|
||||
patchRange: Object,
|
||||
path: {
|
||||
type: String,
|
||||
observer: '_pathObserver',
|
||||
},
|
||||
prefs: {
|
||||
type: Object,
|
||||
observer: '_prefsObserver',
|
||||
},
|
||||
projectName: String,
|
||||
displayLine: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
isImageDiff: {
|
||||
type: Boolean,
|
||||
},
|
||||
commitRange: Object,
|
||||
hidden: {
|
||||
type: Boolean,
|
||||
reflectToAttribute: true,
|
||||
},
|
||||
noRenderOnPrefsChange: Boolean,
|
||||
/** @type {!Array<!Gerrit.HoveredRange>} */
|
||||
_commentRanges: {
|
||||
type: Array,
|
||||
value: () => [],
|
||||
},
|
||||
/** @type {!Array<!Gerrit.CoverageRange>} */
|
||||
coverageRanges: {
|
||||
type: Array,
|
||||
value: () => [],
|
||||
},
|
||||
lineWrapping: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
observer: '_lineWrappingObserver',
|
||||
},
|
||||
viewMode: {
|
||||
type: String,
|
||||
value: DiffViewMode.SIDE_BY_SIDE,
|
||||
observer: '_viewModeObserver',
|
||||
},
|
||||
static get properties() {
|
||||
return {
|
||||
changeNum: String,
|
||||
noAutoRender: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
/** @type {?} */
|
||||
patchRange: Object,
|
||||
path: {
|
||||
type: String,
|
||||
observer: '_pathObserver',
|
||||
},
|
||||
prefs: {
|
||||
type: Object,
|
||||
observer: '_prefsObserver',
|
||||
},
|
||||
projectName: String,
|
||||
displayLine: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
isImageDiff: {
|
||||
type: Boolean,
|
||||
},
|
||||
commitRange: Object,
|
||||
hidden: {
|
||||
type: Boolean,
|
||||
reflectToAttribute: true,
|
||||
},
|
||||
noRenderOnPrefsChange: Boolean,
|
||||
/** @type {!Array<!Gerrit.HoveredRange>} */
|
||||
_commentRanges: {
|
||||
type: Array,
|
||||
value: () => [],
|
||||
},
|
||||
/** @type {!Array<!Gerrit.CoverageRange>} */
|
||||
coverageRanges: {
|
||||
type: Array,
|
||||
value: () => [],
|
||||
},
|
||||
lineWrapping: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
observer: '_lineWrappingObserver',
|
||||
},
|
||||
viewMode: {
|
||||
type: String,
|
||||
value: DiffViewMode.SIDE_BY_SIDE,
|
||||
observer: '_viewModeObserver',
|
||||
},
|
||||
|
||||
/** @type ?Gerrit.LineOfInterest */
|
||||
lineOfInterest: Object,
|
||||
/** @type ?Gerrit.LineOfInterest */
|
||||
lineOfInterest: Object,
|
||||
|
||||
loading: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
observer: '_loadingChanged',
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
observer: '_loadingChanged',
|
||||
},
|
||||
|
||||
loggedIn: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
diff: {
|
||||
type: Object,
|
||||
observer: '_diffChanged',
|
||||
},
|
||||
_diffHeaderItems: {
|
||||
type: Array,
|
||||
value: [],
|
||||
computed: '_computeDiffHeaderItems(diff.*)',
|
||||
},
|
||||
_diffTableClass: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
/** @type {?Object} */
|
||||
baseImage: Object,
|
||||
/** @type {?Object} */
|
||||
revisionImage: Object,
|
||||
loggedIn: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
diff: {
|
||||
type: Object,
|
||||
observer: '_diffChanged',
|
||||
},
|
||||
_diffHeaderItems: {
|
||||
type: Array,
|
||||
value: [],
|
||||
computed: '_computeDiffHeaderItems(diff.*)',
|
||||
},
|
||||
_diffTableClass: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
/** @type {?Object} */
|
||||
baseImage: Object,
|
||||
/** @type {?Object} */
|
||||
revisionImage: Object,
|
||||
|
||||
/**
|
||||
/**
|
||||
* Whether the safety check for large diffs when whole-file is set has
|
||||
* been bypassed. If the value is null, then the safety has not been
|
||||
* bypassed. If the value is a number, then that number represents the
|
||||
@@ -216,83 +225,86 @@
|
||||
*
|
||||
* @type (number|null)
|
||||
*/
|
||||
_safetyBypass: {
|
||||
type: Number,
|
||||
value: null,
|
||||
},
|
||||
_safetyBypass: {
|
||||
type: Number,
|
||||
value: null,
|
||||
},
|
||||
|
||||
_showWarning: Boolean,
|
||||
_showWarning: Boolean,
|
||||
|
||||
/** @type {?string} */
|
||||
errorMessage: {
|
||||
type: String,
|
||||
value: null,
|
||||
},
|
||||
/** @type {?string} */
|
||||
errorMessage: {
|
||||
type: String,
|
||||
value: null,
|
||||
},
|
||||
|
||||
/** @type {?Object} */
|
||||
blame: {
|
||||
type: Object,
|
||||
value: null,
|
||||
observer: '_blameChanged',
|
||||
},
|
||||
/** @type {?Object} */
|
||||
blame: {
|
||||
type: Object,
|
||||
value: null,
|
||||
observer: '_blameChanged',
|
||||
},
|
||||
|
||||
parentIndex: Number,
|
||||
parentIndex: Number,
|
||||
|
||||
_newlineWarning: {
|
||||
type: String,
|
||||
computed: '_computeNewlineWarning(diff)',
|
||||
},
|
||||
_newlineWarning: {
|
||||
type: String,
|
||||
computed: '_computeNewlineWarning(diff)',
|
||||
},
|
||||
|
||||
_diffLength: Number,
|
||||
_diffLength: Number,
|
||||
|
||||
/**
|
||||
/**
|
||||
* Observes comment nodes added or removed after the initial render.
|
||||
* Can be used to unregister when the entire diff is (re-)rendered or upon
|
||||
* detachment.
|
||||
* @type {?PolymerDomApi.ObserveHandle}
|
||||
*/
|
||||
_incrementalNodeObserver: Object,
|
||||
_incrementalNodeObserver: Object,
|
||||
|
||||
/**
|
||||
/**
|
||||
* Observes comment nodes added or removed at any point.
|
||||
* Can be used to unregister upon detachment.
|
||||
* @type {?PolymerDomApi.ObserveHandle}
|
||||
*/
|
||||
_nodeObserver: Object,
|
||||
_nodeObserver: Object,
|
||||
|
||||
/** Set by Polymer. */
|
||||
isAttached: Boolean,
|
||||
layers: Array,
|
||||
},
|
||||
/** Set by Polymer. */
|
||||
isAttached: Boolean,
|
||||
layers: Array,
|
||||
};
|
||||
}
|
||||
|
||||
behaviors: [
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.PatchSetBehavior,
|
||||
],
|
||||
static get observers() {
|
||||
return [
|
||||
'_enableSelectionObserver(loggedIn, isAttached)',
|
||||
];
|
||||
}
|
||||
|
||||
listeners: {
|
||||
'create-range-comment': '_handleCreateRangeComment',
|
||||
'render-content': '_handleRenderContent',
|
||||
},
|
||||
|
||||
observers: [
|
||||
'_enableSelectionObserver(loggedIn, isAttached)',
|
||||
],
|
||||
created() {
|
||||
super.created();
|
||||
this.addEventListener('create-range-comment',
|
||||
e => this._handleCreateRangeComment(e));
|
||||
this.addEventListener('render-content',
|
||||
() => this._handleRenderContent());
|
||||
}
|
||||
|
||||
attached() {
|
||||
super.attached();
|
||||
this._observeNodes();
|
||||
},
|
||||
}
|
||||
|
||||
detached() {
|
||||
super.detached();
|
||||
this._unobserveIncrementalNodes();
|
||||
this._unobserveNodes();
|
||||
},
|
||||
}
|
||||
|
||||
showNoChangeMessage(loading, prefs, diffLength) {
|
||||
return !loading &&
|
||||
prefs && prefs.ignore_whitespace !== 'IGNORE_NONE'
|
||||
&& diffLength === 0;
|
||||
},
|
||||
}
|
||||
|
||||
_enableSelectionObserver(loggedIn, isAttached) {
|
||||
// Polymer 2: check for undefined
|
||||
@@ -307,7 +319,7 @@
|
||||
this.unlisten(document, 'selectionchange', '_handleSelectionChange');
|
||||
this.unlisten(document, 'mouseup', '_handleMouseUp');
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_handleSelectionChange() {
|
||||
// Because of shadow DOM selections, we handle the selectionchange here,
|
||||
@@ -315,7 +327,7 @@
|
||||
// corresponding range is determined and normalized.
|
||||
const selection = this._getShadowOrDocumentSelection();
|
||||
this.$.highlights.handleSelectionChange(selection, false);
|
||||
},
|
||||
}
|
||||
|
||||
_handleMouseUp(e) {
|
||||
// To handle double-click outside of text creating comments, we check on
|
||||
@@ -323,7 +335,7 @@
|
||||
// can't do that on selection change since the user may still be dragging.
|
||||
const selection = this._getShadowOrDocumentSelection();
|
||||
this.$.highlights.handleSelectionChange(selection, true);
|
||||
},
|
||||
}
|
||||
|
||||
/** Gets the current selection, preferring the shadow DOM selection. */
|
||||
_getShadowOrDocumentSelection() {
|
||||
@@ -334,7 +346,7 @@
|
||||
return this.root.getSelection ?
|
||||
this.root.getSelection() :
|
||||
document.getSelection();
|
||||
},
|
||||
}
|
||||
|
||||
_observeNodes() {
|
||||
this._nodeObserver = Polymer.dom(this).observeNodes(info => {
|
||||
@@ -343,7 +355,7 @@
|
||||
this._updateRanges(addedThreadEls, removedThreadEls);
|
||||
this._redispatchHoverEvents(addedThreadEls);
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_updateRanges(addedThreadEls, removedThreadEls) {
|
||||
function commentRangeFromThreadEl(threadEl) {
|
||||
@@ -369,7 +381,7 @@
|
||||
if (addedCommentRanges && addedCommentRanges.length) {
|
||||
this.push('_commentRanges', ...addedCommentRanges);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* The key locations based on the comments and line of interests,
|
||||
@@ -400,7 +412,7 @@
|
||||
}
|
||||
}
|
||||
return keyLocations;
|
||||
},
|
||||
}
|
||||
|
||||
// Dispatch events that are handled by the gr-diff-highlight.
|
||||
_redispatchHoverEvents(addedThreadEls) {
|
||||
@@ -414,13 +426,13 @@
|
||||
'comment-thread-mouseleave', {bubbles: true, composed: true}));
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/** Cancel any remaining diff builder rendering work. */
|
||||
cancel() {
|
||||
this.$.diffBuilder.cancel();
|
||||
this.cancelDebouncer(RENDER_DIFF_TABLE_DEBOUNCE_NAME);
|
||||
},
|
||||
}
|
||||
|
||||
/** @return {!Array<!HTMLElement>} */
|
||||
getCursorStops() {
|
||||
@@ -430,16 +442,16 @@
|
||||
|
||||
return Array.from(
|
||||
Polymer.dom(this.root).querySelectorAll('.diff-row'));
|
||||
},
|
||||
}
|
||||
|
||||
/** @return {boolean} */
|
||||
isRangeSelected() {
|
||||
return !!this.$.highlights.selectedRange;
|
||||
},
|
||||
}
|
||||
|
||||
toggleLeftDiff() {
|
||||
this.toggleClass('no-left');
|
||||
},
|
||||
}
|
||||
|
||||
_blameChanged(newValue) {
|
||||
this.$.diffBuilder.setBlame(newValue);
|
||||
@@ -448,7 +460,7 @@
|
||||
} else {
|
||||
this.classList.remove('showBlame');
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/** @return {string} */
|
||||
_computeContainerClass(loggedIn, viewMode, displayLine) {
|
||||
@@ -473,7 +485,7 @@
|
||||
classes.push('displayLine');
|
||||
}
|
||||
return classes.join(' ');
|
||||
},
|
||||
}
|
||||
|
||||
_handleTap(e) {
|
||||
const el = Polymer.dom(e).localTarget;
|
||||
@@ -491,7 +503,7 @@
|
||||
const target = this.$.diffBuilder.getLineElByChild(el);
|
||||
if (target) { this._selectLine(target); }
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_selectLine(el) {
|
||||
this.fire('line-selected', {
|
||||
@@ -499,7 +511,7 @@
|
||||
number: el.getAttribute('data-value'),
|
||||
path: this.path,
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
addDraftAtLine(el) {
|
||||
this._selectLine(el);
|
||||
@@ -515,7 +527,7 @@
|
||||
}
|
||||
}
|
||||
this._createComment(el, lineNum);
|
||||
},
|
||||
}
|
||||
|
||||
createRangeComment() {
|
||||
if (!this.isRangeSelected()) {
|
||||
@@ -523,7 +535,7 @@
|
||||
}
|
||||
const {side, range} = this.$.highlights.selectedRange;
|
||||
this._createCommentForSelection(side, range);
|
||||
},
|
||||
}
|
||||
|
||||
_createCommentForSelection(side, range) {
|
||||
const lineNum = range.end_line;
|
||||
@@ -531,13 +543,13 @@
|
||||
if (this._isValidElForComment(lineEl)) {
|
||||
this._createComment(lineEl, lineNum, side, range);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_handleCreateRangeComment(e) {
|
||||
const range = e.detail.range;
|
||||
const side = e.detail.side;
|
||||
this._createCommentForSelection(side, range);
|
||||
},
|
||||
}
|
||||
|
||||
/** @return {boolean} */
|
||||
_isValidElForComment(el) {
|
||||
@@ -561,7 +573,7 @@
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Object} lineEl
|
||||
@@ -589,11 +601,11 @@
|
||||
range,
|
||||
},
|
||||
}));
|
||||
},
|
||||
}
|
||||
|
||||
_getThreadGroupForLine(contentEl) {
|
||||
return contentEl.querySelector('.thread-group');
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets or creates a comment thread group for a specific line and side on a
|
||||
@@ -612,7 +624,7 @@
|
||||
contentEl.appendChild(threadGroupEl);
|
||||
}
|
||||
return threadGroupEl;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* The value to be used for the patch number of new comments created at the
|
||||
@@ -638,7 +650,7 @@
|
||||
patchNum = this.patchRange.basePatchNum;
|
||||
}
|
||||
return patchNum;
|
||||
},
|
||||
}
|
||||
|
||||
/** @return {boolean} */
|
||||
_getIsParentCommentByLineAndContent(lineEl, contentEl) {
|
||||
@@ -649,7 +661,7 @@
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
}
|
||||
|
||||
/** @return {string} */
|
||||
_getCommentSideByLineAndContent(lineEl, contentEl) {
|
||||
@@ -659,7 +671,7 @@
|
||||
side = 'left';
|
||||
}
|
||||
return side;
|
||||
},
|
||||
}
|
||||
|
||||
_prefsObserver(newPrefs, oldPrefs) {
|
||||
// Scan the preference objects one level deep to see if they differ.
|
||||
@@ -675,16 +687,16 @@
|
||||
if (differ) {
|
||||
this._prefsChanged(newPrefs);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_pathObserver() {
|
||||
// Call _prefsChanged(), because line-limit style value depends on path.
|
||||
this._prefsChanged(this.prefs);
|
||||
},
|
||||
}
|
||||
|
||||
_viewModeObserver() {
|
||||
this._prefsChanged(this.prefs);
|
||||
},
|
||||
}
|
||||
|
||||
/** @param {boolean} newValue */
|
||||
_loadingChanged(newValue) {
|
||||
@@ -695,11 +707,11 @@
|
||||
this._showWarning = false;
|
||||
this.clearDiffContent();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_lineWrappingObserver() {
|
||||
this._prefsChanged(this.prefs);
|
||||
},
|
||||
}
|
||||
|
||||
_prefsChanged(prefs) {
|
||||
if (!prefs) { return; }
|
||||
@@ -730,14 +742,14 @@
|
||||
if (this.diff && !this.noRenderOnPrefsChange) {
|
||||
this._debounceRenderDiffTable();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_diffChanged(newValue) {
|
||||
if (newValue) {
|
||||
this._diffLength = this.getDiffLength(newValue);
|
||||
this._debounceRenderDiffTable();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* When called multiple times from the same microtask, will call
|
||||
@@ -752,7 +764,7 @@
|
||||
_debounceRenderDiffTable() {
|
||||
this.debounce(
|
||||
RENDER_DIFF_TABLE_DEBOUNCE_NAME, () => this._renderDiffTable());
|
||||
},
|
||||
}
|
||||
|
||||
_renderDiffTable() {
|
||||
this._unobserveIncrementalNodes();
|
||||
@@ -782,7 +794,7 @@
|
||||
detail: {contentRendered: true},
|
||||
}));
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleRenderContent() {
|
||||
this._incrementalNodeObserver = Polymer.dom(this).observeNodes(info => {
|
||||
@@ -821,19 +833,19 @@
|
||||
lastEl.replaceWith(lastEl);
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_unobserveIncrementalNodes() {
|
||||
if (this._incrementalNodeObserver) {
|
||||
Polymer.dom(this).unobserveNodes(this._incrementalNodeObserver);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_unobserveNodes() {
|
||||
if (this._nodeObserver) {
|
||||
Polymer.dom(this).unobserveNodes(this._nodeObserver);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the preferences object including the safety bypass context (if any).
|
||||
@@ -843,12 +855,12 @@
|
||||
return Object.assign({}, this.prefs, {context: this._safetyBypass});
|
||||
}
|
||||
return this.prefs;
|
||||
},
|
||||
}
|
||||
|
||||
clearDiffContent() {
|
||||
this._unobserveIncrementalNodes();
|
||||
this.$.diffTable.innerHTML = null;
|
||||
},
|
||||
}
|
||||
|
||||
/** @return {!Array} */
|
||||
_computeDiffHeaderItems(diffInfoRecord) {
|
||||
@@ -861,27 +873,27 @@
|
||||
item.startsWith('--- ') ||
|
||||
item === 'Binary files differ');
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
/** @return {boolean} */
|
||||
_computeDiffHeaderHidden(items) {
|
||||
return items.length === 0;
|
||||
},
|
||||
}
|
||||
|
||||
_handleFullBypass() {
|
||||
this._safetyBypass = FULL_CONTEXT;
|
||||
this._debounceRenderDiffTable();
|
||||
},
|
||||
}
|
||||
|
||||
_handleLimitedBypass() {
|
||||
this._safetyBypass = LIMITED_CONTEXT;
|
||||
this._debounceRenderDiffTable();
|
||||
},
|
||||
}
|
||||
|
||||
/** @return {string} */
|
||||
_computeWarningClass(showWarning) {
|
||||
return showWarning ? 'warn' : '';
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} errorMessage
|
||||
@@ -889,11 +901,11 @@
|
||||
*/
|
||||
_computeErrorClass(errorMessage) {
|
||||
return errorMessage ? 'showError' : '';
|
||||
},
|
||||
}
|
||||
|
||||
expandAllContext() {
|
||||
this._handleFullBypass();
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the last chunk for the given side.
|
||||
@@ -929,7 +941,7 @@
|
||||
if (chunkIndex === -1) { return null; }
|
||||
|
||||
return chunk;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the specified side of the diff has a trailing newline.
|
||||
@@ -950,7 +962,7 @@
|
||||
lines = leftSide ? chunk.a : chunk.b;
|
||||
}
|
||||
return lines[lines.length - 1] === '';
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Object} diff
|
||||
@@ -968,7 +980,7 @@
|
||||
}
|
||||
if (!messages.length) { return null; }
|
||||
return messages.join(' — ');
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} warning
|
||||
@@ -978,7 +990,7 @@
|
||||
_computeNewlineWarningClass(warning, loading) {
|
||||
if (loading || !warning) { return 'newlineWarning hidden'; }
|
||||
return 'newlineWarning';
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the approximate length of the diff as the sum of the maximum
|
||||
@@ -997,6 +1009,8 @@
|
||||
sec.hasOwnProperty('b') ? sec.b.length : 0);
|
||||
}
|
||||
}, 0);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrDiff.is, GrDiff);
|
||||
})();
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
// Maximum length for patch set descriptions.
|
||||
const PATCH_DESC_MAX_LENGTH = 500;
|
||||
|
||||
/**
|
||||
* @appliesMixin Gerrit.PatchSetMixin
|
||||
*/
|
||||
/**
|
||||
* Fired when the patch range changes
|
||||
*
|
||||
@@ -28,44 +31,47 @@
|
||||
* @property {string} patchNum
|
||||
* @property {string} basePatchNum
|
||||
*/
|
||||
class GrPatchRangeSelect extends Polymer.mixinBehaviors( [
|
||||
Gerrit.PatchSetBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-patch-range-select'; }
|
||||
|
||||
Polymer({
|
||||
is: 'gr-patch-range-select',
|
||||
|
||||
properties: {
|
||||
availablePatches: Array,
|
||||
_baseDropdownContent: {
|
||||
type: Object,
|
||||
computed: '_computeBaseDropdownContent(availablePatches, patchNum,' +
|
||||
static get properties() {
|
||||
return {
|
||||
availablePatches: Array,
|
||||
_baseDropdownContent: {
|
||||
type: Object,
|
||||
computed: '_computeBaseDropdownContent(availablePatches, patchNum,' +
|
||||
'_sortedRevisions, changeComments, revisionInfo)',
|
||||
},
|
||||
_patchDropdownContent: {
|
||||
type: Object,
|
||||
computed: '_computePatchDropdownContent(availablePatches,' +
|
||||
},
|
||||
_patchDropdownContent: {
|
||||
type: Object,
|
||||
computed: '_computePatchDropdownContent(availablePatches,' +
|
||||
'basePatchNum, _sortedRevisions, changeComments)',
|
||||
},
|
||||
changeNum: String,
|
||||
changeComments: Object,
|
||||
/** @type {{ meta_a: !Array, meta_b: !Array}} */
|
||||
filesWeblinks: Object,
|
||||
patchNum: String,
|
||||
basePatchNum: String,
|
||||
revisions: Object,
|
||||
revisionInfo: Object,
|
||||
_sortedRevisions: Array,
|
||||
},
|
||||
},
|
||||
changeNum: String,
|
||||
changeComments: Object,
|
||||
/** @type {{ meta_a: !Array, meta_b: !Array}} */
|
||||
filesWeblinks: Object,
|
||||
patchNum: String,
|
||||
basePatchNum: String,
|
||||
revisions: Object,
|
||||
revisionInfo: Object,
|
||||
_sortedRevisions: Array,
|
||||
};
|
||||
}
|
||||
|
||||
observers: [
|
||||
'_updateSortedRevisions(revisions.*)',
|
||||
],
|
||||
|
||||
behaviors: [
|
||||
Gerrit.PatchSetBehavior,
|
||||
],
|
||||
static get observers() {
|
||||
return [
|
||||
'_updateSortedRevisions(revisions.*)',
|
||||
];
|
||||
}
|
||||
|
||||
_getShaForPatch(patch) {
|
||||
return patch.sha.substring(0, 10);
|
||||
},
|
||||
}
|
||||
|
||||
_computeBaseDropdownContent(availablePatches, patchNum, _sortedRevisions,
|
||||
changeComments, revisionInfo) {
|
||||
@@ -113,13 +119,13 @@
|
||||
}
|
||||
|
||||
return dropdownContent;
|
||||
},
|
||||
}
|
||||
|
||||
_computeMobileText(patchNum, changeComments, revisions) {
|
||||
return `${patchNum}` +
|
||||
`${this._computePatchSetCommentsString(changeComments, patchNum)}` +
|
||||
`${this._computePatchSetDescription(revisions, patchNum, true)}`;
|
||||
},
|
||||
}
|
||||
|
||||
_computePatchDropdownContent(availablePatches, basePatchNum,
|
||||
_sortedRevisions, changeComments) {
|
||||
@@ -145,13 +151,13 @@
|
||||
}));
|
||||
}
|
||||
return dropdownContent;
|
||||
},
|
||||
}
|
||||
|
||||
_computeText(patchNum, prefix, changeComments, sha) {
|
||||
return `${prefix}${patchNum}` +
|
||||
`${this._computePatchSetCommentsString(changeComments, patchNum)}`
|
||||
+ (` | ${sha}`);
|
||||
},
|
||||
}
|
||||
|
||||
_createDropdownEntry(patchNum, prefix, sortedRevisions, changeComments,
|
||||
sha) {
|
||||
@@ -169,12 +175,12 @@
|
||||
entry['date'] = date;
|
||||
}
|
||||
return entry;
|
||||
},
|
||||
}
|
||||
|
||||
_updateSortedRevisions(revisionsRecord) {
|
||||
const revisions = revisionsRecord.base;
|
||||
this._sortedRevisions = this.sortRevisions(Object.values(revisions));
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* The basePatchNum should always be <= patchNum -- because sortedRevisions
|
||||
@@ -187,7 +193,7 @@
|
||||
_computeLeftDisabled(basePatchNum, patchNum, sortedRevisions) {
|
||||
return this.findSortedIndex(basePatchNum, sortedRevisions) <=
|
||||
this.findSortedIndex(patchNum, sortedRevisions);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* The basePatchNum should always be <= patchNum -- because sortedRevisions
|
||||
@@ -216,7 +222,7 @@
|
||||
|
||||
return this.findSortedIndex(basePatchNum, sortedRevisions) <=
|
||||
this.findSortedIndex(patchNum, sortedRevisions);
|
||||
},
|
||||
}
|
||||
|
||||
_computePatchSetCommentsString(changeComments, patchNum) {
|
||||
if (!changeComments) { return; }
|
||||
@@ -237,7 +243,7 @@
|
||||
// Add a comma + space if both comments and unresolved
|
||||
(commentString && unresolvedString ? ', ' : '') +
|
||||
`${unresolvedString})`;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Array} revisions
|
||||
@@ -249,7 +255,7 @@
|
||||
return (rev && rev.description) ?
|
||||
(opt_addFrontSpace ? ' ' : '') +
|
||||
rev.description.substring(0, PATCH_DESC_MAX_LENGTH) : '';
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Array} revisions
|
||||
@@ -258,7 +264,7 @@
|
||||
_computePatchSetDate(revisions, patchNum) {
|
||||
const rev = this.getRevisionByPatchNum(revisions, patchNum);
|
||||
return rev ? rev.created : undefined;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Catches value-change events from the patchset dropdowns and determines
|
||||
@@ -276,6 +282,8 @@
|
||||
|
||||
this.dispatchEvent(
|
||||
new CustomEvent('patch-range-change', {detail, bubbles: false}));
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrPatchRangeSelect.is, GrPatchRangeSelect);
|
||||
})();
|
||||
|
||||
@@ -23,9 +23,10 @@
|
||||
const RANGE_HIGHLIGHT = 'style-scope gr-diff range';
|
||||
const HOVER_HIGHLIGHT = 'style-scope gr-diff rangeHighlight';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-ranged-comment-layer',
|
||||
|
||||
class GrRangedCommentLayer extends Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element)) {
|
||||
static get is() { return 'gr-ranged-comment-layer'; }
|
||||
/**
|
||||
* Fired when the range in a range comment was malformed and had to be
|
||||
* normalized.
|
||||
@@ -35,26 +36,30 @@
|
||||
* @event normalize-range
|
||||
*/
|
||||
|
||||
properties: {
|
||||
static get properties() {
|
||||
return {
|
||||
/** @type {!Array<!Gerrit.HoveredRange>} */
|
||||
commentRanges: Array,
|
||||
_listeners: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
_rangesMap: {
|
||||
type: Object,
|
||||
value() { return {left: {}, right: {}}; },
|
||||
},
|
||||
},
|
||||
commentRanges: Array,
|
||||
_listeners: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
_rangesMap: {
|
||||
type: Object,
|
||||
value() { return {left: {}, right: {}}; },
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
observers: [
|
||||
'_handleCommentRangesChange(commentRanges.*)',
|
||||
],
|
||||
static get observers() {
|
||||
return [
|
||||
'_handleCommentRangesChange(commentRanges.*)',
|
||||
];
|
||||
}
|
||||
|
||||
get styleModuleName() {
|
||||
return 'gr-ranged-comment-styles';
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Layer method to add annotations to a line.
|
||||
@@ -81,7 +86,7 @@
|
||||
range.end - range.start,
|
||||
range.hovering ? HOVER_HIGHLIGHT : RANGE_HIGHLIGHT);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a listener for layer updates.
|
||||
@@ -91,7 +96,7 @@
|
||||
*/
|
||||
addListener(fn) {
|
||||
this._listeners.push(fn);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify Layer listeners of changes to annotations.
|
||||
@@ -103,7 +108,7 @@
|
||||
for (const listener of this._listeners) {
|
||||
listener(start, end, side);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle change in the ranges by updating the ranges maps and by
|
||||
@@ -161,7 +166,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_updateRangesMap(side, range, hovering, operation) {
|
||||
const forSide = this._rangesMap[side] || (this._rangesMap[side] = {});
|
||||
@@ -172,7 +177,7 @@
|
||||
operation(forLine, start, end, hovering);
|
||||
}
|
||||
this._notifyUpdateRange(range.start_line, range.end_line, side);
|
||||
},
|
||||
}
|
||||
|
||||
_getRangesForLine(line, side) {
|
||||
const lineNum = side === 'left' ? line.beforeNumber : line.afterNumber;
|
||||
@@ -200,6 +205,8 @@
|
||||
})
|
||||
// Sort the ranges so that hovering highlights are on top.
|
||||
.sort((a, b) => a.hovering && !b.hovering ? 1 : 0);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrRangedCommentLayer.is, GrRangedCommentLayer);
|
||||
})();
|
||||
|
||||
@@ -17,31 +17,38 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-selection-action-box',
|
||||
|
||||
/**
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
*/
|
||||
class GrSelectionActionBox extends Polymer.mixinBehaviors( [
|
||||
Gerrit.FireBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-selection-action-box'; }
|
||||
/**
|
||||
* Fired when the comment creation action was taken (click).
|
||||
*
|
||||
* @event create-comment-requested
|
||||
*/
|
||||
|
||||
properties: {
|
||||
keyEventTarget: {
|
||||
type: Object,
|
||||
value() { return document.body; },
|
||||
},
|
||||
positionBelow: Boolean,
|
||||
},
|
||||
static get properties() {
|
||||
return {
|
||||
keyEventTarget: {
|
||||
type: Object,
|
||||
value() { return document.body; },
|
||||
},
|
||||
positionBelow: Boolean,
|
||||
};
|
||||
}
|
||||
|
||||
behaviors: [
|
||||
Gerrit.FireBehavior,
|
||||
],
|
||||
created() {
|
||||
super.created();
|
||||
|
||||
listeners: {
|
||||
// See https://crbug.com/gerrit/4767
|
||||
mousedown: '_handleMouseDown',
|
||||
},
|
||||
this.addEventListener('mousedown',
|
||||
e => this._handleMouseDown(e));
|
||||
}
|
||||
|
||||
placeAbove(el) {
|
||||
Polymer.dom.flush();
|
||||
@@ -52,7 +59,7 @@
|
||||
rect.top - parentRect.top - boxRect.height - 6 + 'px';
|
||||
this.style.left =
|
||||
rect.left - parentRect.left + (rect.width - boxRect.width) / 2 + 'px';
|
||||
},
|
||||
}
|
||||
|
||||
placeBelow(el) {
|
||||
Polymer.dom.flush();
|
||||
@@ -63,14 +70,14 @@
|
||||
rect.top - parentRect.top + boxRect.height - 6 + 'px';
|
||||
this.style.left =
|
||||
rect.left - parentRect.left + (rect.width - boxRect.width) / 2 + 'px';
|
||||
},
|
||||
}
|
||||
|
||||
_getParentBoundingClientRect() {
|
||||
// With native shadow DOM, the parent is the shadow root, not the gr-diff
|
||||
// element
|
||||
const parent = this.parentElement || this.parentNode.host;
|
||||
return parent.getBoundingClientRect();
|
||||
},
|
||||
}
|
||||
|
||||
_getTargetBoundingRect(el) {
|
||||
let rect;
|
||||
@@ -83,13 +90,15 @@
|
||||
rect = el.getBoundingClientRect();
|
||||
}
|
||||
return rect;
|
||||
},
|
||||
}
|
||||
|
||||
_handleMouseDown(e) {
|
||||
if (e.button !== 0) { return; } // 0 = main button
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.fire('create-comment-requested');
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrSelectionActionBox.is, GrSelectionActionBox);
|
||||
})();
|
||||
|
||||
@@ -130,54 +130,58 @@
|
||||
const GO_BACKSLASH_LITERAL = '\'\\\\\'';
|
||||
const GLOBAL_LT_PATTERN = /</g;
|
||||
|
||||
Polymer({
|
||||
is: 'gr-syntax-layer',
|
||||
class GrSyntaxLayer extends Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element)) {
|
||||
static get is() { return 'gr-syntax-layer'; }
|
||||
|
||||
properties: {
|
||||
diff: {
|
||||
type: Object,
|
||||
observer: '_diffChanged',
|
||||
},
|
||||
enabled: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
_baseRanges: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
_revisionRanges: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
_baseLanguage: String,
|
||||
_revisionLanguage: String,
|
||||
_listeners: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
/** @type {?number} */
|
||||
_processHandle: Number,
|
||||
/**
|
||||
static get properties() {
|
||||
return {
|
||||
diff: {
|
||||
type: Object,
|
||||
observer: '_diffChanged',
|
||||
},
|
||||
enabled: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
_baseRanges: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
_revisionRanges: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
_baseLanguage: String,
|
||||
_revisionLanguage: String,
|
||||
_listeners: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
/** @type {?number} */
|
||||
_processHandle: Number,
|
||||
/**
|
||||
* The promise last returned from `process()` while the asynchronous
|
||||
* processing is running - `null` otherwise. Provides a `cancel()`
|
||||
* method that rejects it with `{isCancelled: true}`.
|
||||
* @type {?Object}
|
||||
*/
|
||||
_processPromise: {
|
||||
type: Object,
|
||||
value: null,
|
||||
},
|
||||
_hljs: Object,
|
||||
},
|
||||
_processPromise: {
|
||||
type: Object,
|
||||
value: null,
|
||||
},
|
||||
_hljs: Object,
|
||||
};
|
||||
}
|
||||
|
||||
addListener(fn) {
|
||||
this.push('_listeners', fn);
|
||||
},
|
||||
}
|
||||
|
||||
removeListener(fn) {
|
||||
this._listeners = this._listeners.filter(f => f != fn);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Annotation layer method to add syntax annotations to the given element
|
||||
@@ -214,14 +218,14 @@
|
||||
GrAnnotation.annotateElement(
|
||||
el, range.start, range.length, range.className);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_getLanguage(diffFileMetaInfo) {
|
||||
// The Gerrit API provides only content-type, but for other users of
|
||||
// gr-diff it may be more convenient to specify the language directly.
|
||||
return diffFileMetaInfo.language ||
|
||||
LANGUAGE_MAP[diffFileMetaInfo.content_type];
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Start processing syntax for the loaded diff and notify layer listeners
|
||||
@@ -298,7 +302,7 @@
|
||||
}));
|
||||
return this._processPromise
|
||||
.finally(() => { this._processPromise = null; });
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel any asynchronous syntax processing jobs.
|
||||
@@ -311,13 +315,13 @@
|
||||
if (this._processPromise) {
|
||||
this._processPromise.cancel();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_diffChanged() {
|
||||
this._cancel();
|
||||
this._baseRanges = [];
|
||||
this._revisionRanges = [];
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Take a string of HTML with the (potentially nested) syntax markers
|
||||
@@ -339,7 +343,7 @@
|
||||
const ranges = this._rangesFromElement(div, 0);
|
||||
rangesCache.set(str, ranges);
|
||||
return ranges;
|
||||
},
|
||||
}
|
||||
|
||||
_rangesFromElement(elem, offset) {
|
||||
let result = [];
|
||||
@@ -362,7 +366,7 @@
|
||||
offset += nodeLength;
|
||||
}
|
||||
return result;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* For a given state, process the syntax for the next line (or pair of
|
||||
@@ -412,7 +416,7 @@
|
||||
this._rangesFromString(result.value, rangesCache));
|
||||
state.revisionContext = result.top;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Ad hoc fixes for HLJS parsing bugs. Rewrite lines of code in constrained
|
||||
@@ -479,7 +483,7 @@
|
||||
}
|
||||
|
||||
return line;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether the state has exhausted its current section.
|
||||
@@ -494,7 +498,7 @@
|
||||
return (!section.a || state.lineIndex >= section.a.length) &&
|
||||
(!section.b || state.lineIndex >= section.b.length);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* For a given state, notify layer listeners of any processed line ranges
|
||||
@@ -516,18 +520,20 @@
|
||||
'right');
|
||||
state.lastNotify.right = state.lineNums.right;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_notifyRange(start, end, side) {
|
||||
for (const fn of this._listeners) {
|
||||
fn(start, end, side);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_loadHLJS() {
|
||||
return this.$.libLoader.getHLJS().then(hljs => {
|
||||
this._hljs = hljs;
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrSyntaxLayer.is, GrSyntaxLayer);
|
||||
})();
|
||||
|
||||
@@ -17,50 +17,56 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-documentation-search',
|
||||
/**
|
||||
* @appliesMixin Gerrit.ListViewMixin
|
||||
*/
|
||||
class GrDocumentationSearch extends Polymer.mixinBehaviors( [
|
||||
Gerrit.ListViewBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-documentation-search'; }
|
||||
|
||||
properties: {
|
||||
static get properties() {
|
||||
return {
|
||||
/**
|
||||
* URL params passed from the router.
|
||||
*/
|
||||
params: {
|
||||
type: Object,
|
||||
observer: '_paramsChanged',
|
||||
},
|
||||
params: {
|
||||
type: Object,
|
||||
observer: '_paramsChanged',
|
||||
},
|
||||
|
||||
_path: {
|
||||
type: String,
|
||||
readOnly: true,
|
||||
value: '/Documentation',
|
||||
},
|
||||
_documentationSearches: Array,
|
||||
_path: {
|
||||
type: String,
|
||||
readOnly: true,
|
||||
value: '/Documentation',
|
||||
},
|
||||
_documentationSearches: Array,
|
||||
|
||||
_loading: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
_filter: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
Gerrit.ListViewBehavior,
|
||||
],
|
||||
_loading: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
_filter: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
attached() {
|
||||
super.attached();
|
||||
this.dispatchEvent(
|
||||
new CustomEvent('title-change', {title: 'Documentation Search'}));
|
||||
},
|
||||
}
|
||||
|
||||
_paramsChanged(params) {
|
||||
this._loading = true;
|
||||
this._filter = this.getFilterValue(params);
|
||||
|
||||
return this._getDocumentationSearches(this._filter);
|
||||
},
|
||||
}
|
||||
|
||||
_getDocumentationSearches(filter) {
|
||||
this._documentationSearches = [];
|
||||
@@ -71,11 +77,13 @@
|
||||
this._documentationSearches = searches;
|
||||
this._loading = false;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_computeSearchUrl(url) {
|
||||
if (!url) { return ''; }
|
||||
return this.getBaseUrl() + '/' + url;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrDocumentationSearch.is, GrDocumentationSearch);
|
||||
})();
|
||||
|
||||
@@ -17,23 +17,28 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-default-editor',
|
||||
|
||||
class GrDefaultEditor extends Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element)) {
|
||||
static get is() { return 'gr-default-editor'; }
|
||||
/**
|
||||
* Fired when the content of the editor changes.
|
||||
*
|
||||
* @event content-change
|
||||
*/
|
||||
|
||||
properties: {
|
||||
fileContent: String,
|
||||
},
|
||||
static get properties() {
|
||||
return {
|
||||
fileContent: String,
|
||||
};
|
||||
}
|
||||
|
||||
_handleTextareaInput(e) {
|
||||
this.dispatchEvent(new CustomEvent(
|
||||
'content-change',
|
||||
{detail: {value: e.target.value}, bubbles: true, composed: true}));
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrDefaultEditor.is, GrDefaultEditor);
|
||||
})();
|
||||
|
||||
@@ -17,47 +17,52 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-edit-controls',
|
||||
/**
|
||||
* @appliesMixin Gerrit.PatchSetMixin
|
||||
*/
|
||||
class GrEditControls extends Polymer.mixinBehaviors( [
|
||||
Gerrit.PatchSetBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-edit-controls'; }
|
||||
|
||||
properties: {
|
||||
change: Object,
|
||||
patchNum: String,
|
||||
static get properties() {
|
||||
return {
|
||||
change: Object,
|
||||
patchNum: String,
|
||||
|
||||
/**
|
||||
/**
|
||||
* TODO(kaspern): by default, the RESTORE action should be hidden in the
|
||||
* file-list as it is a per-file action only. Remove this default value
|
||||
* when the Actions dictionary is moved to a shared constants file and
|
||||
* use the hiddenActions property in the parent component.
|
||||
*/
|
||||
hiddenActions: {
|
||||
type: Array,
|
||||
value() { return [GrEditConstants.Actions.RESTORE.id]; },
|
||||
},
|
||||
|
||||
_actions: {
|
||||
type: Array,
|
||||
value() { return Object.values(GrEditConstants.Actions); },
|
||||
},
|
||||
_path: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
_newPath: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
_query: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._queryFiles.bind(this);
|
||||
hiddenActions: {
|
||||
type: Array,
|
||||
value() { return [GrEditConstants.Actions.RESTORE.id]; },
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
Gerrit.PatchSetBehavior,
|
||||
],
|
||||
_actions: {
|
||||
type: Array,
|
||||
value() { return Object.values(GrEditConstants.Actions); },
|
||||
},
|
||||
_path: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
_newPath: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
_query: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._queryFiles.bind(this);
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
_handleTap(e) {
|
||||
e.preventDefault();
|
||||
@@ -76,7 +81,7 @@
|
||||
this.openRestoreDialog();
|
||||
return;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string=} opt_path
|
||||
@@ -84,7 +89,7 @@
|
||||
openOpenDialog(opt_path) {
|
||||
if (opt_path) { this._path = opt_path; }
|
||||
return this._showDialog(this.$.openDialog);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string=} opt_path
|
||||
@@ -92,7 +97,7 @@
|
||||
openDeleteDialog(opt_path) {
|
||||
if (opt_path) { this._path = opt_path; }
|
||||
return this._showDialog(this.$.deleteDialog);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string=} opt_path
|
||||
@@ -100,7 +105,7 @@
|
||||
openRenameDialog(opt_path) {
|
||||
if (opt_path) { this._path = opt_path; }
|
||||
return this._showDialog(this.$.renameDialog);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string=} opt_path
|
||||
@@ -108,7 +113,7 @@
|
||||
openRestoreDialog(opt_path) {
|
||||
if (opt_path) { this._path = opt_path; }
|
||||
return this._showDialog(this.$.restoreDialog);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a path string, checks that it is a valid file path.
|
||||
@@ -118,11 +123,11 @@
|
||||
_isValidPath(path) {
|
||||
// Double negation needed for strict boolean return type.
|
||||
return !!path.length && !path.endsWith('/');
|
||||
},
|
||||
}
|
||||
|
||||
_computeRenameDisabled(path, newPath) {
|
||||
return this._isValidPath(path) && this._isValidPath(newPath);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a dom event, gets the dialog that lies along this event path.
|
||||
@@ -134,7 +139,7 @@
|
||||
if (!element.classList) { return false; }
|
||||
return element.classList.contains('dialog');
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_showDialog(dialog) {
|
||||
// Some dialogs may not fire their on-close event when closed in certain
|
||||
@@ -148,12 +153,12 @@
|
||||
if (autocomplete) { autocomplete.focus(); }
|
||||
this.async(() => { this.$.overlay.center(); }, 1);
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_hideAllDialogs() {
|
||||
const dialogs = Polymer.dom(this.root).querySelectorAll('.dialog');
|
||||
for (const dialog of dialogs) { this._closeDialog(dialog); }
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Element|undefined} dialog
|
||||
@@ -175,18 +180,18 @@
|
||||
|
||||
dialog.classList.toggle('invisible', true);
|
||||
return this.$.overlay.close();
|
||||
},
|
||||
}
|
||||
|
||||
_handleDialogCancel(e) {
|
||||
this._closeDialog(this._getDialogFromEvent(e));
|
||||
},
|
||||
}
|
||||
|
||||
_handleOpenConfirm(e) {
|
||||
const url = Gerrit.Nav.getEditUrlForDiff(this.change, this._path,
|
||||
this.patchNum);
|
||||
Gerrit.Nav.navigateToRelativeUrl(url);
|
||||
this._closeDialog(this._getDialogFromEvent(e), true);
|
||||
},
|
||||
}
|
||||
|
||||
_handleDeleteConfirm(e) {
|
||||
// Get the dialog before the api call as the event will change during bubbling
|
||||
@@ -198,7 +203,7 @@
|
||||
this._closeDialog(dialog, true);
|
||||
Gerrit.Nav.navigateToChange(this.change);
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleRestoreConfirm(e) {
|
||||
const dialog = this._getDialogFromEvent(e);
|
||||
@@ -208,7 +213,7 @@
|
||||
this._closeDialog(dialog, true);
|
||||
Gerrit.Nav.navigateToChange(this.change);
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handleRenameConfirm(e) {
|
||||
const dialog = this._getDialogFromEvent(e);
|
||||
@@ -218,17 +223,19 @@
|
||||
this._closeDialog(dialog, true);
|
||||
Gerrit.Nav.navigateToChange(this.change);
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_queryFiles(input) {
|
||||
return this.$.restAPI.queryChangeFiles(this.change._number,
|
||||
this.patchNum, input).then(res => res.map(file => {
|
||||
return {name: file};
|
||||
}));
|
||||
},
|
||||
}
|
||||
|
||||
_computeIsInvisible(id, hiddenActions) {
|
||||
return hiddenActions.includes(id) ? 'invisible' : '';
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrEditControls.is, GrEditControls);
|
||||
})();
|
||||
|
||||
@@ -17,38 +17,41 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-edit-file-controls',
|
||||
|
||||
class GrEditFileControls extends Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element)) {
|
||||
static get is() { return 'gr-edit-file-controls'; }
|
||||
/**
|
||||
* Fired when an action in the overflow menu is tapped.
|
||||
*
|
||||
* @event file-action-tap
|
||||
*/
|
||||
|
||||
properties: {
|
||||
filePath: String,
|
||||
_allFileActions: {
|
||||
type: Array,
|
||||
value: () => Object.values(GrEditConstants.Actions),
|
||||
},
|
||||
_fileActions: {
|
||||
type: Array,
|
||||
computed: '_computeFileActions(_allFileActions)',
|
||||
},
|
||||
},
|
||||
static get properties() {
|
||||
return {
|
||||
filePath: String,
|
||||
_allFileActions: {
|
||||
type: Array,
|
||||
value: () => Object.values(GrEditConstants.Actions),
|
||||
},
|
||||
_fileActions: {
|
||||
type: Array,
|
||||
computed: '_computeFileActions(_allFileActions)',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
_handleActionTap(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this._dispatchFileAction(e.detail.id, this.filePath);
|
||||
},
|
||||
}
|
||||
|
||||
_dispatchFileAction(action, path) {
|
||||
this.dispatchEvent(new CustomEvent(
|
||||
'file-action-tap',
|
||||
{detail: {action, path}, bubbles: true, composed: true}));
|
||||
},
|
||||
}
|
||||
|
||||
_computeFileActions(actions) {
|
||||
// TODO(kaspern): conditionally disable some actions based on file status.
|
||||
@@ -58,6 +61,8 @@
|
||||
id: action.id,
|
||||
};
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrEditFileControls.is, GrEditFileControls);
|
||||
})();
|
||||
|
||||
@@ -24,9 +24,21 @@
|
||||
|
||||
const STORAGE_DEBOUNCE_INTERVAL_MS = 100;
|
||||
|
||||
Polymer({
|
||||
is: 'gr-editor-view',
|
||||
|
||||
/**
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
* @appliesMixin Gerrit.KeyboardShortcutMixin
|
||||
* @appliesMixin Gerrit.PatchSetMixin
|
||||
* @appliesMixin Gerrit.PathListMixin
|
||||
*/
|
||||
class GrEditorView extends Polymer.mixinBehaviors( [
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.KeyboardShortcutBehavior,
|
||||
Gerrit.PatchSetBehavior,
|
||||
Gerrit.PathListBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-editor-view'; }
|
||||
/**
|
||||
* Fired when the title of the page should change.
|
||||
*
|
||||
@@ -39,69 +51,69 @@
|
||||
* @event show-alert
|
||||
*/
|
||||
|
||||
properties: {
|
||||
static get properties() {
|
||||
return {
|
||||
/**
|
||||
* URL params passed from the router.
|
||||
*/
|
||||
params: {
|
||||
type: Object,
|
||||
observer: '_paramsChanged',
|
||||
},
|
||||
params: {
|
||||
type: Object,
|
||||
observer: '_paramsChanged',
|
||||
},
|
||||
|
||||
_change: Object,
|
||||
_changeEditDetail: Object,
|
||||
_changeNum: String,
|
||||
_patchNum: String,
|
||||
_path: String,
|
||||
_type: String,
|
||||
_content: String,
|
||||
_newContent: String,
|
||||
_saving: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_successfulSave: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_saveDisabled: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
computed: '_computeSaveDisabled(_content, _newContent, _saving)',
|
||||
},
|
||||
_prefs: Object,
|
||||
},
|
||||
_change: Object,
|
||||
_changeEditDetail: Object,
|
||||
_changeNum: String,
|
||||
_patchNum: String,
|
||||
_path: String,
|
||||
_type: String,
|
||||
_content: String,
|
||||
_newContent: String,
|
||||
_saving: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_successfulSave: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_saveDisabled: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
computed: '_computeSaveDisabled(_content, _newContent, _saving)',
|
||||
},
|
||||
_prefs: Object,
|
||||
};
|
||||
}
|
||||
|
||||
behaviors: [
|
||||
Gerrit.FireBehavior,
|
||||
Gerrit.KeyboardShortcutBehavior,
|
||||
Gerrit.PatchSetBehavior,
|
||||
Gerrit.PathListBehavior,
|
||||
],
|
||||
get keyBindings() {
|
||||
return {
|
||||
'ctrl+s meta+s': '_handleSaveShortcut',
|
||||
};
|
||||
}
|
||||
|
||||
listeners: {
|
||||
'content-change': '_handleContentChange',
|
||||
},
|
||||
|
||||
keyBindings: {
|
||||
'ctrl+s meta+s': '_handleSaveShortcut',
|
||||
},
|
||||
created() {
|
||||
super.created();
|
||||
this.addEventListener('content-change',
|
||||
e => this._handleContentChange(e));
|
||||
}
|
||||
|
||||
attached() {
|
||||
super.attached();
|
||||
this._getEditPrefs().then(prefs => { this._prefs = prefs; });
|
||||
},
|
||||
}
|
||||
|
||||
get storageKey() {
|
||||
return `c${this._changeNum}_ps${this._patchNum}_${this._path}`;
|
||||
},
|
||||
}
|
||||
|
||||
_getLoggedIn() {
|
||||
return this.$.restAPI.getLoggedIn();
|
||||
},
|
||||
}
|
||||
|
||||
_getEditPrefs() {
|
||||
return this.$.restAPI.getEditPreferences();
|
||||
},
|
||||
}
|
||||
|
||||
_paramsChanged(value) {
|
||||
if (value.view !== Gerrit.Nav.View.EDIT) {
|
||||
@@ -126,13 +138,13 @@
|
||||
promises.push(
|
||||
this._getFileData(this._changeNum, this._path, this._patchNum));
|
||||
return Promise.all(promises);
|
||||
},
|
||||
}
|
||||
|
||||
_getChangeDetail(changeNum) {
|
||||
return this.$.restAPI.getDiffChangeDetail(changeNum).then(change => {
|
||||
this._change = change;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_handlePathChanged(e) {
|
||||
const path = e.detail;
|
||||
@@ -146,13 +158,13 @@
|
||||
this._successfulSave = true;
|
||||
this._viewEditInChangeView();
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_viewEditInChangeView() {
|
||||
const patch = this._successfulSave ? this.EDIT_NAME : this._patchNum;
|
||||
Gerrit.Nav.navigateToChange(this._change, patch, null,
|
||||
patch !== this.EDIT_NAME);
|
||||
},
|
||||
}
|
||||
|
||||
_getFileData(changeNum, path, patchNum) {
|
||||
const storedContent =
|
||||
@@ -183,7 +195,7 @@
|
||||
this._type = '';
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_saveEdit() {
|
||||
this._saving = true;
|
||||
@@ -198,7 +210,7 @@
|
||||
this._content = this._newContent;
|
||||
this._successfulSave = true;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_showAlert(message) {
|
||||
this.dispatchEvent(new CustomEvent('show-alert', {
|
||||
@@ -206,7 +218,7 @@
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
}));
|
||||
},
|
||||
}
|
||||
|
||||
_computeSaveDisabled(content, newContent, saving) {
|
||||
// Polymer 2: check for undefined
|
||||
@@ -222,12 +234,12 @@
|
||||
return true;
|
||||
}
|
||||
return content === newContent;
|
||||
},
|
||||
}
|
||||
|
||||
_handleCloseTap() {
|
||||
// TODO(kaspern): Add a confirm dialog if there are unsaved changes.
|
||||
this._viewEditInChangeView();
|
||||
},
|
||||
}
|
||||
|
||||
_handleContentChange(e) {
|
||||
this.debounce('store', () => {
|
||||
@@ -239,13 +251,15 @@
|
||||
this.$.storage.eraseEditableContentItem(this.storageKey);
|
||||
}
|
||||
}, STORAGE_DEBOUNCE_INTERVAL_MS);
|
||||
},
|
||||
}
|
||||
|
||||
_handleSaveShortcut(e) {
|
||||
e.preventDefault();
|
||||
if (!this._saveDisabled) {
|
||||
this._saveEdit();
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrEditorView.is, GrEditorView);
|
||||
})();
|
||||
|
||||
@@ -17,90 +17,90 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-app-element',
|
||||
|
||||
/**
|
||||
* @appliesMixin Gerrit.BaseUrlMixin
|
||||
* @appliesMixin Gerrit.KeyboardShortcutMixin
|
||||
*/
|
||||
class GrAppElement extends Polymer.mixinBehaviors( [
|
||||
Gerrit.BaseUrlBehavior,
|
||||
Gerrit.KeyboardShortcutBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-app-element'; }
|
||||
/**
|
||||
* Fired when the URL location changes.
|
||||
*
|
||||
* @event location-change
|
||||
*/
|
||||
|
||||
properties: {
|
||||
static get properties() {
|
||||
return {
|
||||
/**
|
||||
* @type {{ query: string, view: string, screen: string }}
|
||||
*/
|
||||
params: Object,
|
||||
keyEventTarget: {
|
||||
type: Object,
|
||||
value() { return document.body; },
|
||||
},
|
||||
params: Object,
|
||||
keyEventTarget: {
|
||||
type: Object,
|
||||
value() { return document.body; },
|
||||
},
|
||||
|
||||
_account: {
|
||||
type: Object,
|
||||
observer: '_accountChanged',
|
||||
},
|
||||
_account: {
|
||||
type: Object,
|
||||
observer: '_accountChanged',
|
||||
},
|
||||
|
||||
/**
|
||||
/**
|
||||
* The last time the g key was pressed in milliseconds (or a keydown event
|
||||
* was handled if the key is held down).
|
||||
* @type {number|null}
|
||||
*/
|
||||
_lastGKeyPressTimestamp: {
|
||||
type: Number,
|
||||
value: null,
|
||||
},
|
||||
_lastGKeyPressTimestamp: {
|
||||
type: Number,
|
||||
value: null,
|
||||
},
|
||||
|
||||
/**
|
||||
/**
|
||||
* @type {{ plugin: Object }}
|
||||
*/
|
||||
_serverConfig: Object,
|
||||
_version: String,
|
||||
_showChangeListView: Boolean,
|
||||
_showDashboardView: Boolean,
|
||||
_showChangeView: Boolean,
|
||||
_showDiffView: Boolean,
|
||||
_showSettingsView: Boolean,
|
||||
_showAdminView: Boolean,
|
||||
_showCLAView: Boolean,
|
||||
_showEditorView: Boolean,
|
||||
_showPluginScreen: Boolean,
|
||||
_showDocumentationSearch: Boolean,
|
||||
/** @type {?} */
|
||||
_viewState: Object,
|
||||
/** @type {?} */
|
||||
_lastError: Object,
|
||||
_lastSearchPage: String,
|
||||
_path: String,
|
||||
_pluginScreenName: {
|
||||
type: String,
|
||||
computed: '_computePluginScreenName(params)',
|
||||
},
|
||||
_settingsUrl: String,
|
||||
_feedbackUrl: String,
|
||||
// Used to allow searching on mobile
|
||||
mobileSearch: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
},
|
||||
_serverConfig: Object,
|
||||
_version: String,
|
||||
_showChangeListView: Boolean,
|
||||
_showDashboardView: Boolean,
|
||||
_showChangeView: Boolean,
|
||||
_showDiffView: Boolean,
|
||||
_showSettingsView: Boolean,
|
||||
_showAdminView: Boolean,
|
||||
_showCLAView: Boolean,
|
||||
_showEditorView: Boolean,
|
||||
_showPluginScreen: Boolean,
|
||||
_showDocumentationSearch: Boolean,
|
||||
/** @type {?} */
|
||||
_viewState: Object,
|
||||
/** @type {?} */
|
||||
_lastError: Object,
|
||||
_lastSearchPage: String,
|
||||
_path: String,
|
||||
_pluginScreenName: {
|
||||
type: String,
|
||||
computed: '_computePluginScreenName(params)',
|
||||
},
|
||||
_settingsUrl: String,
|
||||
_feedbackUrl: String,
|
||||
// Used to allow searching on mobile
|
||||
mobileSearch: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
listeners: {
|
||||
'page-error': '_handlePageError',
|
||||
'title-change': '_handleTitleChange',
|
||||
'location-change': '_handleLocationChange',
|
||||
'rpc-log': '_handleRpcLog',
|
||||
},
|
||||
|
||||
observers: [
|
||||
'_viewChanged(params.view)',
|
||||
'_paramsChanged(params.*)',
|
||||
],
|
||||
|
||||
behaviors: [
|
||||
Gerrit.BaseUrlBehavior,
|
||||
Gerrit.KeyboardShortcutBehavior,
|
||||
],
|
||||
static get observers() {
|
||||
return [
|
||||
'_viewChanged(params.view)',
|
||||
'_paramsChanged(params.*)',
|
||||
];
|
||||
}
|
||||
|
||||
keyboardShortcuts() {
|
||||
return {
|
||||
@@ -111,13 +111,23 @@
|
||||
[this.Shortcut.GO_TO_ABANDONED_CHANGES]: '_goToAbandonedChanges',
|
||||
[this.Shortcut.GO_TO_WATCHED_CHANGES]: '_goToWatchedChanges',
|
||||
};
|
||||
},
|
||||
}
|
||||
|
||||
created() {
|
||||
super.created();
|
||||
this._bindKeyboardShortcuts();
|
||||
},
|
||||
this.addEventListener('page-error',
|
||||
e => this._handlePageError(e));
|
||||
this.addEventListener('title-change',
|
||||
e => this._handleTitleChange(e));
|
||||
this.addEventListener('location-change',
|
||||
e => this._handleLocationChange(e));
|
||||
this.addEventListener('rpc-log',
|
||||
e => this._handleRpcLog(e));
|
||||
}
|
||||
|
||||
ready() {
|
||||
super.ready();
|
||||
this.$.reporting.appStarted();
|
||||
this.$.router.start();
|
||||
|
||||
@@ -165,7 +175,7 @@
|
||||
selectedChangeIndex: 0,
|
||||
},
|
||||
};
|
||||
},
|
||||
}
|
||||
|
||||
_bindKeyboardShortcuts() {
|
||||
this.bindShortcut(this.Shortcut.SEND_REPLY,
|
||||
@@ -287,7 +297,7 @@
|
||||
|
||||
this.bindShortcut(
|
||||
this.Shortcut.SEARCH, '/');
|
||||
},
|
||||
}
|
||||
|
||||
_accountChanged(account) {
|
||||
if (!account) { return; }
|
||||
@@ -298,7 +308,7 @@
|
||||
this.$.restAPI.getEditPreferences();
|
||||
this.$.errorManager.knownAccountId =
|
||||
this._account && this._account._account_id || null;
|
||||
},
|
||||
}
|
||||
|
||||
_viewChanged(view) {
|
||||
this.$.errorView.classList.remove('show');
|
||||
@@ -328,7 +338,7 @@
|
||||
});
|
||||
}
|
||||
this.$.header.unfloat();
|
||||
},
|
||||
}
|
||||
|
||||
_handlePageError(e) {
|
||||
const props = [
|
||||
@@ -356,7 +366,7 @@
|
||||
this._lastError = err;
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_handleLocationChange(e) {
|
||||
const hash = e.detail.hash.substring(1);
|
||||
@@ -365,7 +375,7 @@
|
||||
pathname += '@' + hash;
|
||||
}
|
||||
this.set('_path', pathname);
|
||||
},
|
||||
}
|
||||
|
||||
_paramsChanged(paramsRecord) {
|
||||
const params = paramsRecord.base;
|
||||
@@ -373,7 +383,7 @@
|
||||
if (viewsToCheck.includes(params.view)) {
|
||||
this.set('_lastSearchPage', location.pathname);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_handleTitleChange(e) {
|
||||
if (e.detail.title) {
|
||||
@@ -381,54 +391,54 @@
|
||||
} else {
|
||||
document.title = '';
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_showKeyboardShortcuts(e) {
|
||||
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||
this.$.keyboardShortcuts.open();
|
||||
},
|
||||
}
|
||||
|
||||
_handleKeyboardShortcutDialogClose() {
|
||||
this.$.keyboardShortcuts.close();
|
||||
},
|
||||
}
|
||||
|
||||
_handleAccountDetailUpdate(e) {
|
||||
this.$.mainHeader.reload();
|
||||
if (this.params.view === Gerrit.Nav.View.SETTINGS) {
|
||||
this.$$('gr-settings-view').reloadAccountDetail();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_handleRegistrationDialogClose(e) {
|
||||
this.params.justRegistered = false;
|
||||
this.$.registrationOverlay.close();
|
||||
},
|
||||
}
|
||||
|
||||
_goToOpenedChanges() {
|
||||
Gerrit.Nav.navigateToStatusSearch('open');
|
||||
},
|
||||
}
|
||||
|
||||
_goToUserDashboard() {
|
||||
Gerrit.Nav.navigateToUserDashboard();
|
||||
},
|
||||
}
|
||||
|
||||
_goToMergedChanges() {
|
||||
Gerrit.Nav.navigateToStatusSearch('merged');
|
||||
},
|
||||
}
|
||||
|
||||
_goToAbandonedChanges() {
|
||||
Gerrit.Nav.navigateToStatusSearch('abandoned');
|
||||
},
|
||||
}
|
||||
|
||||
_goToWatchedChanges() {
|
||||
// The query is hardcoded, and doesn't respect custom menu entries
|
||||
Gerrit.Nav.navigateToSearchQuery('is:watched is:open');
|
||||
},
|
||||
}
|
||||
|
||||
_computePluginScreenName({plugin, screen}) {
|
||||
if (!plugin || !screen) return '';
|
||||
return `${plugin}-screen-${screen}`;
|
||||
},
|
||||
}
|
||||
|
||||
_logWelcome() {
|
||||
console.group('Runtime Info');
|
||||
@@ -441,7 +451,7 @@
|
||||
console.log(`Please file bugs and feedback at: ${this._feedbackUrl}`);
|
||||
}
|
||||
console.groupEnd();
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Intercept RPC log events emitted by REST API interfaces.
|
||||
@@ -451,17 +461,19 @@
|
||||
_handleRpcLog(e) {
|
||||
this.$.reporting.reportRpcTiming(e.detail.anonymizedUrl,
|
||||
e.detail.elapsed);
|
||||
},
|
||||
}
|
||||
|
||||
_mobileSearchToggle(e) {
|
||||
this.mobileSearch = !this.mobileSearch;
|
||||
},
|
||||
}
|
||||
|
||||
getThemeEndpoint() {
|
||||
// For now, we only have dark mode and light mode
|
||||
return window.localStorage.getItem('dark-theme') ?
|
||||
'app-theme-dark' :
|
||||
'app-theme-light';
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrAppElement.is, GrAppElement);
|
||||
})();
|
||||
|
||||
@@ -17,7 +17,11 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-app',
|
||||
});
|
||||
class GrApp extends Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element)) {
|
||||
static get is() { return 'gr-app'; }
|
||||
}
|
||||
|
||||
customElements.define(GrApp.is, GrApp);
|
||||
})();
|
||||
|
||||
@@ -19,33 +19,38 @@
|
||||
|
||||
const INIT_PROPERTIES_TIMEOUT_MS = 10000;
|
||||
|
||||
Polymer({
|
||||
is: 'gr-endpoint-decorator',
|
||||
class GrEndpointDecorator extends Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element)) {
|
||||
static get is() { return 'gr-endpoint-decorator'; }
|
||||
|
||||
properties: {
|
||||
name: String,
|
||||
/** @type {!Map} */
|
||||
_domHooks: {
|
||||
type: Map,
|
||||
value() { return new Map(); },
|
||||
},
|
||||
/**
|
||||
static get properties() {
|
||||
return {
|
||||
name: String,
|
||||
/** @type {!Map} */
|
||||
_domHooks: {
|
||||
type: Map,
|
||||
value() { return new Map(); },
|
||||
},
|
||||
/**
|
||||
* This map prevents importing the same endpoint twice.
|
||||
* Without caching, if a plugin is loaded after the loaded plugins
|
||||
* callback fires, it will be imported twice and appear twice on the page.
|
||||
* @type {!Map}
|
||||
*/
|
||||
_initializedPlugins: {
|
||||
type: Map,
|
||||
value() { return new Map(); },
|
||||
},
|
||||
},
|
||||
_initializedPlugins: {
|
||||
type: Map,
|
||||
value() { return new Map(); },
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
detached() {
|
||||
super.detached();
|
||||
for (const [el, domHook] of this._domHooks) {
|
||||
domHook.handleInstanceDetached(el);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @suppress {checkTypes}
|
||||
@@ -54,7 +59,7 @@
|
||||
return new Promise((resolve, reject) => {
|
||||
(this.importHref || Polymer.importHref)(url, resolve, reject);
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_initDecoration(name, plugin) {
|
||||
const el = document.createElement(name);
|
||||
@@ -62,7 +67,7 @@
|
||||
this.getContentChildren().find(
|
||||
el => el.nodeName !== 'GR-ENDPOINT-PARAM'))
|
||||
.then(el => this._appendChild(el));
|
||||
},
|
||||
}
|
||||
|
||||
_initReplacement(name, plugin) {
|
||||
this.getContentChildNodes()
|
||||
@@ -71,12 +76,12 @@
|
||||
const el = document.createElement(name);
|
||||
return this._initProperties(el, plugin).then(
|
||||
el => this._appendChild(el));
|
||||
},
|
||||
}
|
||||
|
||||
_getEndpointParams() {
|
||||
return Array.from(
|
||||
Polymer.dom(this).querySelectorAll('gr-endpoint-param'));
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Element} el
|
||||
@@ -109,11 +114,11 @@
|
||||
clearTimeout(timeoutId);
|
||||
return el;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_appendChild(el) {
|
||||
return Polymer.dom(this.root).appendChild(el);
|
||||
},
|
||||
}
|
||||
|
||||
_initModule({moduleName, plugin, type, domHook}) {
|
||||
const name = plugin.getPluginName() + '.' + moduleName;
|
||||
@@ -137,9 +142,10 @@
|
||||
domHook.handleInstanceAttached(el);
|
||||
this._domHooks.set(el, domHook);
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
ready() {
|
||||
super.ready();
|
||||
Gerrit._endpoints.onNewEndpoint(this.name, this._initModule.bind(this));
|
||||
Gerrit.awaitPluginsLoaded().then(() => Promise.all(
|
||||
Gerrit._endpoints.getPlugins(this.name).map(
|
||||
@@ -149,6 +155,8 @@
|
||||
.getDetails(this.name)
|
||||
.forEach(this._initModule, this)
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrEndpointDecorator.is, GrEndpointDecorator);
|
||||
})();
|
||||
|
||||
@@ -17,17 +17,21 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-endpoint-param',
|
||||
class GrEndpointParam extends Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element)) {
|
||||
static get is() { return 'gr-endpoint-param'; }
|
||||
|
||||
properties: {
|
||||
name: String,
|
||||
value: {
|
||||
type: Object,
|
||||
notify: true,
|
||||
observer: '_valueChanged',
|
||||
},
|
||||
},
|
||||
static get properties() {
|
||||
return {
|
||||
name: String,
|
||||
value: {
|
||||
type: Object,
|
||||
notify: true,
|
||||
observer: '_valueChanged',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
_valueChanged(newValue, oldValue) {
|
||||
/* In polymer 2 the following change was made:
|
||||
@@ -42,6 +46,8 @@
|
||||
value: newValue,
|
||||
};
|
||||
this.dispatchEvent(new CustomEvent('value-changed', {detail}));
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrEndpointParam.is, GrEndpointParam);
|
||||
})();
|
||||
|
||||
@@ -17,20 +17,24 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-external-style',
|
||||
class GrExternalStyle extends Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element)) {
|
||||
static get is() { return 'gr-external-style'; }
|
||||
|
||||
properties: {
|
||||
name: String,
|
||||
_urlsImported: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
_stylesApplied: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
},
|
||||
static get properties() {
|
||||
return {
|
||||
name: String,
|
||||
_urlsImported: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
_stylesApplied: {
|
||||
type: Array,
|
||||
value() { return []; },
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @suppress {checkTypes}
|
||||
@@ -41,7 +45,7 @@
|
||||
return new Promise((resolve, reject) => {
|
||||
(this.importHref || Polymer.importHref)(url, resolve, reject);
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_applyStyle(name) {
|
||||
if (this._stylesApplied.includes(name)) { return; }
|
||||
@@ -56,7 +60,7 @@
|
||||
const topEl = document.getElementsByTagName('body')[0];
|
||||
topEl.insertBefore(cs, topEl.firstChild);
|
||||
Polymer.updateStyles();
|
||||
},
|
||||
}
|
||||
|
||||
_importAndApply() {
|
||||
Promise.all(Gerrit._endpoints.getPlugins(this.name).map(
|
||||
@@ -67,14 +71,18 @@
|
||||
this._applyStyle(name);
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
attached() {
|
||||
super.attached();
|
||||
this._importAndApply();
|
||||
},
|
||||
}
|
||||
|
||||
ready() {
|
||||
super.ready();
|
||||
Gerrit.awaitPluginsLoaded().then(() => this._importAndApply());
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrExternalStyle.is, GrExternalStyle);
|
||||
})();
|
||||
|
||||
@@ -17,15 +17,19 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-plugin-host',
|
||||
class GrPluginHost extends Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element)) {
|
||||
static get is() { return 'gr-plugin-host'; }
|
||||
|
||||
properties: {
|
||||
config: {
|
||||
type: Object,
|
||||
observer: '_configChanged',
|
||||
},
|
||||
},
|
||||
static get properties() {
|
||||
return {
|
||||
config: {
|
||||
type: Object,
|
||||
observer: '_configChanged',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
_configChanged(config) {
|
||||
const plugins = config.plugin;
|
||||
@@ -50,7 +54,7 @@
|
||||
}
|
||||
|
||||
Gerrit._loadPlugins(pluginsPending, pluginOpts);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Omit .js plugins that have .html counterparts.
|
||||
@@ -61,6 +65,8 @@
|
||||
const counterpart = url.replace(/\.js$/, '.html');
|
||||
return !htmlPlugins.includes(counterpart);
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrPluginHost.is, GrPluginHost);
|
||||
})();
|
||||
|
||||
@@ -17,19 +17,23 @@
|
||||
(function(window) {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-plugin-popup',
|
||||
class GrPluginPopup extends Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element)) {
|
||||
static get is() { return 'gr-plugin-popup'; }
|
||||
|
||||
get opened() {
|
||||
return this.$.overlay.opened;
|
||||
},
|
||||
}
|
||||
|
||||
open() {
|
||||
return this.$.overlay.open();
|
||||
},
|
||||
}
|
||||
|
||||
close() {
|
||||
this.$.overlay.close();
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrPluginPopup.is, GrPluginPopup);
|
||||
})(window);
|
||||
|
||||
@@ -17,65 +17,71 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-account-info',
|
||||
|
||||
/**
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
*/
|
||||
class GrAccountInfo extends Polymer.mixinBehaviors( [
|
||||
Gerrit.FireBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-account-info'; }
|
||||
/**
|
||||
* Fired when account details are changed.
|
||||
*
|
||||
* @event account-detail-update
|
||||
*/
|
||||
|
||||
properties: {
|
||||
usernameMutable: {
|
||||
type: Boolean,
|
||||
notify: true,
|
||||
computed: '_computeUsernameMutable(_serverConfig, _account.username)',
|
||||
},
|
||||
nameMutable: {
|
||||
type: Boolean,
|
||||
notify: true,
|
||||
computed: '_computeNameMutable(_serverConfig)',
|
||||
},
|
||||
hasUnsavedChanges: {
|
||||
type: Boolean,
|
||||
notify: true,
|
||||
computed: '_computeHasUnsavedChanges(_hasNameChange, ' +
|
||||
static get properties() {
|
||||
return {
|
||||
usernameMutable: {
|
||||
type: Boolean,
|
||||
notify: true,
|
||||
computed: '_computeUsernameMutable(_serverConfig, _account.username)',
|
||||
},
|
||||
nameMutable: {
|
||||
type: Boolean,
|
||||
notify: true,
|
||||
computed: '_computeNameMutable(_serverConfig)',
|
||||
},
|
||||
hasUnsavedChanges: {
|
||||
type: Boolean,
|
||||
notify: true,
|
||||
computed: '_computeHasUnsavedChanges(_hasNameChange, ' +
|
||||
'_hasUsernameChange, _hasStatusChange)',
|
||||
},
|
||||
},
|
||||
|
||||
_hasNameChange: Boolean,
|
||||
_hasUsernameChange: Boolean,
|
||||
_hasStatusChange: Boolean,
|
||||
_loading: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_saving: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
/** @type {?} */
|
||||
_account: Object,
|
||||
_serverConfig: Object,
|
||||
_username: {
|
||||
type: String,
|
||||
observer: '_usernameChanged',
|
||||
},
|
||||
_avatarChangeUrl: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
},
|
||||
_hasNameChange: Boolean,
|
||||
_hasUsernameChange: Boolean,
|
||||
_hasStatusChange: Boolean,
|
||||
_loading: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_saving: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
/** @type {?} */
|
||||
_account: Object,
|
||||
_serverConfig: Object,
|
||||
_username: {
|
||||
type: String,
|
||||
observer: '_usernameChanged',
|
||||
},
|
||||
_avatarChangeUrl: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
behaviors: [
|
||||
Gerrit.FireBehavior,
|
||||
],
|
||||
|
||||
observers: [
|
||||
'_nameChanged(_account.name)',
|
||||
'_statusChanged(_account.status)',
|
||||
],
|
||||
static get observers() {
|
||||
return [
|
||||
'_nameChanged(_account.name)',
|
||||
'_statusChanged(_account.status)',
|
||||
];
|
||||
}
|
||||
|
||||
loadData() {
|
||||
const promises = [];
|
||||
@@ -104,7 +110,7 @@
|
||||
return Promise.all(promises).then(() => {
|
||||
this._loading = false;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
save() {
|
||||
if (!this.hasUnsavedChanges) {
|
||||
@@ -123,29 +129,29 @@
|
||||
this._saving = false;
|
||||
this.fire('account-detail-update');
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_maybeSetName() {
|
||||
return this._hasNameChange && this.nameMutable ?
|
||||
this.$.restAPI.setAccountName(this._account.name) :
|
||||
Promise.resolve();
|
||||
},
|
||||
}
|
||||
|
||||
_maybeSetUsername() {
|
||||
return this._hasUsernameChange && this.usernameMutable ?
|
||||
this.$.restAPI.setAccountUsername(this._username) :
|
||||
Promise.resolve();
|
||||
},
|
||||
}
|
||||
|
||||
_maybeSetStatus() {
|
||||
return this._hasStatusChange ?
|
||||
this.$.restAPI.setAccountStatus(this._account.status) :
|
||||
Promise.resolve();
|
||||
},
|
||||
}
|
||||
|
||||
_computeHasUnsavedChanges(nameChanged, usernameChanged, statusChanged) {
|
||||
return nameChanged || usernameChanged || statusChanged;
|
||||
},
|
||||
}
|
||||
|
||||
_computeUsernameMutable(config, username) {
|
||||
// Polymer 2: check for undefined
|
||||
@@ -159,34 +165,34 @@
|
||||
// Username may not be changed once it is set.
|
||||
return config.auth.editable_account_fields.includes('USER_NAME') &&
|
||||
!username;
|
||||
},
|
||||
}
|
||||
|
||||
_computeNameMutable(config) {
|
||||
return config.auth.editable_account_fields.includes('FULL_NAME');
|
||||
},
|
||||
}
|
||||
|
||||
_statusChanged() {
|
||||
if (this._loading) { return; }
|
||||
this._hasStatusChange = true;
|
||||
},
|
||||
}
|
||||
|
||||
_usernameChanged() {
|
||||
if (this._loading || !this._account) { return; }
|
||||
this._hasUsernameChange =
|
||||
(this._account.username || '') !== (this._username || '');
|
||||
},
|
||||
}
|
||||
|
||||
_nameChanged() {
|
||||
if (this._loading) { return; }
|
||||
this._hasNameChange = true;
|
||||
},
|
||||
}
|
||||
|
||||
_handleKeydown(e) {
|
||||
if (e.keyCode === 13) { // Enter
|
||||
e.stopPropagation();
|
||||
this.save();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_hideAvatarChangeUrl(avatarChangeUrl) {
|
||||
if (!avatarChangeUrl) {
|
||||
@@ -194,6 +200,8 @@
|
||||
}
|
||||
|
||||
return '';
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrAccountInfo.is, GrAccountInfo);
|
||||
})();
|
||||
|
||||
@@ -17,33 +17,41 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-agreements-list',
|
||||
/**
|
||||
* @appliesMixin Gerrit.BaseUrlMixin
|
||||
*/
|
||||
class GrAgreementsList extends Polymer.mixinBehaviors( [
|
||||
Gerrit.BaseUrlBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-agreements-list'; }
|
||||
|
||||
properties: {
|
||||
_agreements: Array,
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
Gerrit.BaseUrlBehavior,
|
||||
],
|
||||
static get properties() {
|
||||
return {
|
||||
_agreements: Array,
|
||||
};
|
||||
}
|
||||
|
||||
attached() {
|
||||
super.attached();
|
||||
this.loadData();
|
||||
},
|
||||
}
|
||||
|
||||
loadData() {
|
||||
return this.$.restAPI.getAccountAgreements().then(agreements => {
|
||||
this._agreements = agreements;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
getUrl() {
|
||||
return this.getBaseUrl() + '/settings/new-agreement';
|
||||
},
|
||||
}
|
||||
|
||||
getUrlBase(item) {
|
||||
return this.getBaseUrl() + '/' + item;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrAgreementsList.is, GrAgreementsList);
|
||||
})();
|
||||
|
||||
@@ -17,23 +17,28 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-change-table-editor',
|
||||
/**
|
||||
* @appliesMixin Gerrit.ChangeTableMixin
|
||||
*/
|
||||
class GrChangeTableEditor extends Polymer.mixinBehaviors( [
|
||||
Gerrit.ChangeTableBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-change-table-editor'; }
|
||||
|
||||
properties: {
|
||||
displayedColumns: {
|
||||
type: Array,
|
||||
notify: true,
|
||||
},
|
||||
showNumber: {
|
||||
type: Boolean,
|
||||
notify: true,
|
||||
},
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
Gerrit.ChangeTableBehavior,
|
||||
],
|
||||
static get properties() {
|
||||
return {
|
||||
displayedColumns: {
|
||||
type: Array,
|
||||
notify: true,
|
||||
},
|
||||
showNumber: {
|
||||
type: Boolean,
|
||||
notify: true,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of enabled column names from whichever checkboxes are
|
||||
@@ -45,7 +50,7 @@
|
||||
.querySelectorAll('.checkboxContainer input:not([name=number])'))
|
||||
.filter(checkbox => checkbox.checked)
|
||||
.map(checkbox => checkbox.name);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a click on a checkbox container and relay the click to the checkbox it
|
||||
@@ -55,7 +60,7 @@
|
||||
const checkbox = Polymer.dom(e.target).querySelector('input');
|
||||
if (!checkbox) { return; }
|
||||
checkbox.click();
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a click on the number checkbox and update the showNumber property
|
||||
@@ -63,7 +68,7 @@
|
||||
*/
|
||||
_handleNumberCheckboxClick(e) {
|
||||
this.showNumber = Polymer.dom(e).rootTarget.checked;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a click on a displayed column checkboxes (excluding number) and
|
||||
@@ -71,6 +76,8 @@
|
||||
*/
|
||||
_handleTargetClick(e) {
|
||||
this.set('displayedColumns', this._getDisplayedColumns());
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrChangeTableEditor.is, GrChangeTableEditor);
|
||||
})();
|
||||
|
||||
@@ -17,33 +17,40 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-cla-view',
|
||||
/**
|
||||
* @appliesMixin Gerrit.BaseUrlMixin
|
||||
* @appliesMixin Gerrit.FireMixin
|
||||
*/
|
||||
class GrClaView extends Polymer.mixinBehaviors( [
|
||||
Gerrit.BaseUrlBehavior,
|
||||
Gerrit.FireBehavior,
|
||||
], Polymer.GestureEventListeners(
|
||||
Polymer.LegacyElementMixin(
|
||||
Polymer.Element))) {
|
||||
static get is() { return 'gr-cla-view'; }
|
||||
|
||||
properties: {
|
||||
_groups: Object,
|
||||
/** @type {?} */
|
||||
_serverConfig: Object,
|
||||
_agreementsText: String,
|
||||
_agreementName: String,
|
||||
_signedAgreements: Array,
|
||||
_showAgreements: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_agreementsUrl: String,
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
Gerrit.BaseUrlBehavior,
|
||||
Gerrit.FireBehavior,
|
||||
],
|
||||
static get properties() {
|
||||
return {
|
||||
_groups: Object,
|
||||
/** @type {?} */
|
||||
_serverConfig: Object,
|
||||
_agreementsText: String,
|
||||
_agreementName: String,
|
||||
_signedAgreements: Array,
|
||||
_showAgreements: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_agreementsUrl: String,
|
||||
};
|
||||
}
|
||||
|
||||
attached() {
|
||||
super.attached();
|
||||
this.loadData();
|
||||
|
||||
this.fire('title-change', {title: 'New Contributor Agreement'});
|
||||
},
|
||||
}
|
||||
|
||||
loadData() {
|
||||
const promises = [];
|
||||
@@ -62,7 +69,7 @@
|
||||
}));
|
||||
|
||||
return Promise.all(promises);
|
||||
},
|
||||
}
|
||||
|
||||
_getAgreementsUrl(configUrl) {
|
||||
let url;
|
||||
@@ -76,14 +83,14 @@
|
||||
}
|
||||
|
||||
return url;
|
||||
},
|
||||
}
|
||||
|
||||
_handleShowAgreement(e) {
|
||||
this._agreementName = e.target.getAttribute('data-name');
|
||||
this._agreementsUrl =
|
||||
this._getAgreementsUrl(e.target.getAttribute('data-url'));
|
||||
this._showAgreements = true;
|
||||
},
|
||||
}
|
||||
|
||||
_handleSaveAgreements(e) {
|
||||
this._createToast('Agreement saving...');
|
||||
@@ -99,16 +106,16 @@
|
||||
this._agreementsText = '';
|
||||
this._showAgreements = false;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_createToast(message) {
|
||||
this.dispatchEvent(new CustomEvent(
|
||||
'show-alert', {detail: {message}, bubbles: true, composed: true}));
|
||||
},
|
||||
}
|
||||
|
||||
_computeShowAgreementsClass(agreements) {
|
||||
return agreements ? 'show' : '';
|
||||
},
|
||||
}
|
||||
|
||||
_disableAggreements(item, groups, signedAgreements) {
|
||||
for (const group of groups) {
|
||||
@@ -119,16 +126,16 @@
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
}
|
||||
|
||||
_hideAggreements(item, groups, signedAgreements) {
|
||||
return this._disableAggreements(item, groups, signedAgreements) ?
|
||||
'' : 'hide';
|
||||
},
|
||||
}
|
||||
|
||||
_disableAgreementsText(text) {
|
||||
return text.toLowerCase() === 'i agree' ? false : true;
|
||||
},
|
||||
}
|
||||
|
||||
// This checks for auto_verify_group,
|
||||
// if specified it returns 'hideAgreementsTextBox' which
|
||||
@@ -148,6 +155,8 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(GrClaView.is, GrClaView);
|
||||
})();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user