Dave Borowitz | 8cdc76b | 2018-03-26 10:04:27 -0400 | [diff] [blame] | 1 | /** |
| 2 | * @license |
| 3 | * Copyright (C) 2017 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 | */ |
Becky Siegel | 6db432f | 2017-08-25 09:17:42 -0700 | [diff] [blame] | 17 | (function() { |
| 18 | 'use strict'; |
| 19 | |
Becky Siegel | 9640eb2 | 2017-12-11 15:58:57 -0800 | [diff] [blame] | 20 | const Defs = {}; |
| 21 | |
Becky Siegel | 148c7b2 | 2018-01-16 15:01:58 -0800 | [diff] [blame] | 22 | const NOTHING_TO_SAVE = 'No changes to save.'; |
| 23 | |
brohlfs | 3e36426 | 2019-04-08 16:37:22 +0200 | [diff] [blame] | 24 | const MAX_AUTOCOMPLETE_RESULTS = 50; |
Becky Siegel | 8d7b627 | 2018-03-28 09:38:29 -0700 | [diff] [blame] | 25 | |
Becky Siegel | 148c7b2 | 2018-01-16 15:01:58 -0800 | [diff] [blame] | 26 | /** |
| 27 | * Fired when save is a no-op |
| 28 | * |
| 29 | * @event show-alert |
| 30 | */ |
| 31 | |
Becky Siegel | 9640eb2 | 2017-12-11 15:58:57 -0800 | [diff] [blame] | 32 | /** |
| 33 | * @typedef {{ |
| 34 | * value: !Object, |
| 35 | * }} |
| 36 | */ |
| 37 | Defs.rule; |
| 38 | |
| 39 | /** |
| 40 | * @typedef {{ |
| 41 | * rules: !Object<string, Defs.rule> |
| 42 | * }} |
| 43 | */ |
| 44 | Defs.permission; |
| 45 | |
| 46 | /** |
| 47 | * Can be an empty object or consist of permissions. |
| 48 | * |
| 49 | * @typedef {{ |
| 50 | * permissions: !Object<string, Defs.permission> |
| 51 | * }} |
| 52 | */ |
| 53 | Defs.permissions; |
| 54 | |
| 55 | /** |
| 56 | * Can be an empty object or consist of permissions. |
| 57 | * |
Becky Siegel | 148c7b2 | 2018-01-16 15:01:58 -0800 | [diff] [blame] | 58 | * @typedef {!Object<string, Defs.permissions>} |
Becky Siegel | 9640eb2 | 2017-12-11 15:58:57 -0800 | [diff] [blame] | 59 | */ |
| 60 | Defs.sections; |
| 61 | |
| 62 | /** |
| 63 | * @typedef {{ |
Becky Siegel | 148c7b2 | 2018-01-16 15:01:58 -0800 | [diff] [blame] | 64 | * remove: !Defs.sections, |
| 65 | * add: !Defs.sections, |
Becky Siegel | 9640eb2 | 2017-12-11 15:58:57 -0800 | [diff] [blame] | 66 | * }} |
| 67 | */ |
| 68 | Defs.projectAccessInput; |
| 69 | |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame^] | 70 | /** |
| 71 | * @appliesMixin Gerrit.AccessMixin |
| 72 | * @appliesMixin Gerrit.BaseUrlMixin |
| 73 | * @appliesMixin Gerrit.FireMixin |
| 74 | * @appliesMixin Gerrit.URLEncodingMixin |
| 75 | */ |
| 76 | class GrRepoAccess extends Polymer.mixinBehaviors( [ |
| 77 | Gerrit.AccessBehavior, |
| 78 | Gerrit.BaseUrlBehavior, |
| 79 | Gerrit.FireBehavior, |
| 80 | Gerrit.URLEncodingBehavior, |
| 81 | ], Polymer.GestureEventListeners( |
| 82 | Polymer.LegacyElementMixin( |
| 83 | Polymer.Element))) { |
| 84 | static get is() { return 'gr-repo-access'; } |
Becky Siegel | 6db432f | 2017-08-25 09:17:42 -0700 | [diff] [blame] | 85 | |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame^] | 86 | static get properties() { |
| 87 | return { |
| 88 | repo: { |
| 89 | type: String, |
| 90 | observer: '_repoChanged', |
Becky Siegel | 8d7b627 | 2018-03-28 09:38:29 -0700 | [diff] [blame] | 91 | }, |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame^] | 92 | // The current path |
| 93 | path: String, |
Becky Siegel | 6db432f | 2017-08-25 09:17:42 -0700 | [diff] [blame] | 94 | |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame^] | 95 | _canUpload: { |
| 96 | type: Boolean, |
| 97 | value: false, |
| 98 | }, |
| 99 | _inheritFromFilter: String, |
| 100 | _query: { |
| 101 | type: Function, |
| 102 | value() { |
| 103 | return this._getInheritFromSuggestions.bind(this); |
| 104 | }, |
| 105 | }, |
| 106 | _ownerOf: Array, |
| 107 | _capabilities: Object, |
| 108 | _groups: Object, |
| 109 | /** @type {?} */ |
| 110 | _inheritsFrom: Object, |
| 111 | _labels: Object, |
| 112 | _local: Object, |
| 113 | _editing: { |
| 114 | type: Boolean, |
| 115 | value: false, |
| 116 | observer: '_handleEditingChanged', |
| 117 | }, |
| 118 | _modified: { |
| 119 | type: Boolean, |
| 120 | value: false, |
| 121 | }, |
| 122 | _sections: Array, |
| 123 | _weblinks: Array, |
| 124 | _loading: { |
| 125 | type: Boolean, |
| 126 | value: true, |
| 127 | }, |
| 128 | }; |
| 129 | } |
Becky Siegel | 6db432f | 2017-08-25 09:17:42 -0700 | [diff] [blame] | 130 | |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame^] | 131 | created() { |
| 132 | super.created(); |
| 133 | this.addEventListener('access-modified', |
| 134 | () => |
| 135 | this._handleAccessModified()); |
| 136 | } |
Becky Siegel | 9640eb2 | 2017-12-11 15:58:57 -0800 | [diff] [blame] | 137 | |
Becky Siegel | 9640eb2 | 2017-12-11 15:58:57 -0800 | [diff] [blame] | 138 | _handleAccessModified() { |
| 139 | this._modified = true; |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame^] | 140 | } |
Becky Siegel | 9640eb2 | 2017-12-11 15:58:57 -0800 | [diff] [blame] | 141 | |
Becky Siegel | edd3f89 | 2017-08-31 10:52:20 -0700 | [diff] [blame] | 142 | /** |
Paladox none | 2bd5c21 | 2017-11-16 18:54:02 +0000 | [diff] [blame] | 143 | * @param {string} repo |
Becky Siegel | edd3f89 | 2017-08-31 10:52:20 -0700 | [diff] [blame] | 144 | * @return {!Promise} |
| 145 | */ |
Paladox none | 2bd5c21 | 2017-11-16 18:54:02 +0000 | [diff] [blame] | 146 | _repoChanged(repo) { |
Paladox none | 68511792 | 2018-03-17 20:05:21 +0000 | [diff] [blame] | 147 | this._loading = true; |
| 148 | |
Paladox none | 2bd5c21 | 2017-11-16 18:54:02 +0000 | [diff] [blame] | 149 | if (!repo) { return Promise.resolve(); } |
Paladox none | 70cb10c | 2018-02-17 19:12:09 +0000 | [diff] [blame] | 150 | |
Becky Siegel | 6af6325 | 2018-04-26 14:02:36 -0700 | [diff] [blame] | 151 | return this._reload(repo); |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame^] | 152 | } |
Becky Siegel | 6af6325 | 2018-04-26 14:02:36 -0700 | [diff] [blame] | 153 | |
| 154 | _reload(repo) { |
Becky Siegel | 6db432f | 2017-08-25 09:17:42 -0700 | [diff] [blame] | 155 | const promises = []; |
Paladox none | 70cb10c | 2018-02-17 19:12:09 +0000 | [diff] [blame] | 156 | |
| 157 | const errFn = response => { |
| 158 | this.fire('page-error', {response}); |
| 159 | }; |
| 160 | |
Becky Siegel | 6af6325 | 2018-04-26 14:02:36 -0700 | [diff] [blame] | 161 | this._editing = false; |
| 162 | |
Becky Siegel | 4d039c8 | 2017-11-07 10:56:55 -0800 | [diff] [blame] | 163 | // Always reset sections when a project changes. |
| 164 | this._sections = []; |
Paladox none | 70cb10c | 2018-02-17 19:12:09 +0000 | [diff] [blame] | 165 | promises.push(this.$.restAPI.getRepoAccessRights(repo, errFn) |
| 166 | .then(res => { |
| 167 | if (!res) { return Promise.resolve(); } |
Becky Siegel | 6db432f | 2017-08-25 09:17:42 -0700 | [diff] [blame] | 168 | |
Becky Siegel | 8d7b627 | 2018-03-28 09:38:29 -0700 | [diff] [blame] | 169 | // Keep a copy of the original inherit from values separate from |
| 170 | // the ones data bound to gr-autocomplete, so the original value |
| 171 | // can be restored if the user cancels. |
| 172 | this._inheritsFrom = res.inherits_from ? Object.assign({}, |
| 173 | res.inherits_from) : null; |
| 174 | this._originalInheritsFrom = res.inherits_from ? Object.assign({}, |
| 175 | res.inherits_from) : null; |
| 176 | // Initialize the filter value so when the user clicks edit, the |
| 177 | // current value appears. If there is no parent repo, it is |
| 178 | // initialized as an empty string. |
| 179 | this._inheritFromFilter = res.inherits_from ? |
Dmitrii Filippov | b82003c | 2019-11-05 17:02:59 +0100 | [diff] [blame] | 180 | this._inheritsFrom.name : ''; |
Paladox none | 70cb10c | 2018-02-17 19:12:09 +0000 | [diff] [blame] | 181 | this._local = res.local; |
| 182 | this._groups = res.groups; |
| 183 | this._weblinks = res.config_web_links || []; |
| 184 | this._canUpload = res.can_upload; |
Becky Siegel | e42689c | 2018-04-26 11:29:28 -0700 | [diff] [blame] | 185 | this._ownerOf = res.owner_of || []; |
Paladox none | 70cb10c | 2018-02-17 19:12:09 +0000 | [diff] [blame] | 186 | return this.toSortedArray(this._local); |
| 187 | })); |
Becky Siegel | 6db432f | 2017-08-25 09:17:42 -0700 | [diff] [blame] | 188 | |
Paladox none | 70cb10c | 2018-02-17 19:12:09 +0000 | [diff] [blame] | 189 | promises.push(this.$.restAPI.getCapabilities(errFn) |
| 190 | .then(res => { |
| 191 | if (!res) { return Promise.resolve(); } |
| 192 | |
| 193 | return res; |
| 194 | })); |
| 195 | |
| 196 | promises.push(this.$.restAPI.getRepo(repo, errFn) |
| 197 | .then(res => { |
| 198 | if (!res) { return Promise.resolve(); } |
| 199 | |
| 200 | return res.labels; |
| 201 | })); |
Becky Siegel | 6db432f | 2017-08-25 09:17:42 -0700 | [diff] [blame] | 202 | |
Becky Siegel | 4d039c8 | 2017-11-07 10:56:55 -0800 | [diff] [blame] | 203 | return Promise.all(promises).then(([sections, capabilities, labels]) => { |
| 204 | this._capabilities = capabilities; |
| 205 | this._labels = labels; |
| 206 | this._sections = sections; |
Paladox none | 3f3770e | 2018-03-11 22:36:08 +0000 | [diff] [blame] | 207 | this._loading = false; |
Becky Siegel | 6db432f | 2017-08-25 09:17:42 -0700 | [diff] [blame] | 208 | }); |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame^] | 209 | } |
Paladox none | 635ef52 | 2018-03-29 20:38:23 +0000 | [diff] [blame] | 210 | |
Becky Siegel | 8d7b627 | 2018-03-28 09:38:29 -0700 | [diff] [blame] | 211 | _handleUpdateInheritFrom(e) { |
Becky Siegel | 8d7b627 | 2018-03-28 09:38:29 -0700 | [diff] [blame] | 212 | if (!this._inheritsFrom) { |
| 213 | this._inheritsFrom = {}; |
| 214 | } |
Wyatt Allen | 292d013 | 2018-07-30 17:14:49 -0700 | [diff] [blame] | 215 | this._inheritsFrom.id = e.detail.value; |
Becky Siegel | 8d7b627 | 2018-03-28 09:38:29 -0700 | [diff] [blame] | 216 | this._inheritsFrom.name = this._inheritFromFilter; |
| 217 | this._handleAccessModified(); |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame^] | 218 | } |
Becky Siegel | 8d7b627 | 2018-03-28 09:38:29 -0700 | [diff] [blame] | 219 | |
| 220 | _getInheritFromSuggestions() { |
| 221 | return this.$.restAPI.getRepos( |
| 222 | this._inheritFromFilter, |
| 223 | MAX_AUTOCOMPLETE_RESULTS) |
| 224 | .then(response => { |
| 225 | const projects = []; |
| 226 | for (const key in response) { |
| 227 | if (!response.hasOwnProperty(key)) { continue; } |
| 228 | projects.push({ |
Patrick Hiesel | a26ca7f | 2018-08-28 11:42:41 +0200 | [diff] [blame] | 229 | name: response[key].name, |
Becky Siegel | 8d7b627 | 2018-03-28 09:38:29 -0700 | [diff] [blame] | 230 | value: response[key].id, |
| 231 | }); |
| 232 | } |
| 233 | return projects; |
| 234 | }); |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame^] | 235 | } |
Becky Siegel | 6db432f | 2017-08-25 09:17:42 -0700 | [diff] [blame] | 236 | |
Paladox none | 3f3770e | 2018-03-11 22:36:08 +0000 | [diff] [blame] | 237 | _computeLoadingClass(loading) { |
| 238 | return loading ? 'loading' : ''; |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame^] | 239 | } |
Paladox none | 3f3770e | 2018-03-11 22:36:08 +0000 | [diff] [blame] | 240 | |
Becky Siegel | 9640eb2 | 2017-12-11 15:58:57 -0800 | [diff] [blame] | 241 | _handleEdit() { |
| 242 | this._editing = !this._editing; |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame^] | 243 | } |
Becky Siegel | 9640eb2 | 2017-12-11 15:58:57 -0800 | [diff] [blame] | 244 | |
| 245 | _editOrCancel(editing) { |
| 246 | return editing ? 'Cancel' : 'Edit'; |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame^] | 247 | } |
Becky Siegel | 9640eb2 | 2017-12-11 15:58:57 -0800 | [diff] [blame] | 248 | |
Becky Siegel | bdb70cf | 2018-02-05 16:16:59 -0800 | [diff] [blame] | 249 | _computeWebLinkClass(weblinks) { |
Paladox none | ed2e227 | 2019-07-28 13:03:10 +0000 | [diff] [blame] | 250 | return weblinks && weblinks.length ? 'show' : ''; |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame^] | 251 | } |
Becky Siegel | bdb70cf | 2018-02-05 16:16:59 -0800 | [diff] [blame] | 252 | |
Paladox none | 635ef52 | 2018-03-29 20:38:23 +0000 | [diff] [blame] | 253 | _computeShowInherit(inheritsFrom) { |
Becky Siegel | 8d7b627 | 2018-03-28 09:38:29 -0700 | [diff] [blame] | 254 | return inheritsFrom ? 'show' : ''; |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame^] | 255 | } |
Becky Siegel | 8d7b627 | 2018-03-28 09:38:29 -0700 | [diff] [blame] | 256 | |
Becky Siegel | 7c57cf9 | 2018-04-23 14:44:32 -0700 | [diff] [blame] | 257 | _handleAddedSectionRemoved(e) { |
| 258 | const index = e.model.index; |
| 259 | this._sections = this._sections.slice(0, index) |
| 260 | .concat(this._sections.slice(index + 1, this._sections.length)); |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame^] | 261 | } |
Becky Siegel | 7c57cf9 | 2018-04-23 14:44:32 -0700 | [diff] [blame] | 262 | |
Becky Siegel | e6f68d9 | 2018-01-30 15:52:18 -0800 | [diff] [blame] | 263 | _handleEditingChanged(editing, editingOld) { |
| 264 | // Ignore when editing gets set initially. |
| 265 | if (!editingOld || editing) { return; } |
| 266 | // Remove any unsaved but added refs. |
Becky Siegel | 8d7b627 | 2018-03-28 09:38:29 -0700 | [diff] [blame] | 267 | if (this._sections) { |
| 268 | this._sections = this._sections.filter(p => !p.value.added); |
| 269 | } |
| 270 | // Restore inheritFrom. |
| 271 | if (this._inheritsFrom) { |
| 272 | this._inheritsFrom = Object.assign({}, this._originalInheritsFrom); |
| 273 | this._inheritFromFilter = this._inheritsFrom.name; |
| 274 | } |
Becky Siegel | e6f68d9 | 2018-01-30 15:52:18 -0800 | [diff] [blame] | 275 | for (const key of Object.keys(this._local)) { |
| 276 | if (this._local[key].added) { |
| 277 | delete this._local[key]; |
| 278 | } |
| 279 | } |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame^] | 280 | } |
Becky Siegel | e6f68d9 | 2018-01-30 15:52:18 -0800 | [diff] [blame] | 281 | |
Becky Siegel | 9640eb2 | 2017-12-11 15:58:57 -0800 | [diff] [blame] | 282 | /** |
Becky Siegel | 9640eb2 | 2017-12-11 15:58:57 -0800 | [diff] [blame] | 283 | * @param {!Defs.projectAccessInput} addRemoveObj |
Becky Siegel | a3ade7a | 2018-01-03 20:10:23 -0800 | [diff] [blame] | 284 | * @param {!Array} path |
| 285 | * @param {string} type add or remove |
| 286 | * @param {!Object=} opt_value value to add if the type is 'add' |
Becky Siegel | 9640eb2 | 2017-12-11 15:58:57 -0800 | [diff] [blame] | 287 | * @return {!Defs.projectAccessInput} |
| 288 | */ |
Becky Siegel | a3ade7a | 2018-01-03 20:10:23 -0800 | [diff] [blame] | 289 | _updateAddRemoveObj(addRemoveObj, path, type, opt_value) { |
| 290 | let curPos = addRemoveObj[type]; |
| 291 | for (const item of path) { |
| 292 | if (!curPos[item]) { |
| 293 | if (item === path[path.length - 1] && type === 'remove') { |
Becky Siegel | 0a3be39 | 2018-01-03 16:05:33 -0800 | [diff] [blame] | 294 | if (path[path.length - 2] === 'permissions') { |
| 295 | curPos[item] = {rules: {}}; |
Becky Siegel | 148c7b2 | 2018-01-16 15:01:58 -0800 | [diff] [blame] | 296 | } else if (path.length === 1) { |
| 297 | curPos[item] = {permissions: {}}; |
Becky Siegel | 0a3be39 | 2018-01-03 16:05:33 -0800 | [diff] [blame] | 298 | } else { |
Becky Siegel | 148c7b2 | 2018-01-16 15:01:58 -0800 | [diff] [blame] | 299 | curPos[item] = {}; |
Becky Siegel | 0a3be39 | 2018-01-03 16:05:33 -0800 | [diff] [blame] | 300 | } |
Becky Siegel | a3ade7a | 2018-01-03 20:10:23 -0800 | [diff] [blame] | 301 | } else if (item === path[path.length - 1] && type === 'add') { |
| 302 | curPos[item] = opt_value; |
| 303 | } else { |
| 304 | curPos[item] = {}; |
| 305 | } |
| 306 | } |
| 307 | curPos = curPos[item]; |
| 308 | } |
Becky Siegel | 9640eb2 | 2017-12-11 15:58:57 -0800 | [diff] [blame] | 309 | return addRemoveObj; |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame^] | 310 | } |
Becky Siegel | 9640eb2 | 2017-12-11 15:58:57 -0800 | [diff] [blame] | 311 | |
Becky Siegel | 148c7b2 | 2018-01-16 15:01:58 -0800 | [diff] [blame] | 312 | /** |
| 313 | * Used to recursively remove any objects with a 'deleted' bit. |
| 314 | */ |
| 315 | _recursivelyRemoveDeleted(obj) { |
| 316 | for (const k in obj) { |
Kasper Nilsson | 4244224 | 2018-04-04 13:52:26 -0700 | [diff] [blame] | 317 | if (!obj.hasOwnProperty(k)) { continue; } |
| 318 | |
Becky Siegel | 148c7b2 | 2018-01-16 15:01:58 -0800 | [diff] [blame] | 319 | if (typeof obj[k] == 'object') { |
| 320 | if (obj[k].deleted) { |
| 321 | delete obj[k]; |
| 322 | return; |
| 323 | } |
| 324 | this._recursivelyRemoveDeleted(obj[k]); |
| 325 | } |
| 326 | } |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame^] | 327 | } |
Becky Siegel | 148c7b2 | 2018-01-16 15:01:58 -0800 | [diff] [blame] | 328 | |
Becky Siegel | a3ade7a | 2018-01-03 20:10:23 -0800 | [diff] [blame] | 329 | _recursivelyUpdateAddRemoveObj(obj, addRemoveObj, path = []) { |
| 330 | for (const k in obj) { |
Kasper Nilsson | 4244224 | 2018-04-04 13:52:26 -0700 | [diff] [blame] | 331 | if (!obj.hasOwnProperty(k)) { continue; } |
Becky Siegel | a3ade7a | 2018-01-03 20:10:23 -0800 | [diff] [blame] | 332 | if (typeof obj[k] == 'object') { |
Becky Siegel | e6f68d9 | 2018-01-30 15:52:18 -0800 | [diff] [blame] | 333 | const updatedId = obj[k].updatedId; |
| 334 | const ref = updatedId ? updatedId : k; |
Becky Siegel | a3ade7a | 2018-01-03 20:10:23 -0800 | [diff] [blame] | 335 | if (obj[k].deleted) { |
| 336 | this._updateAddRemoveObj(addRemoveObj, |
| 337 | path.concat(k), 'remove'); |
| 338 | continue; |
| 339 | } else if (obj[k].modified) { |
| 340 | this._updateAddRemoveObj(addRemoveObj, |
| 341 | path.concat(k), 'remove'); |
Becky Siegel | 148c7b2 | 2018-01-16 15:01:58 -0800 | [diff] [blame] | 342 | this._updateAddRemoveObj(addRemoveObj, path.concat(ref), 'add', |
| 343 | obj[k]); |
| 344 | /* Special case for ref changes because they need to be added and |
| 345 | removed in a different way. The new ref needs to include all |
| 346 | changes but also the initial state. To do this, instead of |
| 347 | continuing with the same recursion, just remove anything that is |
| 348 | deleted in the current state. */ |
| 349 | if (updatedId && updatedId !== k) { |
| 350 | this._recursivelyRemoveDeleted(addRemoveObj.add[updatedId]); |
| 351 | } |
| 352 | continue; |
Becky Siegel | 86ff45c | 2018-01-04 16:41:49 -0800 | [diff] [blame] | 353 | } else if (obj[k].added) { |
| 354 | this._updateAddRemoveObj(addRemoveObj, |
Becky Siegel | e6f68d9 | 2018-01-30 15:52:18 -0800 | [diff] [blame] | 355 | path.concat(ref), 'add', obj[k]); |
Tao Zhou | 324adea | 2019-08-26 20:13:56 +0200 | [diff] [blame] | 356 | /** |
| 357 | * As add / delete both can happen in the new section, |
| 358 | * so here to make sure it will remove the deleted ones. |
| 359 | * @see Issue 11339 |
| 360 | */ |
| 361 | this._recursivelyRemoveDeleted(addRemoveObj.add[k]); |
Becky Siegel | 148c7b2 | 2018-01-16 15:01:58 -0800 | [diff] [blame] | 362 | continue; |
Becky Siegel | a3ade7a | 2018-01-03 20:10:23 -0800 | [diff] [blame] | 363 | } |
| 364 | this._recursivelyUpdateAddRemoveObj(obj[k], addRemoveObj, |
| 365 | path.concat(k)); |
| 366 | } |
| 367 | } |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame^] | 368 | } |
Becky Siegel | a3ade7a | 2018-01-03 20:10:23 -0800 | [diff] [blame] | 369 | |
Becky Siegel | 9640eb2 | 2017-12-11 15:58:57 -0800 | [diff] [blame] | 370 | /** |
| 371 | * Returns an object formatted for saving or submitting access changes for |
| 372 | * review |
| 373 | * |
| 374 | * @return {!Defs.projectAccessInput} |
| 375 | */ |
| 376 | _computeAddAndRemove() { |
Becky Siegel | a3ade7a | 2018-01-03 20:10:23 -0800 | [diff] [blame] | 377 | const addRemoveObj = { |
Becky Siegel | 9640eb2 | 2017-12-11 15:58:57 -0800 | [diff] [blame] | 378 | add: {}, |
| 379 | remove: {}, |
| 380 | }; |
Becky Siegel | 9640eb2 | 2017-12-11 15:58:57 -0800 | [diff] [blame] | 381 | |
Wyatt Allen | 292d013 | 2018-07-30 17:14:49 -0700 | [diff] [blame] | 382 | const originalInheritsFromId = this._originalInheritsFrom ? |
Dmitrii Filippov | b82003c | 2019-11-05 17:02:59 +0100 | [diff] [blame] | 383 | this.singleDecodeURL(this._originalInheritsFrom.id) : |
| 384 | null; |
Wyatt Allen | 292d013 | 2018-07-30 17:14:49 -0700 | [diff] [blame] | 385 | const inheritsFromId = this._inheritsFrom ? |
Dmitrii Filippov | b82003c | 2019-11-05 17:02:59 +0100 | [diff] [blame] | 386 | this.singleDecodeURL(this._inheritsFrom.id) : |
| 387 | null; |
Wyatt Allen | 292d013 | 2018-07-30 17:14:49 -0700 | [diff] [blame] | 388 | |
Becky Siegel | 8d7b627 | 2018-03-28 09:38:29 -0700 | [diff] [blame] | 389 | const inheritFromChanged = |
| 390 | // Inherit from changed |
Wyatt Allen | 292d013 | 2018-07-30 17:14:49 -0700 | [diff] [blame] | 391 | (originalInheritsFromId |
| 392 | && originalInheritsFromId !== inheritsFromId) || |
| 393 | // Inherit from added (did not have one initially); |
| 394 | (!originalInheritsFromId && inheritsFromId); |
Becky Siegel | 8d7b627 | 2018-03-28 09:38:29 -0700 | [diff] [blame] | 395 | |
Becky Siegel | a3ade7a | 2018-01-03 20:10:23 -0800 | [diff] [blame] | 396 | this._recursivelyUpdateAddRemoveObj(this._local, addRemoveObj); |
Becky Siegel | 8d7b627 | 2018-03-28 09:38:29 -0700 | [diff] [blame] | 397 | |
| 398 | if (inheritFromChanged) { |
Wyatt Allen | 292d013 | 2018-07-30 17:14:49 -0700 | [diff] [blame] | 399 | addRemoveObj.parent = inheritsFromId; |
Becky Siegel | 8d7b627 | 2018-03-28 09:38:29 -0700 | [diff] [blame] | 400 | } |
Becky Siegel | 9640eb2 | 2017-12-11 15:58:57 -0800 | [diff] [blame] | 401 | return addRemoveObj; |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame^] | 402 | } |
Becky Siegel | 9640eb2 | 2017-12-11 15:58:57 -0800 | [diff] [blame] | 403 | |
Becky Siegel | e6f68d9 | 2018-01-30 15:52:18 -0800 | [diff] [blame] | 404 | _handleCreateSection() { |
| 405 | let newRef = 'refs/for/*'; |
| 406 | // Avoid using an already used key for the placeholder, since it |
| 407 | // immediately gets added to an object. |
| 408 | while (this._local[newRef]) { |
| 409 | newRef = `${newRef}*`; |
| 410 | } |
| 411 | const section = {permissions: {}, added: true}; |
| 412 | this.push('_sections', {id: newRef, value: section}); |
| 413 | this.set(['_local', newRef], section); |
| 414 | Polymer.dom.flush(); |
| 415 | Polymer.dom(this.root).querySelector('gr-access-section:last-of-type') |
| 416 | .editReference(); |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame^] | 417 | } |
Becky Siegel | e6f68d9 | 2018-01-30 15:52:18 -0800 | [diff] [blame] | 418 | |
Becky Siegel | 6af6325 | 2018-04-26 14:02:36 -0700 | [diff] [blame] | 419 | _getObjforSave() { |
Becky Siegel | 9640eb2 | 2017-12-11 15:58:57 -0800 | [diff] [blame] | 420 | const addRemoveObj = this._computeAddAndRemove(); |
Becky Siegel | 148c7b2 | 2018-01-16 15:01:58 -0800 | [diff] [blame] | 421 | // If there are no changes, don't actually save. |
| 422 | if (!Object.keys(addRemoveObj.add).length && |
Becky Siegel | 8d7b627 | 2018-03-28 09:38:29 -0700 | [diff] [blame] | 423 | !Object.keys(addRemoveObj.remove).length && |
| 424 | !addRemoveObj.parent) { |
Ole Rehmsen | c82baba | 2019-05-16 14:43:01 +0200 | [diff] [blame] | 425 | this.dispatchEvent(new CustomEvent('show-alert', { |
| 426 | detail: {message: NOTHING_TO_SAVE}, |
| 427 | bubbles: true, |
| 428 | composed: true, |
| 429 | })); |
Becky Siegel | 148c7b2 | 2018-01-16 15:01:58 -0800 | [diff] [blame] | 430 | return; |
| 431 | } |
Becky Siegel | 8d7b627 | 2018-03-28 09:38:29 -0700 | [diff] [blame] | 432 | const obj = { |
Becky Siegel | 9640eb2 | 2017-12-11 15:58:57 -0800 | [diff] [blame] | 433 | add: addRemoveObj.add, |
| 434 | remove: addRemoveObj.remove, |
Becky Siegel | 8d7b627 | 2018-03-28 09:38:29 -0700 | [diff] [blame] | 435 | }; |
| 436 | if (addRemoveObj.parent) { |
| 437 | obj.parent = addRemoveObj.parent; |
| 438 | } |
Becky Siegel | 6af6325 | 2018-04-26 14:02:36 -0700 | [diff] [blame] | 439 | return obj; |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame^] | 440 | } |
Becky Siegel | 6af6325 | 2018-04-26 14:02:36 -0700 | [diff] [blame] | 441 | |
| 442 | _handleSave() { |
| 443 | const obj = this._getObjforSave(); |
| 444 | if (!obj) { return; } |
| 445 | return this.$.restAPI.setRepoAccessRights(this.repo, obj) |
| 446 | .then(() => { |
| 447 | this._reload(this.repo); |
| 448 | }); |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame^] | 449 | } |
Becky Siegel | 6af6325 | 2018-04-26 14:02:36 -0700 | [diff] [blame] | 450 | |
| 451 | _handleSaveForReview() { |
| 452 | const obj = this._getObjforSave(); |
| 453 | if (!obj) { return; } |
| 454 | return this.$.restAPI.setRepoAccessRightsForReview(this.repo, obj) |
Becky Siegel | 8d7b627 | 2018-03-28 09:38:29 -0700 | [diff] [blame] | 455 | .then(change => { |
| 456 | Gerrit.Nav.navigateToChange(change); |
| 457 | }); |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame^] | 458 | } |
Becky Siegel | 9640eb2 | 2017-12-11 15:58:57 -0800 | [diff] [blame] | 459 | |
Becky Siegel | 6af6325 | 2018-04-26 14:02:36 -0700 | [diff] [blame] | 460 | _computeSaveReviewBtnClass(canUpload) { |
| 461 | return !canUpload ? 'invisible' : ''; |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame^] | 462 | } |
Becky Siegel | 9640eb2 | 2017-12-11 15:58:57 -0800 | [diff] [blame] | 463 | |
Becky Siegel | 6af6325 | 2018-04-26 14:02:36 -0700 | [diff] [blame] | 464 | _computeSaveBtnClass(ownerOf) { |
Paladox none | ed2e227 | 2019-07-28 13:03:10 +0000 | [diff] [blame] | 465 | return ownerOf && ownerOf.length === 0 ? 'invisible' : ''; |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame^] | 466 | } |
Becky Siegel | 8d7b627 | 2018-03-28 09:38:29 -0700 | [diff] [blame] | 467 | |
Becky Siegel | e42689c | 2018-04-26 11:29:28 -0700 | [diff] [blame] | 468 | _computeMainClass(ownerOf, canUpload, editing) { |
Becky Siegel | 8d7b627 | 2018-03-28 09:38:29 -0700 | [diff] [blame] | 469 | const classList = []; |
Paladox none | ed2e227 | 2019-07-28 13:03:10 +0000 | [diff] [blame] | 470 | if (ownerOf && ownerOf.length > 0 || canUpload) { |
Becky Siegel | 8d7b627 | 2018-03-28 09:38:29 -0700 | [diff] [blame] | 471 | classList.push('admin'); |
| 472 | } |
| 473 | if (editing) { |
| 474 | classList.push('editing'); |
| 475 | } |
| 476 | return classList.join(' '); |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame^] | 477 | } |
Becky Siegel | 27bbf7a | 2017-09-30 10:14:16 +0100 | [diff] [blame] | 478 | |
Paladox none | 2bd5c21 | 2017-11-16 18:54:02 +0000 | [diff] [blame] | 479 | _computeParentHref(repoName) { |
Becky Siegel | 6db432f | 2017-08-25 09:17:42 -0700 | [diff] [blame] | 480 | return this.getBaseUrl() + |
Paladox none | 2bd5c21 | 2017-11-16 18:54:02 +0000 | [diff] [blame] | 481 | `/admin/repos/${this.encodeURL(repoName, true)},access`; |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame^] | 482 | } |
| 483 | } |
| 484 | |
| 485 | customElements.define(GrRepoAccess.is, GrRepoAccess); |
Paladox none | 3f3770e | 2018-03-11 22:36:08 +0000 | [diff] [blame] | 486 | })(); |