Merge changes I8d678fa7,I882fd504
* changes:
Make a viewState a state in gr-editor-view
Fix “Old Patchset” being displayed on current edits
diff --git a/java/com/google/gerrit/server/mail/send/ChangeEmail.java b/java/com/google/gerrit/server/mail/send/ChangeEmail.java
index 7bbee2a..ff811a0 100644
--- a/java/com/google/gerrit/server/mail/send/ChangeEmail.java
+++ b/java/com/google/gerrit/server/mail/send/ChangeEmail.java
@@ -242,7 +242,9 @@
}
private int getInsertionsCount() {
- return listModifiedFiles().values().stream()
+ return listModifiedFiles().entrySet().stream()
+ .filter(e -> !Patch.COMMIT_MSG.equals(e.getKey()))
+ .map(Map.Entry::getValue)
.map(FileDiffOutput::insertions)
.reduce(0, Integer::sum);
}
@@ -323,8 +325,8 @@
+ "{1,choice,0#0 insertions|1#1 insertion|1<{1} insertions}(+), " //
+ "{2,choice,0#0 deletions|1#1 deletion|1<{2} deletions}(-)" //
+ "\n",
- modifiedFiles.size() - 1, //
- getInsertionsCount(), //
+ modifiedFiles.size() - 1, // -1 to account for the commit message
+ getInsertionsCount(),
getDeletionsCount()));
detail.append("\n");
}
diff --git a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
index e3d69e1..21fc4b4 100644
--- a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
@@ -101,6 +101,7 @@
import com.google.gerrit.entities.BooleanProjectConfig;
import com.google.gerrit.entities.BranchNameKey;
import com.google.gerrit.entities.Change;
+import com.google.gerrit.entities.EmailHeader.StringEmailHeader;
import com.google.gerrit.entities.LabelFunction;
import com.google.gerrit.entities.LabelId;
import com.google.gerrit.entities.LabelType;
@@ -196,6 +197,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Iterator;
@@ -4551,6 +4553,47 @@
.contains(String.format("%s has removed %s", admin.fullName(), reviewerInput.reviewer));
}
+ @Test
+ public void emailSubjectContainsChangeSizeBucket() throws Exception {
+ testEmailSubjectContainsChangeSizeBucket(0, "NoOp");
+ testEmailSubjectContainsChangeSizeBucket(1, "XS");
+ testEmailSubjectContainsChangeSizeBucket(9, "XS");
+ testEmailSubjectContainsChangeSizeBucket(10, "S");
+ testEmailSubjectContainsChangeSizeBucket(49, "S");
+ testEmailSubjectContainsChangeSizeBucket(50, "M");
+ testEmailSubjectContainsChangeSizeBucket(249, "M");
+ testEmailSubjectContainsChangeSizeBucket(250, "L");
+ testEmailSubjectContainsChangeSizeBucket(999, "L");
+ testEmailSubjectContainsChangeSizeBucket(1000, "XL");
+ }
+
+ private void testEmailSubjectContainsChangeSizeBucket(
+ int numberOfLines, String expectedSizeBucket) throws Exception {
+ String change;
+ if (numberOfLines == 0) {
+ // create empty change
+ ChangeInput in = new ChangeInput();
+ in.branch = Constants.MASTER;
+ in.subject = "Create a change from the API";
+ in.project = project.get();
+ ChangeInfo info = gApi.changes().create(in).get();
+ change = info.changeId;
+ } else {
+ change =
+ createChange(
+ "subject",
+ expectedSizeBucket + "-file-with-" + numberOfLines + "lines.txt",
+ Collections.nCopies(numberOfLines, "line").stream().collect(joining("\n")))
+ .getChangeId();
+ }
+ sender.clear();
+ gApi.changes().id(change).addReviewer(user.email());
+ List<Message> messages = sender.getMessages();
+ assertThat(messages).hasSize(1);
+ assertThat(((StringEmailHeader) messages.get(0).headers().get("Subject")).getString())
+ .contains("[" + expectedSizeBucket + "]");
+ }
+
private PushOneCommit.Result createWorkInProgressChange() throws Exception {
return pushTo("refs/for/master%wip");
}
diff --git a/javatests/com/google/gerrit/acceptance/server/mail/ChangeNotificationsIT.java b/javatests/com/google/gerrit/acceptance/server/mail/ChangeNotificationsIT.java
index e44bfcf..cced47f 100644
--- a/javatests/com/google/gerrit/acceptance/server/mail/ChangeNotificationsIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/mail/ChangeNotificationsIT.java
@@ -984,7 +984,7 @@
StagedPreChange spc = stagePreChange("refs/for/master");
assertThat(sender)
.sent("newchange", spc)
- .title(String.format("[S] Change in %s[master]: test commit", project));
+ .title(String.format("[XS] Change in %s[master]: test commit", project));
assertThat(sender).didNotSend();
}
diff --git a/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog.ts b/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog.ts
index 42ec988..bb59c0c 100644
--- a/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog.ts
+++ b/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog.ts
@@ -7,6 +7,7 @@
import {sharedStyles} from '../../../styles/shared-styles';
import {css, html, LitElement} from 'lit';
import {customElement, property} from 'lit/decorators.js';
+import {fireEventNoBubble} from '../../../utils/event-util';
declare global {
interface HTMLElementTagNameMap {
@@ -68,22 +69,12 @@
_handleConfirmTap(e: Event) {
e.preventDefault();
e.stopPropagation();
- this.dispatchEvent(
- new CustomEvent('confirm', {
- composed: true,
- bubbles: false,
- })
- );
+ fireEventNoBubble(this, 'confirm');
}
_handleCancelTap(e: Event) {
e.preventDefault();
e.stopPropagation();
- this.dispatchEvent(
- new CustomEvent('cancel', {
- composed: true,
- bubbles: false,
- })
- );
+ fireEventNoBubble(this, 'cancel');
}
}
diff --git a/polygerrit-ui/app/elements/admin/gr-group/gr-group.ts b/polygerrit-ui/app/elements/admin/gr-group/gr-group.ts
index 8e36aa8..1ec83efa8 100644
--- a/polygerrit-ui/app/elements/admin/gr-group/gr-group.ts
+++ b/polygerrit-ui/app/elements/admin/gr-group/gr-group.ts
@@ -13,7 +13,7 @@
AutocompleteQuery,
} from '../../shared/gr-autocomplete/gr-autocomplete';
import {GroupId, GroupInfo, GroupName} from '../../../types/common';
-import {firePageError, fireTitleChange} from '../../../utils/event-util';
+import {fire, firePageError, fireTitleChange} from '../../../utils/event-util';
import {getAppContext} from '../../../services/app-context';
import {ErrorCallback} from '../../../api/rest';
import {convertToString} from '../../../utils/string-util';
@@ -48,16 +48,13 @@
interface HTMLElementTagNameMap {
'gr-group': GrGroup;
}
+ interface HTMLElementEventMap {
+ 'name-changed': CustomEvent<GroupNameChangedDetail>;
+ }
}
@customElement('gr-group')
export class GrGroup extends LitElement {
- /**
- * Fired when the group name changes.
- *
- * @event name-changed
- */
-
private readonly query: AutocompleteQuery;
@property({type: String})
@@ -373,13 +370,7 @@
name: groupName,
external: !this.groupIsInternal,
};
- this.dispatchEvent(
- new CustomEvent('name-changed', {
- detail,
- composed: true,
- bubbles: true,
- })
- );
+ fire(this, 'name-changed', detail);
this.requestUpdate();
}
diff --git a/polygerrit-ui/app/elements/admin/gr-plugin-config-array-editor/gr-plugin-config-array-editor.ts b/polygerrit-ui/app/elements/admin/gr-plugin-config-array-editor/gr-plugin-config-array-editor.ts
index 54a83ee..5afaa9d 100644
--- a/polygerrit-ui/app/elements/admin/gr-plugin-config-array-editor/gr-plugin-config-array-editor.ts
+++ b/polygerrit-ui/app/elements/admin/gr-plugin-config-array-editor/gr-plugin-config-array-editor.ts
@@ -15,21 +15,19 @@
import {LitElement, html, css} from 'lit';
import {customElement, property, state} from 'lit/decorators.js';
import {BindValueChangeEvent} from '../../../types/events';
+import {fireNoBubbleNoCompose} from '../../../utils/event-util';
declare global {
interface HTMLElementTagNameMap {
'gr-plugin-config-array-editor': GrPluginConfigArrayEditor;
}
+ interface HTMLElementEventMap {
+ 'plugin-config-option-changed': CustomEvent<PluginConfigOptionsChangedEventDetail>;
+ }
}
@customElement('gr-plugin-config-array-editor')
export class GrPluginConfigArrayEditor extends LitElement {
- /**
- * Fired when the plugin config option changes.
- *
- * @event plugin-config-option-changed
- */
-
// private but used in test
@state() newValue = '';
@@ -175,9 +173,7 @@
info: {...info, values},
notifyPath: `${_key}.values`,
};
- this.dispatchEvent(
- new CustomEvent('plugin-config-option-changed', {detail})
- );
+ fireNoBubbleNoCompose(this, 'plugin-config-option-changed', detail);
}
private handleBindValueChangedNewValue(e: BindValueChangeEvent) {
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-plugin-config/gr-repo-plugin-config.ts b/polygerrit-ui/app/elements/admin/gr-repo-plugin-config/gr-repo-plugin-config.ts
index f8dcd32..2772519 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-plugin-config/gr-repo-plugin-config.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-plugin-config/gr-repo-plugin-config.ts
@@ -25,8 +25,7 @@
PluginOption,
} from './gr-repo-plugin-config-types';
import {paperStyles} from '../../../styles/gr-paper-styles';
-
-const PLUGIN_CONFIG_CHANGED_EVENT_NAME = 'plugin-config-changed';
+import {fire} from '../../../utils/event-util';
export interface ConfigChangeInfo {
_key: string; // parameterName of PluginParameterToConfigParameterInfoMap
@@ -255,14 +254,7 @@
name,
config: {...config, [_key]: info},
};
-
- this.dispatchEvent(
- new CustomEvent(PLUGIN_CONFIG_CHANGED_EVENT_NAME, {
- detail,
- bubbles: true,
- composed: true,
- })
- );
+ fire(this, 'plugin-config-changed', detail);
}
/**
@@ -277,4 +269,7 @@
interface HTMLElementTagNameMap {
'gr-repo-plugin-config': GrRepoPluginConfig;
}
+ interface HTMLElementEventMap {
+ 'plugin-config-changed': CustomEvent<PluginConfigChangeDetail>;
+ }
}
diff --git a/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor.ts b/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor.ts
index 5f0a171..82a4eb5 100644
--- a/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor.ts
+++ b/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor.ts
@@ -8,12 +8,12 @@
import '../../shared/gr-select/gr-select';
import {encodeURL, getBaseUrl} from '../../../utils/url-util';
import {AccessPermissionId} from '../../../utils/access-util';
-import {fireEvent} from '../../../utils/event-util';
+import {fire, fireEvent} from '../../../utils/event-util';
import {formStyles} from '../../../styles/gr-form-styles';
import {sharedStyles} from '../../../styles/shared-styles';
import {LitElement, PropertyValues, html, css} from 'lit';
import {customElement, property, state} from 'lit/decorators.js';
-import {BindValueChangeEvent} from '../../../types/events';
+import {BindValueChangeEvent, ValueChangedEvent} from '../../../types/events';
import {ifDefined} from 'lit/directives/if-defined.js';
import {EditablePermissionRuleInfo} from '../gr-repo-access/gr-repo-access-interfaces';
import {PermissionAction} from '../../../constants/constants';
@@ -81,6 +81,9 @@
interface HTMLElementTagNameMap {
'gr-rule-editor': GrRuleEditor;
}
+ interface HTMLElementEventMap {
+ 'rule-changed': ValueChangedEvent<Rule | undefined>;
+ }
}
@customElement('gr-rule-editor')
@@ -537,13 +540,6 @@
private handleRuleChange() {
this.requestUpdate('rule');
-
- this.dispatchEvent(
- new CustomEvent('rule-changed', {
- detail: {value: this.rule},
- composed: true,
- bubbles: true,
- })
- );
+ fire(this, 'rule-changed', {value: this.rule});
}
}
diff --git a/polygerrit-ui/app/elements/change-list/gr-create-destination-dialog/gr-create-destination-dialog.ts b/polygerrit-ui/app/elements/change-list/gr-create-destination-dialog/gr-create-destination-dialog.ts
index 561fffd..90fff4d 100644
--- a/polygerrit-ui/app/elements/change-list/gr-create-destination-dialog/gr-create-destination-dialog.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-create-destination-dialog/gr-create-destination-dialog.ts
@@ -12,6 +12,7 @@
import {assertIsDefined} from '../../../utils/common-util';
import {BindValueChangeEvent} from '../../../types/events';
import {modalStyles} from '../../../styles/gr-modal-styles';
+import {fireNoBubbleNoCompose} from '../../../utils/event-util';
export interface CreateDestinationConfirmDetail {
repo?: RepoName;
@@ -88,7 +89,7 @@
// 'confirm' event here, so let's stop propagation of the bare event.
e.preventDefault();
e.stopPropagation();
- this.dispatchEvent(new CustomEvent('confirm', {detail, bubbles: false}));
+ fireNoBubbleNoCompose(this, 'confirm', detail);
};
}
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts
index e47b450..259c8be 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts
@@ -76,7 +76,9 @@
import {
fire,
fireAlert,
+ fireError,
fireEvent,
+ fireEventNoBubbleNoCompose,
fireReload,
} from '../../../utils/event-util';
import {
@@ -84,7 +86,7 @@
getVotingRange,
StandardLabels,
} from '../../../utils/label-util';
-import {EventType, ShowAlertEventDetail} from '../../../types/events';
+import {EventType} from '../../../types/events';
import {
ActionPriority,
ActionType,
@@ -334,18 +336,6 @@
* @event custom-tap - naming pattern: <action key>-tap
*/
- /**
- * Fires to show an alert when a send is attempted on the non-latest patch.
- *
- * @event show-alert
- */
-
- /**
- * Fires when a change action fails.
- *
- * @event show-error
- */
-
@query('#mainContent') mainContent?: Element;
@query('#actionsModal') actionsModal?: HTMLDialogElement;
@@ -1912,13 +1902,7 @@
) {
if (!response) {
return Promise.resolve(() => {
- this.dispatchEvent(
- new CustomEvent('show-error', {
- detail: {message: `Could not perform action '${action.__key}'`},
- composed: true,
- bubbles: true,
- })
- );
+ fireError(this, `Could not perform action '${action.__key}'`);
});
}
if (action && action.__key === RevisionActions.CHERRYPICK) {
@@ -1936,13 +1920,7 @@
}
}
return response.text().then(errText => {
- this.dispatchEvent(
- new CustomEvent('show-error', {
- detail: {message: `Could not perform action: ${errText}`},
- composed: true,
- bubbles: true,
- })
- );
+ fireError(this, `Could not perform action: ${errText}`);
if (!errText.startsWith('Change is already up to date')) {
throw Error(errText);
}
@@ -1973,19 +1951,13 @@
.fetchChangeUpdates(change)
.then(result => {
if (!result.isLatest) {
- this.dispatchEvent(
- new CustomEvent<ShowAlertEventDetail>(EventType.SHOW_ALERT, {
- detail: {
- message:
- 'Cannot set label: a newer patch has been ' +
- 'uploaded to this change.',
- action: 'Reload',
- callback: () => fireReload(this, true),
- },
- composed: true,
- bubbles: true,
- })
- );
+ fire(this, EventType.SHOW_ALERT, {
+ message:
+ 'Cannot set label: a newer patch has been ' +
+ 'uploaded to this change.',
+ action: 'Reload',
+ callback: () => fireReload(this, true),
+ });
// Because this is not a network error, call the cleanup function
// but not the error handler.
@@ -2241,11 +2213,11 @@
}
private handleEditTap() {
- this.dispatchEvent(new CustomEvent('edit-tap', {bubbles: false}));
+ fireEventNoBubbleNoCompose(this, 'edit-tap');
}
private handleStopEditTap() {
- this.dispatchEvent(new CustomEvent('stop-edit-tap', {bubbles: false}));
+ fireEventNoBubbleNoCompose(this, 'stop-edit-tap');
}
}
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
index 4c7c857..3afe055 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
@@ -119,7 +119,7 @@
EventType,
FileActionTapEvent,
OpenFixPreviewEvent,
- ShowAlertEventDetail,
+ ShowReplyDialogEvent,
SwitchTabEvent,
TabState,
ValueChangedEvent,
@@ -128,6 +128,7 @@
import {GrMessagesList} from '../gr-messages-list/gr-messages-list';
import {GrThreadList} from '../gr-thread-list/gr-thread-list';
import {
+ fire,
fireAlert,
fireDialogChange,
fireEvent,
@@ -2009,7 +2010,7 @@
}
// Private but used in tests.
- handleShowReplyDialog(e: CustomEvent<{value: {ccsOnly: boolean}}>) {
+ handleShowReplyDialog(e: ShowReplyDialogEvent) {
let target = FocusTarget.REVIEWERS;
if (e.detail.value && e.detail.value.ccsOnly) {
target = FocusTarget.CCS;
@@ -3055,20 +3056,14 @@
}
this.cancelUpdateCheckTimer();
- this.dispatchEvent(
- new CustomEvent<ShowAlertEventDetail>(EventType.SHOW_ALERT, {
- detail: {
- message: toastMessage,
- // Persist this alert.
- dismissOnNavigation: true,
- showDismiss: true,
- action: 'Reload',
- callback: () => fireReload(this, true),
- },
- composed: true,
- bubbles: true,
- })
- );
+ fire(this, EventType.SHOW_ALERT, {
+ message: toastMessage,
+ // Persist this alert.
+ dismissOnNavigation: true,
+ showDismiss: true,
+ action: 'Reload',
+ callback: () => fireReload(this, true),
+ });
});
}, this.serverConfig.change.update_delay * 1000);
}
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts
index ac4c1f9..34d11a3 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts
@@ -1772,7 +1772,7 @@
const openStub = sinon.stub(element, 'openReplyDialog');
const e = new CustomEvent('show-reply-dialog', {
- detail: {value: {ccsOnly: false}},
+ detail: {value: {reviewersOnly: true, ccsOnly: false}},
});
element.handleShowReplyDialog(e);
assert(
@@ -1781,7 +1781,7 @@
);
assert.equal(openStub.callCount, 1);
- e.detail.value = {ccsOnly: true};
+ e.detail.value = {reviewersOnly: false, ccsOnly: true};
element.handleShowReplyDialog(e);
assert(
openStub.lastCall.calledWithExactly(FocusTarget.CCS),
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.ts
index 85746df..cbe3430 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.ts
@@ -14,6 +14,7 @@
import {BindValueChangeEvent} from '../../../types/events';
import {ShortcutController} from '../../lit/shortcut-controller';
import {ChangeActionDialog} from '../../../types/common';
+import {fireEventNoBubble, fireNoBubble} from '../../../utils/event-util';
declare global {
interface HTMLElementTagNameMap {
@@ -132,25 +133,14 @@
// private but used in test
confirm() {
- this.dispatchEvent(
- new CustomEvent('confirm', {
- detail: {reason: this.message},
- composed: true,
- bubbles: false,
- })
- );
+ fireNoBubble(this, 'confirm', {reason: this.message});
}
// private but used in test
handleCancelTap(e: Event) {
e.preventDefault();
e.stopPropagation();
- this.dispatchEvent(
- new CustomEvent('cancel', {
- composed: true,
- bubbles: false,
- })
- );
+ fireEventNoBubble(this, 'cancel');
}
private handleBindValueChanged(e: BindValueChangeEvent) {
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-conflict-dialog/gr-confirm-cherrypick-conflict-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-conflict-dialog/gr-confirm-cherrypick-conflict-dialog.ts
index 02156df..34a3161 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-conflict-dialog/gr-confirm-cherrypick-conflict-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-conflict-dialog/gr-confirm-cherrypick-conflict-dialog.ts
@@ -7,6 +7,7 @@
import {customElement} from 'lit/decorators.js';
import {sharedStyles} from '../../../styles/shared-styles';
import {ChangeActionDialog} from '../../../types/common';
+import {fireEventNoBubble} from '../../../utils/event-util';
import '../../shared/gr-dialog/gr-dialog';
@customElement('gr-confirm-cherrypick-conflict-dialog')
@@ -66,23 +67,13 @@
handleConfirmTap(e: Event) {
e.preventDefault();
e.stopPropagation();
- this.dispatchEvent(
- new CustomEvent('confirm', {
- composed: true,
- bubbles: false,
- })
- );
+ fireEventNoBubble(this, 'confirm');
}
handleCancelTap(e: Event) {
e.preventDefault();
e.stopPropagation();
- this.dispatchEvent(
- new CustomEvent('cancel', {
- composed: true,
- bubbles: false,
- })
- );
+ fireEventNoBubble(this, 'cancel');
}
}
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.ts
index 5f3b824..8ce0f51 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.ts
@@ -30,7 +30,7 @@
ChangeStatus,
ProgressStatus,
} from '../../../constants/constants';
-import {fireEvent} from '../../../utils/event-util';
+import {fireEvent, fireEventNoBubble} from '../../../utils/event-util';
import {css, html, LitElement, PropertyValues} from 'lit';
import {sharedStyles} from '../../../styles/shared-styles';
import {choose} from 'lit/directives/choose.js';
@@ -605,23 +605,13 @@
return;
}
// Cherry pick single change
- this.dispatchEvent(
- new CustomEvent('confirm', {
- composed: true,
- bubbles: false,
- })
- );
+ fireEventNoBubble(this, 'confirm');
}
private handleCancelTap(e: Event) {
e.preventDefault();
e.stopPropagation();
- this.dispatchEvent(
- new CustomEvent('cancel', {
- composed: true,
- bubbles: false,
- })
- );
+ fireEventNoBubble(this, 'cancel');
}
resetFocus() {
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.ts
index 3f84189..db14694 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.ts
@@ -15,6 +15,7 @@
import {ValueChangedEvent} from '../../../types/events';
import {ShortcutController} from '../../lit/shortcut-controller';
import {throwingErrorCallback} from '../../shared/gr-rest-api-interface/gr-rest-apis/gr-rest-api-helper';
+import {fireEventNoBubble} from '../../../utils/event-util';
const SUGGESTIONS_LIMIT = 15;
@@ -142,23 +143,13 @@
private handleConfirmTap(e: Event) {
e.preventDefault();
e.stopPropagation();
- this.dispatchEvent(
- new CustomEvent('confirm', {
- composed: true,
- bubbles: false,
- })
- );
+ fireEventNoBubble(this, 'confirm');
}
private handleCancelTap(e: Event) {
e.preventDefault();
e.stopPropagation();
- this.dispatchEvent(
- new CustomEvent('cancel', {
- composed: true,
- bubbles: false,
- })
- );
+ fireEventNoBubble(this, 'cancel');
}
private getProjectBranchesSuggestions(input: string) {
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.ts
index ad2ba8f..3150fc8 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.ts
@@ -22,6 +22,10 @@
import {sharedStyles} from '../../../styles/shared-styles';
import {ValueChangedEvent} from '../../../types/events';
import {throwingErrorCallback} from '../../shared/gr-rest-api-interface/gr-rest-apis/gr-rest-api-helper';
+import {
+ fireEventNoBubbleNoCompose,
+ fireNoBubbleNoCompose,
+} from '../../../utils/event-util';
export interface RebaseChange {
name: string;
@@ -351,14 +355,14 @@
allowConflicts: this.rebaseAllowConflicts.checked,
rebaseChain: !!this.rebaseChain?.checked,
};
- this.dispatchEvent(new CustomEvent('confirm', {detail}));
+ fireNoBubbleNoCompose(this, 'confirm', detail);
this.text = '';
}
private handleCancelTap(e: Event) {
e.preventDefault();
e.stopPropagation();
- this.dispatchEvent(new CustomEvent('cancel'));
+ fireEventNoBubbleNoCompose(this, 'cancel');
this.text = '';
}
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog.ts
index 1b5f171..bf1c5ca 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog.ts
@@ -21,6 +21,7 @@
import {commentsModelToken} from '../../../models/comments/comments-model';
import {changeModelToken} from '../../../models/change/change-model';
import {resolve} from '../../../models/dependency';
+import {fireEventNoBubbleNoCompose} from '../../../utils/event-util';
@customElement('gr-confirm-submit-dialog')
export class GrConfirmSubmitDialog
@@ -193,13 +194,13 @@
private handleConfirmTap(e: Event) {
e.preventDefault();
e.stopPropagation();
- this.dispatchEvent(new CustomEvent('confirm', {bubbles: false}));
+ fireEventNoBubbleNoCompose(this, 'confirm');
}
private handleCancelTap(e: Event) {
e.preventDefault();
e.stopPropagation();
- this.dispatchEvent(new CustomEvent('cancel', {bubbles: false}));
+ fireEventNoBubbleNoCompose(this, 'cancel');
}
}
diff --git a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts
index 5744b02..4403a8f 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts
+++ b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts
@@ -25,7 +25,7 @@
import {DiffPreferencesInfo} from '../../../types/diff';
import {GrDiffModeSelector} from '../../../embed/diff/gr-diff-mode-selector/gr-diff-mode-selector';
import {GrButton} from '../../shared/gr-button/gr-button';
-import {fireEvent} from '../../../utils/event-util';
+import {fireEvent, fireEventNoBubbleNoCompose} from '../../../utils/event-util';
import {css, html, LitElement} from 'lit';
import {sharedStyles} from '../../../styles/shared-styles';
import {when} from 'lit/directives/when.js';
@@ -425,9 +425,7 @@
private handleDownloadTap(e: Event) {
e.preventDefault();
e.stopPropagation();
- this.dispatchEvent(
- new CustomEvent('open-download-dialog', {bubbles: false})
- );
+ fireEventNoBubbleNoCompose(this, 'open-download-dialog');
}
private computeEditModeClass(editMode?: boolean) {
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.ts b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.ts
index b9850dd..ad75253 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.ts
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.ts
@@ -174,11 +174,6 @@
}
@customElement('gr-file-list')
export class GrFileList extends LitElement {
- /**
- * @event files-expanded-changed
- * @event files-shown-changed
- * @event diff-prefs-changed
- */
@query('#diffPreferencesDialog')
diffPreferencesDialog?: GrDiffPreferencesDialog;
@@ -2273,13 +2268,7 @@
const previousNumFilesShown = this.shownFiles ? this.shownFiles.length : 0;
const filesShown = this.files.slice(0, this.numFilesShown);
- this.dispatchEvent(
- new CustomEvent('files-shown-changed', {
- detail: {length: filesShown.length},
- composed: true,
- bubbles: true,
- })
- );
+ fire(this, 'files-shown-changed', {length: filesShown.length});
// Start the timer for the rendering work here because this is where the
// shownFiles property is being set, and shownFiles is used in the
diff --git a/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.ts b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.ts
index fcfe209..c6eaef7 100644
--- a/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.ts
@@ -12,6 +12,7 @@
import {LitElement, PropertyValues, html, css} from 'lit';
import {customElement, property, state} from 'lit/decorators.js';
import {BindValueChangeEvent} from '../../../types/events';
+import {fireEventNoBubble} from '../../../utils/event-util';
interface DisplayGroup {
title: string;
@@ -197,12 +198,7 @@
private handleCloseTap(e: Event) {
e.preventDefault();
e.stopPropagation();
- this.dispatchEvent(
- new CustomEvent('close', {
- composed: true,
- bubbles: false,
- })
- );
+ fireEventNoBubble(this, 'close');
}
}
diff --git a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.ts b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.ts
index 50c5caf..c669209 100644
--- a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.ts
+++ b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.ts
@@ -18,21 +18,20 @@
import {assertIsDefined, hasOwnProperty} from '../../../utils/common-util';
import {Label} from '../../../utils/label-util';
import {LabelNameToValuesMap} from '../../../api/rest-api';
+import {fire} from '../../../utils/event-util';
+import {LabelsChangedDetail} from '../../../api/change-reply';
declare global {
interface HTMLElementTagNameMap {
'gr-label-score-row': GrLabelScoreRow;
}
+ interface HTMLElementEventMap {
+ 'labels-changed': CustomEvent<LabelsChangedDetail>;
+ }
}
@customElement('gr-label-score-row')
export class GrLabelScoreRow extends LitElement {
- /**
- * Fired when any label is changed.
- *
- * @event labels-changed
- */
-
@query('#labelSelector')
labelSelector?: IronSelectorElement;
@@ -365,13 +364,7 @@
this.selectedValueText = selectedItem.getAttribute('title') || '';
const name = selectedItem.dataset['name'];
const value = selectedItem.dataset['value'];
- this.dispatchEvent(
- new CustomEvent('labels-changed', {
- detail: {name, value},
- bubbles: true,
- composed: true,
- })
- );
+ if (name && value) fire(this, 'labels-changed', {name, value});
};
private computePermittedLabelValues() {
diff --git a/polygerrit-ui/app/elements/change/gr-message/gr-message.ts b/polygerrit-ui/app/elements/change/gr-message/gr-message.ts
index a4da747..992a1dc 100644
--- a/polygerrit-ui/app/elements/change/gr-message/gr-message.ts
+++ b/polygerrit-ui/app/elements/change/gr-message/gr-message.ts
@@ -48,6 +48,11 @@
import {FormattedReviewerUpdateInfo} from '../../../types/types';
import {resolve} from '../../../models/dependency';
import {createChangeUrl} from '../../../models/views/change';
+import {fire} from '../../../utils/event-util';
+import {
+ ChangeMessageDeletedEventDetail,
+ ReplyEvent,
+} from '../../../types/events';
const UPLOADED_NEW_PATCHSET_PATTERN = /Uploaded patch set (\d+)./;
const MERGED_PATCHSET_PATTERN = /(\d+) is the latest approved patch-set/;
@@ -55,6 +60,12 @@
interface HTMLElementTagNameMap {
'gr-message': GrMessage;
}
+ interface HTMLElementEventMap {
+ 'message-anchor-tap': CustomEvent<MessageAnchorTapDetail>;
+ 'change-message-deleted': CustomEvent<ChangeMessageDeletedEventDetail>;
+ /* prettier-ignore */
+ 'reply': ReplyEvent;
+ }
}
export interface MessageAnchorTapDetail {
@@ -70,12 +81,6 @@
*/
/**
- * Fired when the message's timestamp is tapped.
- *
- * @event message-anchor-tap
- */
-
- /**
* Fired when a change message is deleted.
*
* @event change-message-deleted
@@ -751,24 +756,13 @@
const detail: MessageAnchorTapDetail = {
id: this.message!.id,
};
- this.dispatchEvent(
- new CustomEvent('message-anchor-tap', {
- bubbles: true,
- composed: true,
- detail,
- })
- );
+ fire(this, 'message-anchor-tap', detail);
}
private handleReplyTap(e: Event) {
e.preventDefault();
- this.dispatchEvent(
- new CustomEvent('reply', {
- detail: {message: this.message},
- composed: true,
- bubbles: true,
- })
- );
+ // TODO: Fix the type casting. Might actually be a bug.
+ fire(this, 'reply', {message: this.message as ChangeMessage});
}
private handleDeleteMessage(e: Event) {
@@ -779,13 +773,10 @@
.deleteChangeCommitMessage(this.changeNum, this.message.id)
.then(() => {
this.isDeletingChangeMsg = false;
- this.dispatchEvent(
- new CustomEvent('change-message-deleted', {
- detail: {message: this.message},
- composed: true,
- bubbles: true,
- })
- );
+ // TODO: Fix the type casting. Might actually be a bug.
+ fire(this, 'change-message-deleted', {
+ message: this.message as ChangeMessage,
+ });
});
}
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts
index da49af0..9f2c6be 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts
@@ -92,7 +92,10 @@
import {pluralize} from '../../../utils/string-util';
import {
fireAlert,
+ fireError,
fireEvent,
+ fireEventNoBubble,
+ fireEventNoBubbleNoCompose,
fireIronAnnounce,
fireReload,
fireServerError,
@@ -1482,12 +1485,7 @@
this.patchsetLevelDraftMessage = '';
this.includeComments = true;
- this.dispatchEvent(
- new CustomEvent('send', {
- composed: true,
- bubbles: false,
- })
- );
+ fireEventNoBubble(this, 'send');
fireIronAnnounce(this, 'Reply sent');
return;
})
@@ -1870,12 +1868,7 @@
async cancel() {
assertIsDefined(this.change, 'change');
if (!this.change?.owner) throw new Error('missing required owner property');
- this.dispatchEvent(
- new CustomEvent('cancel', {
- composed: true,
- bubbles: false,
- })
- );
+ fireEventNoBubble(this, 'cancel');
await this.patchsetLevelGrComment?.save();
this.rebuildReviewerArrays();
}
@@ -1906,13 +1899,7 @@
return;
}
return this.send(this.includeComments, this.canBeStarted).catch(err => {
- this.dispatchEvent(
- new CustomEvent('show-error', {
- bubbles: true,
- composed: true,
- detail: {message: `Error submitting review ${err}`},
- })
- );
+ fireError(this, `Error submitting review ${err}`);
});
}
@@ -2089,7 +2076,7 @@
}
sendDisabledChanged() {
- this.dispatchEvent(new CustomEvent('send-disabled-changed'));
+ fireEventNoBubbleNoCompose(this, 'send-disabled-changed');
}
getReviewerSuggestionsProvider(change?: ChangeInfo | ParsedChangeInfo) {
diff --git a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.ts b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.ts
index 9408b82..db19329 100644
--- a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.ts
+++ b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.ts
@@ -23,15 +23,11 @@
import {sharedStyles} from '../../../styles/shared-styles';
import {css} from 'lit';
import {nothing} from 'lit';
+import {fire} from '../../../utils/event-util';
+import {ShowReplyDialogEvent} from '../../../types/events';
@customElement('gr-reviewer-list')
export class GrReviewerList extends LitElement {
- /**
- * Fired when the "Add reviewer..." button is tapped.
- *
- * @event show-reply-dialog
- */
-
@property({type: Object}) change?: ChangeInfo;
@property({type: Object}) account?: AccountDetailInfo;
@@ -203,22 +199,10 @@
handleAddTap(e: Event) {
e.preventDefault();
const value = {
- reviewersOnly: false,
- ccsOnly: false,
+ reviewersOnly: this.reviewersOnly,
+ ccsOnly: this.ccsOnly,
};
- if (this.reviewersOnly) {
- value.reviewersOnly = true;
- }
- if (this.ccsOnly) {
- value.ccsOnly = true;
- }
- this.dispatchEvent(
- new CustomEvent('show-reply-dialog', {
- detail: {value},
- composed: true,
- bubbles: true,
- })
- );
+ fire(this, 'show-reply-dialog', {value});
}
}
@@ -226,4 +210,8 @@
interface HTMLElementTagNameMap {
'gr-reviewer-list': GrReviewerList;
}
+ interface HTMLElementEventMap {
+ /** Fired when the "Add reviewer..." button is tapped. */
+ 'show-reply-dialog': ShowReplyDialogEvent;
+ }
}
diff --git a/polygerrit-ui/app/elements/checks/gr-checks-runs.ts b/polygerrit-ui/app/elements/checks/gr-checks-runs.ts
index 128a9b0a..8ba9895 100644
--- a/polygerrit-ui/app/elements/checks/gr-checks-runs.ts
+++ b/polygerrit-ui/app/elements/checks/gr-checks-runs.ts
@@ -634,7 +634,7 @@
return Object.entries(this.errorMessages).map(([plugin, message]) => {
const msg = this.collapsed
? 'Error'
- : `Error while fetching results for ${plugin}:<br />${message}`;
+ : html`Error while fetching results for ${plugin}:<br />${message}`;
return html`
<div class="error">
<div class="left">
diff --git a/polygerrit-ui/app/elements/checks/gr-checks-runs_test.ts b/polygerrit-ui/app/elements/checks/gr-checks-runs_test.ts
index 4bd3446..a858e4d 100644
--- a/polygerrit-ui/app/elements/checks/gr-checks-runs_test.ts
+++ b/polygerrit-ui/app/elements/checks/gr-checks-runs_test.ts
@@ -22,6 +22,7 @@
);
const getChecksModel = resolve(element, checksModelToken);
setAllFakeRuns(getChecksModel());
+ element.errorMessages = {'test-plugin-name': 'test-error-message'};
await element.updateComplete;
});
@@ -57,6 +58,17 @@
</gr-button>
</gr-tooltip-content>
</h2>
+ <div class="error">
+ <div class="left">
+ <gr-icon filled="" icon="error"> </gr-icon>
+ </div>
+ <div class="right">
+ <div class="message">
+ Error while fetching results for test-plugin-name: <br />
+ test-error-message
+ </div>
+ </div>
+ </div>
<input
id="filterInput"
placeholder="Filter runs by regular expression"
@@ -121,6 +133,14 @@
</gr-button>
</gr-tooltip-content>
</h2>
+ <div class="error">
+ <div class="left">
+ <gr-icon filled="" icon="error"> </gr-icon>
+ </div>
+ <div class="right">
+ <div class="message">Error</div>
+ </div>
+ </div>
<input
hidden
id="filterInput"
diff --git a/polygerrit-ui/app/elements/checks/gr-checks-util.ts b/polygerrit-ui/app/elements/checks/gr-checks-util.ts
index c7477c4..f1a3fb9 100644
--- a/polygerrit-ui/app/elements/checks/gr-checks-util.ts
+++ b/polygerrit-ui/app/elements/checks/gr-checks-util.ts
@@ -9,6 +9,7 @@
AttemptChoice,
LATEST_ATTEMPT,
} from '../../models/checks/checks-util';
+import {fire} from '../../utils/event-util';
export interface RunSelectedEventDetail {
checkName?: string;
@@ -23,13 +24,7 @@
}
export function fireRunSelected(target: EventTarget, checkName: string) {
- target.dispatchEvent(
- new CustomEvent('run-selected', {
- detail: {reset: false, checkName},
- composed: true,
- bubbles: true,
- })
- );
+ fire(target, 'run-selected', {checkName});
}
export function isAttemptSelected(
diff --git a/polygerrit-ui/app/elements/core/gr-error-dialog/gr-error-dialog.ts b/polygerrit-ui/app/elements/core/gr-error-dialog/gr-error-dialog.ts
index 461781e..3898186 100644
--- a/polygerrit-ui/app/elements/core/gr-error-dialog/gr-error-dialog.ts
+++ b/polygerrit-ui/app/elements/core/gr-error-dialog/gr-error-dialog.ts
@@ -7,6 +7,7 @@
import {sharedStyles} from '../../../styles/shared-styles';
import {LitElement, html, css} from 'lit';
import {customElement, property} from 'lit/decorators.js';
+import {fireEventNoBubbleNoCompose} from '../../../utils/event-util';
declare global {
interface HTMLElementTagNameMap {
@@ -83,6 +84,6 @@
}
private handleConfirm() {
- this.dispatchEvent(new CustomEvent('dismiss'));
+ fireEventNoBubbleNoCompose(this, 'dismiss');
}
}
diff --git a/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.ts b/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.ts
index 45ba33b..68ff9e1 100644
--- a/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.ts
+++ b/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.ts
@@ -16,6 +16,7 @@
ShortcutViewListener,
} from '../../../services/shortcuts/shortcuts-service';
import {resolve} from '../../../models/dependency';
+import {fireEventNoBubble} from '../../../utils/event-util';
declare global {
interface HTMLElementTagNameMap {
@@ -162,12 +163,7 @@
private handleCloseTap(e: MouseEvent) {
e.preventDefault();
e.stopPropagation();
- this.dispatchEvent(
- new CustomEvent('close', {
- composed: true,
- bubbles: false,
- })
- );
+ fireEventNoBubble(this, 'close');
}
onDirectoryUpdated(directory?: Map<ShortcutSection, SectionView>) {
diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router.ts b/polygerrit-ui/app/elements/core/gr-router/gr-router.ts
index fe90471..1b377e8 100644
--- a/polygerrit-ui/app/elements/core/gr-router/gr-router.ts
+++ b/polygerrit-ui/app/elements/core/gr-router/gr-router.ts
@@ -26,7 +26,7 @@
import {AppElement, AppElementParams} from '../../gr-app-types';
import {LocationChangeEventDetail} from '../../../types/events';
import {GerritView, RouterModel} from '../../../services/router/router-model';
-import {fireAlert, firePageError} from '../../../utils/event-util';
+import {fire, fireAlert, firePageError} from '../../../utils/event-util';
import {windowLocationReload} from '../../../utils/dom-util';
import {
encodeURL,
@@ -555,13 +555,7 @@
hash: window.location.hash,
pathname: window.location.pathname,
};
- document.dispatchEvent(
- new CustomEvent('location-change', {
- detail,
- composed: true,
- bubbles: true,
- })
- );
+ fire(document, 'location-change', detail);
}
_testOnly_startRouter() {
diff --git a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.ts b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.ts
index 9dbb01c..406755f 100644
--- a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.ts
+++ b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.ts
@@ -27,6 +27,7 @@
import {resolve} from '../../../models/dependency';
import {subscribe} from '../../lit/subscription-controller';
import {ValueChangedEvent} from '../../../types/events';
+import {fireNoBubbleNoCompose} from '../../../utils/event-util';
// Possible static search options for auto complete, without negations.
const SEARCH_OPERATORS: ReadonlyArray<string> = [
@@ -311,11 +312,7 @@
const detail: SearchBarHandleSearchDetail = {
inputVal: this.inputVal,
};
- this.dispatchEvent(
- new CustomEvent('handle-search', {
- detail,
- })
- );
+ fireNoBubbleNoCompose(this, 'handle-search', detail);
}
}
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-preferences-dialog/gr-diff-preferences-dialog.ts b/polygerrit-ui/app/elements/diff/gr-diff-preferences-dialog/gr-diff-preferences-dialog.ts
index 531d2ae..69ff201 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-preferences-dialog/gr-diff-preferences-dialog.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-preferences-dialog/gr-diff-preferences-dialog.ts
@@ -12,6 +12,7 @@
import {customElement, query, state} from 'lit/decorators.js';
import {ValueChangedEvent} from '../../../types/events';
import {modalStyles} from '../../../styles/gr-modal-styles';
+import {fireEventNoBubble} from '../../../utils/event-util';
@customElement('gr-diff-preferences-dialog')
export class GrDiffPreferencesDialog extends LitElement {
@@ -120,12 +121,7 @@
assertIsDefined(this.diffPreferences, 'diffPreferences');
assertIsDefined(this.diffPrefsModal, 'diffPrefsModal');
await this.diffPreferences.save();
- this.dispatchEvent(
- new CustomEvent('reload-diff-preference', {
- composed: true,
- bubbles: false,
- })
- );
+ fireEventNoBubble(this, 'reload-diff-preference');
this.diffPrefsModal.close();
}
diff --git a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.ts b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.ts
index 58ad721..01c007b 100644
--- a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.ts
+++ b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.ts
@@ -47,6 +47,7 @@
import {GeneratedWebLink} from '../../../utils/weblink-util';
import {changeModelToken} from '../../../models/change/change-model';
import {changeViewModelToken} from '../../../models/views/change';
+import {fireNoBubbleNoCompose} from '../../../utils/event-util';
// Maximum length for patch set descriptions.
const PATCH_DESC_MAX_LENGTH = 500;
@@ -496,8 +497,6 @@
detail.basePatchNum = patchSetValue as BasePatchSetNum;
}
- this.dispatchEvent(
- new CustomEvent('patch-range-change', {detail, bubbles: false})
- );
+ fireNoBubbleNoCompose(this, 'patch-range-change', detail);
}
}
diff --git a/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor.ts b/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor.ts
index 7229c63..25d3cf4 100644
--- a/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor.ts
+++ b/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor.ts
@@ -6,11 +6,16 @@
import {sharedStyles} from '../../../styles/shared-styles';
import {LitElement, css, html} from 'lit';
import {customElement, property} from 'lit/decorators.js';
+import {fire} from '../../../utils/event-util';
+import {ValueChangedEvent} from '../../../types/events';
declare global {
interface HTMLElementTagNameMap {
'gr-default-editor': GrDefaultEditor;
}
+ interface HTMLElementEventMap {
+ 'content-change': ValueChangedEvent;
+ }
}
@customElement('gr-default-editor')
@@ -56,12 +61,7 @@
}
_handleTextareaInput(e: Event) {
- this.dispatchEvent(
- new CustomEvent('content-change', {
- detail: {value: (e.target as HTMLTextAreaElement).value},
- bubbles: true,
- composed: true,
- })
- );
+ const value = (e.target as HTMLTextAreaElement).value;
+ fire(this, 'content-change', {value});
}
}
diff --git a/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls.ts b/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls.ts
index 594d9d9..751b64d 100644
--- a/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls.ts
+++ b/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls.ts
@@ -6,10 +6,11 @@
import '../../shared/gr-dropdown/gr-dropdown';
import {GrEditConstants} from '../gr-edit-constants';
import {sharedStyles} from '../../../styles/shared-styles';
-import {FileActionTapEventDetail} from '../../../types/events';
+import {FileActionTapEvent} from '../../../types/events';
import {LitElement, css, html} from 'lit';
import {customElement, property} from 'lit/decorators.js';
import {DropdownLink} from '../../shared/gr-dropdown/gr-dropdown';
+import {fire} from '../../../utils/event-util';
interface EditAction {
label: string;
@@ -18,12 +19,6 @@
@customElement('gr-edit-file-controls')
export class GrEditFileControls extends LitElement {
- /**
- * Fired when an action in the overflow menu is tapped.
- *
- * @event file-action-tap
- */
-
@property({type: String})
filePath?: string;
@@ -76,13 +71,7 @@
}
_dispatchFileAction(action: string, path: string) {
- this.dispatchEvent(
- new CustomEvent<FileActionTapEventDetail>('file-action-tap', {
- detail: {action, path},
- bubbles: true,
- composed: true,
- })
- );
+ fire(this, 'file-action-tap', {action, path});
}
_computeFileActions(actions: EditAction[]): DropdownLink[] {
@@ -100,4 +89,7 @@
interface HTMLElementTagNameMap {
'gr-edit-file-controls': GrEditFileControls;
}
+ interface HTMLElementEventMap {
+ 'file-action-tap': FileActionTapEvent;
+ }
}
diff --git a/polygerrit-ui/app/elements/plugins/gr-endpoint-param/gr-endpoint-param.ts b/polygerrit-ui/app/elements/plugins/gr-endpoint-param/gr-endpoint-param.ts
index e73aad6..d3429fe 100644
--- a/polygerrit-ui/app/elements/plugins/gr-endpoint-param/gr-endpoint-param.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-endpoint-param/gr-endpoint-param.ts
@@ -5,6 +5,7 @@
*/
import {LitElement, PropertyValues} from 'lit';
import {customElement, property} from 'lit/decorators.js';
+import {fireNoBubbleNoCompose} from '../../../utils/event-util';
declare global {
interface HTMLElementTagNameMap {
@@ -22,9 +23,7 @@
override willUpdate(changedProperties: PropertyValues) {
if (changedProperties.has('value')) {
- this.dispatchEvent(
- new CustomEvent('value-changed', {detail: {value: this.value}})
- );
+ fireNoBubbleNoCompose(this, 'value-changed', {value: this.value});
}
}
}
diff --git a/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.ts b/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.ts
index 31e4f5d..e8c5c92 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.ts
+++ b/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.ts
@@ -17,6 +17,8 @@
import {customElement, property} from 'lit/decorators.js';
import {ClassInfo, classMap} from 'lit/directives/class-map.js';
import {getLabelStatus, hasVoted, LabelStatus} from '../../../utils/label-util';
+import {fire} from '../../../utils/event-util';
+import {RemoveAccountEvent} from '../../../types/events';
@customElement('gr-account-chip')
export class GrAccountChip extends LitElement {
@@ -196,13 +198,8 @@
private handleRemoveTap(e: MouseEvent) {
e.preventDefault();
- this.dispatchEvent(
- new CustomEvent('remove', {
- detail: {account: this.account},
- composed: true,
- bubbles: true,
- })
- );
+ if (!this.account) return;
+ fire(this, 'remove', {account: this.account});
}
private getHasAvatars() {
@@ -232,4 +229,8 @@
interface HTMLElementTagNameMap {
'gr-account-chip': GrAccountChip;
}
+ interface HTMLElementEventMap {
+ /* prettier-ignore */
+ 'remove': RemoveAccountEvent;
+ }
}
diff --git a/polygerrit-ui/app/elements/shared/gr-account-entry/gr-account-entry.ts b/polygerrit-ui/app/elements/shared/gr-account-entry/gr-account-entry.ts
index 08f7c93..f07bee6 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-entry/gr-account-entry.ts
+++ b/polygerrit-ui/app/elements/shared/gr-account-entry/gr-account-entry.ts
@@ -12,9 +12,10 @@
import {sharedStyles} from '../../../styles/shared-styles';
import {LitElement, PropertyValues, html, css} from 'lit';
import {customElement, property, query, state} from 'lit/decorators.js';
-import {BindValueChangeEvent} from '../../../types/events';
+import {AddAccountEvent, BindValueChangeEvent} from '../../../types/events';
import {SuggestedReviewerInfo} from '../../../types/common';
import {PaperInputElement} from '@polymer/paper-input/paper-input';
+import {fire, fireEvent} from '../../../utils/event-util';
/**
* gr-account-entry is an element for entering account
@@ -24,20 +25,6 @@
export class GrAccountEntry extends LitElement {
@query('#input') private input?: GrAutocomplete;
- /**
- * Fired when an account is entered.
- *
- * @event add
- */
-
- /**
- * When allowAnyInput is true, account-text-changed is fired when input text
- * changed. This is needed so that the reply dialog's save button can be
- * enabled for arbitrary cc's, which don't need a 'commit'.
- *
- * @event account-text-changed
- */
-
@property({type: Boolean})
allowAnyInput = false;
@@ -112,21 +99,13 @@
}
private handleInputCommit(e: AutocompleteCommitEvent) {
- this.dispatchEvent(
- new CustomEvent('add', {
- detail: {value: e.detail.value},
- composed: true,
- bubbles: true,
- })
- );
+ fire(this, 'add', {value: e.detail.value});
this.input!.focus();
}
private inputTextChanged() {
if (this.inputText.length && this.allowAnyInput) {
- this.dispatchEvent(
- new CustomEvent('account-text-changed', {bubbles: true, composed: true})
- );
+ fireEvent(this, 'account-text-changed');
}
}
@@ -139,4 +118,17 @@
interface HTMLElementTagNameMap {
'gr-account-entry': GrAccountEntry;
}
+ interface HTMLElementEventMap {
+ /**
+ * Fired when an account is entered.
+ */
+ /* prettier-ignore */
+ 'add': AddAccountEvent;
+ /**
+ * When allowAnyInput is true, account-text-changed is fired when input text
+ * changed. This is needed so that the reply dialog's save button can be
+ * enabled for arbitrary cc's, which don't need a 'commit'.
+ */
+ 'account-text-changed': CustomEvent<void>;
+ }
}
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 bb0200a..0f85266 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
@@ -13,9 +13,9 @@
import {isSelf, isServiceUser} from '../../../utils/account-util';
import {ChangeInfo, AccountInfo, ServerInfo} from '../../../types/common';
import {assertIsDefined, hasOwnProperty} from '../../../utils/common-util';
-import {fireEvent} from '../../../utils/event-util';
+import {fire, fireEvent} from '../../../utils/event-util';
import {isInvolved} from '../../../utils/change-util';
-import {EventType, ShowAlertEventDetail} from '../../../types/events';
+import {EventType} from '../../../types/events';
import {LitElement, css, html, TemplateResult} from 'lit';
import {customElement, property, state} from 'lit/decorators.js';
import {classMap} from 'lit/directives/class-map.js';
@@ -364,16 +364,10 @@
e.stopPropagation();
if (!this.account._account_id) return;
- this.dispatchEvent(
- new CustomEvent<ShowAlertEventDetail>(EventType.SHOW_ALERT, {
- detail: {
- message: 'Saving attention set update ...',
- dismissOnNavigation: true,
- },
- composed: true,
- bubbles: true,
- })
- );
+ fire(this, EventType.SHOW_ALERT, {
+ message: 'Saving attention set update ...',
+ dismissOnNavigation: true,
+ });
// We are deliberately updating the UI before making the API call. It is a
// risk that we are taking to achieve a better UX for 99.9% of the cases.
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.ts b/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.ts
index 10cefd9..34b8f11 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.ts
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.ts
@@ -6,7 +6,7 @@
import '../gr-cursor-manager/gr-cursor-manager';
import '../../../styles/shared-styles';
import {GrCursorManager} from '../gr-cursor-manager/gr-cursor-manager';
-import {fireEvent} from '../../../utils/event-util';
+import {fire, fireEvent} from '../../../utils/event-util';
import {Key} from '../../../utils/dom-util';
import {FitController} from '../../lit/fit-controller';
import {css, html, LitElement, PropertyValues} from 'lit';
@@ -274,32 +274,20 @@
// private but used in tests
handleTab() {
if (this.isSuggestionListInteractible()) {
- this.dispatchEvent(
- new CustomEvent<ItemSelectedEventDetail>('item-selected', {
- detail: {
- trigger: 'tab',
- selected: this.cursor.target,
- },
- composed: true,
- bubbles: true,
- })
- );
+ fire(this, 'item-selected', {
+ trigger: 'tab',
+ selected: this.cursor.target,
+ });
}
}
// private but used in tests
handleEnter() {
if (this.isSuggestionListInteractible()) {
- this.dispatchEvent(
- new CustomEvent<ItemSelectedEventDetail>('item-selected', {
- detail: {
- trigger: 'enter',
- selected: this.cursor.target,
- },
- composed: true,
- bubbles: true,
- })
- );
+ fire(this, 'item-selected', {
+ trigger: 'enter',
+ selected: this.cursor.target,
+ });
}
}
@@ -318,16 +306,10 @@
}
selected = selected.parentElement!;
}
- this.dispatchEvent(
- new CustomEvent<ItemSelectedEventDetail>('item-selected', {
- detail: {
- trigger: 'click',
- selected,
- },
- composed: true,
- bubbles: true,
- })
- );
+ fire(this, 'item-selected', {
+ trigger: 'click',
+ selected,
+ });
}
private fireClose() {
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.ts b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.ts
index 023513b..9b0fa7b 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.ts
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.ts
@@ -74,13 +74,6 @@
*/
/**
- * Fired on keydown to allow for custom hooks into autocomplete textbox
- * behavior.
- *
- * @event input-keydown
- */
-
- /**
* Query for requesting autocomplete suggestions. The function should
* accept the input as a string parameter and return a promise. The
* promise yields an array of suggestion objects with "name", "label",
@@ -611,13 +604,6 @@
this.resetQueryOutput();
this.activeQueryId = 0;
}
- this.dispatchEvent(
- new CustomEvent('input-keydown', {
- detail: {key: e.key, input: this.input},
- composed: true,
- bubbles: true,
- })
- );
}
cancel() {
@@ -720,13 +706,7 @@
// 'commit' event
await this.updateComplete;
if (!silent) {
- this.dispatchEvent(
- new CustomEvent('commit', {
- detail: {value} as AutocompleteCommitEventDetail,
- composed: true,
- bubbles: true,
- })
- );
+ fire(this, 'commit', {value});
}
}
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.ts b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.ts
index c59b8e8..0cef331 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.ts
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.ts
@@ -1063,27 +1063,14 @@
});
});
- test('input-keydown event fired', async () => {
- const listener = sinon.spy();
- element.addEventListener('input-keydown', listener);
- pressKey(inputEl(), Key.TAB);
- await element.updateComplete;
- assert.isTrue(listener.called);
- });
-
test('enter with modifier does not complete', async () => {
- const dispatchEventStub = sinon.stub(element, 'dispatchEvent');
const commitStub = sinon.stub(element, 'handleInputCommit');
+
pressKey(inputEl(), Key.ENTER, Modifier.CTRL_KEY);
await element.updateComplete;
- assert.equal(dispatchEventStub.lastCall.args[0].type, 'input-keydown');
- assert.equal(
- (dispatchEventStub.lastCall.args[0] as CustomEvent).detail.key,
- Key.ENTER
- );
-
assert.isFalse(commitStub.called);
+
pressKey(inputEl(), Key.ENTER);
await element.updateComplete;
diff --git a/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.ts b/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.ts
index 0bb451c..54fb825 100644
--- a/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.ts
+++ b/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.ts
@@ -14,6 +14,7 @@
import {resolve} from '../../../models/dependency';
import {shortcutsServiceToken} from '../../../services/shortcuts/shortcuts-service';
import {assertIsDefined} from '../../../utils/common-util';
+import {fire} from '../../../utils/event-util';
declare global {
interface HTMLElementTagNameMap {
@@ -93,12 +94,6 @@
change: this.change,
starred: newVal,
};
- this.dispatchEvent(
- new CustomEvent('toggle-star', {
- bubbles: true,
- composed: true,
- detail,
- })
- );
+ fire(this, 'toggle-star', detail);
}
}
diff --git a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.ts b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.ts
index c844d42..c36226a 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.ts
+++ b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.ts
@@ -275,6 +275,9 @@
this.save();
});
}
+ this.addEventListener('open-user-suggest-preview', e => {
+ this.handleShowFix(e.detail.code);
+ });
this.messagePlaceholder = 'Mention others with @';
subscribe(
this,
@@ -524,7 +527,6 @@
${this.renderCommentMessage()}
<gr-endpoint-slot name="above-actions"></gr-endpoint-slot>
${this.renderHumanActions()} ${this.renderRobotActions()}
- ${this.renderSuggestEditActions()}
</div>
</div>
</gr-endpoint-decorator>
@@ -776,32 +778,13 @@
return html`
<div class="rightActions">
${this.autoSaving ? html`. ` : ''}
- ${this.renderDiscardButton()} ${this.renderPreviewSuggestEditButton()}
- ${this.renderEditButton()} ${this.renderCancelButton()}
- ${this.renderSaveButton()} ${this.renderCopyLinkIcon()}
+ ${this.renderDiscardButton()} ${this.renderEditButton()}
+ ${this.renderCancelButton()} ${this.renderSaveButton()}
+ ${this.renderCopyLinkIcon()}
</div>
`;
}
- private renderPreviewSuggestEditButton() {
- if (!this.flagsService.isEnabled(KnownExperimentId.SUGGEST_EDIT)) {
- return nothing;
- }
- assertIsDefined(this.comment, 'comment');
- if (!hasUserSuggestion(this.comment)) return nothing;
- return html`
- <gr-button
- link
- secondary
- class="action show-fix"
- ?disabled=${this.saving}
- @click=${this.handleShowFix}
- >
- Preview Fix
- </gr-button>
- `;
- }
-
private renderSuggestEditButton() {
if (!this.flagsService.isEnabled(KnownExperimentId.SUGGEST_EDIT)) {
return nothing;
@@ -892,22 +875,6 @@
`;
}
- private renderSuggestEditActions() {
- if (!this.flagsService.isEnabled(KnownExperimentId.SUGGEST_EDIT)) {
- return nothing;
- }
- if (
- !this.account ||
- isRobot(this.comment) ||
- isDraftOrUnsaved(this.comment)
- ) {
- return nothing;
- }
- return html`
- <div class="robotActions">${this.renderPreviewSuggestEditButton()}</div>
- `;
- }
-
private renderShowFixButton() {
if (!(this.comment as RobotCommentInfo)?.fix_suggestions) return;
return html`
@@ -1037,12 +1004,14 @@
}
// private, but visible for testing
- async createFixPreview(): Promise<OpenFixPreviewEventDetail> {
+ async createFixPreview(
+ replacement?: string
+ ): Promise<OpenFixPreviewEventDetail> {
assertIsDefined(this.comment?.patch_set, 'comment.patch_set');
assertIsDefined(this.comment?.path, 'comment.path');
- if (hasUserSuggestion(this.comment)) {
- const replacement = getUserSuggestion(this.comment);
+ if (hasUserSuggestion(this.comment) || replacement) {
+ replacement = replacement ?? getUserSuggestion(this.comment);
assert(!!replacement, 'malformed user suggestion');
const line = await this.getCommentedCode();
@@ -1150,9 +1119,9 @@
fire(this, 'reply-to-comment', eventDetail);
}
- private async handleShowFix() {
+ private async handleShowFix(replacement?: string) {
// Handled top-level in the diff and change view components.
- fire(this, 'open-fix-preview', await this.createFixPreview());
+ fire(this, 'open-fix-preview', await this.createFixPreview(replacement));
}
async createSuggestEdit(e: MouseEvent) {
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 3390369..6625844 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
@@ -29,19 +29,12 @@
import {
createComment,
createDraft,
- createFixSuggestionInfo,
createRobotComment,
createUnsaved,
} from '../../../test/test-data-generators';
-import {
- ReplyToCommentEvent,
- OpenFixPreviewEventDetail,
-} from '../../../types/events';
+import {ReplyToCommentEvent} from '../../../types/events';
import {GrConfirmDeleteCommentDialog} from '../gr-confirm-delete-comment-dialog/gr-confirm-delete-comment-dialog';
-import {
- DraftInfo,
- USER_SUGGESTION_START_PATTERN,
-} from '../../../utils/comment-util';
+import {DraftInfo} from '../../../utils/comment-util';
import {assertIsDefined} from '../../../utils/common-util';
import {Modifier} from '../../../utils/dom-util';
import {SinonStub} from 'sinon';
@@ -747,23 +740,6 @@
actions = query(element, '.robotActions gr-button.fix');
assert.isNotOk(actions);
});
-
- test('handleShowFix fires open-fix-preview event', async () => {
- const listener = listenOnce<CustomEvent<OpenFixPreviewEventDetail>>(
- element,
- 'open-fix-preview'
- );
- element.comment = {
- ...createRobotComment(),
- fix_suggestions: [{...createFixSuggestionInfo()}],
- };
- await element.updateComplete;
-
- queryAndAssert<GrButton>(element, '.show-fix').click();
-
- const e = await listener;
- assert.deepEqual(e.detail, await element.createFixPreview());
- });
});
suite('auto saving', () => {
@@ -869,33 +845,5 @@
</gr-button> `
);
});
-
- test('renders preview suggest fix', async () => {
- element.comment = {
- ...createComment(),
- author: {
- name: 'Mr. Peanutbutter',
- email: 'tenn1sballchaser@aol.com' as EmailAddress,
- },
- line: 5,
- path: 'test',
- message: `${USER_SUGGESTION_START_PATTERN}afterSuggestion${'\n```'}`,
- };
- await element.updateComplete;
-
- assert.dom.equal(
- queryAndAssert(element, 'gr-button.show-fix'),
- /* HTML */ `<gr-button
- aria-disabled="false"
- class="action show-fix"
- link=""
- role="button"
- secondary
- tabindex="0"
- >
- Preview Fix
- </gr-button> `
- );
- });
});
});
diff --git a/polygerrit-ui/app/elements/shared/gr-confirm-delete-comment-dialog/gr-confirm-delete-comment-dialog.ts b/polygerrit-ui/app/elements/shared/gr-confirm-delete-comment-dialog/gr-confirm-delete-comment-dialog.ts
index 285a41a..1047b87 100644
--- a/polygerrit-ui/app/elements/shared/gr-confirm-delete-comment-dialog/gr-confirm-delete-comment-dialog.ts
+++ b/polygerrit-ui/app/elements/shared/gr-confirm-delete-comment-dialog/gr-confirm-delete-comment-dialog.ts
@@ -11,6 +11,7 @@
import {sharedStyles} from '../../../styles/shared-styles';
import {assertIsDefined} from '../../../utils/common-util';
import {BindValueChangeEvent} from '../../../types/events';
+import {fireEventNoBubble, fireNoBubble} from '../../../utils/event-util';
declare global {
interface HTMLElementTagNameMap {
@@ -108,23 +109,12 @@
private handleConfirmTap(e: Event) {
e.preventDefault();
e.stopPropagation();
- this.dispatchEvent(
- new CustomEvent('confirm', {
- detail: {reason: this.message},
- composed: true,
- bubbles: false,
- })
- );
+ fireNoBubble(this, 'confirm', {reason: this.message});
}
private handleCancelTap(e: Event) {
e.preventDefault();
e.stopPropagation();
- this.dispatchEvent(
- new CustomEvent('cancel', {
- composed: true,
- bubbles: false,
- })
- );
+ fireEventNoBubble(this, 'cancel');
}
}
diff --git a/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.ts b/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.ts
index 350aa7f..8c280c0 100644
--- a/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.ts
+++ b/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.ts
@@ -66,7 +66,10 @@
color: var(--primary-text-color);
}
gr-icon {
- color: var(--deemphasized-text-color);
+ color: var(
+ --gr-copy-clipboard-icon-color,
+ var(--deemphasized-text-color)
+ );
}
gr-button {
display: block;
diff --git a/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog.ts b/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog.ts
index 04d5923..c5ad676 100644
--- a/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog.ts
+++ b/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog.ts
@@ -10,6 +10,7 @@
import {sharedStyles} from '../../../styles/shared-styles';
import {fontStyles} from '../../../styles/gr-font-styles';
import {when} from 'lit/directives/when.js';
+import {fireEventNoBubble} from '../../../utils/event-util';
declare global {
interface HTMLElementTagNameMap {
@@ -199,23 +200,13 @@
e.preventDefault();
e.stopPropagation();
- this.dispatchEvent(
- new CustomEvent('confirm', {
- composed: true,
- bubbles: false,
- })
- );
+ fireEventNoBubble(this, 'confirm');
}
private handleCancelTap(e: Event) {
e.preventDefault();
e.stopPropagation();
- this.dispatchEvent(
- new CustomEvent('cancel', {
- composed: true,
- bubbles: false,
- })
- );
+ fireEventNoBubble(this, 'cancel');
}
_handleKeydown(e: KeyboardEvent) {
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list.ts b/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list.ts
index b6ca9f5..c935e72 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list.ts
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list.ts
@@ -23,6 +23,7 @@
import {incrementalRepeat} from '../../lit/incremental-repeat';
import {when} from 'lit/directives/when.js';
import {isMagicPath} from '../../../utils/path-list-util';
+import {fireNoBubble} from '../../../utils/event-util';
/**
* Required values are text and value. mobileText and triggerText will
@@ -303,12 +304,7 @@
this.text = selectedObj.triggerText
? selectedObj.triggerText
: selectedObj.text;
- this.dispatchEvent(
- new CustomEvent('value-change', {
- detail: {value: this.value},
- bubbles: false,
- })
- );
+ fireNoBubble(this, 'value-change', {value: this.value});
}
/**
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.ts b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.ts
index c78a513..495b448 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.ts
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.ts
@@ -461,13 +461,7 @@
const item = this.items.find(item => item.id === id);
if (id && !this.disabledIds.includes(id)) {
if (item) {
- this.dispatchEvent(
- new CustomEvent('tap-item', {
- detail: item,
- bubbles: true,
- composed: true,
- })
- );
+ fire(this, 'tap-item', item);
}
this.dispatchEvent(new CustomEvent('tap-item-' + id));
}
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.ts b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.ts
index e176598..01ebb27 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.ts
+++ b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.ts
@@ -386,13 +386,7 @@
handleSave(e: Event) {
e.preventDefault();
- this.dispatchEvent(
- new CustomEvent('editable-content-save', {
- detail: {content: this.newContent},
- composed: true,
- bubbles: true,
- })
- );
+ fire(this, 'editable-content-save', {content: this.newContent});
// It would be nice, if we would set this.newContent = undefined here,
// but we can only do that when we are sure that the save operation has
// succeeded.
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.ts b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.ts
index 8ca8820..c8574cd 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.ts
+++ b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.ts
@@ -22,6 +22,7 @@
import {IronInputElement} from '@polymer/iron-input';
import {ShortcutController} from '../../lit/shortcut-controller';
import {ValueChangedEvent} from '../../../types/events';
+import {fire} from '../../../utils/event-util';
const AWAIT_MAX_ITERS = 10;
const AWAIT_STEP = 5;
@@ -309,13 +310,8 @@
this.value = this.inputText || '';
}
this.editing = false;
- this.dispatchEvent(
- new CustomEvent('changed', {
- detail: this.value,
- composed: true,
- bubbles: true,
- })
- );
+ // TODO: This event seems to be unused (no listener). Remove?
+ fire(this, 'changed', this.value);
}
private cancel() {
diff --git a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts
index 45eca40..023d8b5 100644
--- a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts
+++ b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts
@@ -18,6 +18,10 @@
import {CommentLinks, EmailAddress} from '../../../api/rest-api';
import {linkifyUrlsAndApplyRewrite} from '../../../utils/link-util';
import '../gr-account-chip/gr-account-chip';
+import '../gr-user-suggestion-fix/gr-user-suggestion-fix';
+import {KnownExperimentId} from '../../../services/flags/flags';
+import {getAppContext} from '../../../services/app-context';
+import {USER_SUGGESTION_INFO_STRING} from '../../../utils/comment-util';
/**
* This element optionally renders markdown and also applies some regex
@@ -34,6 +38,8 @@
@state()
private repoCommentLinks: CommentLinks = {};
+ private readonly flagsService = getAppContext().flagsService;
+
private readonly getConfigModel = resolve(this, configModelToken);
// Private const but used in tests.
@@ -134,6 +140,10 @@
}
private renderAsMarkdown() {
+ // need to find out here, since customRender is not arrow function
+ const suggestEditsEnable = this.flagsService.isEnabled(
+ KnownExperimentId.SUGGEST_EDIT
+ );
// <marked-element> internals will be in charge of calling our custom
// renderer so we wrap 'this.rewriteText' so that 'this' is preserved via
// closure.
@@ -167,7 +177,18 @@
`![${text}](${href})`;
renderer['codespan'] = (text: string) =>
`<code>${unescapeHTML(text)}</code>`;
- renderer['code'] = (text: string) => `<pre><code>${text}</code></pre>`;
+ renderer['code'] = (text: string, infostring: string) => {
+ if (suggestEditsEnable && infostring === USER_SUGGESTION_INFO_STRING) {
+ // default santizer in markedjs is very restrictive, we need to use
+ // existing html element to mark element. We cannot use css class for it.
+ // Therefore we pick mark - as not frequently used html element to represent
+ // unconverted gr-user-suggestion-fix.
+ // TODO(milutin): Find a way to override sanitizer to directly use gr-user-suggestion-fix
+ return `<mark>${text}</mark>`;
+ } else {
+ return `<pre><code>${text}</code></pre>`;
+ }
+ };
renderer['text'] = boundRewriteText;
}
@@ -211,6 +232,9 @@
override updated() {
// Look for @mentions and replace them with an account-label chip.
this.convertEmailsToAccountChips();
+ if (this.flagsService.isEnabled(KnownExperimentId.SUGGEST_EDIT)) {
+ this.convertCodeToSuggestions();
+ }
}
private convertEmailsToAccountChips() {
@@ -235,6 +259,17 @@
}
}
}
+
+ private convertCodeToSuggestions() {
+ for (const userSuggestionMark of this.renderRoot.querySelectorAll('mark')) {
+ const userSuggestion = document.createElement('gr-user-suggestion-fix');
+ userSuggestion.textContent = userSuggestionMark.textContent ?? '';
+ userSuggestionMark.parentNode?.replaceChild(
+ userSuggestion,
+ userSuggestionMark
+ );
+ }
+ }
}
declare global {
diff --git a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text_test.ts b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text_test.ts
index fcebeea..0e5117a 100644
--- a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text_test.ts
+++ b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text_test.ts
@@ -587,5 +587,25 @@
`
);
});
+
+ suite('user suggest fix', () => {
+ setup(async () => {
+ const flagsService = getAppContext().flagsService;
+ sinon.stub(flagsService, 'isEnabled').returns(true);
+ });
+
+ test('renders', async () => {
+ element.content = '```suggestion\nHello World```';
+ await element.updateComplete;
+ assert.shadowDom.equal(
+ element,
+ /* HTML */ `<marked-element>
+ <div class="markdown-html" slot="markdown-html">
+ <gr-user-suggestion-fix>Hello World</gr-user-suggestion-fix>
+ </div>
+ </marked-element>`
+ );
+ });
+ });
});
});
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-action-context.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-action-context.ts
index 0628d2f..c81f586 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-action-context.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-action-context.ts
@@ -4,13 +4,13 @@
* SPDX-License-Identifier: Apache-2.0
*/
import {RevisionInfo, ChangeInfo, RequestPayload} from '../../../types/common';
-import {EventType, ShowAlertEventDetail} from '../../../types/events';
import {PluginApi} from '../../../api/plugin';
import {UIActionInfo} from './gr-change-actions-js-api';
import {windowLocationReload} from '../../../utils/dom-util';
import {PopupPluginApi} from '../../../api/popup';
import {GrPopupInterface} from '../../plugins/gr-popup-interface/gr-popup-interface';
import {getAppContext} from '../../../services/app-context';
+import {fireAlert} from '../../../utils/event-util';
interface ButtonCallBacks {
onclick: (event: Event) => boolean;
@@ -110,13 +110,7 @@
.send(this.action.method, this.action.__url, payload)
.then(onSuccess)
.catch((error: unknown) => {
- document.dispatchEvent(
- new CustomEvent<ShowAlertEventDetail>(EventType.SHOW_ALERT, {
- detail: {
- message: `Plugin network error: ${error}`,
- },
- })
- );
+ fireAlert(document, `Plugin network error: ${error}`);
});
}
}
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-apis/gr-rest-api-helper.ts b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-apis/gr-rest-api-helper.ts
index 8b3e2a6..615a04a 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-apis/gr-rest-api-helper.ts
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-apis/gr-rest-api-helper.ts
@@ -17,7 +17,11 @@
} from '../../../../types/common';
import {HttpMethod} from '../../../../constants/constants';
import {RpcLogEventDetail} from '../../../../types/events';
-import {fireNetworkError, fireServerError} from '../../../../utils/event-util';
+import {
+ fire,
+ fireNetworkError,
+ fireServerError,
+} from '../../../../utils/event-util';
import {FetchRequest} from '../../../../types/types';
import {ErrorCallback} from '../../../../api/rest';
import {Scheduler, Task} from '../../../../services/scheduler/scheduler';
@@ -337,13 +341,7 @@
elapsed,
anonymizedUrl: req.anonymizedUrl,
};
- document.dispatchEvent(
- new CustomEvent('gr-rpc-log', {
- detail,
- composed: true,
- bubbles: true,
- })
- );
+ fire(document, 'gr-rpc-log', detail);
}
}
diff --git a/polygerrit-ui/app/elements/shared/gr-user-suggestion-fix/gr-user-suggestion-fix.ts b/polygerrit-ui/app/elements/shared/gr-user-suggestion-fix/gr-user-suggestion-fix.ts
new file mode 100644
index 0000000..c557acc
--- /dev/null
+++ b/polygerrit-ui/app/elements/shared/gr-user-suggestion-fix/gr-user-suggestion-fix.ts
@@ -0,0 +1,97 @@
+/**
+ * @license
+ * Copyright 2023 Google LLC
+ * SPDX-License-Identifier: Apache-2.0
+ */
+import {css, html, LitElement, nothing} from 'lit';
+import {customElement} from 'lit/decorators.js';
+import {getAppContext} from '../../../services/app-context';
+import {KnownExperimentId} from '../../../services/flags/flags';
+import {fire} from '../../../utils/event-util';
+
+declare global {
+ interface HTMLElementEventMap {
+ 'open-user-suggest-preview': OpenUserSuggestionPreviewEvent;
+ }
+}
+
+export type OpenUserSuggestionPreviewEvent =
+ CustomEvent<OpenUserSuggestionPreviewEventDetail>;
+export interface OpenUserSuggestionPreviewEventDetail {
+ code: string;
+}
+
+@customElement('gr-user-suggestion-fix')
+export class GrUserSuggetionFix extends LitElement {
+ private readonly flagsService = getAppContext().flagsService;
+
+ static override styles = [
+ css`
+ .header {
+ background-color: var(--user-suggestion-header-background);
+ color: var(--user-suggestion-header-color);
+ border: 1px solid var(--border-color);
+ border-bottom: 0;
+ padding: var(--spacing-xs) var(--spacing-s);
+ display: flex;
+ align-items: center;
+ }
+ .header .title {
+ flex: 1;
+ }
+ gr-copy-clipboard {
+ --gr-copy-clipboard-icon-color: var(--user-suggestion-header-color);
+ }
+ code {
+ max-width: var(--gr-formatted-text-prose-max-width, none);
+ background-color: var(--background-color-secondary);
+ border: 1px solid var(--border-color);
+ border-top: 0;
+ display: block;
+ font-family: var(--monospace-font-family);
+ font-size: var(--font-size-code);
+ line-height: var(--line-height-mono);
+ margin-bottom: var(--spacing-m);
+ padding: var(--spacing-xxs) var(--spacing-s);
+ overflow-x: auto;
+ /* Pre will preserve whitespace and line breaks but not wrap */
+ white-space: pre;
+ }
+ `,
+ ];
+
+ override render() {
+ if (!this.flagsService.isEnabled(KnownExperimentId.SUGGEST_EDIT)) {
+ return nothing;
+ }
+ if (!this.textContent) return nothing;
+ const code = this.textContent;
+ return html`<div class="header">
+ <div class="title">Suggested fix</div>
+ <div>
+ <gr-copy-clipboard hideInput="" text=${code}></gr-copy-clipboard>
+ </div>
+ <div>
+ <gr-button
+ secondary
+ class="action show-fix"
+ @click=${this.handleShowFix}
+ >
+ Preview Fix
+ </gr-button>
+ </div>
+ </div>
+ <code>${code}</code>`;
+ }
+
+ handleShowFix() {
+ if (!this.textContent) return;
+ fire(this, 'open-user-suggest-preview', {code: this.textContent});
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'gr-user-suggestion-fix': GrUserSuggetionFix;
+ }
+}
diff --git a/polygerrit-ui/app/elements/shared/gr-user-suggestion-fix/gr-user-suggestion-fix_test.ts b/polygerrit-ui/app/elements/shared/gr-user-suggestion-fix/gr-user-suggestion-fix_test.ts
new file mode 100644
index 0000000..80422a0
--- /dev/null
+++ b/polygerrit-ui/app/elements/shared/gr-user-suggestion-fix/gr-user-suggestion-fix_test.ts
@@ -0,0 +1,46 @@
+/**
+ * @license
+ * Copyright 2023 Google LLC
+ * SPDX-License-Identifier: Apache-2.0
+ */
+import '../../../test/common-test-setup';
+import './gr-user-suggestion-fix';
+import {fixture, html, assert} from '@open-wc/testing';
+import {GrUserSuggetionFix} from './gr-user-suggestion-fix';
+import {getAppContext} from '../../../services/app-context';
+
+suite('gr-user-suggestion-fix tests', () => {
+ let element: GrUserSuggetionFix;
+
+ setup(async () => {
+ const flagsService = getAppContext().flagsService;
+ sinon.stub(flagsService, 'isEnabled').returns(true);
+ element = await fixture<GrUserSuggetionFix>(html`
+ <gr-user-suggestion-fix>Hello World</gr-user-suggestion-fix>
+ `);
+ await element.updateComplete;
+ });
+
+ test('render', async () => {
+ await element.updateComplete;
+
+ assert.shadowDom.equal(
+ element,
+ /* HTML */ `<div class="header">
+ <div class="title">Suggested fix</div>
+ <div>
+ <gr-copy-clipboard
+ hideinput=""
+ text="Hello World"
+ ></gr-copy-clipboard>
+ </div>
+ <div>
+ <gr-button class="action show-fix" secondary=""
+ >Preview Fix</gr-button
+ >
+ </div>
+ </div>
+ <code>Hello World</code>`
+ );
+ });
+});
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-builder-legacy.ts b/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-builder-legacy.ts
index 5270603..b3f3714 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-builder-legacy.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-builder-legacy.ts
@@ -3,10 +3,7 @@
* Copyright 2016 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
-import {
- MovedLinkClickedEventDetail,
- RenderPreferences,
-} from '../../../api/diff';
+import {RenderPreferences} from '../../../api/diff';
import {fire} from '../../../utils/event-util';
import {GrDiffLine, GrDiffLineType, LineNumber} from '../gr-diff/gr-diff-line';
import {GrDiffGroup, GrDiffGroupType} from '../gr-diff/gr-diff-group';
@@ -430,16 +427,10 @@
anchor.setAttribute('href', `#${line}`);
anchor.addEventListener('click', e => {
e.preventDefault();
- anchor.dispatchEvent(
- new CustomEvent<MovedLinkClickedEventDetail>('moved-link-clicked', {
- detail: {
- lineNum: line,
- side,
- },
- composed: true,
- bubbles: true,
- })
- );
+ fire(anchor, 'moved-link-clicked', {
+ lineNum: line,
+ side,
+ });
});
return anchor;
}
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-section.ts b/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-section.ts
index d40fdda..e5d3d2e 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-section.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-section.ts
@@ -9,7 +9,6 @@
DiffInfo,
DiffLayer,
DiffViewMode,
- MovedLinkClickedEventDetail,
RenderPreferences,
Side,
LineNumber,
@@ -27,6 +26,7 @@
import '../gr-range-header/gr-range-header';
import './gr-diff-row';
import {when} from 'lit/directives/when.js';
+import {fire} from '../../../utils/event-util';
@customElement('gr-diff-section')
export class GrDiffSection extends LitElement {
@@ -235,16 +235,11 @@
side: Side,
line: number
) {
- anchor?.dispatchEvent(
- new CustomEvent<MovedLinkClickedEventDetail>('moved-link-clicked', {
- detail: {
- lineNum: line,
- side,
- },
- composed: true,
- bubbles: true,
- })
- );
+ if (!anchor) return;
+ fire(anchor, 'moved-link-clicked', {
+ lineNum: line,
+ side,
+ });
}
}
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-cursor/gr-diff-cursor.ts b/polygerrit-ui/app/embed/diff/gr-diff-cursor/gr-diff-cursor.ts
index cc16de5..9e3640b 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-cursor/gr-diff-cursor.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-cursor/gr-diff-cursor.ts
@@ -9,7 +9,6 @@
DiffViewMode,
GrDiffCursor as GrDiffCursorApi,
LineNumber,
- LineNumberEventDetail,
LineSelectedEventDetail,
} from '../../../api/diff';
import {ScrollMode, Side} from '../../../constants/constants';
@@ -21,6 +20,7 @@
import {GrDiffLineType} from '../gr-diff/gr-diff-line';
import {GrDiffGroupType} from '../gr-diff/gr-diff-group';
import {GrDiff} from '../gr-diff/gr-diff';
+import {fire} from '../../../utils/event-util';
type GrDiffRowType = GrDiffLineType | GrDiffGroupType;
@@ -484,16 +484,10 @@
const address = this.getAddressFor(row, side);
if (address) {
const {leftSide, number} = address;
- row.dispatchEvent(
- new CustomEvent<LineNumberEventDetail>(event, {
- detail: {
- lineNum: number,
- side: leftSide ? Side.LEFT : Side.RIGHT,
- },
- composed: true,
- bubbles: true,
- })
- );
+ fire(row, event, {
+ lineNum: number,
+ side: leftSide ? Side.LEFT : Side.RIGHT,
+ });
}
}
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-highlight/gr-diff-highlight.ts b/polygerrit-ui/app/embed/diff/gr-diff-highlight/gr-diff-highlight.ts
index a2a0d0a..02f2233 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-highlight/gr-diff-highlight.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-highlight/gr-diff-highlight.ts
@@ -20,6 +20,7 @@
} from '../gr-diff/gr-diff-utils';
import {debounce, DelayedTask} from '../../../utils/async-util';
import {assertIsDefined, queryAndAssert} from '../../../utils/common-util';
+import {fire} from '../../../utils/event-util';
interface SidedRange {
side: Side;
@@ -458,13 +459,9 @@
}
private fireCreateRangeComment(side: Side, range: CommentRange) {
- this.diffTable?.dispatchEvent(
- new CustomEvent<CreateRangeCommentEventDetail>('create-range-comment', {
- detail: {side, range},
- composed: true,
- bubbles: true,
- })
- );
+ if (this.diffTable) {
+ fire(this.diffTable, 'create-range-comment', {side, range});
+ }
this.removeActionBox();
}
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-image-viewer/gr-image-viewer.ts b/polygerrit-ui/app/embed/diff/gr-diff-image-viewer/gr-image-viewer.ts
index 3a3f0f7..cb466c3 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-image-viewer/gr-image-viewer.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-image-viewer/gr-image-viewer.ts
@@ -24,15 +24,10 @@
import {classMap} from 'lit/directives/class-map.js';
import {StyleInfo, styleMap} from 'lit/directives/style-map.js';
-import {
- createEvent,
- Dimensions,
- fitToFrame,
- FrameConstrainer,
- Point,
- Rect,
-} from './util';
+import {Dimensions, fitToFrame, FrameConstrainer, Point, Rect} from './util';
import {ValueChangedEvent} from '../../../types/events';
+import {fireNoBubbleNoCompose} from '../../../utils/event-util';
+import {ImageDiffAction} from '../../../api/diff';
const DRAG_DEAD_ZONE_PIXELS = 5;
@@ -687,27 +682,25 @@
});
}
+ fireAction(detail: ImageDiffAction) {
+ fireNoBubbleNoCompose(this, 'image-diff-action', detail);
+ }
+
selectBase() {
if (!this.baseUrl) return;
this.baseSelected = true;
- this.dispatchEvent(
- createEvent({type: 'version-switcher-clicked', button: 'base'})
- );
+ this.fireAction({type: 'version-switcher-clicked', button: 'base'});
}
selectRevision() {
if (!this.revisionUrl) return;
this.baseSelected = false;
- this.dispatchEvent(
- createEvent({type: 'version-switcher-clicked', button: 'revision'})
- );
+ this.fireAction({type: 'version-switcher-clicked', button: 'revision'});
}
manualBlink() {
this.toggleImage();
- this.dispatchEvent(
- createEvent({type: 'version-switcher-clicked', button: 'switch'})
- );
+ this.fireAction({type: 'version-switcher-clicked', button: 'switch'});
}
private toggleImage() {
@@ -718,9 +711,10 @@
toggleAutomaticBlink() {
this.automaticBlink = !this.automaticBlink;
- this.dispatchEvent(
- createEvent({type: 'automatic-blink-changed', value: this.automaticBlink})
- );
+ this.fireAction({
+ type: 'automatic-blink-changed',
+ value: this.automaticBlink,
+ });
}
private updateAutomaticBlink() {
@@ -752,13 +746,11 @@
private toggleHighlight(source: 'controls' | 'magnifier') {
this.showHighlight = !this.showHighlight;
- this.dispatchEvent(
- createEvent({
- type: 'highlight-changes-changed',
- value: this.showHighlight,
- source,
- })
- );
+ this.fireAction({
+ type: 'highlight-changes-changed',
+ value: this.showHighlight,
+ source,
+ });
}
zoomControlChanged(event: ValueChangedEvent<'fit' | number>) {
@@ -766,38 +758,30 @@
if (!value) return;
if (value === 'fit') {
this.scaledSelected = true;
- this.dispatchEvent(
- createEvent({type: 'zoom-level-changed', scale: 'fit'})
- );
+ this.fireAction({type: 'zoom-level-changed', scale: 'fit'});
}
if (typeof value === 'number' && value > 0) {
this.scaledSelected = false;
this.scale = value;
- this.dispatchEvent(
- createEvent({type: 'zoom-level-changed', scale: value})
- );
+ this.fireAction({type: 'zoom-level-changed', scale: value});
}
this.updateSizes();
}
followMouseChanged() {
this.followMouse = !this.followMouse;
- this.dispatchEvent(
- createEvent({type: 'follow-mouse-changed', value: this.followMouse})
- );
+ this.fireAction({type: 'follow-mouse-changed', value: this.followMouse});
}
pickColor(value: string) {
this.checkerboardSelected = false;
this.backgroundColor = value;
- this.dispatchEvent(createEvent({type: 'background-color-changed', value}));
+ this.fireAction({type: 'background-color-changed', value});
}
pickCheckerboard() {
this.checkerboardSelected = true;
- this.dispatchEvent(
- createEvent({type: 'background-color-changed', value: 'checkerboard'})
- );
+ this.fireAction({type: 'background-color-changed', value: 'checkerboard'});
}
mousemoveImageArea(event: MouseEvent) {
@@ -850,9 +834,9 @@
// external mice.
if (distance < DRAG_DEAD_ZONE_PIXELS) {
this.toggleImage();
- this.dispatchEvent(createEvent({type: 'magnifier-clicked'}));
+ this.fireAction({type: 'magnifier-clicked'});
} else {
- this.dispatchEvent(createEvent({type: 'magnifier-dragged'}));
+ this.fireAction({type: 'magnifier-dragged'});
}
}
@@ -895,7 +879,7 @@
if (!this.ownsMouseDown) return;
this.grabbing = false;
this.ownsMouseDown = false;
- this.dispatchEvent(createEvent({type: 'magnifier-dragged'}));
+ this.fireAction({type: 'magnifier-dragged'});
}
dragstartMagnifier(event: DragEvent) {
@@ -956,4 +940,7 @@
interface HTMLElementTagNameMap {
'gr-image-viewer': GrImageViewer;
}
+ interface HTMLElementEventMap {
+ 'image-diff-action': CustomEvent<ImageDiffAction>;
+ }
}
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-image-viewer/gr-overview-image.ts b/polygerrit-ui/app/embed/diff/gr-diff-image-viewer/gr-overview-image.ts
index b9354eb..21a7cf8 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-image-viewer/gr-overview-image.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-image-viewer/gr-overview-image.ts
@@ -7,8 +7,9 @@
import {customElement, property, query, state} from 'lit/decorators.js';
import {StyleInfo, styleMap} from 'lit/directives/style-map.js';
import {ImageDiffAction} from '../../../api/diff';
+import {fire} from '../../../utils/event-util';
-import {createEvent, Dimensions, fitToFrame, Point, Rect} from './util';
+import {Dimensions, fitToFrame, Point, Rect} from './util';
/**
* Displays a scaled-down version of an image with a draggable frame for
@@ -243,7 +244,7 @@
const detail: ImageDiffAction = {
type: this.dragging ? 'overview-frame-dragged' : 'overview-image-clicked',
};
- this.dispatchEvent(createEvent(detail));
+ fire(this, 'image-diff-action', detail);
this.dragging = false;
this.closeOverlay();
@@ -297,13 +298,7 @@
}
private notifyNewCenter(center: Point) {
- this.dispatchEvent(
- new CustomEvent<Point>('center-updated', {
- detail: {...center},
- bubbles: true,
- composed: true,
- })
- );
+ fire(this, 'center-updated', {...center});
}
}
@@ -311,4 +306,7 @@
interface HTMLElementTagNameMap {
'gr-overview-image': GrOverviewImage;
}
+ interface HTMLElementEventMap {
+ 'center-updated': CustomEvent<Point>;
+ }
}
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-image-viewer/util.ts b/polygerrit-ui/app/embed/diff/gr-diff-image-viewer/util.ts
index 38a07b7..896dc11 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-image-viewer/util.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-image-viewer/util.ts
@@ -3,7 +3,6 @@
* Copyright 2021 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
-import {ImageDiffAction} from '../../../api/diff';
export interface Point {
x: number;
@@ -224,13 +223,3 @@
};
}
}
-
-export function createEvent(
- detail: ImageDiffAction
-): CustomEvent<ImageDiffAction> {
- return new CustomEvent('image-diff-action', {
- detail,
- bubbles: true,
- composed: true,
- });
-}
diff --git a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff.ts b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff.ts
index c04549b..0f4ab2e 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff.ts
@@ -54,7 +54,6 @@
RenderPreferences,
GrDiff as GrDiffApi,
DisplayLine,
- LineSelectedEventDetail,
} from '../../../api/diff';
import {isSafari, toggleClass} from '../../../utils/dom-util';
import {assertIsDefined} from '../../../utils/common-util';
@@ -1349,17 +1348,11 @@
}
private dispatchSelectedLine(number: LineNumber, side: Side) {
- this.dispatchEvent(
- new CustomEvent<LineSelectedEventDetail>('line-selected', {
- detail: {
- number,
- side,
- path: this.path,
- },
- composed: true,
- bubbles: true,
- })
- );
+ fire(this, 'line-selected', {
+ number,
+ side,
+ path: this.path,
+ });
}
addDraftAtLine(el: Element) {
@@ -1411,18 +1404,12 @@
if (!contentEl) throw new Error('content el not found for line el');
side = side ?? this.getCommentSideByLineAndContent(lineEl, contentEl);
assertIsDefined(this.path, 'path');
- this.dispatchEvent(
- new CustomEvent<CreateCommentEventDetail>('create-comment', {
- bubbles: true,
- composed: true,
- detail: {
- path: this.path,
- side,
- lineNum,
- range,
- },
- })
- );
+ fire(this, 'create-comment', {
+ path: this.path,
+ side,
+ lineNum,
+ range,
+ });
}
private getCommentSideByLineAndContent(
diff --git a/polygerrit-ui/app/services/gr-auth/gr-auth_mock.ts b/polygerrit-ui/app/services/gr-auth/gr-auth_mock.ts
index 480484e..37c2311 100644
--- a/polygerrit-ui/app/services/gr-auth/gr-auth_mock.ts
+++ b/polygerrit-ui/app/services/gr-auth/gr-auth_mock.ts
@@ -3,6 +3,7 @@
* Copyright 2020 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
+import {fire} from '../../utils/event-util';
import {
AuthRequestInit,
AuthService,
@@ -28,14 +29,10 @@
private _setStatus(status: AuthStatus) {
if (this._status === status) return;
if (this._status === AuthStatus.AUTHED) {
- document.dispatchEvent(
- new CustomEvent('auth-error', {
- detail: {
- message: Auth.CREDS_EXPIRED_MSG,
- action: 'Refresh credentials',
- },
- })
- );
+ fire(document, 'auth-error', {
+ message: Auth.CREDS_EXPIRED_MSG,
+ action: 'Refresh credentials',
+ });
}
this._status = status;
}
diff --git a/polygerrit-ui/app/styles/themes/app-theme.ts b/polygerrit-ui/app/styles/themes/app-theme.ts
index 107ee16..0503e4c 100644
--- a/polygerrit-ui/app/styles/themes/app-theme.ts
+++ b/polygerrit-ui/app/styles/themes/app-theme.ts
@@ -278,6 +278,11 @@
--robot-comment-background-color: var(--blue-50);
--unresolved-comment-background-color: #fef7e0;
+
+ /* Suggest edits */
+ --user-suggestion-header-background: var(--gray-700);
+ --user-suggestion-header-color: white;
+
/* vote background colors */
--vote-color-approved: var(--green-300);
--vote-color-disliked: var(--red-50);
diff --git a/polygerrit-ui/app/styles/themes/dark-theme.ts b/polygerrit-ui/app/styles/themes/dark-theme.ts
index a183c86..dc3d4e9 100644
--- a/polygerrit-ui/app/styles/themes/dark-theme.ts
+++ b/polygerrit-ui/app/styles/themes/dark-theme.ts
@@ -138,6 +138,10 @@
--robot-comment-background-color: #1e3a5f;
--unresolved-comment-background-color: #614a19;
+ /* Suggest edits */
+ --user-suggestion-header-background: var(--gray-700);
+ --user-suggestion-header-color: white;
+
/* vote background colors */
--vote-color-approved: var(--green-300);
--vote-color-disliked: var(--red-tonal);
diff --git a/polygerrit-ui/app/types/events.ts b/polygerrit-ui/app/types/events.ts
index d8a4d2c..c28aade 100644
--- a/polygerrit-ui/app/types/events.ts
+++ b/polygerrit-ui/app/types/events.ts
@@ -15,7 +15,6 @@
BIND_VALUE_CHANGED = 'bind-value-changed',
CHANGE = 'change',
CHANGED = 'changed',
- CHANGE_MESSAGE_DELETED = 'change-message-deleted',
COMMIT = 'commit',
DIALOG_CHANGE = 'dialog-change',
DROP = 'drop',
@@ -49,7 +48,6 @@
'change': ChangeEvent;
/* prettier-ignore */
'changed': ChangedEvent;
- 'change-message-deleted': ChangeMessageDeletedEvent;
/* prettier-ignore */
'commit': AutocompleteCommitEvent;
'dialog-change': DialogChangeEvent;
@@ -68,8 +66,6 @@
/* prettier-ignore */
'reload': ReloadEvent;
'remove-reviewer': RemoveReviewerEvent;
- /* prettier-ignore */
- 'reply': ReplyEvent;
'show-alert': ShowAlertEvent;
'show-error': ShowErrorEvent;
'show-tab': SwitchTabEvent;
@@ -93,6 +89,11 @@
}
}
+export interface AddAccountEventDetail {
+ value: string;
+}
+export type AddAccountEvent = CustomEvent<AddAccountEventDetail>;
+
export interface AddReviewerEventDetail {
reviewer: AccountInfo;
}
@@ -110,7 +111,8 @@
export type ChangeEvent = InputEvent;
-export type ChangedEvent = CustomEvent<string>;
+// TODO: This event seems to be unused (no listener). Remove?
+export type ChangedEvent = CustomEvent<string | undefined>;
export interface ChangeMessageDeletedEventDetail {
message: ChangeMessage;
@@ -181,6 +183,7 @@
userWantsToEdit: boolean;
unresolved: boolean;
}
+
export type ReplyToCommentEvent = CustomEvent<ReplyToCommentEventDetail>;
export interface PageErrorEventDetail {
@@ -193,6 +196,11 @@
}
export type ReloadEvent = CustomEvent<ReloadEventDetail>;
+export interface RemoveAccountEventDetail {
+ account: AccountInfo;
+}
+export type RemoveAccountEvent = CustomEvent<RemoveAccountEventDetail>;
+
export interface ReplyEventDetail {
message: ChangeMessage;
}
@@ -218,6 +226,14 @@
}
export type ShowErrorEvent = CustomEvent<ShowErrorEventDetail>;
+export interface ShowReplyDialogEventDetail {
+ value: {
+ reviewersOnly: boolean;
+ ccsOnly: boolean;
+ };
+}
+export type ShowReplyDialogEvent = CustomEvent<ShowReplyDialogEventDetail>;
+
export interface AuthErrorEventDetail {
message: string;
action: string;
diff --git a/polygerrit-ui/app/utils/comment-util.ts b/polygerrit-ui/app/utils/comment-util.ts
index a92f0f8..34a90de 100644
--- a/polygerrit-ui/app/utils/comment-util.ts
+++ b/polygerrit-ui/app/utils/comment-util.ts
@@ -523,7 +523,8 @@
};
}
-export const USER_SUGGESTION_START_PATTERN = '```suggestion\n';
+export const USER_SUGGESTION_INFO_STRING = 'suggestion';
+export const USER_SUGGESTION_START_PATTERN = `\`\`\`${USER_SUGGESTION_INFO_STRING}\n`;
// This can either mean a user or a checks provided fix.
// "Provided" means that the fix is sent along with the request
diff --git a/polygerrit-ui/app/utils/event-util.ts b/polygerrit-ui/app/utils/event-util.ts
index 49d5382..d45ef55 100644
--- a/polygerrit-ui/app/utils/event-util.ts
+++ b/polygerrit-ui/app/utils/event-util.ts
@@ -20,6 +20,24 @@
);
}
+export function fireEventNoBubble(target: EventTarget, type: string) {
+ target.dispatchEvent(
+ new CustomEvent(type, {
+ composed: true,
+ bubbles: false,
+ })
+ );
+}
+
+export function fireEventNoBubbleNoCompose(target: EventTarget, type: string) {
+ target.dispatchEvent(
+ new CustomEvent(type, {
+ composed: false,
+ bubbles: false,
+ })
+ );
+}
+
export type HTMLElementEventDetailType<K extends keyof HTMLElementEventMap> =
HTMLElementEventMap[K] extends CustomEvent<infer DT>
? unknown extends DT
@@ -56,10 +74,42 @@
);
}
+export function fireNoBubble<K extends keyof HTMLElementEventMap, T>(
+ target: EventTarget,
+ type: K,
+ detail: T
+) {
+ target.dispatchEvent(
+ new CustomEvent<T>(type, {
+ detail,
+ composed: true,
+ bubbles: false,
+ })
+ );
+}
+
+export function fireNoBubbleNoCompose<K extends keyof HTMLElementEventMap, T>(
+ target: EventTarget,
+ type: K,
+ detail: T
+) {
+ target.dispatchEvent(
+ new CustomEvent<T>(type, {
+ detail,
+ composed: false,
+ bubbles: false,
+ })
+ );
+}
+
export function fireAlert(target: EventTarget, message: string) {
fire(target, EventType.SHOW_ALERT, {message, showDismiss: true});
}
+export function fireError(target: EventTarget, message: string) {
+ fire(target, EventType.SHOW_ERROR, {message});
+}
+
export function firePageError(response?: Response | null) {
if (response === null) response = undefined;
fire(document, EventType.PAGE_ERROR, {response});