gr-account-label to lit
Change-Id: Ie81cb81d2cce59d776c36ba8a6160e12eaae4b42
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_html.ts b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_html.ts
index bd4cb76..8201dbc 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_html.ts
@@ -487,8 +487,8 @@
account="[[account]]"
force-attention="[[_computeHasNewAttention(account, _newAttentionSet)]]"
selected="[[_computeHasNewAttention(account, _newAttentionSet)]]"
- hide-hovercard=""
- selection-chip-style
+ hideHovercard
+ selectionChipStyle
on-click="_handleAttentionClick"
></gr-account-label>
</template>
@@ -558,8 +558,8 @@
account="[[_owner]]"
force-attention="[[_computeHasNewAttention(_owner, _newAttentionSet)]]"
selected="[[_computeHasNewAttention(_owner, _newAttentionSet)]]"
- hide-hovercard=""
- selection-chip-style
+ hideHovercard
+ selectionChipStyle
on-click="_handleAttentionClick"
>
</gr-account-label>
@@ -573,8 +573,8 @@
account="[[_uploader]]"
force-attention="[[_computeHasNewAttention(_uploader, _newAttentionSet)]]"
selected="[[_computeHasNewAttention(_uploader, _newAttentionSet)]]"
- hide-hovercard=""
- selection-chip-style
+ hideHovercard
+ selectionChipStyle
on-click="_handleAttentionClick"
>
</gr-account-label>
@@ -593,8 +593,8 @@
account="[[account]]"
force-attention="[[_computeHasNewAttention(account, _newAttentionSet)]]"
selected="[[_computeHasNewAttention(account, _newAttentionSet)]]"
- hide-hovercard=""
- selection-chip-style
+ hideHovercard
+ selectionChipStyle
on-click="_handleAttentionClick"
>
</gr-account-label>
@@ -614,8 +614,8 @@
account="[[account]]"
force-attention="[[_computeHasNewAttention(account, _newAttentionSet)]]"
selected="[[_computeHasNewAttention(account, _newAttentionSet)]]"
- hide-hovercard=""
- selection-chip-style
+ hideHovercard
+ selectionChipStyle
on-click="_handleAttentionClick"
>
</gr-account-label>
diff --git a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_html.ts b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_html.ts
index 73f3dd3..93a432b 100644
--- a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_html.ts
@@ -109,7 +109,7 @@
<gr-account-label
account="[[item]]"
on-click="handleAccountClicked"
- selection-chip-style
+ selectionChipStyle
selected="[[isSelected(item, selectedAuthors)]]"
> </gr-account-label>
</template>
diff --git a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.ts b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.ts
index cc66734..66214b4 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.ts
+++ b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.ts
@@ -15,30 +15,25 @@
* limitations under the License.
*/
import '@polymer/iron-icon/iron-icon';
-import '../../../styles/shared-styles';
import '../gr-avatar/gr-avatar';
import '../gr-hovercard-account/gr-hovercard-account';
-import {PolymerElement} from '@polymer/polymer/polymer-element';
-import {htmlTemplate} from './gr-account-label_html';
import {appContext} from '../../../services/app-context';
import {getDisplayName} from '../../../utils/display-name-util';
import {isSelf, isServiceUser} from '../../../utils/account-util';
-import {customElement, property} from '@polymer/decorators';
import {ReportingService} from '../../../services/gr-reporting/gr-reporting';
import {ChangeInfo, AccountInfo, ServerInfo} from '../../../types/common';
import {hasOwnProperty} from '../../../utils/common-util';
import {fireEvent} from '../../../utils/event-util';
import {isInvolved} from '../../../utils/change-util';
import {ShowAlertEventDetail} from '../../../types/events';
+import {GrLitElement} from '../../lit/gr-lit-element';
+import {css, customElement, html, property, state} from 'lit-element';
+import {classMap} from 'lit-html/directives/class-map';
@customElement('gr-account-label')
-export class GrAccountLabel extends PolymerElement {
- static get template() {
- return htmlTemplate;
- }
-
+export class GrAccountLabel extends GrLitElement {
@property({type: Object})
- account!: AccountInfo;
+ account?: AccountInfo;
@property({type: Object})
_selfAccount?: AccountInfo;
@@ -49,7 +44,7 @@
* related features like adding the user as a reviewer.
*/
@property({type: Object})
- change!: ChangeInfo;
+ change?: ChangeInfo;
@property({type: String})
voteableText?: string;
@@ -83,44 +78,190 @@
@property({
type: Boolean,
- reflectToAttribute: true,
- computed:
- '_computeCancelLeftPadding(hideAvatar, ' +
- 'highlightAttention, account, change, forceAttention)',
+ reflect: true,
})
cancelLeftPadding = false;
@property({type: Boolean})
hideStatus = false;
- @property({type: Object})
+ @state()
_config?: ServerInfo;
- @property({type: Boolean, reflectToAttribute: true})
+ @property({type: Boolean, reflect: true})
selectionChipStyle = false;
@property({
type: Boolean,
- reflectToAttribute: true,
- observer: 'selectedChanged',
+ reflect: true,
})
selected = false;
- @property({type: Boolean, reflectToAttribute: true})
+ @property({type: Boolean, reflect: true})
deselected = false;
reporting: ReportingService;
private readonly restApiService = appContext.restApiService;
+ static get styles() {
+ return [
+ css`
+ :host {
+ display: inline-block;
+ vertical-align: top;
+ position: relative;
+ border-radius: var(--label-border-radius);
+ box-sizing: border-box;
+ white-space: nowrap;
+ padding: 0 var(--account-label-padding-horizontal, 0);
+ }
+ /* If the first element is the avatar, then we cancel the left padding,
+ so we can fit nicely into the gr-account-chip rounding. The obvious
+ alternative of 'chip has padding' and 'avatar gets negative margin'
+ does not work, because we need 'overflow:hidden' on the label. */
+ :host([cancelLeftPadding]) {
+ padding-left: 0;
+ }
+ :host::after {
+ content: var(--account-label-suffix);
+ }
+ :host([deselected][selectionChipStyle]) {
+ background-color: var(--background-color-primary);
+ border: 1px solid var(--comment-separator-color);
+ border-radius: 8px;
+ color: var(--deemphasized-text-color);
+ }
+ :host([selected][selectionChipStyle]) {
+ background-color: var(--chip-selected-background-color);
+ border: 1px solid var(--chip-selected-background-color);
+ border-radius: 8px;
+ color: var(--chip-selected-text-color);
+ }
+ :host([selected]) iron-icon.attention {
+ color: var(--chip-selected-text-color);
+ }
+ gr-avatar {
+ height: calc(var(--line-height-normal) - 2px);
+ width: calc(var(--line-height-normal) - 2px);
+ vertical-align: top;
+ position: relative;
+ top: 1px;
+ }
+ #attentionButton {
+ /* This negates the 4px horizontal padding, which we appreciate as a
+ larger click target, but which we don't want to consume space. :-) */
+ margin: 0 -4px 0 -4px;
+ vertical-align: top;
+ }
+ iron-icon.attention {
+ color: var(--deemphasized-text-color);
+ width: 12px;
+ height: 12px;
+ vertical-align: top;
+ }
+ iron-icon.status {
+ color: var(--deemphasized-text-color);
+ width: 14px;
+ height: 14px;
+ vertical-align: top;
+ position: relative;
+ top: 2px;
+ }
+ .name {
+ display: inline-block;
+ text-decoration: inherit;
+ vertical-align: top;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ max-width: var(--account-max-length, 180px);
+ }
+ .hasAttention .name {
+ font-weight: var(--font-weight-bold);
+ }
+ `,
+ ];
+ }
+
+ render() {
+ const {account, change, highlightAttention, forceAttention} = this;
+ if (!account) return;
+ const hasAttention =
+ forceAttention ||
+ this._hasUnforcedAttention(highlightAttention, account, change);
+ this.deselected = !this.selected;
+ this.cancelLeftPadding = !this.hideAvatar && !hasAttention;
+ return html`<span>
+ ${!this.hideHovercard
+ ? html`<gr-hovercard-account
+ for="hovercardTarget"
+ .account="${account}"
+ .change="${change}"
+ ?highlight-attention=${highlightAttention}
+ .voteable-text=${this.voteableText}
+ ></gr-hovercard-account>`
+ : ''}
+ ${hasAttention
+ ? html`<gr-button
+ id="attentionButton"
+ link=""
+ aria-label="Remove user from attention set"
+ @click=${this._handleRemoveAttentionClick}
+ ?disabled=${!this._computeAttentionButtonEnabled(
+ highlightAttention,
+ account,
+ change,
+ this.selected,
+ this._selfAccount
+ )}
+ ?has-tooltip=${this._computeAttentionButtonEnabled(
+ highlightAttention,
+ account,
+ change,
+ false,
+ this._selfAccount
+ )}
+ title="${this._computeAttentionIconTitle(
+ highlightAttention,
+ account,
+ change,
+ forceAttention,
+ this.selected,
+ this._selfAccount
+ )}"
+ ><iron-icon
+ class="attention"
+ icon="gr-icons:attention"
+ ></iron-icon>
+ </gr-button>`
+ : ''}
+ </span>
+ <span
+ id="hovercardTarget"
+ class="${classMap({
+ hasAttention: !!hasAttention,
+ })}"
+ >
+ ${!this.hideAvatar
+ ? html`<gr-avatar .account="${account}" imageSize="32"></gr-avatar>`
+ : ''}
+ <span class="text" part="gr-account-label-text">
+ <span class="name"
+ >${this._computeName(account, this.firstName, this._config)}</span
+ >
+ ${!this.hideStatus && account.status
+ ? html`<iron-icon
+ class="status"
+ icon="gr-icons:calendar"
+ ></iron-icon>`
+ : ''}
+ </span>
+ </span>`;
+ }
+
constructor() {
super();
this.reporting = appContext.reportingService;
- }
-
- /** @override */
- ready() {
- super.ready();
this.restApiService.getConfig().then(config => {
this._config = config;
});
@@ -129,72 +270,42 @@
});
this.addEventListener('attention-set-updated', () => {
// For re-evaluation of everything that depends on 'change'.
- this.change = {...this.change};
+ if (this.change) this.change = {...this.change};
});
}
- selectedChanged(selected?: boolean) {
- this.deselected = !selected;
- }
-
_isAttentionSetEnabled(
highlight: boolean,
account: AccountInfo,
- change: ChangeInfo
+ change?: ChangeInfo
) {
return highlight && !!change && !!account && !isServiceUser(account);
}
- _computeCancelLeftPadding(
- hideAvatar: boolean,
- highlight: boolean,
- account: AccountInfo,
- change: ChangeInfo,
- force: boolean
- ) {
- return (
- !hideAvatar && !this._hasAttention(highlight, account, change, force)
- );
- }
-
- _hasAttention(
- highlight: boolean,
- account: AccountInfo,
- change: ChangeInfo,
- force: boolean
- ) {
- return force || this._hasUnforcedAttention(highlight, account, change);
- }
-
_hasUnforcedAttention(
highlight: boolean,
account: AccountInfo,
- change: ChangeInfo
+ change?: ChangeInfo
) {
return (
this._isAttentionSetEnabled(highlight, account, change) &&
+ change &&
change.attention_set &&
!!account._account_id &&
hasOwnProperty(change.attention_set, account._account_id)
);
}
- _computeHasAttentionClass(
- highlight: boolean,
- account: AccountInfo,
- change: ChangeInfo,
- force: boolean
+ _computeName(
+ account?: AccountInfo,
+ firstName?: boolean,
+ config?: ServerInfo
) {
- return this._hasAttention(highlight, account, change, force)
- ? 'hasAttention'
- : '';
- }
-
- _computeName(account: AccountInfo, firstName: boolean, config?: ServerInfo) {
return getDisplayName(config, account, firstName);
}
_handleRemoveAttentionClick(e: MouseEvent) {
+ if (!this.account || !this.change) return;
if (this.selected) return;
e.preventDefault();
e.stopPropagation();
@@ -236,6 +347,7 @@
}
_reportingDetails() {
+ if (!this.account) return;
const targetId = this.account._account_id;
const ownerId =
(this.change && this.change.owner && this.change.owner._account_id) || -1;
@@ -259,7 +371,7 @@
_computeAttentionButtonEnabled(
highlight: boolean,
account: AccountInfo,
- change: ChangeInfo,
+ change: ChangeInfo | undefined,
selected: boolean,
selfAccount?: AccountInfo
) {
@@ -273,7 +385,7 @@
_computeAttentionIconTitle(
highlight: boolean,
account: AccountInfo,
- change: ChangeInfo,
+ change: ChangeInfo | undefined,
force: boolean,
selected: boolean,
selfAccount?: AccountInfo
diff --git a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_html.ts b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_html.ts
deleted file mode 100644
index 352763b..0000000
--- a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_html.ts
+++ /dev/null
@@ -1,137 +0,0 @@
-/**
- * @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 {html} from '@polymer/polymer/lib/utils/html-tag';
-
-export const htmlTemplate = html`
- <style>
- :host {
- display: inline-block;
- vertical-align: top;
- position: relative;
- border-radius: var(--label-border-radius);
- box-sizing: border-box;
- white-space: nowrap;
- padding: 0 var(--account-label-padding-horizontal, 0);
- }
- /* If the first element is the avatar, then we cancel the left padding, so
- we can fit nicely into the gr-account-chip rounding.
- The obvious alternative of 'chip has padding' and 'avatar gets negative
- margin' does not work, because we need 'overflow:hidden' on the label. */
- :host([cancel-left-padding]) {
- padding-left: 0;
- }
- :host::after {
- content: var(--account-label-suffix);
- }
- :host([deselected][selection-chip-style]) {
- background-color: var(--background-color-primary);
- border: 1px solid var(--comment-separator-color);
- border-radius: 8px;
- color: var(--deemphasized-text-color);
- }
- :host([selected][selection-chip-style]) {
- background-color: var(--chip-selected-background-color);
- border: 1px solid var(--chip-selected-background-color);
- border-radius: 8px;
- color: var(--chip-selected-text-color);
- }
- :host([selected]) iron-icon.attention {
- color: var(--chip-selected-text-color);
- }
- gr-avatar {
- height: calc(var(--line-height-normal) - 2px);
- width: calc(var(--line-height-normal) - 2px);
- vertical-align: top;
- position: relative;
- top: 1px;
- }
- #attentionButton {
- /* This negates the 4px horizontal padding, which we appreciate as a
- larger click target, but which we don't want to consume space. :-) */
- margin: 0 -4px 0 -4px;
- vertical-align: top;
- }
- iron-icon.attention {
- color: var(--deemphasized-text-color);
- width: 12px;
- height: 12px;
- vertical-align: top;
- }
- iron-icon.status {
- color: var(--deemphasized-text-color);
- width: 14px;
- height: 14px;
- vertical-align: top;
- position: relative;
- top: 2px;
- }
- .name {
- display: inline-block;
- text-decoration: inherit;
- vertical-align: top;
- overflow: hidden;
- text-overflow: ellipsis;
- max-width: var(--account-max-length, 180px);
- }
- .hasAttention .name {
- font-weight: var(--font-weight-bold);
- }
- </style>
- <span>
- <template is="dom-if" if="[[!hideHovercard]]">
- <gr-hovercard-account
- for="hovercardTarget"
- account="[[account]]"
- change="[[change]]"
- highlight-attention="[[highlightAttention]]"
- voteable-text="[[voteableText]]"
- >
- </gr-hovercard-account>
- </template>
- <template
- is="dom-if"
- if="[[_hasAttention(highlightAttention, account, change, forceAttention)]]"
- >
- <gr-button
- id="attentionButton"
- link=""
- aria-label="Remove user from attention set"
- on-click="_handleRemoveAttentionClick"
- disabled="[[!_computeAttentionButtonEnabled(highlightAttention, account, change, selected, _selfAccount)]]"
- has-tooltip="[[_computeAttentionButtonEnabled(highlightAttention, account, change, false, _selfAccount)]]"
- title="[[_computeAttentionIconTitle(highlightAttention, account, change, forceAttention, selected, _selfAccount)]]"
- ><iron-icon class="attention" icon="gr-icons:attention"></iron-icon>
- </gr-button>
- </template>
- </span>
- <span
- id="hovercardTarget"
- class$="[[_computeHasAttentionClass(highlightAttention, account, change, forceAttention)]]"
- >
- <template is="dom-if" if="[[!hideAvatar]]">
- <gr-avatar account="[[account]]" imageSize="32"></gr-avatar>
- </template>
- <span class="text" part="gr-account-label-text">
- <span class="name">[[_computeName(account, firstName, _config)]]</span>
- <template is="dom-if" if="[[!hideStatus]]">
- <template is="dom-if" if="[[account.status]]">
- <iron-icon class="status" icon="gr-icons:calendar"></iron-icon>
- </template>
- </template>
- </span>
- </span>
-`;
diff --git a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.ts b/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.ts
index 317806c..a610ffa 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.ts
+++ b/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.ts
@@ -89,12 +89,12 @@
<gr-account-label
.account="${this.account}"
.change="${this.change}"
- ?force-attention=${this.forceAttention}
- ?highlight-attention=${this.highlightAttention}
- ?hide-avatar=${this.hideAvatar}
- ?hide-status=${this.hideStatus}
- ?first-name=${this.firstName}
- .voteable-text=${this.voteableText}
+ ?forceAttention=${this.forceAttention}
+ ?highlightAttention=${this.highlightAttention}
+ ?hideAvatar=${this.hideAvatar}
+ ?hideStatus=${this.hideStatus}
+ ?firstName=${this.firstName}
+ .voteableText=${this.voteableText}
part="gr-account-link-text => gr-account-label-text"
>
</gr-account-label>
diff --git a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_html.ts b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_html.ts
index a848b2f..3e0b9a4 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_html.ts
@@ -262,7 +262,7 @@
<gr-account-label
account="[[_getAuthor(comment, _selfAccount)]]"
class$="[[_computeAccountLabelClass(draft)]]"
- hide-status=""
+ hideStatus
>
</gr-account-label>
</template>
diff --git a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_test.ts b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_test.ts
index bbf3442..a218959 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_test.ts
+++ b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_test.ts
@@ -367,23 +367,20 @@
getTimerStub = stubReporting('getTimer').returns(mockTimer);
});
- test('create', () => {
+ test('create', async () => {
element.patchNum = 1 as PatchSetNum;
element.comment = {};
- return element._handleSave(mockEvent)!.then(() => {
- assert.equal(
- (queryAndAssert(
- element,
- 'gr-account-label'
- ).shadowRoot?.querySelector(
- 'span.name'
- ) as HTMLSpanElement).innerText.trim(),
- 'Dhruv Srivastava'
- );
- assert.isTrue(endStub.calledOnce);
- assert.isTrue(getTimerStub.calledOnce);
- assert.equal(getTimerStub.lastCall.args[0], 'CreateDraftComment');
- });
+ await element._handleSave(mockEvent);
+ await flush();
+ const grAccountLabel = queryAndAssert(element, 'gr-account-label');
+ const spanName = queryAndAssert<HTMLSpanElement>(
+ grAccountLabel,
+ 'span.name'
+ );
+ assert.equal(spanName.innerText.trim(), 'Dhruv Srivastava');
+ assert.isTrue(endStub.calledOnce);
+ assert.isTrue(getTimerStub.calledOnce);
+ assert.equal(getTimerStub.lastCall.args[0], 'CreateDraftComment');
});
test('update', () => {