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