Dave Borowitz | 8cdc76b | 2018-03-26 10:04:27 -0400 | [diff] [blame] | 1 | /** |
| 2 | * @license |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 3 | * Copyright (C) 2015 The Android Open Source Project |
Dave Borowitz | 8cdc76b | 2018-03-26 10:04:27 -0400 | [diff] [blame] | 4 | * |
| 5 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | * you may not use this file except in compliance with the License. |
| 7 | * You may obtain a copy of the License at |
| 8 | * |
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | * |
| 11 | * Unless required by applicable law or agreed to in writing, software |
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | * See the License for the specific language governing permissions and |
| 15 | * limitations under the License. |
| 16 | */ |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 17 | import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea'; |
| 18 | import '../../../styles/shared-styles'; |
| 19 | import '../../plugins/gr-endpoint-decorator/gr-endpoint-decorator'; |
| 20 | import '../../plugins/gr-endpoint-param/gr-endpoint-param'; |
| 21 | import '../gr-button/gr-button'; |
| 22 | import '../gr-dialog/gr-dialog'; |
| 23 | import '../gr-date-formatter/gr-date-formatter'; |
| 24 | import '../gr-formatted-text/gr-formatted-text'; |
| 25 | import '../gr-icons/gr-icons'; |
| 26 | import '../gr-overlay/gr-overlay'; |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 27 | import '../gr-storage/gr-storage'; |
| 28 | import '../gr-textarea/gr-textarea'; |
| 29 | import '../gr-tooltip-content/gr-tooltip-content'; |
| 30 | import '../gr-confirm-delete-comment-dialog/gr-confirm-delete-comment-dialog'; |
| 31 | import '../gr-account-label/gr-account-label'; |
| 32 | import {flush} from '@polymer/polymer/lib/legacy/polymer.dom'; |
| 33 | import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners'; |
| 34 | import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin'; |
| 35 | import {PolymerElement} from '@polymer/polymer/polymer-element'; |
| 36 | import {htmlTemplate} from './gr-comment_html'; |
| 37 | import {KeyboardShortcutMixin} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin'; |
| 38 | import {getRootElement} from '../../../scripts/rootElement'; |
| 39 | import {appContext} from '../../../services/app-context'; |
Ben Rohlfs | 1d48706 | 2020-09-26 11:26:03 +0200 | [diff] [blame] | 40 | import {customElement, observe, property} from '@polymer/decorators'; |
Dhruv Srivastava | 0287bf9 | 2020-09-11 16:56:38 +0200 | [diff] [blame] | 41 | import {GerritNav} from '../../core/gr-navigation/gr-navigation'; |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 42 | import {GrTextarea} from '../gr-textarea/gr-textarea'; |
| 43 | import {GrStorage, StorageLocation} from '../gr-storage/gr-storage'; |
| 44 | import {GrOverlay} from '../gr-overlay/gr-overlay'; |
| 45 | import { |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 46 | AccountDetailInfo, |
Dmitrii Filippov | 30ba596 | 2020-09-29 18:41:45 +0200 | [diff] [blame] | 47 | NumericChangeId, |
Ben Rohlfs | 1d48706 | 2020-09-26 11:26:03 +0200 | [diff] [blame] | 48 | ConfigInfo, |
| 49 | PatchSetNum, |
Dhruv Srivastava | 0287bf9 | 2020-09-11 16:56:38 +0200 | [diff] [blame] | 50 | RepoName, |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 51 | } from '../../../types/common'; |
| 52 | import {GrButton} from '../gr-button/gr-button'; |
| 53 | import {GrConfirmDeleteCommentDialog} from '../gr-confirm-delete-comment-dialog/gr-confirm-delete-comment-dialog'; |
| 54 | import {GrDialog} from '../gr-dialog/gr-dialog'; |
Ben Rohlfs | 1d48706 | 2020-09-26 11:26:03 +0200 | [diff] [blame] | 55 | import { |
| 56 | isDraft, |
| 57 | UIComment, |
| 58 | UIDraft, |
| 59 | UIRobot, |
Ben Rohlfs | 31825d8 | 2020-10-02 18:08:04 +0200 | [diff] [blame] | 60 | } from '../../../utils/comment-util'; |
Dmitrii Filippov | 6a03800 | 2020-10-14 18:50:07 +0200 | [diff] [blame] | 61 | import {OpenFixPreviewEventDetail} from '../../../types/events'; |
Milutin Kristofic | 860fe4d | 2020-11-23 16:13:45 +0100 | [diff] [blame] | 62 | import {fireAlert} from '../../../utils/event-util'; |
Milutin Kristofic | 5b3f087 | 2020-12-05 22:08:09 +0100 | [diff] [blame] | 63 | import {pluralize} from '../../../utils/string-util'; |
Wyatt Allen | 494e7d4 | 2017-09-12 17:01:42 -0700 | [diff] [blame] | 64 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 65 | const STORAGE_DEBOUNCE_INTERVAL = 400; |
| 66 | const TOAST_DEBOUNCE_INTERVAL = 200; |
Wyatt Allen | 7a4aa8c | 2016-05-18 12:37:53 -0700 | [diff] [blame] | 67 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 68 | const SAVED_MESSAGE = 'All changes saved'; |
Dhruv Srivastava | 8b015a6 | 2020-07-09 17:45:25 +0200 | [diff] [blame] | 69 | const UNSAVED_MESSAGE = 'Unable to save draft'; |
Wyatt Allen | 846ac2f | 2018-05-14 12:59:23 -0700 | [diff] [blame] | 70 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 71 | const REPORT_CREATE_DRAFT = 'CreateDraftComment'; |
| 72 | const REPORT_UPDATE_DRAFT = 'UpdateDraftComment'; |
| 73 | const REPORT_DISCARD_DRAFT = 'DiscardDraftComment'; |
| 74 | |
| 75 | const FILE = 'FILE'; |
| 76 | |
Dhruv Srivastava | 8b015a6 | 2020-07-09 17:45:25 +0200 | [diff] [blame] | 77 | export const __testOnly_UNSAVED_MESSAGE = UNSAVED_MESSAGE; |
| 78 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 79 | /** |
| 80 | * All candidates tips to show, will pick randomly. |
| 81 | */ |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 82 | const RESPECTFUL_REVIEW_TIPS = [ |
Tao Zhou | e540985 | 2020-03-27 14:11:00 +0100 | [diff] [blame] | 83 | 'Assume competence.', |
| 84 | 'Provide rationale or context.', |
| 85 | 'Consider how comments may be interpreted.', |
| 86 | 'Avoid harsh language.', |
| 87 | 'Make your comments specific and actionable.', |
| 88 | 'When disagreeing, explain the advantage of your approach.', |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 89 | ]; |
| 90 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 91 | interface CommentOverlays { |
| 92 | confirmDelete?: GrOverlay | null; |
| 93 | confirmDiscard?: GrOverlay | null; |
| 94 | } |
| 95 | |
| 96 | export interface GrComment { |
| 97 | $: { |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 98 | storage: GrStorage; |
| 99 | container: HTMLDivElement; |
| 100 | resolvedCheckbox: HTMLInputElement; |
| 101 | }; |
| 102 | } |
Dmitrii Filippov | 3f3c205 | 2020-09-22 16:51:18 +0200 | [diff] [blame] | 103 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 104 | @customElement('gr-comment') |
| 105 | export class GrComment extends KeyboardShortcutMixin( |
| 106 | GestureEventListeners(LegacyElementMixin(PolymerElement)) |
| 107 | ) { |
| 108 | static get template() { |
| 109 | return htmlTemplate; |
| 110 | } |
| 111 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 112 | /** |
| 113 | * Fired when the create fix comment action is triggered. |
| 114 | * |
| 115 | * @event create-fix-comment |
| 116 | */ |
Kasper Nilsson | d43d2a7 | 2018-10-19 14:26:41 -0700 | [diff] [blame] | 117 | |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame] | 118 | /** |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 119 | * Fired when the show fix preview action is triggered. |
| 120 | * |
| 121 | * @event open-fix-preview |
Tao Zhou | 500437d | 2020-02-14 16:57:27 +0100 | [diff] [blame] | 122 | */ |
Tao Zhou | 500437d | 2020-02-14 16:57:27 +0100 | [diff] [blame] | 123 | |
| 124 | /** |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 125 | * Fired when this comment is discarded. |
| 126 | * |
| 127 | * @event comment-discard |
Tao Zhou | 9a07681 | 2019-12-17 09:59:28 +0100 | [diff] [blame] | 128 | */ |
Andrew Bonventre | 78792e8 | 2016-03-04 17:48:22 -0500 | [diff] [blame] | 129 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 130 | /** |
| 131 | * Fired when this comment is saved. |
| 132 | * |
| 133 | * @event comment-save |
| 134 | */ |
Julie Pan | 49d0a6e | 2019-10-07 07:37:02 -0700 | [diff] [blame] | 135 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 136 | /** |
| 137 | * Fired when this comment is updated. |
| 138 | * |
| 139 | * @event comment-update |
| 140 | */ |
Andrew Bonventre | 78792e8 | 2016-03-04 17:48:22 -0500 | [diff] [blame] | 141 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 142 | /** |
Tao Zhou | 31f3f10 | 2020-04-27 16:15:29 +0200 | [diff] [blame] | 143 | * Fired when editing status changed. |
| 144 | * |
| 145 | * @event comment-editing-changed |
| 146 | */ |
| 147 | |
| 148 | /** |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 149 | * Fired when the comment's timestamp is tapped. |
| 150 | * |
| 151 | * @event comment-anchor-tap |
| 152 | */ |
Andrew Bonventre | 2816526 | 2016-05-19 17:24:45 -0700 | [diff] [blame] | 153 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 154 | @property({type: Number}) |
Dmitrii Filippov | 30ba596 | 2020-09-29 18:41:45 +0200 | [diff] [blame] | 155 | changeNum?: NumericChangeId; |
Viktar Donich | 7ad2892 | 2016-05-23 15:24:05 -0700 | [diff] [blame] | 156 | |
Dhruv Srivastava | 0287bf9 | 2020-09-11 16:56:38 +0200 | [diff] [blame] | 157 | @property({type: String}) |
| 158 | projectName?: RepoName; |
| 159 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 160 | @property({type: Object, notify: true, observer: '_commentChanged'}) |
Dhruv Srivastava | 573ac7d | 2020-12-03 10:59:22 +0100 | [diff] [blame] | 161 | comment?: UIComment; |
Kasper Nilsson | d43d2a7 | 2018-10-19 14:26:41 -0700 | [diff] [blame] | 162 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 163 | @property({type: Array}) |
Dhruv Srivastava | 573ac7d | 2020-12-03 10:59:22 +0100 | [diff] [blame] | 164 | comments?: UIComment[]; |
Andrew Bonventre | 78792e8 | 2016-03-04 17:48:22 -0500 | [diff] [blame] | 165 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 166 | @property({type: Boolean, reflectToAttribute: true}) |
| 167 | isRobotComment = false; |
Kasper Nilsson | 8d1ac7e | 2017-01-04 16:45:21 -0800 | [diff] [blame] | 168 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 169 | @property({type: Boolean, reflectToAttribute: true}) |
| 170 | disabled = false; |
Wyatt Allen | 494e7d4 | 2017-09-12 17:01:42 -0700 | [diff] [blame] | 171 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 172 | @property({type: Boolean, observer: '_draftChanged'}) |
| 173 | draft = false; |
Wyatt Allen | 5eab49a | 2017-11-02 18:17:52 -0700 | [diff] [blame] | 174 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 175 | @property({type: Boolean, observer: '_editingChanged'}) |
| 176 | editing = false; |
Wyatt Allen | ed22566 | 2018-04-05 10:48:03 -0700 | [diff] [blame] | 177 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 178 | @property({type: Boolean, reflectToAttribute: true}) |
| 179 | discarding = false; |
| 180 | |
| 181 | @property({type: Boolean}) |
| 182 | hasChildren?: boolean; |
| 183 | |
| 184 | @property({type: String}) |
Milutin Kristofic | a6af5aa | 2020-09-23 09:08:14 +0200 | [diff] [blame] | 185 | patchNum?: PatchSetNum; |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 186 | |
| 187 | @property({type: Boolean}) |
| 188 | showActions?: boolean; |
| 189 | |
| 190 | @property({type: Boolean}) |
| 191 | _showHumanActions?: boolean; |
| 192 | |
| 193 | @property({type: Boolean}) |
| 194 | _showRobotActions?: boolean; |
| 195 | |
| 196 | @property({ |
| 197 | type: Boolean, |
| 198 | reflectToAttribute: true, |
| 199 | observer: '_toggleCollapseClass', |
| 200 | }) |
| 201 | collapsed = true; |
| 202 | |
| 203 | @property({type: Object}) |
| 204 | projectConfig?: ConfigInfo; |
| 205 | |
| 206 | @property({type: Boolean}) |
| 207 | robotButtonDisabled?: boolean; |
| 208 | |
| 209 | @property({type: Boolean}) |
| 210 | _hasHumanReply?: boolean; |
| 211 | |
| 212 | @property({type: Boolean}) |
| 213 | _isAdmin = false; |
| 214 | |
| 215 | @property({type: Object}) |
Dhruv Srivastava | f97b055 | 2020-11-30 14:14:09 +0100 | [diff] [blame] | 216 | // eslint-disable-next-line @typescript-eslint/no-explicit-any |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 217 | _xhrPromise?: Promise<any>; // Used for testing. |
| 218 | |
| 219 | @property({type: String, observer: '_messageTextChanged'}) |
| 220 | _messageText = ''; |
| 221 | |
| 222 | @property({type: String}) |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 223 | side?: string; |
| 224 | |
| 225 | @property({type: Boolean}) |
| 226 | resolved?: boolean; |
| 227 | |
| 228 | // Intentional to share the object across instances. |
| 229 | @property({type: Object}) |
| 230 | _numPendingDraftRequests: {number: number} = {number: 0}; |
| 231 | |
| 232 | @property({type: Boolean}) |
| 233 | _enableOverlay = false; |
| 234 | |
| 235 | /** |
| 236 | * Property for storing references to overlay elements. When the overlays |
| 237 | * are moved to getRootElement() to be shown they are no-longer |
| 238 | * children, so they can't be queried along the tree, so they are stored |
| 239 | * here. |
| 240 | */ |
| 241 | @property({type: Object}) |
| 242 | _overlays: CommentOverlays = {}; |
| 243 | |
| 244 | @property({type: Boolean}) |
| 245 | _showRespectfulTip = false; |
| 246 | |
| 247 | @property({type: Boolean}) |
| 248 | showPatchset = true; |
| 249 | |
| 250 | @property({type: String}) |
| 251 | _respectfulReviewTip?: string; |
| 252 | |
| 253 | @property({type: Boolean}) |
| 254 | _respectfulTipDismissed = false; |
| 255 | |
| 256 | @property({type: Boolean}) |
| 257 | _unableToSave = false; |
| 258 | |
| 259 | @property({type: Object}) |
| 260 | _selfAccount?: AccountDetailInfo; |
Tao Zhou | 500437d | 2020-02-14 16:57:27 +0100 | [diff] [blame] | 261 | |
Dhruv Srivastava | 0287bf9 | 2020-09-11 16:56:38 +0200 | [diff] [blame] | 262 | @property({type: Boolean}) |
| 263 | showPortedComment = false; |
| 264 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 265 | get keyBindings() { |
| 266 | return { |
| 267 | 'ctrl+enter meta+enter ctrl+s meta+s': '_handleSaveKey', |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 268 | esc: '_handleEsc', |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 269 | }; |
| 270 | } |
| 271 | |
Ben Rohlfs | 43935a4 | 2020-12-01 19:14:09 +0100 | [diff] [blame] | 272 | private readonly restApiService = appContext.restApiService; |
| 273 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 274 | reporting = appContext.reportingService; |
| 275 | |
| 276 | /** @override */ |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 277 | attached() { |
| 278 | super.attached(); |
Ben Rohlfs | 43935a4 | 2020-12-01 19:14:09 +0100 | [diff] [blame] | 279 | this.restApiService.getAccount().then(account => { |
Dhruv Srivastava | cf70e79 | 2020-07-24 15:35:39 +0200 | [diff] [blame] | 280 | this._selfAccount = account; |
| 281 | }); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 282 | if (this.editing) { |
| 283 | this.collapsed = false; |
| 284 | } else if (this.comment) { |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 285 | this.collapsed = !!this.comment.collapsed; |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame] | 286 | } |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 287 | this._getIsAdmin().then(isAdmin => { |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 288 | this._isAdmin = !!isAdmin; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 289 | }); |
| 290 | } |
Andrew Bonventre | 78792e8 | 2016-03-04 17:48:22 -0500 | [diff] [blame] | 291 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 292 | /** @override */ |
| 293 | detached() { |
| 294 | super.detached(); |
| 295 | this.cancelDebouncer('fire-update'); |
| 296 | if (this.textarea) { |
| 297 | this.textarea.closeDropdown(); |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame] | 298 | } |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 299 | } |
Andrew Bonventre | 78792e8 | 2016-03-04 17:48:22 -0500 | [diff] [blame] | 300 | |
Ben Rohlfs | 1d48706 | 2020-09-26 11:26:03 +0200 | [diff] [blame] | 301 | _getAuthor(comment: UIComment) { |
Dhruv Srivastava | cf70e79 | 2020-07-24 15:35:39 +0200 | [diff] [blame] | 302 | return comment.author || this._selfAccount; |
| 303 | } |
| 304 | |
Dhruv Srivastava | 0287bf9 | 2020-09-11 16:56:38 +0200 | [diff] [blame] | 305 | _getUrlForComment(comment: UIComment) { |
| 306 | if (!this.changeNum || !this.projectName) return ''; |
| 307 | if (!comment.id) throw new Error('comment must have an id'); |
| 308 | return GerritNav.getUrlForComment( |
| 309 | this.changeNum as NumericChangeId, |
| 310 | this.projectName, |
| 311 | comment.id |
| 312 | ); |
| 313 | } |
| 314 | |
Dhruv Srivastava | c8df760 | 2021-01-15 10:59:00 +0100 | [diff] [blame^] | 315 | _handlePortedMessageClick() { |
| 316 | if (!this.comment) throw new Error('comment not set'); |
| 317 | this.reporting.reportInteraction('navigate-to-original-comment', { |
| 318 | line: this.comment.line, |
| 319 | range: this.comment.range, |
| 320 | }); |
| 321 | } |
| 322 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 323 | @observe('editing') |
| 324 | _onEditingChange(editing?: boolean) { |
| 325 | this.dispatchEvent( |
| 326 | new CustomEvent('comment-editing-changed', { |
| 327 | detail: !!editing, |
| 328 | bubbles: true, |
| 329 | composed: true, |
| 330 | }) |
| 331 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 332 | if (!editing) return; |
| 333 | // visibility based on cache this will make sure we only and always show |
| 334 | // a tip once every Math.max(a day, period between creating comments) |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 335 | const cachedVisibilityOfRespectfulTip = this.$.storage.getRespectfulTipVisibility(); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 336 | if (!cachedVisibilityOfRespectfulTip) { |
| 337 | // we still want to show the tip with a probability of 30% |
| 338 | if (this.getRandomNum(0, 3) >= 1) return; |
| 339 | this._showRespectfulTip = true; |
| 340 | const randomIdx = this.getRandomNum(0, RESPECTFUL_REVIEW_TIPS.length); |
| 341 | this._respectfulReviewTip = RESPECTFUL_REVIEW_TIPS[randomIdx]; |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 342 | this.reporting.reportInteraction('respectful-tip-appeared', { |
| 343 | tip: this._respectfulReviewTip, |
| 344 | }); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 345 | // update cache |
| 346 | this.$.storage.setRespectfulTipVisibility(); |
| 347 | } |
| 348 | } |
| 349 | |
| 350 | /** Set as a separate method so easy to stub. */ |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 351 | getRandomNum(min: number, max: number) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 352 | return Math.floor(Math.random() * (max - min) + min); |
| 353 | } |
| 354 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 355 | _computeVisibilityOfTip(showTip: boolean, tipDismissed: boolean) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 356 | return showTip && !tipDismissed; |
| 357 | } |
| 358 | |
| 359 | _dismissRespectfulTip() { |
| 360 | this._respectfulTipDismissed = true; |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 361 | this.reporting.reportInteraction('respectful-tip-dismissed', { |
| 362 | tip: this._respectfulReviewTip, |
| 363 | }); |
Tao Zhou | e540985 | 2020-03-27 14:11:00 +0100 | [diff] [blame] | 364 | // add a 14-day delay to the tip cache |
| 365 | this.$.storage.setRespectfulTipVisibility(/* delayDays= */ 14); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 366 | } |
| 367 | |
| 368 | _onRespectfulReadMoreClick() { |
Milutin Kristofic | da88b33 | 2020-03-24 10:19:12 +0100 | [diff] [blame] | 369 | this.reporting.reportInteraction('respectful-read-more-clicked'); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 370 | } |
| 371 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 372 | get textarea(): GrTextarea | null { |
| 373 | return this.shadowRoot?.querySelector('#editTextarea') as GrTextarea | null; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 374 | } |
| 375 | |
| 376 | get confirmDeleteOverlay() { |
| 377 | if (!this._overlays.confirmDelete) { |
| 378 | this._enableOverlay = true; |
| 379 | flush(); |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 380 | this._overlays.confirmDelete = this.shadowRoot?.querySelector( |
| 381 | '#confirmDeleteOverlay' |
| 382 | ) as GrOverlay | null; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 383 | } |
| 384 | return this._overlays.confirmDelete; |
| 385 | } |
| 386 | |
| 387 | get confirmDiscardOverlay() { |
| 388 | if (!this._overlays.confirmDiscard) { |
| 389 | this._enableOverlay = true; |
| 390 | flush(); |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 391 | this._overlays.confirmDiscard = this.shadowRoot?.querySelector( |
| 392 | '#confirmDiscardOverlay' |
| 393 | ) as GrOverlay | null; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 394 | } |
| 395 | return this._overlays.confirmDiscard; |
| 396 | } |
| 397 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 398 | _computeShowHideIcon(collapsed: boolean) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 399 | return collapsed ? 'gr-icons:expand-more' : 'gr-icons:expand-less'; |
| 400 | } |
| 401 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 402 | _computeShowHideAriaLabel(collapsed: boolean) { |
Tao Zhou | 2ccf416 | 2020-05-25 15:04:34 +0200 | [diff] [blame] | 403 | return collapsed ? 'Expand' : 'Collapse'; |
| 404 | } |
| 405 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 406 | @observe('showActions', 'isRobotComment') |
| 407 | _calculateActionstoShow(showActions?: boolean, isRobotComment?: boolean) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 408 | // Polymer 2: check for undefined |
Dhruv Srivastava | 6894356 | 2020-06-26 12:46:44 +0200 | [diff] [blame] | 409 | if ([showActions, isRobotComment].includes(undefined)) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 410 | return; |
Tao Zhou | 500437d | 2020-02-14 16:57:27 +0100 | [diff] [blame] | 411 | } |
| 412 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 413 | this._showHumanActions = showActions && !isRobotComment; |
| 414 | this._showRobotActions = showActions && isRobotComment; |
| 415 | } |
| 416 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 417 | @observe('comment') |
Ben Rohlfs | 1d48706 | 2020-09-26 11:26:03 +0200 | [diff] [blame] | 418 | _isRobotComment(comment: UIRobot) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 419 | this.isRobotComment = !!comment.robot_id; |
| 420 | } |
| 421 | |
| 422 | isOnParent() { |
| 423 | return this.side === 'PARENT'; |
| 424 | } |
| 425 | |
| 426 | _getIsAdmin() { |
Ben Rohlfs | 43935a4 | 2020-12-01 19:14:09 +0100 | [diff] [blame] | 427 | return this.restApiService.getIsAdmin(); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 428 | } |
| 429 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 430 | _computeDraftTooltip(unableToSave: boolean) { |
| 431 | return unableToSave |
| 432 | ? 'Unable to save draft. Please try to save again.' |
| 433 | : "This draft is only visible to you. To publish drafts, click the 'Reply'" + |
| 434 | "or 'Start review' button at the top of the change or press the 'A' key."; |
Dhruv Srivastava | 8b015a6 | 2020-07-09 17:45:25 +0200 | [diff] [blame] | 435 | } |
| 436 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 437 | _computeDraftText(unableToSave: boolean) { |
Dhruv Srivastava | 8b015a6 | 2020-07-09 17:45:25 +0200 | [diff] [blame] | 438 | return 'DRAFT' + (unableToSave ? '(Failed to save)' : ''); |
| 439 | } |
| 440 | |
Ben Rohlfs | 1d48706 | 2020-09-26 11:26:03 +0200 | [diff] [blame] | 441 | save(opt_comment?: UIComment) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 442 | let comment = opt_comment; |
| 443 | if (!comment) { |
| 444 | comment = this.comment; |
Tao Zhou | 500437d | 2020-02-14 16:57:27 +0100 | [diff] [blame] | 445 | } |
| 446 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 447 | this.set('comment.message', this._messageText); |
| 448 | this.editing = false; |
| 449 | this.disabled = true; |
| 450 | |
| 451 | if (!this._messageText) { |
| 452 | return this._discardDraft(); |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame] | 453 | } |
Wyatt Allen | ed22566 | 2018-04-05 10:48:03 -0700 | [diff] [blame] | 454 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 455 | this._xhrPromise = this._saveDraft(comment) |
| 456 | .then(response => { |
| 457 | this.disabled = false; |
| 458 | if (!response.ok) { |
| 459 | return; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 460 | } |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 461 | |
| 462 | this._eraseDraftComment(); |
Ben Rohlfs | 43935a4 | 2020-12-01 19:14:09 +0100 | [diff] [blame] | 463 | return this.restApiService.getResponseObject(response).then(obj => { |
Ben Rohlfs | 1d48706 | 2020-09-26 11:26:03 +0200 | [diff] [blame] | 464 | const resComment = (obj as unknown) as UIDraft; |
| 465 | if (!isDraft(this.comment)) throw new Error('Can only save drafts.'); |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 466 | resComment.__draft = true; |
| 467 | // Maintain the ephemeral draft ID for identification by other |
| 468 | // elements. |
Milutin Kristofic | a6af5aa | 2020-09-23 09:08:14 +0200 | [diff] [blame] | 469 | if (this.comment?.__draftID) { |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 470 | resComment.__draftID = this.comment.__draftID; |
| 471 | } |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 472 | this.comment = resComment; |
| 473 | this._fireSave(); |
| 474 | return obj; |
Kasper Nilsson | a4c24de | 2017-05-16 13:50:27 -0700 | [diff] [blame] | 475 | }); |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 476 | }) |
| 477 | .catch(err => { |
| 478 | this.disabled = false; |
| 479 | throw err; |
| 480 | }); |
Wyatt Allen | d563a71 | 2017-10-26 14:11:24 -0700 | [diff] [blame] | 481 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 482 | return this._xhrPromise; |
| 483 | } |
| 484 | |
| 485 | _eraseDraftComment() { |
| 486 | // Prevents a race condition in which removing the draft comment occurs |
| 487 | // prior to it being saved. |
| 488 | this.cancelDebouncer('store'); |
| 489 | |
Dhruv Srivastava | dbddc1b | 2020-09-24 21:23:27 +0200 | [diff] [blame] | 490 | if (!this.comment?.path) throw new Error('Cannot erase Draft Comment'); |
Milutin Kristofic | a6af5aa | 2020-09-23 09:08:14 +0200 | [diff] [blame] | 491 | if (this.changeNum === undefined) { |
| 492 | throw new Error('undefined changeNum'); |
| 493 | } |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 494 | this.$.storage.eraseDraftComment({ |
| 495 | changeNum: this.changeNum, |
| 496 | patchNum: this._getPatchNum(), |
| 497 | path: this.comment.path, |
| 498 | line: this.comment.line, |
| 499 | range: this.comment.range, |
| 500 | }); |
| 501 | } |
| 502 | |
Ben Rohlfs | 1d48706 | 2020-09-26 11:26:03 +0200 | [diff] [blame] | 503 | _commentChanged(comment: UIComment) { |
Dhruv Srivastava | 573ac7d | 2020-12-03 10:59:22 +0100 | [diff] [blame] | 504 | this.editing = isDraft(comment) && !!comment.__editing; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 505 | this.resolved = !comment.unresolved; |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 506 | if (this.editing) { |
| 507 | // It's a new draft/reply, notify. |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 508 | this._fireUpdate(); |
| 509 | } |
| 510 | } |
| 511 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 512 | @observe('comment', 'comments.*') |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 513 | _computeHasHumanReply() { |
Milutin Kristofic | a6af5aa | 2020-09-23 09:08:14 +0200 | [diff] [blame] | 514 | const comment = this.comment; |
| 515 | if (!comment || !this.comments) return; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 516 | // hide please fix button for robot comment that has human reply |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 517 | this._hasHumanReply = this.comments.some( |
| 518 | c => |
| 519 | c.in_reply_to && |
Milutin Kristofic | a6af5aa | 2020-09-23 09:08:14 +0200 | [diff] [blame] | 520 | c.in_reply_to === comment.id && |
Ben Rohlfs | 1d48706 | 2020-09-26 11:26:03 +0200 | [diff] [blame] | 521 | !(c as UIRobot).robot_id |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 522 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 523 | } |
| 524 | |
Dmitrii Filippov | 6a03800 | 2020-10-14 18:50:07 +0200 | [diff] [blame] | 525 | _getEventPayload(): OpenFixPreviewEventDetail { |
Dmitrii Filippov | 3f3c205 | 2020-09-22 16:51:18 +0200 | [diff] [blame] | 526 | return {comment: this.comment, patchNum: this.patchNum}; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 527 | } |
| 528 | |
| 529 | _fireSave() { |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 530 | this.dispatchEvent( |
| 531 | new CustomEvent('comment-save', { |
| 532 | detail: this._getEventPayload(), |
| 533 | composed: true, |
| 534 | bubbles: true, |
| 535 | }) |
| 536 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 537 | } |
| 538 | |
| 539 | _fireUpdate() { |
| 540 | this.debounce('fire-update', () => { |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 541 | this.dispatchEvent( |
| 542 | new CustomEvent('comment-update', { |
| 543 | detail: this._getEventPayload(), |
| 544 | composed: true, |
| 545 | bubbles: true, |
| 546 | }) |
| 547 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 548 | }); |
| 549 | } |
| 550 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 551 | _computeAccountLabelClass(draft: boolean) { |
Dhruv Srivastava | cf70e79 | 2020-07-24 15:35:39 +0200 | [diff] [blame] | 552 | return draft ? 'draft' : ''; |
| 553 | } |
| 554 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 555 | _draftChanged(draft: boolean) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 556 | this.$.container.classList.toggle('draft', draft); |
| 557 | } |
| 558 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 559 | _editingChanged(editing?: boolean, previousValue?: boolean) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 560 | // Polymer 2: observer fires when at least one property is defined. |
| 561 | // Do nothing to prevent comment.__editing being overwritten |
| 562 | // if previousValue is undefined |
| 563 | if (previousValue === undefined) return; |
| 564 | |
| 565 | this.$.container.classList.toggle('editing', editing); |
| 566 | if (this.comment && this.comment.id) { |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 567 | const cancelButton = this.shadowRoot?.querySelector( |
| 568 | '.cancel' |
| 569 | ) as GrButton | null; |
Milutin Kristofic | c218df5 | 2020-05-15 21:55:08 +0200 | [diff] [blame] | 570 | if (cancelButton) { |
| 571 | cancelButton.hidden = !editing; |
| 572 | } |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 573 | } |
Dhruv Srivastava | 573ac7d | 2020-12-03 10:59:22 +0100 | [diff] [blame] | 574 | if (isDraft(this.comment)) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 575 | this.comment.__editing = this.editing; |
| 576 | } |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 577 | if (!!editing !== !!previousValue) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 578 | // To prevent event firing on comment creation. |
| 579 | this._fireUpdate(); |
| 580 | } |
| 581 | if (editing) { |
| 582 | this.async(() => { |
| 583 | flush(); |
| 584 | this.textarea && this.textarea.putCursorAtEnd(); |
| 585 | }, 1); |
| 586 | } |
| 587 | } |
| 588 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 589 | _computeDeleteButtonClass(isAdmin: boolean, draft: boolean) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 590 | return isAdmin && !draft ? 'showDeleteButtons' : ''; |
| 591 | } |
| 592 | |
Milutin Kristofic | a6af5aa | 2020-09-23 09:08:14 +0200 | [diff] [blame] | 593 | _computeSaveDisabled( |
| 594 | draft: string, |
Ben Rohlfs | 1d48706 | 2020-09-26 11:26:03 +0200 | [diff] [blame] | 595 | comment: UIComment | undefined, |
Milutin Kristofic | a6af5aa | 2020-09-23 09:08:14 +0200 | [diff] [blame] | 596 | resolved?: boolean |
| 597 | ) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 598 | // If resolved state has changed and a msg exists, save should be enabled. |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 599 | if (!comment || (comment.unresolved === resolved && draft)) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 600 | return false; |
| 601 | } |
| 602 | return !draft || draft.trim() === ''; |
| 603 | } |
| 604 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 605 | _handleSaveKey(e: Event) { |
| 606 | if ( |
| 607 | !this._computeSaveDisabled(this._messageText, this.comment, this.resolved) |
| 608 | ) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 609 | e.preventDefault(); |
| 610 | this._handleSave(e); |
| 611 | } |
| 612 | } |
| 613 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 614 | _handleEsc(e: Event) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 615 | if (!this._messageText.length) { |
| 616 | e.preventDefault(); |
| 617 | this._handleCancel(e); |
| 618 | } |
| 619 | } |
| 620 | |
| 621 | _handleToggleCollapsed() { |
| 622 | this.collapsed = !this.collapsed; |
| 623 | } |
| 624 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 625 | _toggleCollapseClass(collapsed: boolean) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 626 | if (collapsed) { |
| 627 | this.$.container.classList.add('collapsed'); |
| 628 | } else { |
| 629 | this.$.container.classList.remove('collapsed'); |
| 630 | } |
| 631 | } |
| 632 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 633 | @observe('comment.message') |
| 634 | _commentMessageChanged(message: string) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 635 | this._messageText = message || ''; |
| 636 | } |
| 637 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 638 | _messageTextChanged(_: string, oldValue: string) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 639 | if (!this.comment || (this.comment && this.comment.id)) { |
| 640 | return; |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame] | 641 | } |
Andrew Bonventre | 78792e8 | 2016-03-04 17:48:22 -0500 | [diff] [blame] | 642 | |
Milutin Kristofic | a6af5aa | 2020-09-23 09:08:14 +0200 | [diff] [blame] | 643 | const patchNum = this.comment.patch_set |
| 644 | ? this.comment.patch_set |
| 645 | : this._getPatchNum(); |
Milutin Kristofic | 87f402b | 2020-09-23 17:46:40 +0200 | [diff] [blame] | 646 | const {path, line, range} = this.comment; |
Dhruv Srivastava | dbddc1b | 2020-09-24 21:23:27 +0200 | [diff] [blame] | 647 | if (path) { |
Milutin Kristofic | 87f402b | 2020-09-23 17:46:40 +0200 | [diff] [blame] | 648 | this.debounce( |
| 649 | 'store', |
| 650 | () => { |
| 651 | const message = this._messageText; |
| 652 | if (this.changeNum === undefined) { |
| 653 | throw new Error('undefined changeNum'); |
| 654 | } |
| 655 | const commentLocation: StorageLocation = { |
| 656 | changeNum: this.changeNum, |
| 657 | patchNum, |
| 658 | path, |
| 659 | line, |
| 660 | range, |
| 661 | }; |
Becky Siegel | f3a9894 | 2016-12-01 10:55:14 -0800 | [diff] [blame] | 662 | |
Milutin Kristofic | 87f402b | 2020-09-23 17:46:40 +0200 | [diff] [blame] | 663 | if ((!message || !message.length) && oldValue) { |
| 664 | // If the draft has been modified to be empty, then erase the storage |
| 665 | // entry. |
| 666 | this.$.storage.eraseDraftComment(commentLocation); |
| 667 | } else { |
| 668 | this.$.storage.setDraftComment(commentLocation, message); |
| 669 | } |
| 670 | }, |
| 671 | STORAGE_DEBOUNCE_INTERVAL |
| 672 | ); |
| 673 | } |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 674 | } |
| 675 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 676 | _handleAnchorClick(e: Event) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 677 | e.preventDefault(); |
Dhruv Srivastava | dbddc1b | 2020-09-24 21:23:27 +0200 | [diff] [blame] | 678 | if (!this.comment) return; |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 679 | this.dispatchEvent( |
| 680 | new CustomEvent('comment-anchor-tap', { |
| 681 | bubbles: true, |
| 682 | composed: true, |
| 683 | detail: { |
| 684 | number: this.comment.line || FILE, |
| 685 | side: this.side, |
| 686 | }, |
| 687 | }) |
| 688 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 689 | } |
| 690 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 691 | _handleEdit(e: Event) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 692 | e.preventDefault(); |
Milutin Kristofic | 87f402b | 2020-09-23 17:46:40 +0200 | [diff] [blame] | 693 | if (this.comment?.message) this._messageText = this.comment.message; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 694 | this.editing = true; |
Milutin Kristofic | da88b33 | 2020-03-24 10:19:12 +0100 | [diff] [blame] | 695 | this.reporting.recordDraftInteraction(); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 696 | } |
| 697 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 698 | _handleSave(e: Event) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 699 | e.preventDefault(); |
| 700 | |
| 701 | // Ignore saves started while already saving. |
| 702 | if (this.disabled) { |
| 703 | return; |
| 704 | } |
Milutin Kristofic | a6af5aa | 2020-09-23 09:08:14 +0200 | [diff] [blame] | 705 | const timingLabel = this.comment?.id |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 706 | ? REPORT_UPDATE_DRAFT |
| 707 | : REPORT_CREATE_DRAFT; |
Milutin Kristofic | da88b33 | 2020-03-24 10:19:12 +0100 | [diff] [blame] | 708 | const timer = this.reporting.getTimer(timingLabel); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 709 | this.set('comment.__editing', false); |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 710 | return this.save().then(() => { |
| 711 | timer.end(); |
| 712 | }); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 713 | } |
| 714 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 715 | _handleCancel(e: Event) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 716 | e.preventDefault(); |
| 717 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 718 | if ( |
Milutin Kristofic | a6af5aa | 2020-09-23 09:08:14 +0200 | [diff] [blame] | 719 | !this.comment?.message || |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 720 | this.comment.message.trim().length === 0 || |
| 721 | !this.comment.id |
| 722 | ) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 723 | this._fireDiscard(); |
| 724 | return; |
| 725 | } |
| 726 | this._messageText = this.comment.message; |
| 727 | this.editing = false; |
| 728 | } |
| 729 | |
| 730 | _fireDiscard() { |
| 731 | this.cancelDebouncer('fire-update'); |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 732 | this.dispatchEvent( |
| 733 | new CustomEvent('comment-discard', { |
| 734 | detail: this._getEventPayload(), |
| 735 | composed: true, |
| 736 | bubbles: true, |
| 737 | }) |
| 738 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 739 | } |
| 740 | |
| 741 | _handleFix() { |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 742 | this.dispatchEvent( |
| 743 | new CustomEvent('create-fix-comment', { |
| 744 | bubbles: true, |
| 745 | composed: true, |
| 746 | detail: this._getEventPayload(), |
| 747 | }) |
| 748 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 749 | } |
| 750 | |
| 751 | _handleShowFix() { |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 752 | this.dispatchEvent( |
| 753 | new CustomEvent('open-fix-preview', { |
| 754 | bubbles: true, |
| 755 | composed: true, |
| 756 | detail: this._getEventPayload(), |
| 757 | }) |
| 758 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 759 | } |
| 760 | |
Ben Rohlfs | 1d48706 | 2020-09-26 11:26:03 +0200 | [diff] [blame] | 761 | _hasNoFix(comment: UIComment) { |
| 762 | return !comment || !(comment as UIRobot).fix_suggestions; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 763 | } |
| 764 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 765 | _handleDiscard(e: Event) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 766 | e.preventDefault(); |
Milutin Kristofic | da88b33 | 2020-03-24 10:19:12 +0100 | [diff] [blame] | 767 | this.reporting.recordDraftInteraction(); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 768 | |
| 769 | if (!this._messageText) { |
| 770 | this._discardDraft(); |
| 771 | return; |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame] | 772 | } |
Becky Siegel | 6bf4e4f | 2016-10-06 10:18:32 -0700 | [diff] [blame] | 773 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 774 | this._openOverlay(this.confirmDiscardOverlay).then(() => { |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 775 | const dialog = this.confirmDiscardOverlay?.querySelector( |
| 776 | '#confirmDiscardDialog' |
| 777 | ) as GrDialog | null; |
| 778 | if (dialog) dialog.resetFocus(); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 779 | }); |
| 780 | } |
| 781 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 782 | _handleConfirmDiscard(e: Event) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 783 | e.preventDefault(); |
Milutin Kristofic | da88b33 | 2020-03-24 10:19:12 +0100 | [diff] [blame] | 784 | const timer = this.reporting.getTimer(REPORT_DISCARD_DRAFT); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 785 | this._closeConfirmDiscardOverlay(); |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 786 | return this._discardDraft().then(() => { |
| 787 | timer.end(); |
| 788 | }); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 789 | } |
| 790 | |
| 791 | _discardDraft() { |
Milutin Kristofic | a6af5aa | 2020-09-23 09:08:14 +0200 | [diff] [blame] | 792 | if (!this.comment) return Promise.reject(new Error('undefined comment')); |
Ben Rohlfs | 1d48706 | 2020-09-26 11:26:03 +0200 | [diff] [blame] | 793 | if (!isDraft(this.comment)) { |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 794 | return Promise.reject(new Error('Cannot discard a non-draft comment.')); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 795 | } |
| 796 | this.discarding = true; |
| 797 | this.editing = false; |
| 798 | this.disabled = true; |
| 799 | this._eraseDraftComment(); |
| 800 | |
| 801 | if (!this.comment.id) { |
| 802 | this.disabled = false; |
| 803 | this._fireDiscard(); |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 804 | return Promise.resolve(); |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame] | 805 | } |
Andrew Bonventre | a12d3cd | 2016-05-23 19:03:11 -0400 | [diff] [blame] | 806 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 807 | this._xhrPromise = this._deleteDraft(this.comment) |
| 808 | .then(response => { |
| 809 | this.disabled = false; |
| 810 | if (!response.ok) { |
| 811 | this.discarding = false; |
| 812 | } |
Wyatt Allen | 7a4aa8c | 2016-05-18 12:37:53 -0700 | [diff] [blame] | 813 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 814 | this._fireDiscard(); |
| 815 | return response; |
| 816 | }) |
| 817 | .catch(err => { |
| 818 | this.disabled = false; |
| 819 | throw err; |
| 820 | }); |
Wyatt Allen | 035c74f | 2016-05-23 13:53:10 -0700 | [diff] [blame] | 821 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 822 | return this._xhrPromise; |
| 823 | } |
| 824 | |
| 825 | _closeConfirmDiscardOverlay() { |
| 826 | this._closeOverlay(this.confirmDiscardOverlay); |
| 827 | } |
| 828 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 829 | _getSavingMessage(numPending: number, requestFailed?: boolean) { |
Dhruv Srivastava | 8b015a6 | 2020-07-09 17:45:25 +0200 | [diff] [blame] | 830 | if (requestFailed) { |
| 831 | return UNSAVED_MESSAGE; |
| 832 | } |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 833 | if (numPending === 0) { |
| 834 | return SAVED_MESSAGE; |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame] | 835 | } |
Milutin Kristofic | 5b3f087 | 2020-12-05 22:08:09 +0100 | [diff] [blame] | 836 | return `Saving ${pluralize(numPending, 'draft')}...`; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 837 | } |
Wyatt Allen | 7a4aa8c | 2016-05-18 12:37:53 -0700 | [diff] [blame] | 838 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 839 | _showStartRequest() { |
| 840 | const numPending = ++this._numPendingDraftRequests.number; |
| 841 | this._updateRequestToast(numPending); |
| 842 | } |
| 843 | |
| 844 | _showEndRequest() { |
| 845 | const numPending = --this._numPendingDraftRequests.number; |
| 846 | this._updateRequestToast(numPending); |
| 847 | } |
| 848 | |
| 849 | _handleFailedDraftRequest() { |
| 850 | this._numPendingDraftRequests.number--; |
| 851 | |
| 852 | // Cancel the debouncer so that error toasts from the error-manager will |
| 853 | // not be overridden. |
| 854 | this.cancelDebouncer('draft-toast'); |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 855 | this._updateRequestToast( |
| 856 | this._numPendingDraftRequests.number, |
| 857 | /* requestFailed=*/ true |
| 858 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 859 | } |
| 860 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 861 | _updateRequestToast(numPending: number, requestFailed?: boolean) { |
Dhruv Srivastava | 8b015a6 | 2020-07-09 17:45:25 +0200 | [diff] [blame] | 862 | const message = this._getSavingMessage(numPending, requestFailed); |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 863 | this.debounce( |
| 864 | 'draft-toast', |
| 865 | () => { |
| 866 | // Note: the event is fired on the body rather than this element because |
| 867 | // this element may not be attached by the time this executes, in which |
| 868 | // case the event would not bubble. |
Milutin Kristofic | 860fe4d | 2020-11-23 16:13:45 +0100 | [diff] [blame] | 869 | fireAlert(document.body, message); |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 870 | }, |
| 871 | TOAST_DEBOUNCE_INTERVAL |
| 872 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 873 | } |
| 874 | |
Dhruv Srivastava | 4d38dba | 2020-08-28 11:29:24 +0200 | [diff] [blame] | 875 | _handleDraftFailure() { |
| 876 | this.$.container.classList.add('unableToSave'); |
| 877 | this._unableToSave = true; |
| 878 | this._handleFailedDraftRequest(); |
| 879 | } |
| 880 | |
Ben Rohlfs | 1d48706 | 2020-09-26 11:26:03 +0200 | [diff] [blame] | 881 | _saveDraft(draft?: UIComment) { |
Milutin Kristofic | a6af5aa | 2020-09-23 09:08:14 +0200 | [diff] [blame] | 882 | if (!draft || this.changeNum === undefined || this.patchNum === undefined) { |
| 883 | throw new Error('undefined draft or changeNum or patchNum'); |
| 884 | } |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 885 | this._showStartRequest(); |
Ben Rohlfs | 43935a4 | 2020-12-01 19:14:09 +0100 | [diff] [blame] | 886 | return this.restApiService |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 887 | .saveDiffDraft(this.changeNum, this.patchNum, draft) |
| 888 | .then(result => { |
| 889 | if (result.ok) { |
| 890 | // remove |
| 891 | this._unableToSave = false; |
| 892 | this.$.container.classList.remove('unableToSave'); |
| 893 | this._showEndRequest(); |
| 894 | } else { |
Dhruv Srivastava | 4d38dba | 2020-08-28 11:29:24 +0200 | [diff] [blame] | 895 | this._handleDraftFailure(); |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 896 | } |
| 897 | return result; |
| 898 | }) |
| 899 | .catch(err => { |
| 900 | this._handleDraftFailure(); |
| 901 | throw err; |
| 902 | }); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 903 | } |
| 904 | |
Ben Rohlfs | 1d48706 | 2020-09-26 11:26:03 +0200 | [diff] [blame] | 905 | _deleteDraft(draft: UIComment) { |
Milutin Kristofic | a6af5aa | 2020-09-23 09:08:14 +0200 | [diff] [blame] | 906 | if (this.changeNum === undefined || this.patchNum === undefined) { |
| 907 | throw new Error('undefined changeNum or patchNum'); |
| 908 | } |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 909 | this._showStartRequest(); |
Ben Rohlfs | 739b1d2 | 2020-09-21 12:26:31 +0200 | [diff] [blame] | 910 | if (!draft.id) throw new Error('Missing id in comment draft.'); |
Ben Rohlfs | 43935a4 | 2020-12-01 19:14:09 +0100 | [diff] [blame] | 911 | return this.restApiService |
Ben Rohlfs | 739b1d2 | 2020-09-21 12:26:31 +0200 | [diff] [blame] | 912 | .deleteDiffDraft(this.changeNum, this.patchNum, {id: draft.id}) |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 913 | .then(result => { |
| 914 | if (result.ok) { |
| 915 | this._showEndRequest(); |
| 916 | } else { |
| 917 | this._handleFailedDraftRequest(); |
| 918 | } |
| 919 | return result; |
| 920 | }); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 921 | } |
| 922 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 923 | _getPatchNum(): PatchSetNum { |
Milutin Kristofic | a6af5aa | 2020-09-23 09:08:14 +0200 | [diff] [blame] | 924 | const patchNum = this.isOnParent() |
| 925 | ? ('PARENT' as PatchSetNum) |
| 926 | : this.patchNum; |
| 927 | if (patchNum === undefined) throw new Error('patchNum undefined'); |
| 928 | return patchNum; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 929 | } |
| 930 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 931 | @observe('changeNum', 'patchNum', 'comment') |
| 932 | _loadLocalDraft( |
| 933 | changeNum: number, |
| 934 | patchNum?: PatchSetNum, |
Ben Rohlfs | 1d48706 | 2020-09-26 11:26:03 +0200 | [diff] [blame] | 935 | comment?: UIComment |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 936 | ) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 937 | // Polymer 2: check for undefined |
Dhruv Srivastava | 6894356 | 2020-06-26 12:46:44 +0200 | [diff] [blame] | 938 | if ([changeNum, patchNum, comment].includes(undefined)) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 939 | return; |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame] | 940 | } |
Andrew Bonventre | 78792e8 | 2016-03-04 17:48:22 -0500 | [diff] [blame] | 941 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 942 | // Only apply local drafts to comments that haven't been saved |
| 943 | // remotely, and haven't been given a default message already. |
Dhruv Srivastava | 2e9b695 | 2020-12-03 09:39:28 +0100 | [diff] [blame] | 944 | if (!comment || comment.id || comment.message || !comment.path) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 945 | return; |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame] | 946 | } |
Andrew Bonventre | 78792e8 | 2016-03-04 17:48:22 -0500 | [diff] [blame] | 947 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 948 | const draft = this.$.storage.getDraftComment({ |
| 949 | changeNum, |
| 950 | patchNum: this._getPatchNum(), |
| 951 | path: comment.path, |
| 952 | line: comment.line, |
| 953 | range: comment.range, |
| 954 | }); |
Wyatt Allen | fb3733c | 2017-10-24 16:34:10 -0700 | [diff] [blame] | 955 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 956 | if (draft) { |
| 957 | this.set('comment.message', draft.message); |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame] | 958 | } |
| 959 | } |
| 960 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 961 | _handleToggleResolved() { |
Milutin Kristofic | da88b33 | 2020-03-24 10:19:12 +0100 | [diff] [blame] | 962 | this.reporting.recordDraftInteraction(); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 963 | this.resolved = !this.resolved; |
| 964 | // Modify payload instead of this.comment, as this.comment is passed from |
| 965 | // the parent by ref. |
| 966 | const payload = this._getEventPayload(); |
Milutin Kristofic | a6af5aa | 2020-09-23 09:08:14 +0200 | [diff] [blame] | 967 | if (!payload.comment) { |
| 968 | throw new Error('comment not defined in payload'); |
| 969 | } |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 970 | payload.comment.unresolved = !this.$.resolvedCheckbox.checked; |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 971 | this.dispatchEvent( |
| 972 | new CustomEvent('comment-update', { |
| 973 | detail: payload, |
| 974 | composed: true, |
| 975 | bubbles: true, |
| 976 | }) |
| 977 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 978 | if (!this.editing) { |
| 979 | // Save the resolved state immediately. |
| 980 | this.save(payload.comment); |
| 981 | } |
| 982 | } |
| 983 | |
| 984 | _handleCommentDelete() { |
| 985 | this._openOverlay(this.confirmDeleteOverlay); |
| 986 | } |
| 987 | |
| 988 | _handleCancelDeleteComment() { |
| 989 | this._closeOverlay(this.confirmDeleteOverlay); |
| 990 | } |
| 991 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 992 | _openOverlay(overlay?: GrOverlay | null) { |
| 993 | if (!overlay) { |
| 994 | return Promise.reject(new Error('undefined overlay')); |
| 995 | } |
Tao Zhou | 93a4ed7 | 2020-08-21 09:52:02 +0200 | [diff] [blame] | 996 | getRootElement().appendChild(overlay); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 997 | return overlay.open(); |
| 998 | } |
| 999 | |
Ben Rohlfs | 1d48706 | 2020-09-26 11:26:03 +0200 | [diff] [blame] | 1000 | _computeHideRunDetails(comment: UIRobot, collapsed: boolean) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1001 | if (!comment) return true; |
| 1002 | return !(comment.robot_id && comment.url && !collapsed); |
| 1003 | } |
| 1004 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 1005 | _closeOverlay(overlay?: GrOverlay | null) { |
| 1006 | if (overlay) { |
| 1007 | getRootElement().removeChild(overlay); |
| 1008 | overlay.close(); |
| 1009 | } |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1010 | } |
| 1011 | |
| 1012 | _handleConfirmDeleteComment() { |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 1013 | const dialog = this.confirmDeleteOverlay?.querySelector( |
| 1014 | '#confirmDeleteComment' |
| 1015 | ) as GrConfirmDeleteCommentDialog | null; |
| 1016 | if (!dialog || !dialog.message) { |
| 1017 | throw new Error('missing confirm delete dialog'); |
| 1018 | } |
Milutin Kristofic | a6af5aa | 2020-09-23 09:08:14 +0200 | [diff] [blame] | 1019 | if ( |
| 1020 | !this.comment || |
Ben Rohlfs | 739b1d2 | 2020-09-21 12:26:31 +0200 | [diff] [blame] | 1021 | !this.comment.id || |
Milutin Kristofic | a6af5aa | 2020-09-23 09:08:14 +0200 | [diff] [blame] | 1022 | this.changeNum === undefined || |
| 1023 | this.patchNum === undefined |
| 1024 | ) { |
Ben Rohlfs | 739b1d2 | 2020-09-21 12:26:31 +0200 | [diff] [blame] | 1025 | throw new Error('undefined comment or id or changeNum or patchNum'); |
Milutin Kristofic | a6af5aa | 2020-09-23 09:08:14 +0200 | [diff] [blame] | 1026 | } |
Ben Rohlfs | 43935a4 | 2020-12-01 19:14:09 +0100 | [diff] [blame] | 1027 | this.restApiService |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 1028 | .deleteComment( |
| 1029 | this.changeNum, |
| 1030 | this.patchNum, |
| 1031 | this.comment.id, |
| 1032 | dialog.message |
| 1033 | ) |
| 1034 | .then(newComment => { |
| 1035 | this._handleCancelDeleteComment(); |
| 1036 | this.comment = newComment; |
| 1037 | }); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1038 | } |
| 1039 | } |
| 1040 | |
Milutin Kristofic | afae005 | 2020-09-17 10:38:08 +0200 | [diff] [blame] | 1041 | declare global { |
| 1042 | interface HTMLElementTagNameMap { |
| 1043 | 'gr-comment': GrComment; |
| 1044 | } |
| 1045 | } |