Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 1 | /** |
| 2 | * @license |
| 3 | * Copyright (C) 2020 The Android Open Source Project |
| 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 | */ |
| 17 | |
| 18 | import { |
Chris Poucet | 985e27a | 2022-11-28 14:08:10 +0100 | [diff] [blame] | 19 | AccountInfo, |
Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 20 | BasePatchSetNum, |
| 21 | RevisionPatchSetNum, |
| 22 | } from '@gerritcodereview/typescript-api/rest-api'; |
| 23 | import {css, html, LitElement, nothing, PropertyValues} from 'lit'; |
| 24 | import {customElement, property} from 'lit/decorators'; |
| 25 | import {OwnerStatus} from './code-owners-api'; |
Chris Poucet | 010ca99 | 2023-10-12 10:10:20 +0200 | [diff] [blame] | 26 | import {FileStatus, PluginState} from './code-owners-model'; |
Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 27 | import {CodeOwnersModelMixin} from './code-owners-model-mixin'; |
| 28 | |
| 29 | // TODO: Extend the API for plugins. |
| 30 | export interface PatchRange { |
| 31 | patchNum: RevisionPatchSetNum; |
| 32 | basePatchNum: BasePatchSetNum; |
| 33 | } |
| 34 | |
Kamil Musin | 8a9288f | 2023-08-24 14:15:29 +0200 | [diff] [blame] | 35 | const ACCOUNT_TEMPLATE_REGEX = '<GERRIT_ACCOUNT_(\\d+)>'; |
| 36 | |
Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 37 | const MAGIC_FILES = ['/COMMIT_MSG', '/MERGE_LIST', '/PATCHSET_LEVEL']; |
| 38 | const STATUS_CODE = { |
Chris Poucet | 1565aa6 | 2022-11-21 11:46:47 +0100 | [diff] [blame] | 39 | NO_STATUS: 'no-status', |
Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 40 | PENDING: 'pending', |
| 41 | PENDING_OLD_PATH: 'pending-old-path', |
| 42 | MISSING: 'missing', |
| 43 | MISSING_OLD_PATH: 'missing-old-path', |
| 44 | APPROVED: 'approved', |
Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 45 | }; |
| 46 | |
| 47 | const STATUS_PRIORITY_ORDER = [ |
Chris Poucet | 1565aa6 | 2022-11-21 11:46:47 +0100 | [diff] [blame] | 48 | STATUS_CODE.NO_STATUS, |
Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 49 | STATUS_CODE.MISSING, |
| 50 | STATUS_CODE.PENDING, |
| 51 | STATUS_CODE.MISSING_OLD_PATH, |
| 52 | STATUS_CODE.PENDING_OLD_PATH, |
| 53 | STATUS_CODE.APPROVED, |
| 54 | ]; |
| 55 | |
| 56 | const STATUS_ICON = { |
| 57 | [STATUS_CODE.PENDING]: 'schedule', |
| 58 | [STATUS_CODE.MISSING]: 'close', |
| 59 | [STATUS_CODE.PENDING_OLD_PATH]: 'schedule', |
Chris Poucet | f08b0a4 | 2022-09-09 17:28:05 +0200 | [diff] [blame] | 60 | [STATUS_CODE.MISSING_OLD_PATH]: 'close', |
Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 61 | [STATUS_CODE.APPROVED]: 'check', |
Chris Poucet | 1565aa6 | 2022-11-21 11:46:47 +0100 | [diff] [blame] | 62 | [STATUS_CODE.NO_STATUS]: 'check_circle', |
Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 63 | }; |
| 64 | |
Ben Rohlfs | 0bb3ca5 | 2022-10-28 22:01:59 +0200 | [diff] [blame] | 65 | const STATUS_SUMMARY = { |
| 66 | [STATUS_CODE.PENDING]: 'Pending', |
| 67 | [STATUS_CODE.MISSING]: 'Missing', |
| 68 | [STATUS_CODE.PENDING_OLD_PATH]: 'Pending Old Path', |
| 69 | [STATUS_CODE.MISSING_OLD_PATH]: 'Missing Old Path', |
| 70 | [STATUS_CODE.APPROVED]: 'Approved', |
Chris Poucet | 1565aa6 | 2022-11-21 11:46:47 +0100 | [diff] [blame] | 71 | [STATUS_CODE.NO_STATUS]: 'Does not need approval', |
Ben Rohlfs | 0bb3ca5 | 2022-10-28 22:01:59 +0200 | [diff] [blame] | 72 | }; |
| 73 | |
Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 74 | const STATUS_TOOLTIP = { |
| 75 | [STATUS_CODE.PENDING]: 'Pending code owner approval', |
| 76 | [STATUS_CODE.MISSING]: 'Missing code owner approval', |
| 77 | [STATUS_CODE.PENDING_OLD_PATH]: |
| 78 | 'Pending code owner approval on pre-renamed file', |
| 79 | [STATUS_CODE.MISSING_OLD_PATH]: |
| 80 | 'Missing code owner approval on pre-renamed file', |
| 81 | [STATUS_CODE.APPROVED]: 'Approved by code owner', |
Chris Poucet | 1565aa6 | 2022-11-21 11:46:47 +0100 | [diff] [blame] | 82 | [STATUS_CODE.NO_STATUS]: 'Does not need approval', |
Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 83 | }; |
| 84 | |
Chris Poucet | f08b0a4 | 2022-09-09 17:28:05 +0200 | [diff] [blame] | 85 | export function hasPath(ownedPaths: Set<string>, path: string | undefined) { |
| 86 | if (!path) return false; |
Chris Poucet | 985e27a | 2022-11-28 14:08:10 +0100 | [diff] [blame] | 87 | if (path.charAt(0) !== '/') path = '/' + path; |
| 88 | return ownedPaths.has(path); |
| 89 | } |
| 90 | |
| 91 | export function getOwners( |
| 92 | owners: Map<string, Array<AccountInfo>>, |
| 93 | path: string | undefined |
| 94 | ): Array<AccountInfo> { |
| 95 | if (!path) return []; |
| 96 | if (path.charAt(0) !== '/') path = '/' + path; |
| 97 | return owners.get(path) ?? []; |
Chris Poucet | f08b0a4 | 2022-09-09 17:28:05 +0200 | [diff] [blame] | 98 | } |
| 99 | |
Chris Poucet | 7579846 | 2022-12-12 11:43:38 +0100 | [diff] [blame] | 100 | export function uniqueAccountId( |
| 101 | account: AccountInfo, |
| 102 | index: number, |
| 103 | accountArray: AccountInfo[] |
| 104 | ) { |
| 105 | return ( |
| 106 | index === |
| 107 | accountArray.findIndex(other => account._account_id === other._account_id) |
| 108 | ); |
| 109 | } |
| 110 | |
Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 111 | const base = CodeOwnersModelMixin(LitElement); |
| 112 | |
| 113 | class BaseEl extends base { |
| 114 | @property({type: Object}) |
| 115 | patchRange?: PatchRange; |
| 116 | |
Chris Poucet | 25a6e41 | 2022-12-12 11:15:44 +0100 | [diff] [blame] | 117 | protected override willUpdate(changedProperties: PropertyValues): void { |
| 118 | super.willUpdate(changedProperties); |
| 119 | this.hidden = this.computeHidden(); |
| 120 | } |
| 121 | |
Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 122 | computeHidden() { |
| 123 | const newerPatchsetUploaded = this.status?.newerPatchsetUploaded; |
| 124 | if ( |
| 125 | this.change === undefined || |
| 126 | this.patchRange === undefined || |
| 127 | newerPatchsetUploaded === undefined |
| 128 | ) { |
| 129 | return true; |
| 130 | } |
Chris Poucet | 010ca99 | 2023-10-12 10:10:20 +0200 | [diff] [blame] | 131 | if (this.pluginStatus?.state !== PluginState.Enabled) return true; |
Chris Poucet | 25a6e41 | 2022-12-12 11:15:44 +0100 | [diff] [blame] | 132 | if (this.change.status === 'MERGED') return true; |
Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 133 | // if code-owners is not a submit requirement, don't show status column |
| 134 | if ( |
| 135 | this.change.requirements && |
| 136 | !this.change.requirements.find(r => r.type === 'code-owners') |
| 137 | ) { |
Chris Poucet | 1565aa6 | 2022-11-21 11:46:47 +0100 | [diff] [blame] | 138 | return false; |
Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 139 | } |
| 140 | |
| 141 | if (newerPatchsetUploaded) return true; |
| 142 | |
| 143 | const latestPatchset = |
| 144 | this.change.revisions![this.change.current_revision!]; |
| 145 | // Note: in some special cases, patchNum is undefined on latest patchset |
| 146 | // like after publishing the edit, still show for them |
| 147 | // TODO: this should be fixed in Gerrit |
| 148 | if (this.patchRange?.patchNum === undefined) return false; |
| 149 | // only show if its latest patchset |
| 150 | if (`${this.patchRange.patchNum}` !== `${latestPatchset._number}`) |
| 151 | return true; |
| 152 | return false; |
| 153 | } |
| 154 | } |
| 155 | |
| 156 | export const OWNERS_STATUS_COLUMN_HEADER = 'owner-status-column-header'; |
| 157 | /** |
| 158 | * Column header element for owner status. |
| 159 | */ |
| 160 | @customElement(OWNERS_STATUS_COLUMN_HEADER) |
| 161 | export class OwnerStatusColumnHeader extends BaseEl { |
| 162 | static override get styles() { |
| 163 | return [ |
| 164 | css` |
| 165 | :host() { |
| 166 | display: block; |
| 167 | padding-right: var(--spacing-m); |
Chris Poucet | 985e27a | 2022-11-28 14:08:10 +0100 | [diff] [blame] | 168 | width: 5em; |
Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 169 | } |
Chris Poucet | 25a6e41 | 2022-12-12 11:15:44 +0100 | [diff] [blame] | 170 | :host[hidden] { |
| 171 | display: none; |
| 172 | } |
Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 173 | `, |
| 174 | ]; |
| 175 | } |
| 176 | |
| 177 | override render() { |
| 178 | if (this.computeHidden()) return nothing; |
Chris Poucet | 2b4691e | 2022-11-25 14:43:10 +0100 | [diff] [blame] | 179 | return html`<div>Owners</div>`; |
Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 180 | } |
| 181 | } |
| 182 | |
| 183 | export const OWNER_STATUS_COLUMN_CONTENT = 'owner-status-column-content'; |
| 184 | /** |
| 185 | * Row content element for owner status. |
| 186 | */ |
| 187 | @customElement(OWNER_STATUS_COLUMN_CONTENT) |
| 188 | export class OwnerStatusColumnContent extends BaseEl { |
| 189 | @property({type: String}) |
| 190 | path?: string; |
| 191 | |
| 192 | @property({type: String}) |
| 193 | oldPath?: string; |
| 194 | |
| 195 | @property({type: Array}) |
| 196 | cleanlyMergedPaths?: Array<string>; |
| 197 | |
| 198 | @property({type: Array}) |
| 199 | cleanlyMergedOldPaths?: Array<string>; |
| 200 | |
| 201 | @property({type: String, reflect: true, attribute: 'owner-status'}) |
| 202 | ownerStatus?: string; |
| 203 | |
Kamil Musin | 8a9288f | 2023-08-24 14:15:29 +0200 | [diff] [blame] | 204 | @property({type: Array}) |
| 205 | ownerReasons?: Array<string>; |
| 206 | |
Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 207 | static override get styles() { |
| 208 | return [ |
| 209 | css` |
| 210 | :host { |
Chris Poucet | f08b0a4 | 2022-09-09 17:28:05 +0200 | [diff] [blame] | 211 | display: flex; |
Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 212 | padding-right: var(--spacing-m); |
Chris Poucet | 985e27a | 2022-11-28 14:08:10 +0100 | [diff] [blame] | 213 | width: 5em; |
Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 214 | text-align: center; |
| 215 | } |
Chris Poucet | 25a6e41 | 2022-12-12 11:15:44 +0100 | [diff] [blame] | 216 | :host[hidden] { |
| 217 | display: none; |
| 218 | } |
Chris Poucet | 013b0f0 | 2022-09-12 09:17:28 +0200 | [diff] [blame] | 219 | gr-icon { |
Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 220 | padding: var(--spacing-xs) 0px; |
| 221 | } |
Chris Poucet | f08b0a4 | 2022-09-09 17:28:05 +0200 | [diff] [blame] | 222 | :host([owner-status='approved']) gr-icon.status { |
Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 223 | color: var(--positive-green-text-color); |
| 224 | } |
Chris Poucet | f08b0a4 | 2022-09-09 17:28:05 +0200 | [diff] [blame] | 225 | :host([owner-status='pending']) gr-icon.status { |
Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 226 | color: #ffa62f; |
| 227 | } |
Chris Poucet | 1565aa6 | 2022-11-21 11:46:47 +0100 | [diff] [blame] | 228 | :host([owner-status='missing']) gr-icon.status { |
Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 229 | color: var(--negative-red-text-color); |
| 230 | } |
Chris Poucet | 985e27a | 2022-11-28 14:08:10 +0100 | [diff] [blame] | 231 | gr-avatar-stack { |
| 232 | padding: var(--spacing-xs) 0px; |
| 233 | display: flex; |
| 234 | --avatar-size: 20px; |
| 235 | } |
| 236 | .ellipsis { |
| 237 | /* These are required to get the ... to line up with the bottom of |
| 238 | the avatar icons. */ |
| 239 | margin-bottom: -2px; |
| 240 | display: flex; |
| 241 | align-items: flex-end; |
| 242 | } |
| 243 | .error { |
| 244 | color: var(--negative-red-text-color); |
| 245 | } |
Chris Poucet | 483a0c0 | 2022-12-06 13:53:02 +0100 | [diff] [blame] | 246 | .fallback-icon { |
| 247 | /* Undo the padding for the gr-avatar-stack in case of fallback */ |
| 248 | padding: calc(-1 * var(--spacing-xs)) 0px; |
| 249 | } |
Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 250 | `, |
| 251 | ]; |
| 252 | } |
| 253 | |
| 254 | protected override willUpdate(changedProperties: PropertyValues): void { |
| 255 | super.willUpdate(changedProperties); |
| 256 | this.computeStatus(); |
| 257 | } |
| 258 | |
Kamil Musin | 8a9288f | 2023-08-24 14:15:29 +0200 | [diff] [blame] | 259 | private renderReason(reason: string): string { |
| 260 | let reasonWithAccounts = reason.replace( |
| 261 | new RegExp(ACCOUNT_TEMPLATE_REGEX, 'g'), |
| 262 | (_accountIdTemplate, accountId) => { |
| 263 | const parsedAccountId = Number(accountId); |
| 264 | const accountInText = (this.status?.accounts || {})[parsedAccountId]; |
| 265 | if (!accountInText) { |
| 266 | return `Gerrit Account ${parsedAccountId}`; |
| 267 | } |
| 268 | return accountInText.display_name ?? accountInText.name ?? ''; |
| 269 | } |
| 270 | ); |
| 271 | return ( |
| 272 | reasonWithAccounts.charAt(0).toUpperCase() + reasonWithAccounts.slice(1) |
| 273 | ); |
| 274 | } |
| 275 | |
Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 276 | override render() { |
Chris Poucet | 985e27a | 2022-11-28 14:08:10 +0100 | [diff] [blame] | 277 | if ( |
| 278 | this.computeHidden() || |
| 279 | this.status === undefined || |
Kamil Musin | 8a9288f | 2023-08-24 14:15:29 +0200 | [diff] [blame] | 280 | !this.path || |
Chris Poucet | 43aacf1 | 2023-01-05 10:43:25 +0100 | [diff] [blame] | 281 | MAGIC_FILES.includes(this.path) |
Chris Poucet | 985e27a | 2022-11-28 14:08:10 +0100 | [diff] [blame] | 282 | ) |
| 283 | return nothing; |
Chris Poucet | f08b0a4 | 2022-09-09 17:28:05 +0200 | [diff] [blame] | 284 | return html`${this.renderStatus()}${this.renderOwnership()}`; |
| 285 | } |
Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 286 | |
Chris Poucet | f08b0a4 | 2022-09-09 17:28:05 +0200 | [diff] [blame] | 287 | private renderStatus() { |
Kamil Musin | 8a9288f | 2023-08-24 14:15:29 +0200 | [diff] [blame] | 288 | let info = STATUS_TOOLTIP[this.ownerStatus!]; |
| 289 | if (this.ownerReasons) { |
| 290 | info = this.ownerReasons.map(r => this.renderReason(r)).join('\n'); |
| 291 | } |
Ben Rohlfs | 0bb3ca5 | 2022-10-28 22:01:59 +0200 | [diff] [blame] | 292 | const summary = STATUS_SUMMARY[this.ownerStatus!]; |
| 293 | const icon = STATUS_ICON[this.ownerStatus!]; |
Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 294 | return html` |
Ben Rohlfs | 0bb3ca5 | 2022-10-28 22:01:59 +0200 | [diff] [blame] | 295 | <gr-tooltip-content |
| 296 | title=${info} |
| 297 | aria-label=${summary} |
| 298 | aria-description=${info} |
| 299 | has-tooltip |
| 300 | > |
| 301 | <gr-icon class="status" icon=${icon} aria-hidden="true"></gr-icon> |
Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 302 | </gr-tooltip-content> |
| 303 | `; |
| 304 | } |
| 305 | |
Chris Poucet | f08b0a4 | 2022-09-09 17:28:05 +0200 | [diff] [blame] | 306 | private renderOwnership() { |
Chris Poucet | 985e27a | 2022-11-28 14:08:10 +0100 | [diff] [blame] | 307 | if (this.isOwned()) { |
| 308 | return html` |
| 309 | <gr-tooltip-content |
| 310 | title="You are in OWNERS for this file" |
| 311 | aria-label="owned" |
| 312 | aria-description="You are an owner of this file" |
| 313 | has-tooltip |
| 314 | > |
| 315 | <gr-icon filled icon="policy" aria-hidden="true"></gr-icon> |
| 316 | </gr-tooltip-content> |
| 317 | `; |
| 318 | } else if (this.ownedPaths) { |
Chris Poucet | 7579846 | 2022-12-12 11:43:38 +0100 | [diff] [blame] | 319 | let oldOwners = getOwners(this.ownedPaths.oldPathOwners, this.oldPath); |
Chris Poucet | 985e27a | 2022-11-28 14:08:10 +0100 | [diff] [blame] | 320 | const newOwners = getOwners(this.ownedPaths.newPathOwners, this.path); |
Chris Poucet | 7579846 | 2022-12-12 11:43:38 +0100 | [diff] [blame] | 321 | if (this.oldPath === undefined || this.oldPath === null) { |
| 322 | // In case of a file deletion, the Gerrit FE gives 'path' but not 'oldPath' |
| 323 | // but code-owners considers a deleted file an oldpath so check the oldpath owners. |
| 324 | oldOwners = getOwners(this.ownedPaths.oldPathOwners, this.path); |
| 325 | } |
| 326 | const allOwners = oldOwners.concat(newOwners).filter(uniqueAccountId); |
Chris Poucet | 985e27a | 2022-11-28 14:08:10 +0100 | [diff] [blame] | 327 | |
| 328 | return html` <gr-avatar-stack |
| 329 | .accounts=${allOwners.slice(0, 3)} |
| 330 | .forceFetch=${true} |
Chris Poucet | 21078b5 | 2023-08-18 10:21:32 +0200 | [diff] [blame] | 331 | .enableHover=${true} |
Chris Poucet | 985e27a | 2022-11-28 14:08:10 +0100 | [diff] [blame] | 332 | > |
| 333 | <gr-tooltip-content |
| 334 | slot="fallback" |
| 335 | title="No reviewer owns this file" |
| 336 | aria-label="missing owner" |
| 337 | aria-description="No reviewer owns this file" |
| 338 | has-tooltip |
| 339 | > |
Chris Poucet | 483a0c0 | 2022-12-06 13:53:02 +0100 | [diff] [blame] | 340 | <gr-icon icon="help" class="error fallback-icon"></gr-icon> |
Chris Poucet | 985e27a | 2022-11-28 14:08:10 +0100 | [diff] [blame] | 341 | </gr-tooltip-content> |
| 342 | </gr-avatar-stack> |
| 343 | ${allOwners.length > 3 |
| 344 | ? html`<div class="ellipsis">…</div>` |
| 345 | : nothing}`; |
| 346 | } |
| 347 | return nothing; |
Chris Poucet | f08b0a4 | 2022-09-09 17:28:05 +0200 | [diff] [blame] | 348 | } |
| 349 | |
| 350 | private isOwned() { |
| 351 | if (!this.ownedPaths) return false; |
| 352 | if ( |
| 353 | hasPath(this.ownedPaths.newPaths, this.path) || |
Chris Poucet | 7579846 | 2022-12-12 11:43:38 +0100 | [diff] [blame] | 354 | hasPath(this.ownedPaths.oldPaths, this.oldPath) || |
| 355 | // In case of deletions, the FE gives a path, but code-owners |
| 356 | // computes this as being part of the old path. |
| 357 | ((this.oldPath === undefined || this.oldPath === null) && |
| 358 | hasPath(this.ownedPaths.oldPaths, this.path)) |
Chris Poucet | f08b0a4 | 2022-09-09 17:28:05 +0200 | [diff] [blame] | 359 | ) |
| 360 | return true; |
| 361 | return false; |
| 362 | } |
| 363 | |
Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 364 | override loadPropertiesAfterModelChanged() { |
| 365 | super.loadPropertiesAfterModelChanged(); |
| 366 | this.modelLoader?.loadStatus(); |
Chris Poucet | f08b0a4 | 2022-09-09 17:28:05 +0200 | [diff] [blame] | 367 | this.modelLoader?.loadOwnedPaths(); |
Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 368 | } |
| 369 | |
| 370 | private computeStatus() { |
| 371 | if ( |
| 372 | this.status === undefined || |
| 373 | (this.cleanlyMergedPaths === undefined && |
| 374 | (this.path === undefined || this.oldPath === undefined)) |
| 375 | ) { |
| 376 | return; |
| 377 | } |
| 378 | |
| 379 | const codeOwnerStatusMap = this.status.codeOwnerStatusMap; |
| 380 | const paths = |
| 381 | this.path === undefined ? this.cleanlyMergedPaths : [this.path]; |
| 382 | const oldPaths = |
| 383 | this.oldPath === undefined ? this.cleanlyMergedOldPaths : [this.oldPath]; |
| 384 | |
| 385 | const statuses = (paths ?? []) |
| 386 | .filter(path => !MAGIC_FILES.includes(path)) |
Kamil Musin | 8a9288f | 2023-08-24 14:15:29 +0200 | [diff] [blame] | 387 | .map(path => ({ |
Kamil Musin | 847bee6 | 2023-08-28 11:53:28 +0200 | [diff] [blame] | 388 | status: this.extractStatus(codeOwnerStatusMap.get(path), false), |
| 389 | reasons: codeOwnerStatusMap.get(path)?.reasons, |
Kamil Musin | 8a9288f | 2023-08-24 14:15:29 +0200 | [diff] [blame] | 390 | })); |
Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 391 | // oldPath may contain null, so filter that as well. |
| 392 | const oldStatuses = (oldPaths ?? []) |
| 393 | .filter(path => !MAGIC_FILES.includes(path) && !!path) |
Kamil Musin | 8a9288f | 2023-08-24 14:15:29 +0200 | [diff] [blame] | 394 | .map(path => ({ |
Kamil Musin | 847bee6 | 2023-08-28 11:53:28 +0200 | [diff] [blame] | 395 | status: this.extractStatus(codeOwnerStatusMap.get(path), true), |
| 396 | reasons: codeOwnerStatusMap.get(path)?.reasons, |
Kamil Musin | 8a9288f | 2023-08-24 14:15:29 +0200 | [diff] [blame] | 397 | })); |
Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 398 | const allStatuses = statuses.concat(oldStatuses); |
| 399 | if (allStatuses.length === 0) { |
| 400 | return; |
| 401 | } |
Kamil Musin | 8a9288f | 2023-08-24 14:15:29 +0200 | [diff] [blame] | 402 | const computedStatus = allStatuses.reduce((a, b) => |
| 403 | STATUS_PRIORITY_ORDER.indexOf(a.status) < |
| 404 | STATUS_PRIORITY_ORDER.indexOf(b.status) |
Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 405 | ? a |
| 406 | : b |
| 407 | ); |
Kamil Musin | 8a9288f | 2023-08-24 14:15:29 +0200 | [diff] [blame] | 408 | this.ownerStatus = computedStatus.status; |
| 409 | this.ownerReasons = computedStatus.reasons; |
Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 410 | } |
| 411 | |
Kamil Musin | 847bee6 | 2023-08-28 11:53:28 +0200 | [diff] [blame] | 412 | private extractStatus(statusItem: FileStatus | undefined, oldPath: boolean) { |
Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 413 | if (statusItem === undefined) { |
Chris Poucet | 1565aa6 | 2022-11-21 11:46:47 +0100 | [diff] [blame] | 414 | return STATUS_CODE.NO_STATUS; |
Chris Poucet | e5cc37b | 2022-08-23 16:27:36 +0200 | [diff] [blame] | 415 | } else if (statusItem.status === OwnerStatus.INSUFFICIENT_REVIEWERS) { |
| 416 | return oldPath ? STATUS_CODE.MISSING_OLD_PATH : STATUS_CODE.MISSING; |
| 417 | } else if (statusItem.status === OwnerStatus.PENDING) { |
| 418 | return oldPath ? STATUS_CODE.PENDING_OLD_PATH : STATUS_CODE.PENDING; |
| 419 | } else { |
| 420 | return STATUS_CODE.APPROVED; |
| 421 | } |
| 422 | } |
| 423 | } |