Dave Borowitz | 8cdc76b | 2018-03-26 10:04:27 -0400 | [diff] [blame] | 1 | /** |
| 2 | * @license |
Ben Rohlfs | 94fcbbc | 2022-05-27 10:45:03 +0200 | [diff] [blame] | 3 | * Copyright 2017 Google LLC |
| 4 | * SPDX-License-Identifier: Apache-2.0 |
Dave Borowitz | 8cdc76b | 2018-03-26 10:04:27 -0400 | [diff] [blame] | 5 | */ |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 6 | import '../gr-access-section/gr-access-section'; |
Ben Rohlfs | 678e19d | 2023-01-13 14:26:14 +0000 | [diff] [blame] | 7 | import {singleDecodeURL} from '../../../utils/url-util'; |
Ben Rohlfs | aa53390 | 2022-09-22 09:07:12 +0200 | [diff] [blame] | 8 | import {navigationToken} from '../../core/gr-navigation/gr-navigation'; |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 9 | import {toSortedPermissionsArray} from '../../../utils/access-util'; |
Dmitrii Filippov | e3c09ae | 2020-07-10 11:39:50 +0200 | [diff] [blame] | 10 | import { |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 11 | RepoName, |
| 12 | ProjectInfo, |
| 13 | CapabilityInfoMap, |
| 14 | LabelNameToLabelTypeInfoMap, |
| 15 | ProjectAccessInput, |
| 16 | GitRef, |
| 17 | UrlEncodedRepoName, |
Ben Rohlfs | bfc688b | 2022-10-21 12:38:37 +0200 | [diff] [blame] | 18 | RepoAccessGroups, |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 19 | } from '../../../types/common'; |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 20 | import {GrButton} from '../../shared/gr-button/gr-button'; |
| 21 | import {GrAccessSection} from '../gr-access-section/gr-access-section'; |
| 22 | import { |
| 23 | AutocompleteQuery, |
| 24 | AutocompleteSuggestion, |
| 25 | } from '../../shared/gr-autocomplete/gr-autocomplete'; |
| 26 | import { |
| 27 | EditableLocalAccessSectionInfo, |
| 28 | PermissionAccessSection, |
| 29 | PropertyTreeNode, |
| 30 | PrimitiveValue, |
| 31 | } from './gr-repo-access-interfaces'; |
Milutin Kristofic | 860fe4d | 2020-11-23 16:13:45 +0100 | [diff] [blame] | 32 | import {firePageError, fireAlert} from '../../../utils/event-util'; |
Chris Poucet | c6e880b | 2021-11-15 19:57:06 +0100 | [diff] [blame] | 33 | import {getAppContext} from '../../../services/app-context'; |
Dhruv Srivastava | d4880e3 | 2021-01-29 13:42:58 +0100 | [diff] [blame] | 34 | import {WebLinkInfo} from '../../../types/diff'; |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 35 | import {fontStyles} from '../../../styles/gr-font-styles'; |
| 36 | import {menuPageStyles} from '../../../styles/gr-menu-page-styles'; |
| 37 | import {subpageStyles} from '../../../styles/gr-subpage-styles'; |
| 38 | import {sharedStyles} from '../../../styles/shared-styles'; |
| 39 | import {LitElement, PropertyValues, css, html} from 'lit'; |
Frank Borden | 42c1a45 | 2022-08-11 16:27:20 +0200 | [diff] [blame] | 40 | import {customElement, property, query, state} from 'lit/decorators.js'; |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 41 | import {assertIsDefined} from '../../../utils/common-util'; |
Dhruv Srivastava | 25e53d8 | 2023-02-28 19:13:19 +0100 | [diff] [blame] | 42 | import { |
| 43 | AutocompleteCommitEvent, |
| 44 | ValueChangedEvent, |
| 45 | } from '../../../types/events'; |
Ben Rohlfs | aa53390 | 2022-09-22 09:07:12 +0200 | [diff] [blame] | 46 | import {resolve} from '../../../models/dependency'; |
| 47 | import {createChangeUrl} from '../../../models/views/change'; |
Kamil Musin | 12755c4 | 2022-11-29 17:11:43 +0100 | [diff] [blame] | 48 | import {throwingErrorCallback} from '../../shared/gr-rest-api-interface/gr-rest-apis/gr-rest-api-helper'; |
Ben Rohlfs | 678e19d | 2023-01-13 14:26:14 +0000 | [diff] [blame] | 49 | import {createRepoUrl, RepoDetailView} from '../../../models/views/repo'; |
Ben Rohlfs | 59ee7a2 | 2023-03-31 10:09:42 +0200 | [diff] [blame] | 50 | import '../../shared/gr-weblink/gr-weblink'; |
Becky Siegel | 148c7b2 | 2018-01-16 15:01:58 -0800 | [diff] [blame] | 51 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 52 | const NOTHING_TO_SAVE = 'No changes to save.'; |
Becky Siegel | 8d7b627 | 2018-03-28 09:38:29 -0700 | [diff] [blame] | 53 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 54 | const MAX_AUTOCOMPLETE_RESULTS = 50; |
Becky Siegel | 148c7b2 | 2018-01-16 15:01:58 -0800 | [diff] [blame] | 55 | |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 56 | declare global { |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 57 | interface HTMLElementTagNameMap { |
| 58 | 'gr-repo-access': GrRepoAccess; |
| 59 | } |
| 60 | } |
| 61 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 62 | /** |
| 63 | * Fired when save is a no-op |
| 64 | * |
| 65 | * @event show-alert |
| 66 | */ |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 67 | @customElement('gr-repo-access') |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 68 | export class GrRepoAccess extends LitElement { |
| 69 | @query('gr-access-section:last-of-type') accessSection?: GrAccessSection; |
Becky Siegel | 9640eb2 | 2017-12-11 15:58:57 -0800 | [diff] [blame] | 70 | |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 71 | @property({type: String}) |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 72 | repo?: RepoName; |
Becky Siegel | 9640eb2 | 2017-12-11 15:58:57 -0800 | [diff] [blame] | 73 | |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 74 | // private but used in test |
| 75 | @state() canUpload?: boolean = false; // restAPI can return undefined |
Becky Siegel | 9640eb2 | 2017-12-11 15:58:57 -0800 | [diff] [blame] | 76 | |
Dmitrii Filippov | 625fd7e | 2024-05-17 16:06:23 +0200 | [diff] [blame^] | 77 | @state() disableSaveWithoutReview = true; |
| 78 | |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 79 | // private but used in test |
| 80 | @state() inheritFromFilter?: RepoName; |
Becky Siegel | 9640eb2 | 2017-12-11 15:58:57 -0800 | [diff] [blame] | 81 | |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 82 | // private but used in test |
| 83 | @state() ownerOf?: GitRef[]; |
Becky Siegel | 6db432f | 2017-08-25 09:17:42 -0700 | [diff] [blame] | 84 | |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 85 | // private but used in test |
| 86 | @state() capabilities?: CapabilityInfoMap; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 87 | |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 88 | // private but used in test |
Ben Rohlfs | bfc688b | 2022-10-21 12:38:37 +0200 | [diff] [blame] | 89 | @state() groups?: RepoAccessGroups; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 90 | |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 91 | // private but used in test |
| 92 | @state() inheritsFrom?: ProjectInfo; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 93 | |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 94 | // private but used in test |
| 95 | @state() labels?: LabelNameToLabelTypeInfoMap; |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 96 | |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 97 | // private but used in test |
| 98 | @state() local?: EditableLocalAccessSectionInfo; |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 99 | |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 100 | // private but used in test |
| 101 | @state() editing = false; |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 102 | |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 103 | // private but used in test |
| 104 | @state() modified = false; |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 105 | |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 106 | // private but used in test |
| 107 | @state() sections?: PermissionAccessSection[]; |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 108 | |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 109 | @state() private weblinks?: WebLinkInfo[]; |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 110 | |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 111 | // private but used in test |
| 112 | @state() loading = true; |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 113 | |
Paladox none | eb72adf | 2021-11-23 16:14:51 +0000 | [diff] [blame] | 114 | // private but used in the tests |
| 115 | originalInheritsFrom?: ProjectInfo; |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 116 | |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 117 | private readonly query: AutocompleteQuery; |
| 118 | |
Chris Poucet | c6e880b | 2021-11-15 19:57:06 +0100 | [diff] [blame] | 119 | private readonly restApiService = getAppContext().restApiService; |
Ben Rohlfs | 43935a4 | 2020-12-01 19:14:09 +0100 | [diff] [blame] | 120 | |
Ben Rohlfs | aa53390 | 2022-09-22 09:07:12 +0200 | [diff] [blame] | 121 | private readonly getNavigation = resolve(this, navigationToken); |
| 122 | |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 123 | constructor() { |
| 124 | super(); |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 125 | this.query = () => this.getInheritFromSuggestions(); |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 126 | this.addEventListener('access-modified', () => |
| 127 | this._handleAccessModified() |
| 128 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 129 | } |
Becky Siegel | 6db432f | 2017-08-25 09:17:42 -0700 | [diff] [blame] | 130 | |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 131 | static override get styles() { |
| 132 | return [ |
| 133 | fontStyles, |
| 134 | menuPageStyles, |
| 135 | subpageStyles, |
| 136 | sharedStyles, |
| 137 | css` |
| 138 | gr-button, |
| 139 | #inheritsFrom, |
| 140 | #editInheritFromInput, |
| 141 | .editing #inheritFromName, |
| 142 | .weblinks, |
| 143 | .editing .invisible { |
| 144 | display: none; |
| 145 | } |
| 146 | #inheritsFrom.show { |
| 147 | display: flex; |
| 148 | min-height: 2em; |
| 149 | align-items: center; |
| 150 | } |
Ben Rohlfs | 59ee7a2 | 2023-03-31 10:09:42 +0200 | [diff] [blame] | 151 | gr-weblink { |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 152 | margin-right: var(--spacing-xs); |
| 153 | } |
| 154 | gr-access-section { |
| 155 | margin-top: var(--spacing-l); |
| 156 | } |
| 157 | .weblinks.show, |
| 158 | .referenceContainer { |
| 159 | display: block; |
| 160 | } |
| 161 | .rightsText { |
| 162 | margin-right: var(--spacing-s); |
| 163 | } |
| 164 | |
| 165 | .editing gr-button, |
| 166 | .admin #editBtn { |
| 167 | display: inline-block; |
| 168 | margin: var(--spacing-l) 0; |
| 169 | } |
| 170 | .editing #editInheritFromInput { |
| 171 | display: inline-block; |
| 172 | } |
| 173 | `, |
| 174 | ]; |
| 175 | } |
| 176 | |
| 177 | override render() { |
| 178 | return html` |
| 179 | <div class="main ${this.computeMainClass()}"> |
| 180 | <div id="loading" class=${this.loading ? 'loading' : ''}> |
| 181 | Loading... |
| 182 | </div> |
| 183 | <div id="loadedContent" class=${this.loading ? 'loading' : ''}> |
| 184 | <h3 |
| 185 | id="inheritsFrom" |
| 186 | class="heading-3 ${this.editing || this.inheritsFrom?.id?.length |
| 187 | ? 'show' |
| 188 | : ''}" |
| 189 | > |
| 190 | <span class="rightsText">Rights Inherit From</span> |
| 191 | <a |
| 192 | id="inheritFromName" |
| 193 | href=${this.computeParentHref()} |
| 194 | rel="noopener" |
| 195 | > |
| 196 | ${this.inheritsFrom?.name}</a |
| 197 | > |
| 198 | <gr-autocomplete |
| 199 | id="editInheritFromInput" |
| 200 | .text=${this.inheritFromFilter} |
| 201 | .query=${this.query} |
Dhruv Srivastava | 46db10c | 2023-02-17 18:37:37 +0100 | [diff] [blame] | 202 | @commit=${(e: AutocompleteCommitEvent) => { |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 203 | this.handleUpdateInheritFrom(e); |
| 204 | }} |
| 205 | @bind-value-changed=${(e: ValueChangedEvent) => { |
| 206 | this.handleUpdateInheritFrom(e); |
| 207 | }} |
| 208 | @text-changed=${(e: ValueChangedEvent) => { |
| 209 | this.handleEditInheritFromTextChanged(e); |
| 210 | }} |
| 211 | ></gr-autocomplete> |
| 212 | </h3> |
| 213 | <div class="weblinks ${this.weblinks?.length ? 'show' : ''}"> |
| 214 | History: |
Ben Rohlfs | 59ee7a2 | 2023-03-31 10:09:42 +0200 | [diff] [blame] | 215 | ${this.weblinks?.map( |
| 216 | info => html`<gr-weblink .info=${info}></gr-weblink>` |
| 217 | )} |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 218 | </div> |
| 219 | ${this.sections?.map((section, index) => |
| 220 | this.renderPermissionSections(section, index) |
| 221 | )} |
| 222 | <div class="referenceContainer"> |
| 223 | <gr-button |
| 224 | id="addReferenceBtn" |
| 225 | @click=${() => this.handleCreateSection()} |
| 226 | >Add Reference</gr-button |
| 227 | > |
| 228 | </div> |
| 229 | <div> |
| 230 | <gr-button |
| 231 | id="editBtn" |
| 232 | @click=${() => { |
| 233 | this.handleEdit(); |
| 234 | }} |
| 235 | >${this.editing ? 'Cancel' : 'Edit'}</gr-button |
| 236 | > |
| 237 | <gr-button |
| 238 | id="saveBtn" |
| 239 | class=${this.ownerOf && this.ownerOf.length === 0 |
| 240 | ? 'invisible' |
| 241 | : ''} |
| 242 | primary |
Dmitrii Filippov | 625fd7e | 2024-05-17 16:06:23 +0200 | [diff] [blame^] | 243 | ?disabled=${!this.modified || this.disableSaveWithoutReview} |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 244 | @click=${this.handleSave} |
| 245 | >Save</gr-button |
| 246 | > |
| 247 | <gr-button |
| 248 | id="saveReviewBtn" |
| 249 | class=${!this.canUpload ? 'invisible' : ''} |
| 250 | primary |
| 251 | ?disabled=${!this.modified} |
| 252 | @click=${this.handleSaveForReview} |
| 253 | >Save for review</gr-button |
| 254 | > |
| 255 | </div> |
| 256 | </div> |
| 257 | </div> |
| 258 | `; |
| 259 | } |
| 260 | |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 261 | private renderPermissionSections( |
| 262 | section: PermissionAccessSection, |
| 263 | index: number |
| 264 | ) { |
| 265 | return html` |
| 266 | <gr-access-section |
| 267 | .capabilities=${this.capabilities} |
| 268 | .section=${section} |
| 269 | .labels=${this.labels} |
| 270 | .canUpload=${this.canUpload} |
| 271 | .editing=${this.editing} |
| 272 | .ownerOf=${this.ownerOf} |
| 273 | .groups=${this.groups} |
| 274 | .repo=${this.repo} |
| 275 | @added-section-removed=${() => { |
| 276 | this.handleAddedSectionRemoved(index); |
| 277 | }} |
| 278 | @section-changed=${(e: ValueChangedEvent<PermissionAccessSection>) => { |
| 279 | this.handleAccessSectionChanged(e, index); |
| 280 | }} |
| 281 | ></gr-access-section> |
| 282 | `; |
| 283 | } |
| 284 | |
| 285 | override willUpdate(changedProperties: PropertyValues) { |
| 286 | if (changedProperties.has('repo')) { |
| 287 | this._repoChanged(this.repo); |
| 288 | } |
| 289 | |
| 290 | if (changedProperties.has('editing')) { |
| 291 | this.handleEditingChanged(changedProperties.get('editing') as boolean); |
| 292 | this.requestUpdate(); |
| 293 | } |
| 294 | } |
| 295 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 296 | _handleAccessModified() { |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 297 | this.modified = true; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 298 | } |
Becky Siegel | 9640eb2 | 2017-12-11 15:58:57 -0800 | [diff] [blame] | 299 | |
Paladox none | eb72adf | 2021-11-23 16:14:51 +0000 | [diff] [blame] | 300 | _repoChanged(repo?: RepoName) { |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 301 | this.loading = true; |
Becky Siegel | 9640eb2 | 2017-12-11 15:58:57 -0800 | [diff] [blame] | 302 | |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 303 | if (!repo) { |
| 304 | return Promise.resolve(); |
| 305 | } |
Paladox none | 68511792 | 2018-03-17 20:05:21 +0000 | [diff] [blame] | 306 | |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 307 | return this.reload(repo); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 308 | } |
Paladox none | 70cb10c | 2018-02-17 19:12:09 +0000 | [diff] [blame] | 309 | |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 310 | private reload(repo: RepoName) { |
Dhruv Srivastava | b0131f9 | 2020-11-24 09:31:54 +0100 | [diff] [blame] | 311 | const errFn = (response?: Response | null) => { |
Ben Rohlfs | a76c82f | 2021-01-22 22:22:32 +0100 | [diff] [blame] | 312 | firePageError(response); |
Dhruv Srivastava | b0131f9 | 2020-11-24 09:31:54 +0100 | [diff] [blame] | 313 | }; |
Paladox none | 70cb10c | 2018-02-17 19:12:09 +0000 | [diff] [blame] | 314 | |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 315 | this.editing = false; |
Paladox none | 70cb10c | 2018-02-17 19:12:09 +0000 | [diff] [blame] | 316 | |
Ben Rohlfs | bfc688b | 2022-10-21 12:38:37 +0200 | [diff] [blame] | 317 | // Always reset sections when a repo changes. |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 318 | this.sections = []; |
Ben Rohlfs | 43935a4 | 2020-12-01 19:14:09 +0100 | [diff] [blame] | 319 | const sectionsPromises = this.restApiService |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 320 | .getRepoAccessRights(repo, errFn) |
| 321 | .then(res => { |
| 322 | if (!res) { |
| 323 | return Promise.resolve(undefined); |
| 324 | } |
Becky Siegel | 6af6325 | 2018-04-26 14:02:36 -0700 | [diff] [blame] | 325 | |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 326 | // Keep a copy of the original inherit from values separate from |
| 327 | // the ones data bound to gr-autocomplete, so the original value |
| 328 | // can be restored if the user cancels. |
frankborden2@gmail.com | 4c610db | 2021-08-12 17:56:01 +0200 | [diff] [blame] | 329 | if (res.inherits_from) { |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 330 | this.inheritsFrom = {...res.inherits_from}; |
frankborden2@gmail.com | 4c610db | 2021-08-12 17:56:01 +0200 | [diff] [blame] | 331 | this.originalInheritsFrom = {...res.inherits_from}; |
| 332 | } else { |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 333 | this.inheritsFrom = undefined; |
frankborden2@gmail.com | 4c610db | 2021-08-12 17:56:01 +0200 | [diff] [blame] | 334 | this.originalInheritsFrom = undefined; |
| 335 | } |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 336 | // Initialize the filter value so when the user clicks edit, the |
| 337 | // current value appears. If there is no parent repo, it is |
| 338 | // initialized as an empty string. |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 339 | this.inheritFromFilter = res.inherits_from |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 340 | ? res.inherits_from.name |
| 341 | : ('' as RepoName); |
| 342 | // 'as EditableLocalAccessSectionInfo' is required because res.local |
| 343 | // type doesn't have index signature |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 344 | this.local = res.local as EditableLocalAccessSectionInfo; |
| 345 | this.groups = res.groups; |
| 346 | this.weblinks = res.config_web_links || []; |
| 347 | this.canUpload = res.can_upload; |
Dmitrii Filippov | 625fd7e | 2024-05-17 16:06:23 +0200 | [diff] [blame^] | 348 | this.disableSaveWithoutReview = !!res.require_change_for_config_update; |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 349 | this.ownerOf = res.owner_of || []; |
| 350 | return toSortedPermissionsArray(this.local); |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 351 | }); |
Becky Siegel | 6af6325 | 2018-04-26 14:02:36 -0700 | [diff] [blame] | 352 | |
Ben Rohlfs | 43935a4 | 2020-12-01 19:14:09 +0100 | [diff] [blame] | 353 | const capabilitiesPromises = this.restApiService |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 354 | .getCapabilities(errFn) |
| 355 | .then(res => { |
| 356 | if (!res) { |
| 357 | return Promise.resolve(undefined); |
| 358 | } |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 359 | |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 360 | return res; |
| 361 | }); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 362 | |
Ben Rohlfs | 43935a4 | 2020-12-01 19:14:09 +0100 | [diff] [blame] | 363 | const labelsPromises = this.restApiService |
| 364 | .getRepo(repo, errFn) |
| 365 | .then(res => { |
| 366 | if (!res) { |
| 367 | return Promise.resolve(undefined); |
| 368 | } |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 369 | |
Ben Rohlfs | 43935a4 | 2020-12-01 19:14:09 +0100 | [diff] [blame] | 370 | return res.labels; |
| 371 | }); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 372 | |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 373 | return Promise.all([ |
| 374 | sectionsPromises, |
| 375 | capabilitiesPromises, |
| 376 | labelsPromises, |
| 377 | ]).then(([sections, capabilities, labels]) => { |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 378 | this.capabilities = capabilities; |
| 379 | this.labels = labels; |
| 380 | this.sections = sections; |
| 381 | this.loading = false; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 382 | }); |
| 383 | } |
| 384 | |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 385 | // private but used in test |
Dhruv Srivastava | 46db10c | 2023-02-17 18:37:37 +0100 | [diff] [blame] | 386 | handleUpdateInheritFrom(e: AutocompleteCommitEvent) { |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 387 | this.inheritsFrom = { |
| 388 | ...(this.inheritsFrom ?? {}), |
Dhruv Srivastava | 7176818 | 2021-06-18 15:59:08 +0200 | [diff] [blame] | 389 | id: e.detail.value as UrlEncodedRepoName, |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 390 | name: this.inheritFromFilter, |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 391 | }; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 392 | this._handleAccessModified(); |
| 393 | } |
| 394 | |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 395 | private getInheritFromSuggestions(): Promise<AutocompleteSuggestion[]> { |
Ben Rohlfs | 43935a4 | 2020-12-01 19:14:09 +0100 | [diff] [blame] | 396 | return this.restApiService |
Kamil Musin | 12755c4 | 2022-11-29 17:11:43 +0100 | [diff] [blame] | 397 | .getRepos( |
| 398 | this.inheritFromFilter, |
| 399 | MAX_AUTOCOMPLETE_RESULTS, |
| 400 | /* offset=*/ undefined, |
| 401 | throwingErrorCallback |
| 402 | ) |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 403 | .then(response => { |
Ben Rohlfs | bfc688b | 2022-10-21 12:38:37 +0200 | [diff] [blame] | 404 | const repos: AutocompleteSuggestion[] = []; |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 405 | if (!response) { |
Ben Rohlfs | bfc688b | 2022-10-21 12:38:37 +0200 | [diff] [blame] | 406 | return repos; |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 407 | } |
| 408 | for (const item of response) { |
Ben Rohlfs | bfc688b | 2022-10-21 12:38:37 +0200 | [diff] [blame] | 409 | repos.push({ |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 410 | name: item.name, |
| 411 | value: item.id, |
| 412 | }); |
| 413 | } |
Ben Rohlfs | bfc688b | 2022-10-21 12:38:37 +0200 | [diff] [blame] | 414 | return repos; |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 415 | }); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 416 | } |
| 417 | |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 418 | private handleEdit() { |
| 419 | this.editing = !this.editing; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 420 | } |
| 421 | |
Dhruv Srivastava | 0d13395 | 2022-08-23 10:41:45 +0200 | [diff] [blame] | 422 | // private but used in tests |
| 423 | handleAddedSectionRemoved(index: number) { |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 424 | if (!this.sections) return; |
Dhruv Srivastava | 0d13395 | 2022-08-23 10:41:45 +0200 | [diff] [blame] | 425 | assertIsDefined(this.local, 'local'); |
| 426 | delete this.local[this.sections[index].id]; |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 427 | this.sections = this.sections |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 428 | .slice(0, index) |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 429 | .concat(this.sections.slice(index + 1, this.sections.length)); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 430 | } |
| 431 | |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 432 | private handleEditingChanged(editingOld: boolean) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 433 | // Ignore when editing gets set initially. |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 434 | if (!editingOld || this.editing) { |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 435 | return; |
| 436 | } |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 437 | // Remove any unsaved but added refs. |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 438 | if (this.sections) { |
| 439 | this.sections = this.sections.filter(p => !p.value.added); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 440 | } |
| 441 | // Restore inheritFrom. |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 442 | if (this.inheritsFrom) { |
| 443 | this.inheritsFrom = this.originalInheritsFrom |
Dmitrii Filippov | aab9825 | 2021-04-06 19:04:11 +0200 | [diff] [blame] | 444 | ? {...this.originalInheritsFrom} |
frankborden2@gmail.com | 4c610db | 2021-08-12 17:56:01 +0200 | [diff] [blame] | 445 | : undefined; |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 446 | this.inheritFromFilter = this.originalInheritsFrom?.name; |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 447 | } |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 448 | if (!this.local) { |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 449 | return; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 450 | } |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 451 | for (const key of Object.keys(this.local)) { |
| 452 | if (this.local[key].added) { |
| 453 | delete this.local[key]; |
Tao Zhou | 704cfe73 | 2020-03-12 08:32:46 +0100 | [diff] [blame] | 454 | } |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame] | 455 | } |
| 456 | } |
| 457 | |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 458 | private updateRemoveObj( |
| 459 | addRemoveObj: {remove: PropertyTreeNode}, |
| 460 | path: string[] |
| 461 | ) { |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 462 | let curPos: PropertyTreeNode = addRemoveObj.remove; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 463 | for (const item of path) { |
| 464 | if (!curPos[item]) { |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 465 | if (item === path[path.length - 1]) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 466 | if (path[path.length - 2] === 'permissions') { |
| 467 | curPos[item] = {rules: {}}; |
| 468 | } else if (path.length === 1) { |
| 469 | curPos[item] = {permissions: {}}; |
| 470 | } else { |
| 471 | curPos[item] = {}; |
| 472 | } |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 473 | } else { |
| 474 | curPos[item] = {}; |
| 475 | } |
| 476 | } |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 477 | // The last item can be a PrimitiveValue, but we don't use it |
| 478 | // All intermediate items are PropertyTreeNode |
| 479 | // TODO(TS): rewrite this loop and process the last item explicitly |
| 480 | curPos = curPos[item] as PropertyTreeNode; |
| 481 | } |
| 482 | return addRemoveObj; |
| 483 | } |
| 484 | |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 485 | private updateAddObj( |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 486 | addRemoveObj: {add: PropertyTreeNode}, |
| 487 | path: string[], |
| 488 | value: PropertyTreeNode | PrimitiveValue |
| 489 | ) { |
| 490 | let curPos: PropertyTreeNode = addRemoveObj.add; |
| 491 | for (const item of path) { |
| 492 | if (!curPos[item]) { |
| 493 | if (item === path[path.length - 1]) { |
| 494 | curPos[item] = value; |
| 495 | } else { |
| 496 | curPos[item] = {}; |
| 497 | } |
| 498 | } |
| 499 | // The last item can be a PrimitiveValue, but we don't use it |
| 500 | // All intermediate items are PropertyTreeNode |
| 501 | // TODO(TS): rewrite this loop and process the last item explicitly |
| 502 | curPos = curPos[item] as PropertyTreeNode; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 503 | } |
| 504 | return addRemoveObj; |
| 505 | } |
| 506 | |
| 507 | /** |
| 508 | * Used to recursively remove any objects with a 'deleted' bit. |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 509 | * |
| 510 | * private but used in test |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 511 | */ |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 512 | recursivelyRemoveDeleted(obj?: PropertyTreeNode) { |
Ben Rohlfs | 7b71b11 | 2021-02-12 10:36:08 +0100 | [diff] [blame] | 513 | if (!obj) return; |
| 514 | for (const k of Object.keys(obj)) { |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 515 | const node = obj[k]; |
| 516 | if (typeof node === 'object') { |
| 517 | if (node.deleted) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 518 | delete obj[k]; |
| 519 | return; |
| 520 | } |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 521 | this.recursivelyRemoveDeleted(node); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 522 | } |
| 523 | } |
| 524 | } |
| 525 | |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 526 | // private but used in test |
| 527 | recursivelyUpdateAddRemoveObj( |
Ben Rohlfs | 7b71b11 | 2021-02-12 10:36:08 +0100 | [diff] [blame] | 528 | obj: PropertyTreeNode | undefined, |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 529 | addRemoveObj: { |
| 530 | add: PropertyTreeNode; |
| 531 | remove: PropertyTreeNode; |
| 532 | }, |
| 533 | path: string[] = [] |
| 534 | ) { |
Ben Rohlfs | 7b71b11 | 2021-02-12 10:36:08 +0100 | [diff] [blame] | 535 | if (!obj) return; |
| 536 | for (const k of Object.keys(obj)) { |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 537 | const node = obj[k]; |
| 538 | if (typeof node === 'object') { |
| 539 | const updatedId = node.updatedId; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 540 | const ref = updatedId ? updatedId : k; |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 541 | if (node.deleted) { |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 542 | this.updateRemoveObj(addRemoveObj, path.concat(k)); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 543 | continue; |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 544 | } else if (node.modified) { |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 545 | this.updateRemoveObj(addRemoveObj, path.concat(k)); |
| 546 | this.updateAddObj(addRemoveObj, path.concat(ref), node); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 547 | /* Special case for ref changes because they need to be added and |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 548 | removed in a different way. The new ref needs to include all |
| 549 | changes but also the initial state. To do this, instead of |
| 550 | continuing with the same recursion, just remove anything that is |
| 551 | deleted in the current state. */ |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 552 | if (updatedId && updatedId !== k) { |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 553 | this.recursivelyRemoveDeleted( |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 554 | addRemoveObj.add[updatedId] as PropertyTreeNode |
| 555 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 556 | } |
| 557 | continue; |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 558 | } else if (node.added) { |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 559 | this.updateAddObj(addRemoveObj, path.concat(ref), node); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 560 | /** |
| 561 | * As add / delete both can happen in the new section, |
| 562 | * so here to make sure it will remove the deleted ones. |
| 563 | * |
| 564 | * @see Issue 11339 |
| 565 | */ |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 566 | this.recursivelyRemoveDeleted( |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 567 | addRemoveObj.add[k] as PropertyTreeNode |
| 568 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 569 | continue; |
| 570 | } |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 571 | this.recursivelyUpdateAddRemoveObj(node, addRemoveObj, path.concat(k)); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 572 | } |
| 573 | } |
| 574 | } |
| 575 | |
| 576 | /** |
| 577 | * Returns an object formatted for saving or submitting access changes for |
| 578 | * review |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 579 | * |
| 580 | * private but used in test |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 581 | */ |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 582 | computeAddAndRemove() { |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 583 | const addRemoveObj: { |
| 584 | add: PropertyTreeNode; |
| 585 | remove: PropertyTreeNode; |
| 586 | parent?: string | null; |
| 587 | } = { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 588 | add: {}, |
| 589 | remove: {}, |
| 590 | }; |
| 591 | |
Dhruv Srivastava | 7e454cd | 2021-02-22 15:06:58 +0100 | [diff] [blame] | 592 | const originalInheritsFromId = this.originalInheritsFrom |
| 593 | ? singleDecodeURL(this.originalInheritsFrom.id) |
frankborden2@gmail.com | 4c610db | 2021-08-12 17:56:01 +0200 | [diff] [blame] | 594 | : undefined; |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 595 | const inheritsFromId = this.inheritsFrom |
| 596 | ? singleDecodeURL(this.inheritsFrom.id) |
frankborden2@gmail.com | 4c610db | 2021-08-12 17:56:01 +0200 | [diff] [blame] | 597 | : undefined; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 598 | |
| 599 | const inheritFromChanged = |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 600 | // Inherit from changed |
| 601 | (originalInheritsFromId && originalInheritsFromId !== inheritsFromId) || |
| 602 | // Inherit from added (did not have one initially); |
| 603 | (!originalInheritsFromId && inheritsFromId); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 604 | |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 605 | if (!this.local) { |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 606 | return addRemoveObj; |
| 607 | } |
| 608 | |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 609 | this.recursivelyUpdateAddRemoveObj( |
| 610 | this.local as unknown as PropertyTreeNode, |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 611 | addRemoveObj |
| 612 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 613 | |
| 614 | if (inheritFromChanged) { |
| 615 | addRemoveObj.parent = inheritsFromId; |
| 616 | } |
| 617 | return addRemoveObj; |
| 618 | } |
| 619 | |
Ben Rohlfs | 53953e1 | 2022-05-04 11:35:46 +0200 | [diff] [blame] | 620 | private handleCreateSection() { |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 621 | if (!this.local) return; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 622 | let newRef = 'refs/for/*'; |
| 623 | // Avoid using an already used key for the placeholder, since it |
| 624 | // immediately gets added to an object. |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 625 | while (this.local[newRef]) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 626 | newRef = `${newRef}*`; |
| 627 | } |
| 628 | const section = {permissions: {}, added: true}; |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 629 | this.sections!.push({id: newRef as GitRef, value: section}); |
| 630 | this.local[newRef] = section; |
| 631 | this.requestUpdate(); |
| 632 | assertIsDefined(this.accessSection, 'accessSection'); |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 633 | // Template already instantiated at this point |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 634 | this.accessSection.editReference(); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 635 | } |
| 636 | |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 637 | private getObjforSave(): ProjectAccessInput | undefined { |
| 638 | const addRemoveObj = this.computeAddAndRemove(); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 639 | // If there are no changes, don't actually save. |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 640 | if ( |
| 641 | !Object.keys(addRemoveObj.add).length && |
| 642 | !Object.keys(addRemoveObj.remove).length && |
| 643 | !addRemoveObj.parent |
| 644 | ) { |
Milutin Kristofic | 860fe4d | 2020-11-23 16:13:45 +0100 | [diff] [blame] | 645 | fireAlert(this, NOTHING_TO_SAVE); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 646 | return; |
| 647 | } |
Chris Poucet | caeea1b | 2021-08-19 22:12:56 +0000 | [diff] [blame] | 648 | const obj: ProjectAccessInput = { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 649 | add: addRemoveObj.add, |
| 650 | remove: addRemoveObj.remove, |
Chris Poucet | caeea1b | 2021-08-19 22:12:56 +0000 | [diff] [blame] | 651 | } as unknown as ProjectAccessInput; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 652 | if (addRemoveObj.parent) { |
| 653 | obj.parent = addRemoveObj.parent; |
| 654 | } |
| 655 | return obj; |
| 656 | } |
| 657 | |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 658 | // private but used in test |
| 659 | handleSave(e: Event) { |
| 660 | const obj = this.getObjforSave(); |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 661 | if (!obj) { |
| 662 | return; |
| 663 | } |
| 664 | const button = e && (e.target as GrButton); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 665 | if (button) { |
| 666 | button.loading = true; |
| 667 | } |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 668 | const repo = this.repo; |
| 669 | if (!repo) { |
| 670 | return Promise.resolve(); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 671 | } |
Ben Rohlfs | 43935a4 | 2020-12-01 19:14:09 +0100 | [diff] [blame] | 672 | return this.restApiService |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 673 | .setRepoAccessRights(repo, obj) |
| 674 | .then(() => { |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 675 | this.reload(repo); |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 676 | }) |
| 677 | .finally(() => { |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 678 | this.modified = false; |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 679 | if (button) { |
| 680 | button.loading = false; |
| 681 | } |
| 682 | }); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 683 | } |
| 684 | |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 685 | // private but used in test |
| 686 | handleSaveForReview(e: Event) { |
| 687 | const obj = this.getObjforSave(); |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 688 | if (!obj) { |
| 689 | return; |
| 690 | } |
| 691 | const button = e && (e.target as GrButton); |
| 692 | if (button) { |
| 693 | button.loading = true; |
| 694 | } |
| 695 | if (!this.repo) { |
| 696 | return; |
| 697 | } |
Ben Rohlfs | 43935a4 | 2020-12-01 19:14:09 +0100 | [diff] [blame] | 698 | return this.restApiService |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 699 | .setRepoAccessRightsForReview(this.repo, obj) |
| 700 | .then(change => { |
Kamil Musin | 10c31de | 2024-02-08 16:49:38 +0100 | [diff] [blame] | 701 | // Don't navigate on server error. |
| 702 | if (change) { |
| 703 | this.getNavigation().setUrl(createChangeUrl({change})); |
| 704 | } |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 705 | }) |
| 706 | .finally(() => { |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 707 | this.modified = false; |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 708 | if (button) { |
| 709 | button.loading = false; |
| 710 | } |
| 711 | }); |
| 712 | } |
| 713 | |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 714 | // private but used in test |
| 715 | computeMainClass() { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 716 | const classList = []; |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 717 | if ((this.ownerOf && this.ownerOf.length > 0) || this.canUpload) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 718 | classList.push('admin'); |
| 719 | } |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 720 | if (this.editing) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 721 | classList.push('editing'); |
| 722 | } |
| 723 | return classList.join(' '); |
| 724 | } |
| 725 | |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 726 | computeParentHref() { |
| 727 | if (!this.inheritsFrom?.name) return ''; |
Ben Rohlfs | 678e19d | 2023-01-13 14:26:14 +0000 | [diff] [blame] | 728 | return createRepoUrl({ |
| 729 | repo: this.inheritsFrom.name, |
| 730 | detail: RepoDetailView.ACCESS, |
| 731 | }); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 732 | } |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 733 | |
Paladox none | a6c0589 | 2021-11-23 22:19:27 +0000 | [diff] [blame] | 734 | private handleEditInheritFromTextChanged(e: ValueChangedEvent) { |
| 735 | this.inheritFromFilter = e.detail.value as RepoName; |
| 736 | } |
| 737 | |
| 738 | private handleAccessSectionChanged( |
| 739 | e: ValueChangedEvent<PermissionAccessSection>, |
| 740 | index: number |
| 741 | ) { |
| 742 | this.sections![index] = e.detail.value; |
| 743 | this.requestUpdate(); |
Dmitrii Filippov | 460685c2 | 2020-08-21 11:12:49 +0200 | [diff] [blame] | 744 | } |
| 745 | } |