blob: 947fe35833a07f5cb1a051e63d2ab1ffdc3f91c1 [file] [log] [blame]
/**
* @license
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {CodeOwnerService, OwnerStatus} from './code-owners-service.js';
const MAGIC_FILES = ['/COMMIT_MSG', '/MERGE_LIST', '/PATCHSET_LEVEL'];
const STATUS_CODE = {
PENDING: 'pending',
MISSING: 'missing',
APPROVED: 'approved',
ERROR: 'error',
};
const STATUS_ICON = {
[STATUS_CODE.PENDING]: 'gr-icons:schedule',
[STATUS_CODE.MISSING]: 'gr-icons:close',
[STATUS_CODE.APPROVED]: 'gr-icons:check',
// TODO: not finalized yet
[STATUS_CODE.ERROR]: 'gr-icons:info-outline',
};
const STATUS_TOOLTIP = {
[STATUS_CODE.PENDING]: 'Owner has not approved yet.',
[STATUS_CODE.MISSING]: 'Missing owner in reviewers, please add.',
[STATUS_CODE.APPROVED]: 'This file has been approved by the owner'
+ 'or owned by you.',
[STATUS_CODE.ERROR]: 'Can not determine owner status for this file.',
};
class BaseEl extends Polymer.Element {
computeHidden(change, patchRange) {
if ([change, patchRange].includes(undefined)) return true;
const latestPatchset = change.revisions[change.current_revision];
// only show if its comparing against base
if (patchRange.basePatchNum !== 'PARENT') return true;
// only show if its latest patchset
if (`${patchRange.patchNum}` !== `${latestPatchset._number}`) return true;
return false;
}
onInputChanged(restApi, change) {
if ([restApi, change].includes(undefined)) return;
this.ownerService = CodeOwnerService.getOwnerService(this.restApi, change);
}
}
/**
* Column header element for owner status.
*/
export class OwnerStatusColumnHeader extends BaseEl {
static get is() {
return 'owner-status-column-header';
}
static get template() {
return Polymer.html`
<style include="shared-styles">
:host(:not([hidden])) {
display: block;
padding-right: var(--spacing-m);
width: 3em;
}
</style>
<div>Owners</div>
`;
}
static get properties() {
return {
change: Object,
patchRange: Object,
hidden: {
type: Boolean,
reflectToAttribute: true,
computed: 'computeHidden(change, patchRange)',
},
restApi: Object,
ownerService: Object,
};
}
static get observers() {
return [
'onInputChanged(restApi, change)',
'onOwnerServiceChanged(ownerServive)',
];
}
}
customElements.define(OwnerStatusColumnHeader.is, OwnerStatusColumnHeader);
/**
* Row content element for owner status.
*/
export class OwnerStatusColumnContent extends BaseEl {
static get is() {
return 'owner-status-column-content';
}
static get properties() {
return {
change: Object,
path: String,
patchRange: Object,
hidden: {
type: Boolean,
reflectToAttribute: true,
computed: 'computeHidden(change, patchRange)',
},
restApi: Object,
ownerService: Object,
statusIcon: String,
statusInfo: String,
status: {
type: String,
reflectToAttribute: true,
},
};
}
static get template() {
return Polymer.html`
<style include="shared-styles">
:host(:not([hidden])) {
display:block;
padding-right: var(--spacing-m);
width: 3em;
text-align: center;
}
:host([status=approved]) iron-icon {
color: var(--vote-color-approved);
}
:host([status=pending]) iron-icon {
color: #ffa62f;
}
:host([status=missing]) iron-icon,
:host([status=error]) iron-icon {
color: var(--vote-color-disliked);
}
</style>
<gr-tooltip-content title="[[statusInfo]]" has-tooltip>
<iron-icon icon="[[statusIcon]]"></iron-icon>
</gr-tooltip-content>
`;
}
static get observers() {
return [
'onInputChanged(restApi, change)',
'computeStatusIcon(ownerService, path)',
];
}
computeStatusIcon(ownerService, path) {
if ([ownerService, path].includes(undefined)) return;
if (MAGIC_FILES.includes(path)) return;
ownerService.getStatusForPath(path)
.then(status => {
switch (status) {
case OwnerStatus.APPROVED:
this.status = STATUS_CODE.APPROVED;
break;
case OwnerStatus.INSUFFICIENT_REVIEWERS:
this.status = STATUS_CODE.MISSING;
break;
case OwnerStatus.PENDING:
this.status = STATUS_CODE.PENDING;
break;
default:
this.status = STATUS_CODE.ERROR;
break;
}
this.statusIcon = STATUS_ICON[this.status];
this.statusInfo = STATUS_TOOLTIP[this.status];
})
.catch(e => {
this.status = STATUS_CODE.ERROR;
this.statusIcon = STATUS_ICON[this.status];
this.statusInfo = STATUS_TOOLTIP[this.status];
throw e;
});
}
}
customElements.define(OwnerStatusColumnContent.is, OwnerStatusColumnContent);