Dave Borowitz | 8cdc76b | 2018-03-26 10:04:27 -0400 | [diff] [blame] | 1 | /** |
| 2 | * @license |
| 3 | * Copyright (C) 2016 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 | */ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 17 | import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin'; |
| 18 | import {PolymerElement} from '@polymer/polymer/polymer-element'; |
| 19 | import { |
| 20 | page, |
| 21 | PageContext, |
| 22 | PageNextCallback, |
| 23 | } from '../../../utils/page-wrapper-utils'; |
| 24 | import {htmlTemplate} from './gr-router_html'; |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 25 | import { |
| 26 | DashboardSection, |
Ben Rohlfs | ebe4acc | 2020-12-11 21:16:10 +0100 | [diff] [blame] | 27 | GeneratedWebLink, |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 28 | GenerateUrlChangeViewParameters, |
| 29 | GenerateUrlDashboardViewParameters, |
| 30 | GenerateUrlDiffViewParameters, |
| 31 | GenerateUrlEditViewParameters, |
| 32 | GenerateUrlGroupViewParameters, |
| 33 | GenerateUrlParameters, |
| 34 | GenerateUrlRepoViewParameters, |
| 35 | GenerateUrlSearchViewParameters, |
| 36 | GenerateWebLinksChangeParameters, |
| 37 | GenerateWebLinksFileParameters, |
| 38 | GenerateWebLinksParameters, |
| 39 | GenerateWebLinksPatchsetParameters, |
Ben Rohlfs | ebe4acc | 2020-12-11 21:16:10 +0100 | [diff] [blame] | 40 | GerritNav, |
| 41 | GroupDetailView, |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 42 | isGenerateUrlDiffViewParameters, |
| 43 | RepoDetailView, |
| 44 | WeblinkType, |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 45 | } from '../gr-navigation/gr-navigation'; |
| 46 | import {appContext} from '../../../services/app-context'; |
Dhruv Srivastava | d1da458 | 2021-01-11 16:34:19 +0100 | [diff] [blame] | 47 | import {convertToPatchSetNum} from '../../../utils/patch-set-util'; |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 48 | import {customElement, property} from '@polymer/decorators'; |
| 49 | import {assertNever} from '../../../utils/common-util'; |
| 50 | import { |
Dhruv Srivastava | 591b490 | 2021-03-10 11:48:12 +0100 | [diff] [blame] | 51 | BasePatchSetNum, |
Dmitrii Filippov | 12f22a9 | 2020-10-12 16:16:30 +0200 | [diff] [blame] | 52 | DashboardId, |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 53 | GroupId, |
| 54 | NumericChangeId, |
| 55 | PatchSetNum, |
| 56 | RepoName, |
| 57 | ServerInfo, |
| 58 | UrlEncodedCommentId, |
| 59 | } from '../../../types/common'; |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 60 | import { |
| 61 | AppElement, |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 62 | AppElementAgreementParam, |
Ben Rohlfs | ebe4acc | 2020-12-11 21:16:10 +0100 | [diff] [blame] | 63 | AppElementParams, |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 64 | } from '../../gr-app-types'; |
Dmitrii Filippov | 6a03800 | 2020-10-14 18:50:07 +0200 | [diff] [blame] | 65 | import {LocationChangeEventDetail} from '../../../types/events'; |
Ben Rohlfs | ebe4acc | 2020-12-11 21:16:10 +0100 | [diff] [blame] | 66 | import {GerritView, updateState} from '../../../services/router/router-model'; |
Ben Rohlfs | a76c82f | 2021-01-22 22:22:32 +0100 | [diff] [blame] | 67 | import {firePageError} from '../../../utils/event-util'; |
Milutin Kristofic | dfb781d | 2021-01-29 13:24:43 +0100 | [diff] [blame] | 68 | import {addQuotesWhen} from '../../../utils/string-util'; |
Ben Rohlfs | 5ae40eb | 2021-02-11 20:16:22 +0100 | [diff] [blame] | 69 | import {windowLocationReload} from '../../../utils/dom-util'; |
Milutin Kristofic | e366b93 | 2021-03-10 17:09:52 +0100 | [diff] [blame] | 70 | import { |
| 71 | encodeURL, |
| 72 | getBaseUrl, |
| 73 | toPath, |
| 74 | toPathname, |
| 75 | toSearchParams, |
| 76 | } from '../../../utils/url-util'; |
Ben Rohlfs | 6fb09dd | 2021-03-12 09:24:26 +0100 | [diff] [blame^] | 77 | import {Execution, LifeCycle} from '../../../constants/reporting'; |
Wyatt Allen | ee2016c | 2017-10-31 13:41:52 -0700 | [diff] [blame] | 78 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 79 | const RoutePattern = { |
| 80 | ROOT: '/', |
Wyatt Allen | ee2016c | 2017-10-31 13:41:52 -0700 | [diff] [blame] | 81 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 82 | DASHBOARD: /^\/dashboard\/(.+)$/, |
| 83 | CUSTOM_DASHBOARD: /^\/dashboard\/?$/, |
| 84 | PROJECT_DASHBOARD: /^\/p\/(.+)\/\+\/dashboard\/(.+)/, |
Jacek Centkowski | d322bd4 | 2020-09-16 10:34:55 +0200 | [diff] [blame] | 85 | LEGACY_PROJECT_DASHBOARD: /^\/projects\/(.+),dashboards\/(.+)/, |
Wyatt Allen | 089dfb3 | 2017-08-24 17:55:38 -0700 | [diff] [blame] | 86 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 87 | AGREEMENTS: /^\/settings\/agreements\/?/, |
| 88 | NEW_AGREEMENTS: /^\/settings\/new-agreement\/?/, |
| 89 | REGISTER: /^\/register(\/.*)?$/, |
Wyatt Allen | 6376e7a | 2017-08-31 10:11:59 -0700 | [diff] [blame] | 90 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 91 | // Pattern for login and logout URLs intended to be passed-through. May |
| 92 | // include a return URL. |
| 93 | LOG_IN_OR_OUT: /\/log(in|out)(\/(.+))?$/, |
Wyatt Allen | f197138 | 2017-08-29 13:22:15 -0700 | [diff] [blame] | 94 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 95 | // Pattern for a catchall route when no other pattern is matched. |
| 96 | DEFAULT: /.*/, |
Wyatt Allen | 089dfb3 | 2017-08-24 17:55:38 -0700 | [diff] [blame] | 97 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 98 | // Matches /admin/groups/[uuid-]<group> |
| 99 | GROUP: /^\/admin\/groups\/(?:uuid-)?([^,]+)$/, |
Paladox none | f7303f7 | 2019-06-27 14:57:11 +0000 | [diff] [blame] | 100 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 101 | // Redirects /groups/self to /settings/#Groups for GWT compatibility |
| 102 | GROUP_SELF: /^\/groups\/self/, |
Wyatt Allen | 089dfb3 | 2017-08-24 17:55:38 -0700 | [diff] [blame] | 103 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 104 | // Matches /admin/groups/[uuid-]<group>,info (backwords compat with gwtui) |
| 105 | // Redirects to /admin/groups/[uuid-]<group> |
| 106 | GROUP_INFO: /^\/admin\/groups\/(?:uuid-)?(.+),info$/, |
Wyatt Allen | 089dfb3 | 2017-08-24 17:55:38 -0700 | [diff] [blame] | 107 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 108 | // Matches /admin/groups/<group>,audit-log |
| 109 | GROUP_AUDIT_LOG: /^\/admin\/groups\/(?:uuid-)?(.+),audit-log$/, |
Wyatt Allen | 089dfb3 | 2017-08-24 17:55:38 -0700 | [diff] [blame] | 110 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 111 | // Matches /admin/groups/[uuid-]<group>,members |
| 112 | GROUP_MEMBERS: /^\/admin\/groups\/(?:uuid-)?(.+),members$/, |
Wyatt Allen | 089dfb3 | 2017-08-24 17:55:38 -0700 | [diff] [blame] | 113 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 114 | // Matches /admin/groups[,<offset>][/]. |
| 115 | GROUP_LIST_OFFSET: /^\/admin\/groups(,(\d+))?(\/)?$/, |
| 116 | GROUP_LIST_FILTER: '/admin/groups/q/filter::filter', |
| 117 | GROUP_LIST_FILTER_OFFSET: '/admin/groups/q/filter::filter,:offset', |
Becky Siegel | 28d1bf6 | 2017-09-01 12:07:09 -0700 | [diff] [blame] | 118 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 119 | // Matches /admin/create-project |
| 120 | LEGACY_CREATE_PROJECT: /^\/admin\/create-project\/?$/, |
Becky Siegel | 28d1bf6 | 2017-09-01 12:07:09 -0700 | [diff] [blame] | 121 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 122 | // Matches /admin/create-project |
| 123 | LEGACY_CREATE_GROUP: /^\/admin\/create-group\/?$/, |
Wyatt Allen | 089dfb3 | 2017-08-24 17:55:38 -0700 | [diff] [blame] | 124 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 125 | PROJECT_OLD: /^\/admin\/(projects)\/?(.+)?$/, |
Wyatt Allen | 089dfb3 | 2017-08-24 17:55:38 -0700 | [diff] [blame] | 126 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 127 | // Matches /admin/repos/<repo> |
| 128 | REPO: /^\/admin\/repos\/([^,]+)$/, |
Becky Siegel | 6db432f | 2017-08-25 09:17:42 -0700 | [diff] [blame] | 129 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 130 | // Matches /admin/repos/<repo>,commands. |
| 131 | REPO_COMMANDS: /^\/admin\/repos\/(.+),commands$/, |
Wyatt Allen | 089dfb3 | 2017-08-24 17:55:38 -0700 | [diff] [blame] | 132 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 133 | // Matches /admin/repos/<repos>,access. |
| 134 | REPO_ACCESS: /^\/admin\/repos\/(.+),access$/, |
Becky Siegel | c588ab7 | 2018-01-16 17:43:10 -0800 | [diff] [blame] | 135 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 136 | // Matches /admin/repos/<repos>,access. |
| 137 | REPO_DASHBOARDS: /^\/admin\/repos\/(.+),dashboards$/, |
Paladox none | 2bd5c21 | 2017-11-16 18:54:02 +0000 | [diff] [blame] | 138 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 139 | // Matches /admin/repos[,<offset>][/]. |
| 140 | REPO_LIST_OFFSET: /^\/admin\/repos(,(\d+))?(\/)?$/, |
| 141 | REPO_LIST_FILTER: '/admin/repos/q/filter::filter', |
| 142 | REPO_LIST_FILTER_OFFSET: '/admin/repos/q/filter::filter,:offset', |
Wyatt Allen | 089dfb3 | 2017-08-24 17:55:38 -0700 | [diff] [blame] | 143 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 144 | // Matches /admin/repos/<repo>,branches[,<offset>]. |
| 145 | BRANCH_LIST_OFFSET: /^\/admin\/repos\/(.+),branches(,(.+))?$/, |
| 146 | BRANCH_LIST_FILTER: '/admin/repos/:repo,branches/q/filter::filter', |
| 147 | BRANCH_LIST_FILTER_OFFSET: |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 148 | '/admin/repos/:repo,branches/q/filter::filter,:offset', |
Wyatt Allen | 089dfb3 | 2017-08-24 17:55:38 -0700 | [diff] [blame] | 149 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 150 | // Matches /admin/repos/<repo>,tags[,<offset>]. |
| 151 | TAG_LIST_OFFSET: /^\/admin\/repos\/(.+),tags(,(.+))?$/, |
| 152 | TAG_LIST_FILTER: '/admin/repos/:repo,tags/q/filter::filter', |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 153 | TAG_LIST_FILTER_OFFSET: '/admin/repos/:repo,tags/q/filter::filter,:offset', |
Paladox none | 3bfada8 | 2017-09-01 09:29:21 +0000 | [diff] [blame] | 154 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 155 | PLUGINS: /^\/plugins\/(.+)$/, |
Wyatt Allen | 089dfb3 | 2017-08-24 17:55:38 -0700 | [diff] [blame] | 156 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 157 | PLUGIN_LIST: /^\/admin\/plugins(\/)?$/, |
Wyatt Allen | 089dfb3 | 2017-08-24 17:55:38 -0700 | [diff] [blame] | 158 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 159 | // Matches /admin/plugins[,<offset>][/]. |
| 160 | PLUGIN_LIST_OFFSET: /^\/admin\/plugins(,(\d+))?(\/)?$/, |
| 161 | PLUGIN_LIST_FILTER: '/admin/plugins/q/filter::filter', |
| 162 | PLUGIN_LIST_FILTER_OFFSET: '/admin/plugins/q/filter::filter,:offset', |
Wyatt Allen | 089dfb3 | 2017-08-24 17:55:38 -0700 | [diff] [blame] | 163 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 164 | QUERY: /^\/q\/([^,]+)(,(\d+))?$/, |
Wyatt Allen | 089dfb3 | 2017-08-24 17:55:38 -0700 | [diff] [blame] | 165 | |
Wyatt Allen | fd6a947 | 2017-08-28 16:42:40 -0700 | [diff] [blame] | 166 | /** |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 167 | * Support vestigial params from GWT UI. |
Tao Zhou | 9a07681 | 2019-12-17 09:59:28 +0100 | [diff] [blame] | 168 | * |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 169 | * @see Issue 7673. |
| 170 | * @type {!RegExp} |
Wyatt Allen | fd6a947 | 2017-08-28 16:42:40 -0700 | [diff] [blame] | 171 | */ |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 172 | QUERY_LEGACY_SUFFIX: /^\/q\/.+,n,z$/, |
Wyatt Allen | fd6a947 | 2017-08-28 16:42:40 -0700 | [diff] [blame] | 173 | |
Peter Collingbourne | 8cab933 | 2020-08-18 14:42:44 -0700 | [diff] [blame] | 174 | CHANGE_ID_QUERY: /^\/id\/(I[0-9a-f]{40})$/, |
| 175 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 176 | // Matches /c/<changeNum>/[<basePatchNum>..][<patchNum>][/]. |
| 177 | CHANGE_LEGACY: /^\/c\/(\d+)\/?(((-?\d+|edit)(\.\.(\d+|edit))?))?\/?$/, |
| 178 | CHANGE_NUMBER_LEGACY: /^\/(\d+)\/?/, |
Logan Hanks | aa501d0 | 2017-09-30 04:07:34 -0700 | [diff] [blame] | 179 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 180 | // Matches |
| 181 | // /c/<project>/+/<changeNum>/[<basePatchNum|edit>..][<patchNum|edit>]. |
| 182 | // TODO(kaspern): Migrate completely to project based URLs, with backwards |
| 183 | // compatibility for change-only. |
| 184 | CHANGE: /^\/c\/(.+)\/\+\/(\d+)(\/?((-?\d+|edit)(\.\.(\d+|edit))?))?\/?$/, |
Logan Hanks | aa501d0 | 2017-09-30 04:07:34 -0700 | [diff] [blame] | 185 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 186 | // Matches /c/<project>/+/<changeNum>/[<patchNum|edit>],edit |
| 187 | CHANGE_EDIT: /^\/c\/(.+)\/\+\/(\d+)(\/(\d+))?,edit\/?$/, |
Wyatt Allen | 84f0a57 | 2017-11-06 15:45:58 -0800 | [diff] [blame] | 188 | |
Dhruv Srivastava | 9024045 | 2020-07-02 15:51:53 +0200 | [diff] [blame] | 189 | // Matches /c/<project>/+/<changeNum>/comment/<commentId>/ |
| 190 | // Navigates to the diff view |
| 191 | // This route is needed to resolve to patchNum vs latestPatchNum used in the |
| 192 | // links generated in the emails. |
| 193 | COMMENT: /^\/c\/(.+)\/\+\/(\d+)\/comment\/(\w+)\/?$/, |
| 194 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 195 | // Matches |
| 196 | // /c/<project>/+/<changeNum>/[<basePatchNum|edit>..]<patchNum|edit>/<path>. |
| 197 | // TODO(kaspern): Migrate completely to project based URLs, with backwards |
| 198 | // compatibility for change-only. |
| 199 | // eslint-disable-next-line max-len |
| 200 | DIFF: /^\/c\/(.+)\/\+\/(\d+)(\/((-?\d+|edit)(\.\.(\d+|edit))?(\/(.+))))\/?$/, |
Wyatt Allen | 52d7613 | 2017-11-06 16:58:52 -0800 | [diff] [blame] | 201 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 202 | // Matches /c/<project>/+/<changeNum>/[<patchNum|edit>]/<path>,edit[#lineNum] |
David Ostrovsky | cfe6530 | 2020-05-07 22:10:38 +0200 | [diff] [blame] | 203 | DIFF_EDIT: /^\/c\/(.+)\/\+\/(\d+)\/(\d+|edit)\/(.+),edit(#\d+)?$/, |
Wyatt Allen | 02add88 | 2018-08-13 19:06:52 -0700 | [diff] [blame] | 204 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 205 | // Matches non-project-relative |
| 206 | // /c/<changeNum>/[<basePatchNum>..]<patchNum>/<path>. |
| 207 | DIFF_LEGACY: /^\/c\/(\d+)\/((-?\d+|edit)(\.\.(\d+|edit))?)\/(.+)/, |
| 208 | |
| 209 | // Matches diff routes using @\d+ to specify a file name (whether or not |
| 210 | // the project name is included). |
| 211 | // eslint-disable-next-line max-len |
| 212 | DIFF_LEGACY_LINENUM: /^\/c\/((.+)\/\+\/)?(\d+)(\/?((-?\d+|edit)(\.\.(\d+|edit))?\/(.+))?)@[ab]?\d+$/, |
| 213 | |
| 214 | SETTINGS: /^\/settings\/?/, |
| 215 | SETTINGS_LEGACY: /^\/settings\/VE\/(\S+)/, |
| 216 | |
| 217 | // Matches /c/<changeNum>/ /<URL tail> |
| 218 | // Catches improperly encoded URLs (context: Issue 7100) |
David Ostrovsky | cfe6530 | 2020-05-07 22:10:38 +0200 | [diff] [blame] | 219 | IMPROPERLY_ENCODED_PLUS: /^\/c\/(.+)\/ \/(.+)$/, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 220 | |
| 221 | PLUGIN_SCREEN: /^\/x\/([\w-]+)\/([\w-]+)\/?/, |
| 222 | |
| 223 | DOCUMENTATION_SEARCH_FILTER: '/Documentation/q/filter::filter', |
| 224 | DOCUMENTATION_SEARCH: /^\/Documentation\/q\/(.*)$/, |
| 225 | DOCUMENTATION: /^\/Documentation(\/)?(.+)?/, |
| 226 | }; |
| 227 | |
Dhruv Srivastava | 9024045 | 2020-07-02 15:51:53 +0200 | [diff] [blame] | 228 | export const _testOnly_RoutePattern = RoutePattern; |
| 229 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 230 | /** |
| 231 | * Pattern to recognize and parse the diff line locations as they appear in |
| 232 | * the hash of diff URLs. In this format, a number on its own indicates that |
| 233 | * line number in the revision of the diff. A number prefixed by either an 'a' |
| 234 | * or a 'b' indicates that line number of the base of the diff. |
| 235 | * |
| 236 | * @type {RegExp} |
| 237 | */ |
| 238 | const LINE_ADDRESS_PATTERN = /^([ab]?)(\d+)$/; |
| 239 | |
| 240 | /** |
| 241 | * Pattern to recognize '+' in url-encoded strings for replacement with ' '. |
| 242 | */ |
| 243 | const PLUS_PATTERN = /\+/g; |
| 244 | |
| 245 | /** |
| 246 | * Pattern to recognize leading '?' in window.location.search, for stripping. |
| 247 | */ |
| 248 | const QUESTION_PATTERN = /^\?*/; |
| 249 | |
| 250 | /** |
| 251 | * GWT UI would use @\d+ at the end of a path to indicate linenum. |
| 252 | */ |
| 253 | const LEGACY_LINENUM_PATTERN = /@([ab]?\d+)$/; |
| 254 | |
| 255 | const LEGACY_QUERY_SUFFIX_PATTERN = /,n,z$/; |
| 256 | |
David Ostrovsky | cfe6530 | 2020-05-07 22:10:38 +0200 | [diff] [blame] | 257 | const REPO_TOKEN_PATTERN = /\${(project|repo)}/g; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 258 | |
| 259 | // Polymer makes `app` intrinsically defined on the window by virtue of the |
| 260 | // custom element having the id "app", but it is made explicit here. |
Dmitrii Filippov | 6dbb171 | 2020-03-19 12:11:50 +0100 | [diff] [blame] | 261 | // If you move this code to other place, please update comment about |
| 262 | // gr-router and gr-app in the PolyGerritIndexHtml.soy file if needed |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 263 | const app = document.querySelector('#app'); |
| 264 | if (!app) { |
Tao Zhou | cd01d8f | 2020-07-22 12:35:31 +0200 | [diff] [blame] | 265 | console.info('No gr-app found (running tests)'); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 266 | } |
| 267 | |
| 268 | // Setup listeners outside of the router component initialization. |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 269 | (function () { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 270 | window.addEventListener('WebComponentsReady', () => { |
Milutin Kristofic | da88b33 | 2020-03-24 10:19:12 +0100 | [diff] [blame] | 271 | appContext.reportingService.timeEnd('WebComponentsReady'); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 272 | }); |
| 273 | })(); |
| 274 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 275 | export interface PageContextWithQueryMap extends PageContext { |
| 276 | queryMap: Map<string, string> | URLSearchParams; |
| 277 | } |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 278 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 279 | type QueryStringItem = [string, string]; // [key, value] |
| 280 | |
| 281 | type GenerateUrlLegacyChangeViewParameters = Omit< |
| 282 | GenerateUrlChangeViewParameters, |
| 283 | 'project' |
| 284 | >; |
| 285 | type GenerateUrlLegacyDiffViewParameters = Omit< |
| 286 | GenerateUrlDiffViewParameters, |
| 287 | 'project' |
| 288 | >; |
| 289 | |
| 290 | interface PatchRangeParams { |
| 291 | patchNum?: PatchSetNum | null; |
Dhruv Srivastava | 591b490 | 2021-03-10 11:48:12 +0100 | [diff] [blame] | 292 | basePatchNum?: BasePatchSetNum | null; |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 293 | } |
| 294 | |
| 295 | @customElement('gr-router') |
Ben Rohlfs | d94011e | 2021-03-08 23:37:58 +0100 | [diff] [blame] | 296 | export class GrRouter extends LegacyElementMixin(PolymerElement) { |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 297 | static get template() { |
| 298 | return htmlTemplate; |
Viktar Donich | 6606704 | 2016-08-25 15:54:19 -0700 | [diff] [blame] | 299 | } |
Andrew Bonventre | f3b33a0 | 2016-03-29 13:30:10 -0400 | [diff] [blame] | 300 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 301 | @property({type: Object}) |
| 302 | readonly _app = app; |
| 303 | |
| 304 | @property({type: Boolean}) |
| 305 | _isRedirecting?: boolean; |
| 306 | |
| 307 | // This variable is to differentiate between internal navigation (false) |
| 308 | // and for first navigation in app after loaded from server (true). |
| 309 | @property({type: Boolean}) |
| 310 | _isInitialLoad = true; |
| 311 | |
| 312 | private readonly reporting = appContext.reportingService; |
| 313 | |
Ben Rohlfs | 43935a4 | 2020-12-01 19:14:09 +0100 | [diff] [blame] | 314 | private readonly restApiService = appContext.restApiService; |
| 315 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 316 | start() { |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 317 | if (!this._app) { |
| 318 | return; |
| 319 | } |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 320 | this._startRouter(); |
| 321 | } |
Wyatt Allen | 3a69d82 | 2017-02-14 15:50:01 -0800 | [diff] [blame] | 322 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 323 | _setParams(params: AppElementParams | GenerateUrlParameters) { |
Ben Rohlfs | ebe4acc | 2020-12-11 21:16:10 +0100 | [diff] [blame] | 324 | updateState( |
| 325 | params.view, |
| 326 | 'changeNum' in params ? params.changeNum : undefined, |
| 327 | 'patchNum' in params ? params.patchNum ?? undefined : undefined |
| 328 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 329 | this._appElement().params = params; |
| 330 | } |
| 331 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 332 | _appElement(): AppElement { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 333 | // In Polymer2 you have to reach through the shadow root of the app |
| 334 | // element. This obviously breaks encapsulation. |
| 335 | // TODO(brohlfs): Make this more elegant, e.g. by exposing app-element |
| 336 | // explicitly in app, or by delegating to it. |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 337 | |
| 338 | // It is expected that application has a GrAppElement(id=='app-element') |
| 339 | // at the document level or inside the shadow root of the GrApp (id='app') |
| 340 | // element. |
| 341 | return (document.getElementById('app-element') || |
| 342 | document |
| 343 | .getElementById('app')! |
| 344 | .shadowRoot!.getElementById('app-element')!) as AppElement; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 345 | } |
| 346 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 347 | _redirect(url: string) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 348 | this._isRedirecting = true; |
| 349 | page.redirect(url); |
| 350 | } |
Wyatt Allen | 3a69d82 | 2017-02-14 15:50:01 -0800 | [diff] [blame] | 351 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 352 | _generateUrl(params: GenerateUrlParameters) { |
Dmitrii Filippov | 0049afe | 2020-07-08 14:08:17 +0200 | [diff] [blame] | 353 | const base = getBaseUrl(); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 354 | let url = ''; |
Wyatt Allen | 84505ea | 2017-08-24 10:53:05 -0700 | [diff] [blame] | 355 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 356 | if (params.view === GerritView.SEARCH) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 357 | url = this._generateSearchUrl(params); |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 358 | } else if (params.view === GerritView.CHANGE) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 359 | url = this._generateChangeUrl(params); |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 360 | } else if (params.view === GerritView.DASHBOARD) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 361 | url = this._generateDashboardUrl(params); |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 362 | } else if ( |
| 363 | params.view === GerritView.DIFF || |
| 364 | params.view === GerritView.EDIT |
| 365 | ) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 366 | url = this._generateDiffOrEditUrl(params); |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 367 | } else if (params.view === GerritView.GROUP) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 368 | url = this._generateGroupUrl(params); |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 369 | } else if (params.view === GerritView.REPO) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 370 | url = this._generateRepoUrl(params); |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 371 | } else if (params.view === GerritView.ROOT) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 372 | url = '/'; |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 373 | } else if (params.view === GerritView.SETTINGS) { |
| 374 | url = this._generateSettingsUrl(); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 375 | } else { |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 376 | assertNever(params, "Can't generate"); |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame] | 377 | } |
Wyatt Allen | 84505ea | 2017-08-24 10:53:05 -0700 | [diff] [blame] | 378 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 379 | return base + url; |
| 380 | } |
| 381 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 382 | _generateWeblinks( |
| 383 | params: GenerateWebLinksParameters |
| 384 | ): GeneratedWebLink[] | GeneratedWebLink { |
| 385 | switch (params.type) { |
| 386 | case WeblinkType.FILE: |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 387 | return this._getFileWebLinks(params); |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 388 | case WeblinkType.CHANGE: |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 389 | return this._getChangeWeblinks(params); |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 390 | case WeblinkType.PATCHSET: |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 391 | return this._getPatchSetWeblink(params); |
| 392 | default: |
Dhruv Srivastava | f97b055 | 2020-11-30 14:14:09 +0100 | [diff] [blame] | 393 | // eslint-disable-next-line @typescript-eslint/no-explicit-any |
Dhruv Srivastava | b68c85f | 2020-11-30 19:04:34 +0100 | [diff] [blame] | 394 | assertNever(params, `Unsupported weblink ${(params as any).type}!`); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 395 | } |
| 396 | } |
| 397 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 398 | _getPatchSetWeblink( |
| 399 | params: GenerateWebLinksPatchsetParameters |
| 400 | ): GeneratedWebLink { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 401 | const {commit, options} = params; |
| 402 | const {weblinks, config} = options || {}; |
| 403 | const name = commit && commit.slice(0, 7); |
| 404 | const weblink = this._getBrowseCommitWeblink(weblinks, config); |
| 405 | if (!weblink || !weblink.url) { |
| 406 | return {name}; |
| 407 | } else { |
| 408 | return {name, url: weblink.url}; |
| 409 | } |
| 410 | } |
| 411 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 412 | _firstCodeBrowserWeblink(weblinks: GeneratedWebLink[]) { |
Tao Zhou | 9a8951d | 2020-06-30 11:18:09 +0200 | [diff] [blame] | 413 | // This is an ordered allowed list of web link types that provide direct |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 414 | // links to the commit in the url property. |
| 415 | const codeBrowserLinks = ['gitiles', 'browse', 'gitweb']; |
| 416 | for (let i = 0; i < codeBrowserLinks.length; i++) { |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 417 | const weblink = weblinks.find( |
| 418 | weblink => weblink.name === codeBrowserLinks[i] |
| 419 | ); |
| 420 | if (weblink) { |
| 421 | return weblink; |
| 422 | } |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 423 | } |
| 424 | return null; |
| 425 | } |
| 426 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 427 | _getBrowseCommitWeblink(weblinks?: GeneratedWebLink[], config?: ServerInfo) { |
| 428 | if (!weblinks) { |
| 429 | return null; |
| 430 | } |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 431 | let weblink; |
| 432 | // Use primary weblink if configured and exists. |
Tao Zhou | 34b0f12 | 2020-08-31 13:44:50 +0200 | [diff] [blame] | 433 | if (config?.gerrit?.primary_weblink_name) { |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 434 | const primaryWeblinkName = config.gerrit.primary_weblink_name; |
| 435 | weblink = weblinks.find(weblink => weblink.name === primaryWeblinkName); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 436 | } |
| 437 | if (!weblink) { |
| 438 | weblink = this._firstCodeBrowserWeblink(weblinks); |
| 439 | } |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 440 | if (!weblink) { |
| 441 | return null; |
| 442 | } |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 443 | return weblink; |
| 444 | } |
| 445 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 446 | _getChangeWeblinks( |
| 447 | params: GenerateWebLinksChangeParameters |
| 448 | ): GeneratedWebLink[] { |
| 449 | const weblinks = params.options?.weblinks; |
| 450 | const config = params.options?.config; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 451 | if (!weblinks || !weblinks.length) return []; |
| 452 | const commitWeblink = this._getBrowseCommitWeblink(weblinks, config); |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 453 | return weblinks.filter( |
| 454 | weblink => |
| 455 | !commitWeblink || |
| 456 | !commitWeblink.name || |
| 457 | weblink.name !== commitWeblink.name |
| 458 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 459 | } |
| 460 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 461 | _getFileWebLinks(params: GenerateWebLinksFileParameters): GeneratedWebLink[] { |
| 462 | return params.options?.weblinks || []; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 463 | } |
| 464 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 465 | _generateSearchUrl(params: GenerateUrlSearchViewParameters) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 466 | let offsetExpr = ''; |
| 467 | if (params.offset && params.offset > 0) { |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 468 | offsetExpr = `,${params.offset}`; |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame] | 469 | } |
Wyatt Allen | 84505ea | 2017-08-24 10:53:05 -0700 | [diff] [blame] | 470 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 471 | if (params.query) { |
Dmitrii Filippov | e3c09ae | 2020-07-10 11:39:50 +0200 | [diff] [blame] | 472 | return '/q/' + encodeURL(params.query, true) + offsetExpr; |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame] | 473 | } |
Ben Rohlfs | e3b4542 | 2019-06-07 09:36:34 +0200 | [diff] [blame] | 474 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 475 | const operators: string[] = []; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 476 | if (params.owner) { |
Dmitrii Filippov | e3c09ae | 2020-07-10 11:39:50 +0200 | [diff] [blame] | 477 | operators.push('owner:' + encodeURL(params.owner, false)); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 478 | } |
| 479 | if (params.project) { |
Dmitrii Filippov | e3c09ae | 2020-07-10 11:39:50 +0200 | [diff] [blame] | 480 | operators.push('project:' + encodeURL(params.project, false)); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 481 | } |
| 482 | if (params.branch) { |
Dmitrii Filippov | e3c09ae | 2020-07-10 11:39:50 +0200 | [diff] [blame] | 483 | operators.push('branch:' + encodeURL(params.branch, false)); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 484 | } |
| 485 | if (params.topic) { |
Milutin Kristofic | dfb781d | 2021-01-29 13:24:43 +0100 | [diff] [blame] | 486 | operators.push( |
| 487 | 'topic:' + |
| 488 | addQuotesWhen(encodeURL(params.topic, false), /\s/.test(params.topic)) |
| 489 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 490 | } |
| 491 | if (params.hashtag) { |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 492 | operators.push( |
Milutin Kristofic | dfb781d | 2021-01-29 13:24:43 +0100 | [diff] [blame] | 493 | 'hashtag:' + |
| 494 | addQuotesWhen( |
| 495 | encodeURL(params.hashtag.toLowerCase(), false), |
| 496 | /\s/.test(params.hashtag) |
| 497 | ) |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 498 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 499 | } |
| 500 | if (params.statuses) { |
| 501 | if (params.statuses.length === 1) { |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 502 | operators.push('status:' + encodeURL(params.statuses[0], false)); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 503 | } else if (params.statuses.length > 1) { |
| 504 | operators.push( |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 505 | '(' + |
| 506 | params.statuses |
| 507 | .map(s => `status:${encodeURL(s, false)}`) |
| 508 | .join(' OR ') + |
| 509 | ')' |
| 510 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 511 | } |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame] | 512 | } |
Wyatt Allen | 84505ea | 2017-08-24 10:53:05 -0700 | [diff] [blame] | 513 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 514 | return '/q/' + operators.join('+') + offsetExpr; |
| 515 | } |
| 516 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 517 | _generateChangeUrl(params: GenerateUrlChangeViewParameters) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 518 | let range = this._getPatchRangeExpression(params); |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 519 | if (range.length) { |
| 520 | range = '/' + range; |
| 521 | } |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 522 | let suffix = `${range}`; |
| 523 | if (params.querystring) { |
| 524 | suffix += '?' + params.querystring; |
| 525 | } else if (params.edit) { |
| 526 | suffix += ',edit'; |
| 527 | } |
| 528 | if (params.messageHash) { |
| 529 | suffix += params.messageHash; |
| 530 | } |
| 531 | if (params.project) { |
Dmitrii Filippov | e3c09ae | 2020-07-10 11:39:50 +0200 | [diff] [blame] | 532 | const encodedProject = encodeURL(params.project, true); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 533 | return `/c/${encodedProject}/+/${params.changeNum}${suffix}`; |
| 534 | } else { |
| 535 | return `/c/${params.changeNum}${suffix}`; |
| 536 | } |
| 537 | } |
| 538 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 539 | _generateDashboardUrl(params: GenerateUrlDashboardViewParameters) { |
| 540 | const repoName = params.repo || params.project || undefined; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 541 | if (params.sections) { |
| 542 | // Custom dashboard. |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 543 | const queryParams = this._sectionsToEncodedParams( |
| 544 | params.sections, |
| 545 | repoName |
| 546 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 547 | if (params.title) { |
| 548 | queryParams.push('title=' + encodeURIComponent(params.title)); |
| 549 | } |
| 550 | const user = params.user ? params.user : ''; |
| 551 | return `/dashboard/${user}?${queryParams.join('&')}`; |
| 552 | } else if (repoName) { |
| 553 | // Project dashboard. |
Dmitrii Filippov | e3c09ae | 2020-07-10 11:39:50 +0200 | [diff] [blame] | 554 | const encodedRepo = encodeURL(repoName, true); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 555 | return `/p/${encodedRepo}/+/dashboard/${params.dashboard}`; |
| 556 | } else { |
| 557 | // User dashboard. |
| 558 | return `/dashboard/${params.user || 'self'}`; |
| 559 | } |
| 560 | } |
| 561 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 562 | _sectionsToEncodedParams(sections: DashboardSection[], repoName?: RepoName) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 563 | return sections.map(section => { |
| 564 | // If there is a repo name provided, make sure to substitute it into the |
| 565 | // ${repo} (or legacy ${project}) query tokens. |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 566 | const query = repoName |
| 567 | ? section.query.replace(REPO_TOKEN_PATTERN, repoName) |
| 568 | : section.query; |
| 569 | return encodeURIComponent(section.name) + '=' + encodeURIComponent(query); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 570 | }); |
| 571 | } |
| 572 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 573 | _generateDiffOrEditUrl( |
| 574 | params: GenerateUrlDiffViewParameters | GenerateUrlEditViewParameters |
| 575 | ) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 576 | let range = this._getPatchRangeExpression(params); |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 577 | if (range.length) { |
| 578 | range = '/' + range; |
| 579 | } |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 580 | |
Dhruv Srivastava | 2c35afe | 2020-04-28 12:16:56 +0200 | [diff] [blame] | 581 | let suffix = `${range}/${encodeURL(params.path || '', true)}`; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 582 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 583 | if (params.view === GerritView.EDIT) { |
| 584 | suffix += ',edit'; |
| 585 | } |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 586 | |
| 587 | if (params.lineNum) { |
| 588 | suffix += '#'; |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 589 | if (isGenerateUrlDiffViewParameters(params) && params.leftSide) { |
| 590 | suffix += 'b'; |
| 591 | } |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 592 | suffix += params.lineNum; |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame] | 593 | } |
Wyatt Allen | 797480f | 2017-06-08 09:20:46 -0700 | [diff] [blame] | 594 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 595 | if (isGenerateUrlDiffViewParameters(params) && params.commentId) { |
Dhruv Srivastava | 2c35afe | 2020-04-28 12:16:56 +0200 | [diff] [blame] | 596 | suffix = `/comment/${params.commentId}` + suffix; |
| 597 | } |
| 598 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 599 | if (params.project) { |
Dmitrii Filippov | e3c09ae | 2020-07-10 11:39:50 +0200 | [diff] [blame] | 600 | const encodedProject = encodeURL(params.project, true); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 601 | return `/c/${encodedProject}/+/${params.changeNum}${suffix}`; |
| 602 | } else { |
| 603 | return `/c/${params.changeNum}${suffix}`; |
| 604 | } |
| 605 | } |
Wyatt Allen | 797480f | 2017-06-08 09:20:46 -0700 | [diff] [blame] | 606 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 607 | _generateGroupUrl(params: GenerateUrlGroupViewParameters) { |
| 608 | let url = `/admin/groups/${encodeURL(`${params.groupId}`, true)}`; |
| 609 | if (params.detail === GroupDetailView.MEMBERS) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 610 | url += ',members'; |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 611 | } else if (params.detail === GroupDetailView.LOG) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 612 | url += ',audit-log'; |
| 613 | } |
| 614 | return url; |
| 615 | } |
| 616 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 617 | _generateRepoUrl(params: GenerateUrlRepoViewParameters) { |
| 618 | let url = `/admin/repos/${encodeURL(`${params.repoName}`, true)}`; |
| 619 | if (params.detail === RepoDetailView.ACCESS) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 620 | url += ',access'; |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 621 | } else if (params.detail === RepoDetailView.BRANCHES) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 622 | url += ',branches'; |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 623 | } else if (params.detail === RepoDetailView.TAGS) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 624 | url += ',tags'; |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 625 | } else if (params.detail === RepoDetailView.COMMANDS) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 626 | url += ',commands'; |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 627 | } else if (params.detail === RepoDetailView.DASHBOARDS) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 628 | url += ',dashboards'; |
| 629 | } |
| 630 | return url; |
| 631 | } |
| 632 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 633 | _generateSettingsUrl() { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 634 | return '/settings'; |
| 635 | } |
| 636 | |
| 637 | /** |
| 638 | * Given an object of parameters, potentially including a `patchNum` or a |
| 639 | * `basePatchNum` or both, return a string representation of that range. If |
| 640 | * no range is indicated in the params, the empty string is returned. |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 641 | */ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 642 | _getPatchRangeExpression(params: PatchRangeParams) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 643 | let range = ''; |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 644 | if (params.patchNum) { |
| 645 | range = `${params.patchNum}`; |
| 646 | } |
| 647 | if (params.basePatchNum) { |
| 648 | range = `${params.basePatchNum}..${range}`; |
| 649 | } |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 650 | return range; |
| 651 | } |
| 652 | |
| 653 | /** |
| 654 | * Given a set of params without a project, gets the project from the rest |
| 655 | * API project lookup and then sets the app params. |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 656 | */ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 657 | _normalizeLegacyRouteParams( |
| 658 | params: Readonly< |
| 659 | | GenerateUrlLegacyChangeViewParameters |
| 660 | | GenerateUrlLegacyDiffViewParameters |
| 661 | > |
| 662 | ) { |
| 663 | if (!params.changeNum) { |
| 664 | return Promise.resolve(); |
| 665 | } |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 666 | |
Ben Rohlfs | 43935a4 | 2020-12-01 19:14:09 +0100 | [diff] [blame] | 667 | return this.restApiService |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 668 | .getFromProjectLookup(params.changeNum) |
| 669 | .then(project => { |
| 670 | // Show a 404 and terminate if the lookup request failed. Attempting |
| 671 | // to redirect after failing to get the project loops infinitely. |
| 672 | if (!project) { |
| 673 | this._show404(); |
| 674 | return; |
| 675 | } |
| 676 | const updatedParams: |
| 677 | | GenerateUrlChangeViewParameters |
| 678 | | GenerateUrlDiffViewParameters = {...params, project}; |
| 679 | this._normalizePatchRangeParams(updatedParams); |
| 680 | this._redirect(this._generateUrl(updatedParams)); |
| 681 | }); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 682 | } |
| 683 | |
| 684 | /** |
| 685 | * Normalizes the params object, and determines if the URL needs to be |
| 686 | * modified to fit the proper schema. |
| 687 | * |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 688 | */ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 689 | _normalizePatchRangeParams(params: PatchRangeParams) { |
| 690 | if (params.basePatchNum === null || params.basePatchNum === undefined) { |
| 691 | return false; |
| 692 | } |
| 693 | const hasPatchNum = |
| 694 | params.patchNum !== null && params.patchNum !== undefined; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 695 | let needsRedirect = false; |
| 696 | |
| 697 | // Diffing a patch against itself is invalid, so if the base and revision |
| 698 | // patches are equal clear the base. |
Dhruv Srivastava | d1da458 | 2021-01-11 16:34:19 +0100 | [diff] [blame] | 699 | if (params.patchNum && params.basePatchNum === params.patchNum) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 700 | needsRedirect = true; |
| 701 | params.basePatchNum = null; |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 702 | } else if (!hasPatchNum) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 703 | // Regexes set basePatchNum instead of patchNum when only one is |
| 704 | // specified. Redirect is not needed in this case. |
| 705 | params.patchNum = params.basePatchNum; |
| 706 | params.basePatchNum = null; |
| 707 | } |
| 708 | return needsRedirect; |
| 709 | } |
| 710 | |
| 711 | /** |
| 712 | * Redirect the user to login using the given return-URL for redirection |
| 713 | * after authentication success. |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 714 | */ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 715 | _redirectToLogin(returnUrl: string) { |
Dmitrii Filippov | 0049afe | 2020-07-08 14:08:17 +0200 | [diff] [blame] | 716 | const basePath = getBaseUrl() || ''; |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 717 | page('/login/' + encodeURIComponent(returnUrl.substring(basePath.length))); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 718 | } |
| 719 | |
| 720 | /** |
| 721 | * Hashes parsed by page.js exclude "inner" hashes, so a URL like "/a#b#c" |
| 722 | * is parsed to have a hash of "b" rather than "b#c". Instead, this method |
| 723 | * parses hashes correctly. Will return an empty string if there is no hash. |
| 724 | * |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 725 | * @return Everything after the first '#' ("a#b#c" -> "b#c"). |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 726 | */ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 727 | _getHashFromCanonicalPath(canonicalPath: string) { |
| 728 | return canonicalPath.split('#').slice(1).join('#'); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 729 | } |
| 730 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 731 | _parseLineAddress(hash: string) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 732 | const match = hash.match(LINE_ADDRESS_PATTERN); |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 733 | if (!match) { |
| 734 | return null; |
| 735 | } |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 736 | return { |
| 737 | leftSide: !!match[1], |
Dhruv Srivastava | b8edee9 | 2020-10-19 10:20:07 +0200 | [diff] [blame] | 738 | lineNum: Number(match[2]), |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 739 | }; |
| 740 | } |
| 741 | |
| 742 | /** |
| 743 | * Check to see if the user is logged in and return a promise that only |
| 744 | * resolves if the user is logged in. If the user us not logged in, the |
| 745 | * promise is rejected and the page is redirected to the login flow. |
| 746 | * |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 747 | * @return A promise yielding the original route data |
| 748 | * (if it resolves). |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 749 | */ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 750 | _redirectIfNotLoggedIn(data: PageContext) { |
Ben Rohlfs | 43935a4 | 2020-12-01 19:14:09 +0100 | [diff] [blame] | 751 | return this.restApiService.getLoggedIn().then(loggedIn => { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 752 | if (loggedIn) { |
| 753 | return Promise.resolve(); |
Wyatt Allen | 797480f | 2017-06-08 09:20:46 -0700 | [diff] [blame] | 754 | } else { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 755 | this._redirectToLogin(data.canonicalPath); |
| 756 | return Promise.reject(new Error()); |
Wyatt Allen | 797480f | 2017-06-08 09:20:46 -0700 | [diff] [blame] | 757 | } |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 758 | }); |
| 759 | } |
Wyatt Allen | 797480f | 2017-06-08 09:20:46 -0700 | [diff] [blame] | 760 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 761 | /** Page.js middleware that warms the REST API's logged-in cache line. */ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 762 | _loadUserMiddleware(_: PageContext, next: PageNextCallback) { |
Ben Rohlfs | 43935a4 | 2020-12-01 19:14:09 +0100 | [diff] [blame] | 763 | this.restApiService.getLoggedIn().then(() => { |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 764 | next(); |
| 765 | }); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 766 | } |
| 767 | |
Tao Zhou | 4fd32d5 | 2020-04-06 17:23:10 +0200 | [diff] [blame] | 768 | /** Page.js middleware that try parse the querystring into queryMap. */ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 769 | _queryStringMiddleware(ctx: PageContext, next: PageNextCallback) { |
Ben Rohlfs | 7b16e9c | 2021-03-04 16:45:25 +0100 | [diff] [blame] | 770 | (ctx as PageContextWithQueryMap).queryMap = this.createQueryMap(ctx); |
| 771 | next(); |
| 772 | } |
| 773 | |
| 774 | private createQueryMap(ctx: PageContext) { |
Tao Zhou | 4fd32d5 | 2020-04-06 17:23:10 +0200 | [diff] [blame] | 775 | if (ctx.querystring) { |
| 776 | // https://caniuse.com/#search=URLSearchParams |
| 777 | if (window.URLSearchParams) { |
Ben Rohlfs | 7b16e9c | 2021-03-04 16:45:25 +0100 | [diff] [blame] | 778 | return new URLSearchParams(ctx.querystring); |
Tao Zhou | 4fd32d5 | 2020-04-06 17:23:10 +0200 | [diff] [blame] | 779 | } else { |
Milutin Kristofic | 2fddf92 | 2021-03-11 10:35:19 +0100 | [diff] [blame] | 780 | this.reporting.reportExecution(Execution.REACHABLE_CODE, { |
| 781 | id: 'noURLSearchParams', |
| 782 | }); |
Ben Rohlfs | 7b16e9c | 2021-03-04 16:45:25 +0100 | [diff] [blame] | 783 | return new Map(this._parseQueryString(ctx.querystring)); |
Tao Zhou | 4fd32d5 | 2020-04-06 17:23:10 +0200 | [diff] [blame] | 784 | } |
| 785 | } |
Ben Rohlfs | 7b16e9c | 2021-03-04 16:45:25 +0100 | [diff] [blame] | 786 | return new Map<string, string>(); |
Tao Zhou | 4fd32d5 | 2020-04-06 17:23:10 +0200 | [diff] [blame] | 787 | } |
| 788 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 789 | /** |
| 790 | * Map a route to a method on the router. |
| 791 | * |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 792 | * @param pattern The page.js pattern for the route. |
| 793 | * @param handlerName The method name for the handler. If the |
| 794 | * route is matched, the handler will be executed with `this` referring |
| 795 | * to the component. Its return value will be discarded so that it does |
| 796 | * not interfere with page.js. |
| 797 | * @param authRedirect If true, then auth is checked before |
| 798 | * executing the handler. If the user is not logged in, it will redirect |
| 799 | * to the login flow and the handler will not be executed. The login |
| 800 | * redirect specifies the matched URL to be used after successfull auth. |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 801 | */ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 802 | _mapRoute( |
| 803 | pattern: string | RegExp, |
| 804 | handlerName: keyof GrRouter, |
| 805 | authRedirect?: boolean |
| 806 | ) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 807 | if (!this[handlerName]) { |
Milutin Kristofic | 380b9f6 | 2020-12-03 09:24:17 +0100 | [diff] [blame] | 808 | this.reporting.error( |
| 809 | new Error(`Attempted to map route to unknown method: ${handlerName}`) |
| 810 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 811 | return; |
| 812 | } |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 813 | page( |
| 814 | pattern, |
| 815 | (ctx, next) => this._loadUserMiddleware(ctx, next), |
| 816 | (ctx, next) => this._queryStringMiddleware(ctx, next), |
Ben Rohlfs | 7b16e9c | 2021-03-04 16:45:25 +0100 | [diff] [blame] | 817 | ctx => { |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 818 | this.reporting.locationChanged(handlerName); |
| 819 | const promise = authRedirect |
Ben Rohlfs | 7b16e9c | 2021-03-04 16:45:25 +0100 | [diff] [blame] | 820 | ? this._redirectIfNotLoggedIn(ctx) |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 821 | : Promise.resolve(); |
| 822 | promise.then(() => { |
Ben Rohlfs | 7b16e9c | 2021-03-04 16:45:25 +0100 | [diff] [blame] | 823 | this[handlerName](ctx as PageContextWithQueryMap); |
Tao Zhou | 4fd32d5 | 2020-04-06 17:23:10 +0200 | [diff] [blame] | 824 | }); |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 825 | } |
| 826 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 827 | } |
| 828 | |
| 829 | _startRouter() { |
Dmitrii Filippov | 0049afe | 2020-07-08 14:08:17 +0200 | [diff] [blame] | 830 | const base = getBaseUrl(); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 831 | if (base) { |
| 832 | page.base(base); |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame] | 833 | } |
Wyatt Allen | 4fd17cc | 2017-06-23 09:32:47 -0700 | [diff] [blame] | 834 | |
Dmitrii Filippov | eb8b269 | 2020-04-06 18:02:35 +0200 | [diff] [blame] | 835 | GerritNav.setup( |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 836 | (url, redirect?) => { |
| 837 | if (redirect) { |
| 838 | page.redirect(url); |
| 839 | } else { |
| 840 | page.show(url); |
| 841 | } |
| 842 | }, |
| 843 | params => this._generateUrl(params), |
| 844 | params => this._generateWeblinks(params), |
| 845 | x => x |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 846 | ); |
| 847 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 848 | page.exit('*', (_, next) => { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 849 | if (!this._isRedirecting) { |
Milutin Kristofic | da88b33 | 2020-03-24 10:19:12 +0100 | [diff] [blame] | 850 | this.reporting.beforeLocationChanged(); |
Viktar Donich | a28dee06 | 2017-11-10 16:03:13 -0800 | [diff] [blame] | 851 | } |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 852 | this._isRedirecting = false; |
| 853 | this._isInitialLoad = false; |
| 854 | next(); |
| 855 | }); |
Viktar Donich | a28dee06 | 2017-11-10 16:03:13 -0800 | [diff] [blame] | 856 | |
Ben Rohlfs | 7b16e9c | 2021-03-04 16:45:25 +0100 | [diff] [blame] | 857 | // Remove the tracking param 'usp' (User Source Parameter) from the URL, |
| 858 | // just to have users look at cleaner URLs. |
| 859 | page((ctx, next) => { |
| 860 | if (window.URLSearchParams) { |
| 861 | const pathname = toPathname(ctx.canonicalPath); |
| 862 | const searchParams = toSearchParams(ctx.canonicalPath); |
| 863 | if (searchParams.has('usp')) { |
Ben Rohlfs | 6fb09dd | 2021-03-12 09:24:26 +0100 | [diff] [blame^] | 864 | const usp = searchParams.get('usp'); |
| 865 | this.reporting.reportLifeCycle(LifeCycle.USER_REFERRED_FROM, {usp}); |
Ben Rohlfs | 7b16e9c | 2021-03-04 16:45:25 +0100 | [diff] [blame] | 866 | searchParams.delete('usp'); |
| 867 | this._redirect(toPath(pathname, searchParams)); |
| 868 | return; |
| 869 | } |
| 870 | } |
| 871 | next(); |
| 872 | }); |
| 873 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 874 | // Middleware |
| 875 | page((ctx, next) => { |
| 876 | document.body.scrollTop = 0; |
Viktar Donich | a28dee06 | 2017-11-10 16:03:13 -0800 | [diff] [blame] | 877 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 878 | if (ctx.hash.match(RoutePattern.PLUGIN_SCREEN)) { |
| 879 | // Redirect all urls using hash #/x/plugin/screen to /x/plugin/screen |
| 880 | // This is needed to allow plugins to add basic #/x/ screen links to |
| 881 | // any location. |
| 882 | this._redirect(ctx.hash); |
Wyatt Allen | 089dfb3 | 2017-08-24 17:55:38 -0700 | [diff] [blame] | 883 | return; |
| 884 | } |
Wyatt Allen | 089dfb3 | 2017-08-24 17:55:38 -0700 | [diff] [blame] | 885 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 886 | // Fire asynchronously so that the URL is changed by the time the event |
| 887 | // is processed. |
Ben Rohlfs | 6b07893 | 2021-03-10 15:20:03 +0100 | [diff] [blame] | 888 | setTimeout(() => { |
Dmitrii Filippov | 6a03800 | 2020-10-14 18:50:07 +0200 | [diff] [blame] | 889 | const detail: LocationChangeEventDetail = { |
| 890 | hash: window.location.hash, |
| 891 | pathname: window.location.pathname, |
| 892 | }; |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 893 | this.dispatchEvent( |
| 894 | new CustomEvent('location-change', { |
Dmitrii Filippov | 6a03800 | 2020-10-14 18:50:07 +0200 | [diff] [blame] | 895 | detail, |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 896 | composed: true, |
| 897 | bubbles: true, |
| 898 | }) |
| 899 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 900 | }, 1); |
| 901 | next(); |
| 902 | }); |
| 903 | |
| 904 | this._mapRoute(RoutePattern.ROOT, '_handleRootRoute'); |
| 905 | |
| 906 | this._mapRoute(RoutePattern.DASHBOARD, '_handleDashboardRoute'); |
| 907 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 908 | this._mapRoute( |
| 909 | RoutePattern.CUSTOM_DASHBOARD, |
| 910 | '_handleCustomDashboardRoute' |
| 911 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 912 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 913 | this._mapRoute( |
| 914 | RoutePattern.PROJECT_DASHBOARD, |
| 915 | '_handleProjectDashboardRoute' |
| 916 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 917 | |
Jacek Centkowski | d322bd4 | 2020-09-16 10:34:55 +0200 | [diff] [blame] | 918 | this._mapRoute( |
| 919 | RoutePattern.LEGACY_PROJECT_DASHBOARD, |
| 920 | '_handleLegacyProjectDashboardRoute' |
| 921 | ); |
| 922 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 923 | this._mapRoute(RoutePattern.GROUP_INFO, '_handleGroupInfoRoute', true); |
| 924 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 925 | this._mapRoute( |
| 926 | RoutePattern.GROUP_AUDIT_LOG, |
| 927 | '_handleGroupAuditLogRoute', |
| 928 | true |
| 929 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 930 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 931 | this._mapRoute( |
| 932 | RoutePattern.GROUP_MEMBERS, |
| 933 | '_handleGroupMembersRoute', |
| 934 | true |
| 935 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 936 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 937 | this._mapRoute( |
| 938 | RoutePattern.GROUP_LIST_OFFSET, |
| 939 | '_handleGroupListOffsetRoute', |
| 940 | true |
| 941 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 942 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 943 | this._mapRoute( |
| 944 | RoutePattern.GROUP_LIST_FILTER_OFFSET, |
| 945 | '_handleGroupListFilterOffsetRoute', |
| 946 | true |
| 947 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 948 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 949 | this._mapRoute( |
| 950 | RoutePattern.GROUP_LIST_FILTER, |
| 951 | '_handleGroupListFilterRoute', |
| 952 | true |
| 953 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 954 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 955 | this._mapRoute( |
| 956 | RoutePattern.GROUP_SELF, |
| 957 | '_handleGroupSelfRedirectRoute', |
| 958 | true |
| 959 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 960 | |
| 961 | this._mapRoute(RoutePattern.GROUP, '_handleGroupRoute', true); |
| 962 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 963 | this._mapRoute(RoutePattern.PROJECT_OLD, '_handleProjectsOldRoute'); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 964 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 965 | this._mapRoute( |
| 966 | RoutePattern.REPO_COMMANDS, |
| 967 | '_handleRepoCommandsRoute', |
| 968 | true |
| 969 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 970 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 971 | this._mapRoute(RoutePattern.REPO_ACCESS, '_handleRepoAccessRoute'); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 972 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 973 | this._mapRoute(RoutePattern.REPO_DASHBOARDS, '_handleRepoDashboardsRoute'); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 974 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 975 | this._mapRoute( |
| 976 | RoutePattern.BRANCH_LIST_OFFSET, |
| 977 | '_handleBranchListOffsetRoute' |
| 978 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 979 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 980 | this._mapRoute( |
| 981 | RoutePattern.BRANCH_LIST_FILTER_OFFSET, |
| 982 | '_handleBranchListFilterOffsetRoute' |
| 983 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 984 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 985 | this._mapRoute( |
| 986 | RoutePattern.BRANCH_LIST_FILTER, |
| 987 | '_handleBranchListFilterRoute' |
| 988 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 989 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 990 | this._mapRoute(RoutePattern.TAG_LIST_OFFSET, '_handleTagListOffsetRoute'); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 991 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 992 | this._mapRoute( |
| 993 | RoutePattern.TAG_LIST_FILTER_OFFSET, |
| 994 | '_handleTagListFilterOffsetRoute' |
| 995 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 996 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 997 | this._mapRoute(RoutePattern.TAG_LIST_FILTER, '_handleTagListFilterRoute'); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 998 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 999 | this._mapRoute( |
| 1000 | RoutePattern.LEGACY_CREATE_GROUP, |
| 1001 | '_handleCreateGroupRoute', |
| 1002 | true |
| 1003 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1004 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1005 | this._mapRoute( |
| 1006 | RoutePattern.LEGACY_CREATE_PROJECT, |
| 1007 | '_handleCreateProjectRoute', |
| 1008 | true |
| 1009 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1010 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1011 | this._mapRoute(RoutePattern.REPO_LIST_OFFSET, '_handleRepoListOffsetRoute'); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1012 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1013 | this._mapRoute( |
| 1014 | RoutePattern.REPO_LIST_FILTER_OFFSET, |
| 1015 | '_handleRepoListFilterOffsetRoute' |
| 1016 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1017 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1018 | this._mapRoute(RoutePattern.REPO_LIST_FILTER, '_handleRepoListFilterRoute'); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1019 | |
| 1020 | this._mapRoute(RoutePattern.REPO, '_handleRepoRoute'); |
| 1021 | |
| 1022 | this._mapRoute(RoutePattern.PLUGINS, '_handlePassThroughRoute'); |
| 1023 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1024 | this._mapRoute( |
| 1025 | RoutePattern.PLUGIN_LIST_OFFSET, |
| 1026 | '_handlePluginListOffsetRoute', |
| 1027 | true |
| 1028 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1029 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1030 | this._mapRoute( |
| 1031 | RoutePattern.PLUGIN_LIST_FILTER_OFFSET, |
| 1032 | '_handlePluginListFilterOffsetRoute', |
| 1033 | true |
| 1034 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1035 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1036 | this._mapRoute( |
| 1037 | RoutePattern.PLUGIN_LIST_FILTER, |
| 1038 | '_handlePluginListFilterRoute', |
| 1039 | true |
| 1040 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1041 | |
| 1042 | this._mapRoute(RoutePattern.PLUGIN_LIST, '_handlePluginListRoute', true); |
| 1043 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1044 | this._mapRoute( |
| 1045 | RoutePattern.QUERY_LEGACY_SUFFIX, |
| 1046 | '_handleQueryLegacySuffixRoute' |
| 1047 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1048 | |
| 1049 | this._mapRoute(RoutePattern.QUERY, '_handleQueryRoute'); |
| 1050 | |
Peter Collingbourne | 8cab933 | 2020-08-18 14:42:44 -0700 | [diff] [blame] | 1051 | this._mapRoute(RoutePattern.CHANGE_ID_QUERY, '_handleChangeIdQueryRoute'); |
| 1052 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1053 | this._mapRoute(RoutePattern.DIFF_LEGACY_LINENUM, '_handleLegacyLinenum'); |
| 1054 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1055 | this._mapRoute( |
| 1056 | RoutePattern.CHANGE_NUMBER_LEGACY, |
| 1057 | '_handleChangeNumberLegacyRoute' |
| 1058 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1059 | |
| 1060 | this._mapRoute(RoutePattern.DIFF_EDIT, '_handleDiffEditRoute', true); |
| 1061 | |
| 1062 | this._mapRoute(RoutePattern.CHANGE_EDIT, '_handleChangeEditRoute', true); |
| 1063 | |
Dhruv Srivastava | 9024045 | 2020-07-02 15:51:53 +0200 | [diff] [blame] | 1064 | this._mapRoute(RoutePattern.COMMENT, '_handleCommentRoute'); |
| 1065 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1066 | this._mapRoute(RoutePattern.DIFF, '_handleDiffRoute'); |
| 1067 | |
| 1068 | this._mapRoute(RoutePattern.CHANGE, '_handleChangeRoute'); |
| 1069 | |
| 1070 | this._mapRoute(RoutePattern.CHANGE_LEGACY, '_handleChangeLegacyRoute'); |
| 1071 | |
| 1072 | this._mapRoute(RoutePattern.DIFF_LEGACY, '_handleDiffLegacyRoute'); |
| 1073 | |
| 1074 | this._mapRoute(RoutePattern.AGREEMENTS, '_handleAgreementsRoute', true); |
| 1075 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1076 | this._mapRoute( |
| 1077 | RoutePattern.NEW_AGREEMENTS, |
| 1078 | '_handleNewAgreementsRoute', |
| 1079 | true |
| 1080 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1081 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1082 | this._mapRoute( |
| 1083 | RoutePattern.SETTINGS_LEGACY, |
| 1084 | '_handleSettingsLegacyRoute', |
| 1085 | true |
| 1086 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1087 | |
| 1088 | this._mapRoute(RoutePattern.SETTINGS, '_handleSettingsRoute', true); |
| 1089 | |
| 1090 | this._mapRoute(RoutePattern.REGISTER, '_handleRegisterRoute'); |
| 1091 | |
| 1092 | this._mapRoute(RoutePattern.LOG_IN_OR_OUT, '_handlePassThroughRoute'); |
| 1093 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1094 | this._mapRoute( |
| 1095 | RoutePattern.IMPROPERLY_ENCODED_PLUS, |
| 1096 | '_handleImproperlyEncodedPlusRoute' |
| 1097 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1098 | |
| 1099 | this._mapRoute(RoutePattern.PLUGIN_SCREEN, '_handlePluginScreen'); |
| 1100 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1101 | this._mapRoute( |
| 1102 | RoutePattern.DOCUMENTATION_SEARCH_FILTER, |
| 1103 | '_handleDocumentationSearchRoute' |
| 1104 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1105 | |
| 1106 | // redirects /Documentation/q/* to /Documentation/q/filter:* |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1107 | this._mapRoute( |
| 1108 | RoutePattern.DOCUMENTATION_SEARCH, |
| 1109 | '_handleDocumentationSearchRedirectRoute' |
| 1110 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1111 | |
| 1112 | // Makes sure /Documentation/* links work (doin't return 404) |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1113 | this._mapRoute( |
| 1114 | RoutePattern.DOCUMENTATION, |
| 1115 | '_handleDocumentationRedirectRoute' |
| 1116 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1117 | |
| 1118 | // Note: this route should appear last so it only catches URLs unmatched |
| 1119 | // by other patterns. |
| 1120 | this._mapRoute(RoutePattern.DEFAULT, '_handleDefaultRoute'); |
| 1121 | |
| 1122 | page.start(); |
| 1123 | } |
| 1124 | |
| 1125 | /** |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1126 | * @return if handling the route involves asynchrony, then a |
| 1127 | * promise is returned. Otherwise, synchronous handling returns null. |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1128 | */ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1129 | _handleRootRoute(data: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1130 | if (data.querystring.match(/^closeAfterLogin/)) { |
| 1131 | // Close child window on redirect after login. |
| 1132 | window.close(); |
| 1133 | return null; |
| 1134 | } |
| 1135 | let hash = this._getHashFromCanonicalPath(data.canonicalPath); |
| 1136 | // For backward compatibility with GWT links. |
| 1137 | if (hash) { |
| 1138 | // In certain login flows the server may redirect to a hash without |
| 1139 | // a leading slash, which page.js doesn't handle correctly. |
| 1140 | if (hash[0] !== '/') { |
| 1141 | hash = '/' + hash; |
| 1142 | } |
| 1143 | if (hash.includes('/ /') && data.canonicalPath.includes('/+/')) { |
| 1144 | // Path decodes all '+' to ' ' -- this breaks project-based URLs. |
| 1145 | // See Issue 6888. |
| 1146 | hash = hash.replace('/ /', '/+/'); |
| 1147 | } |
Dmitrii Filippov | 0049afe | 2020-07-08 14:08:17 +0200 | [diff] [blame] | 1148 | const base = getBaseUrl(); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1149 | let newUrl = base + hash; |
| 1150 | if (hash.startsWith('/VE/')) { |
| 1151 | newUrl = base + '/settings' + hash; |
Wyatt Allen | 84505ea | 2017-08-24 10:53:05 -0700 | [diff] [blame] | 1152 | } |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1153 | this._redirect(newUrl); |
| 1154 | return null; |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame] | 1155 | } |
Ben Rohlfs | 43935a4 | 2020-12-01 19:14:09 +0100 | [diff] [blame] | 1156 | return this.restApiService.getLoggedIn().then(loggedIn => { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1157 | if (loggedIn) { |
| 1158 | this._redirect('/dashboard/self'); |
| 1159 | } else { |
Ben Rohlfs | 718957b | 2020-04-15 13:59:17 +0200 | [diff] [blame] | 1160 | this._redirect('/q/status:open+-is:wip'); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1161 | } |
| 1162 | }); |
| 1163 | } |
Wyatt Allen | 089dfb3 | 2017-08-24 17:55:38 -0700 | [diff] [blame] | 1164 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1165 | /** |
| 1166 | * Decode an application/x-www-form-urlencoded string. |
| 1167 | * |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1168 | * @param qs The application/x-www-form-urlencoded string. |
| 1169 | * @return The decoded string. |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1170 | */ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1171 | _decodeQueryString(qs: string) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1172 | return decodeURIComponent(qs.replace(PLUS_PATTERN, ' ')); |
| 1173 | } |
| 1174 | |
| 1175 | /** |
| 1176 | * Parse a query string (e.g. window.location.search) into an array of |
| 1177 | * name/value pairs. |
| 1178 | * |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1179 | * @param qs The application/x-www-form-urlencoded query string. |
| 1180 | * @return An array of name/value pairs, where each |
| 1181 | * element is a 2-element array. |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1182 | */ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1183 | _parseQueryString(qs: string): Array<QueryStringItem> { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1184 | qs = qs.replace(QUESTION_PATTERN, ''); |
| 1185 | if (!qs) { |
| 1186 | return []; |
| 1187 | } |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1188 | const params: Array<[string, string]> = []; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1189 | qs.split('&').forEach(param => { |
| 1190 | const idx = param.indexOf('='); |
| 1191 | let name; |
| 1192 | let value; |
| 1193 | if (idx < 0) { |
| 1194 | name = this._decodeQueryString(param); |
| 1195 | value = ''; |
| 1196 | } else { |
| 1197 | name = this._decodeQueryString(param.substring(0, idx)); |
| 1198 | value = this._decodeQueryString(param.substring(idx + 1)); |
Wyatt Allen | 089dfb3 | 2017-08-24 17:55:38 -0700 | [diff] [blame] | 1199 | } |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1200 | if (name) { |
| 1201 | params.push([name, value]); |
Wyatt Allen | 089dfb3 | 2017-08-24 17:55:38 -0700 | [diff] [blame] | 1202 | } |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1203 | }); |
| 1204 | return params; |
| 1205 | } |
| 1206 | |
| 1207 | /** |
| 1208 | * Handle dashboard routes. These may be user, or project dashboards. |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1209 | */ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1210 | _handleDashboardRoute(data: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1211 | // User dashboard. We require viewing user to be logged in, else we |
| 1212 | // redirect to login for self dashboard or simple owner search for |
| 1213 | // other user dashboard. |
Ben Rohlfs | 43935a4 | 2020-12-01 19:14:09 +0100 | [diff] [blame] | 1214 | return this.restApiService.getLoggedIn().then(loggedIn => { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1215 | if (!loggedIn) { |
| 1216 | if (data.params[0].toLowerCase() === 'self') { |
| 1217 | this._redirectToLogin(data.canonicalPath); |
Wyatt Allen | 089dfb3 | 2017-08-24 17:55:38 -0700 | [diff] [blame] | 1218 | } else { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1219 | this._redirect('/q/owner:' + encodeURIComponent(data.params[0])); |
Wyatt Allen | 089dfb3 | 2017-08-24 17:55:38 -0700 | [diff] [blame] | 1220 | } |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1221 | } else { |
Logan Hanks | aa501d0 | 2017-09-30 04:07:34 -0700 | [diff] [blame] | 1222 | this._setParams({ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1223 | view: GerritView.DASHBOARD, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1224 | user: data.params[0], |
Logan Hanks | aa501d0 | 2017-09-30 04:07:34 -0700 | [diff] [blame] | 1225 | }); |
Wyatt Allen | 089dfb3 | 2017-08-24 17:55:38 -0700 | [diff] [blame] | 1226 | } |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1227 | }); |
| 1228 | } |
Wyatt Allen | 089dfb3 | 2017-08-24 17:55:38 -0700 | [diff] [blame] | 1229 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1230 | /** |
| 1231 | * Handle custom dashboard routes. |
| 1232 | * |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1233 | * @param qs Optional query string associated with the route. |
| 1234 | * If not given, window.location.search is used. (Used by tests). |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1235 | */ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1236 | _handleCustomDashboardRoute( |
| 1237 | _: PageContextWithQueryMap, |
| 1238 | qs: string = window.location.search |
| 1239 | ) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1240 | const queryParams = this._parseQueryString(qs); |
| 1241 | let title = 'Custom Dashboard'; |
| 1242 | const titleParam = queryParams.find( |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1243 | elem => elem[0].toLowerCase() === 'title' |
| 1244 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1245 | if (titleParam) { |
| 1246 | title = titleParam[1]; |
| 1247 | } |
| 1248 | // Dashboards support a foreach param which adds a base query to any |
| 1249 | // additional query. |
| 1250 | const forEachParam = queryParams.find( |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1251 | elem => elem[0].toLowerCase() === 'foreach' |
| 1252 | ); |
| 1253 | let forEachQuery: string | null = null; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1254 | if (forEachParam) { |
| 1255 | forEachQuery = forEachParam[1]; |
| 1256 | } |
| 1257 | const sectionParams = queryParams.filter( |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1258 | elem => |
| 1259 | elem[0] && |
| 1260 | elem[1] && |
| 1261 | elem[0].toLowerCase() !== 'title' && |
| 1262 | elem[0].toLowerCase() !== 'foreach' |
| 1263 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1264 | const sections = sectionParams.map(elem => { |
| 1265 | const query = forEachQuery ? `${forEachQuery} ${elem[1]}` : elem[1]; |
| 1266 | return { |
| 1267 | name: elem[0], |
| 1268 | query, |
| 1269 | }; |
| 1270 | }); |
| 1271 | |
| 1272 | if (sections.length > 0) { |
| 1273 | // Custom dashboard view. |
| 1274 | this._setParams({ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1275 | view: GerritView.DASHBOARD, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1276 | user: 'self', |
| 1277 | sections, |
| 1278 | title, |
| 1279 | }); |
Wyatt Allen | ee2016c | 2017-10-31 13:41:52 -0700 | [diff] [blame] | 1280 | return Promise.resolve(); |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame] | 1281 | } |
Wyatt Allen | 089dfb3 | 2017-08-24 17:55:38 -0700 | [diff] [blame] | 1282 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1283 | // Redirect /dashboard/ -> /dashboard/self. |
| 1284 | this._redirect('/dashboard/self'); |
| 1285 | return Promise.resolve(); |
| 1286 | } |
Logan Hanks | c34e0b6 | 2017-10-03 01:40:54 -0700 | [diff] [blame] | 1287 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1288 | _handleProjectDashboardRoute(data: PageContextWithQueryMap) { |
| 1289 | const project = data.params[0] as RepoName; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1290 | this._setParams({ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1291 | view: GerritView.DASHBOARD, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1292 | project, |
Dmitrii Filippov | 12f22a9 | 2020-10-12 16:16:30 +0200 | [diff] [blame] | 1293 | dashboard: decodeURIComponent(data.params[1]) as DashboardId, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1294 | }); |
Milutin Kristofic | da88b33 | 2020-03-24 10:19:12 +0100 | [diff] [blame] | 1295 | this.reporting.setRepoName(project); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1296 | } |
Wyatt Allen | 089dfb3 | 2017-08-24 17:55:38 -0700 | [diff] [blame] | 1297 | |
Jacek Centkowski | d322bd4 | 2020-09-16 10:34:55 +0200 | [diff] [blame] | 1298 | _handleLegacyProjectDashboardRoute(data: PageContextWithQueryMap) { |
| 1299 | this._redirect('/p/' + data.params[0] + '/+/dashboard/' + data.params[1]); |
| 1300 | } |
| 1301 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1302 | _handleGroupInfoRoute(data: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1303 | this._redirect('/admin/groups/' + encodeURIComponent(data.params[0])); |
| 1304 | } |
Paladox none | f7303f7 | 2019-06-27 14:57:11 +0000 | [diff] [blame] | 1305 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1306 | _handleGroupSelfRedirectRoute(_: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1307 | this._redirect('/settings/#Groups'); |
| 1308 | } |
Wyatt Allen | c172767 | 2017-10-19 15:06:54 -0700 | [diff] [blame] | 1309 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1310 | _handleGroupRoute(data: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1311 | this._setParams({ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1312 | view: GerritView.GROUP, |
| 1313 | groupId: data.params[0] as GroupId, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1314 | }); |
| 1315 | } |
Wyatt Allen | 089dfb3 | 2017-08-24 17:55:38 -0700 | [diff] [blame] | 1316 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1317 | _handleGroupAuditLogRoute(data: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1318 | this._setParams({ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1319 | view: GerritView.GROUP, |
| 1320 | detail: GroupDetailView.LOG, |
| 1321 | groupId: data.params[0] as GroupId, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1322 | }); |
| 1323 | } |
Wyatt Allen | 089dfb3 | 2017-08-24 17:55:38 -0700 | [diff] [blame] | 1324 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1325 | _handleGroupMembersRoute(data: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1326 | this._setParams({ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1327 | view: GerritView.GROUP, |
| 1328 | detail: GroupDetailView.MEMBERS, |
| 1329 | groupId: data.params[0] as GroupId, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1330 | }); |
| 1331 | } |
Wyatt Allen | 089dfb3 | 2017-08-24 17:55:38 -0700 | [diff] [blame] | 1332 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1333 | _handleGroupListOffsetRoute(data: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1334 | this._setParams({ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1335 | view: GerritView.ADMIN, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1336 | adminView: 'gr-admin-group-list', |
| 1337 | offset: data.params[1] || 0, |
| 1338 | filter: null, |
| 1339 | openCreateModal: data.hash === 'create', |
| 1340 | }); |
| 1341 | } |
Wyatt Allen | 089dfb3 | 2017-08-24 17:55:38 -0700 | [diff] [blame] | 1342 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1343 | _handleGroupListFilterOffsetRoute(data: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1344 | this._setParams({ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1345 | view: GerritView.ADMIN, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1346 | adminView: 'gr-admin-group-list', |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1347 | offset: data.params['offset'], |
| 1348 | filter: data.params['filter'], |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1349 | }); |
| 1350 | } |
Wyatt Allen | 089dfb3 | 2017-08-24 17:55:38 -0700 | [diff] [blame] | 1351 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1352 | _handleGroupListFilterRoute(data: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1353 | this._setParams({ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1354 | view: GerritView.ADMIN, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1355 | adminView: 'gr-admin-group-list', |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1356 | filter: data.params['filter'] || null, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1357 | }); |
| 1358 | } |
Paladox none | 87f9960 | 2019-07-05 12:58:23 +0000 | [diff] [blame] | 1359 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1360 | _handleProjectsOldRoute(data: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1361 | let params = ''; |
| 1362 | if (data.params[1]) { |
| 1363 | params = encodeURIComponent(data.params[1]); |
| 1364 | if (data.params[1].includes(',')) { |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1365 | params = encodeURIComponent(data.params[1]).replace('%2C', ','); |
Kasper Nilsson | 8d399e0 | 2017-08-29 11:19:04 -0700 | [diff] [blame] | 1366 | } |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame] | 1367 | } |
Kasper Nilsson | 8d399e0 | 2017-08-29 11:19:04 -0700 | [diff] [blame] | 1368 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1369 | this._redirect(`/admin/repos/${params}`); |
| 1370 | } |
| 1371 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1372 | _handleRepoCommandsRoute(data: PageContextWithQueryMap) { |
| 1373 | const repo = data.params[0] as RepoName; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1374 | this._setParams({ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1375 | view: GerritView.REPO, |
| 1376 | detail: RepoDetailView.COMMANDS, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1377 | repo, |
| 1378 | }); |
Milutin Kristofic | da88b33 | 2020-03-24 10:19:12 +0100 | [diff] [blame] | 1379 | this.reporting.setRepoName(repo); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1380 | } |
| 1381 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1382 | _handleRepoAccessRoute(data: PageContextWithQueryMap) { |
| 1383 | const repo = data.params[0] as RepoName; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1384 | this._setParams({ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1385 | view: GerritView.REPO, |
| 1386 | detail: RepoDetailView.ACCESS, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1387 | repo, |
| 1388 | }); |
Milutin Kristofic | da88b33 | 2020-03-24 10:19:12 +0100 | [diff] [blame] | 1389 | this.reporting.setRepoName(repo); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1390 | } |
| 1391 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1392 | _handleRepoDashboardsRoute(data: PageContextWithQueryMap) { |
| 1393 | const repo = data.params[0] as RepoName; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1394 | this._setParams({ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1395 | view: GerritView.REPO, |
| 1396 | detail: RepoDetailView.DASHBOARDS, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1397 | repo, |
| 1398 | }); |
Milutin Kristofic | da88b33 | 2020-03-24 10:19:12 +0100 | [diff] [blame] | 1399 | this.reporting.setRepoName(repo); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1400 | } |
| 1401 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1402 | _handleBranchListOffsetRoute(data: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1403 | this._setParams({ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1404 | view: GerritView.REPO, |
| 1405 | detail: RepoDetailView.BRANCHES, |
| 1406 | repo: data.params[0] as RepoName, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1407 | offset: data.params[2] || 0, |
| 1408 | filter: null, |
| 1409 | }); |
| 1410 | } |
| 1411 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1412 | _handleBranchListFilterOffsetRoute(data: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1413 | this._setParams({ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1414 | view: GerritView.REPO, |
| 1415 | detail: RepoDetailView.BRANCHES, |
| 1416 | repo: data.params['repo'] as RepoName, |
| 1417 | offset: data.params['offset'], |
| 1418 | filter: data.params['filter'], |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1419 | }); |
| 1420 | } |
| 1421 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1422 | _handleBranchListFilterRoute(data: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1423 | this._setParams({ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1424 | view: GerritView.REPO, |
| 1425 | detail: RepoDetailView.BRANCHES, |
| 1426 | repo: data.params['repo'] as RepoName, |
| 1427 | filter: data.params['filter'] || null, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1428 | }); |
| 1429 | } |
| 1430 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1431 | _handleTagListOffsetRoute(data: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1432 | this._setParams({ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1433 | view: GerritView.REPO, |
| 1434 | detail: RepoDetailView.TAGS, |
| 1435 | repo: data.params[0] as RepoName, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1436 | offset: data.params[2] || 0, |
| 1437 | filter: null, |
| 1438 | }); |
| 1439 | } |
| 1440 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1441 | _handleTagListFilterOffsetRoute(data: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1442 | this._setParams({ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1443 | view: GerritView.REPO, |
| 1444 | detail: RepoDetailView.TAGS, |
| 1445 | repo: data.params['repo'] as RepoName, |
| 1446 | offset: data.params['offset'], |
| 1447 | filter: data.params['filter'], |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1448 | }); |
| 1449 | } |
| 1450 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1451 | _handleTagListFilterRoute(data: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1452 | this._setParams({ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1453 | view: GerritView.REPO, |
| 1454 | detail: RepoDetailView.TAGS, |
| 1455 | repo: data.params['repo'] as RepoName, |
| 1456 | filter: data.params['filter'] || null, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1457 | }); |
| 1458 | } |
| 1459 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1460 | _handleRepoListOffsetRoute(data: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1461 | this._setParams({ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1462 | view: GerritView.ADMIN, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1463 | adminView: 'gr-repo-list', |
| 1464 | offset: data.params[1] || 0, |
| 1465 | filter: null, |
| 1466 | openCreateModal: data.hash === 'create', |
| 1467 | }); |
| 1468 | } |
| 1469 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1470 | _handleRepoListFilterOffsetRoute(data: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1471 | this._setParams({ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1472 | view: GerritView.ADMIN, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1473 | adminView: 'gr-repo-list', |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1474 | offset: data.params['offset'], |
| 1475 | filter: data.params['filter'], |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1476 | }); |
| 1477 | } |
| 1478 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1479 | _handleRepoListFilterRoute(data: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1480 | this._setParams({ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1481 | view: GerritView.ADMIN, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1482 | adminView: 'gr-repo-list', |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1483 | filter: data.params['filter'] || null, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1484 | }); |
| 1485 | } |
| 1486 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1487 | _handleCreateProjectRoute(_: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1488 | // Redirects the legacy route to the new route, which displays the project |
| 1489 | // list with a hash 'create'. |
| 1490 | this._redirect('/admin/repos#create'); |
| 1491 | } |
| 1492 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1493 | _handleCreateGroupRoute(_: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1494 | // Redirects the legacy route to the new route, which displays the group |
| 1495 | // list with a hash 'create'. |
| 1496 | this._redirect('/admin/groups#create'); |
| 1497 | } |
| 1498 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1499 | _handleRepoRoute(data: PageContextWithQueryMap) { |
| 1500 | const repo = data.params[0] as RepoName; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1501 | this._setParams({ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1502 | view: GerritView.REPO, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1503 | repo, |
| 1504 | }); |
Milutin Kristofic | da88b33 | 2020-03-24 10:19:12 +0100 | [diff] [blame] | 1505 | this.reporting.setRepoName(repo); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1506 | } |
| 1507 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1508 | _handlePluginListOffsetRoute(data: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1509 | this._setParams({ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1510 | view: GerritView.ADMIN, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1511 | adminView: 'gr-plugin-list', |
| 1512 | offset: data.params[1] || 0, |
| 1513 | filter: null, |
| 1514 | }); |
| 1515 | } |
| 1516 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1517 | _handlePluginListFilterOffsetRoute(data: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1518 | this._setParams({ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1519 | view: GerritView.ADMIN, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1520 | adminView: 'gr-plugin-list', |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1521 | offset: data.params['offset'], |
| 1522 | filter: data.params['filter'], |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1523 | }); |
| 1524 | } |
| 1525 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1526 | _handlePluginListFilterRoute(data: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1527 | this._setParams({ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1528 | view: GerritView.ADMIN, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1529 | adminView: 'gr-plugin-list', |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1530 | filter: data.params['filter'] || null, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1531 | }); |
| 1532 | } |
| 1533 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1534 | _handlePluginListRoute(_: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1535 | this._setParams({ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1536 | view: GerritView.ADMIN, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1537 | adminView: 'gr-plugin-list', |
| 1538 | }); |
| 1539 | } |
| 1540 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1541 | _handleQueryRoute(data: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1542 | this._setParams({ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1543 | view: GerritView.SEARCH, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1544 | query: data.params[0], |
| 1545 | offset: data.params[2], |
| 1546 | }); |
| 1547 | } |
| 1548 | |
Peter Collingbourne | 8cab933 | 2020-08-18 14:42:44 -0700 | [diff] [blame] | 1549 | _handleChangeIdQueryRoute(data: PageContextWithQueryMap) { |
| 1550 | // TODO(pcc): This will need to indicate that this was a change ID query if |
| 1551 | // standard queries gain the ability to search places like commit messages |
| 1552 | // for change IDs. |
| 1553 | this._setParams({ |
| 1554 | view: GerritNav.View.SEARCH, |
| 1555 | query: data.params[0], |
| 1556 | }); |
| 1557 | } |
| 1558 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1559 | _handleQueryLegacySuffixRoute(ctx: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1560 | this._redirect(ctx.path.replace(LEGACY_QUERY_SUFFIX_PATTERN, '')); |
| 1561 | } |
| 1562 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1563 | _handleChangeNumberLegacyRoute(ctx: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1564 | this._redirect('/c/' + encodeURIComponent(ctx.params[0])); |
| 1565 | } |
| 1566 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1567 | _handleChangeRoute(ctx: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1568 | // Parameter order is based on the regex group number matched. |
Milutin Kristofic | 3a84452 | 2021-01-21 10:01:55 +0100 | [diff] [blame] | 1569 | const changeNum = Number(ctx.params[1]) as NumericChangeId; |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1570 | const params: GenerateUrlChangeViewParameters = { |
| 1571 | project: ctx.params[0] as RepoName, |
Milutin Kristofic | 3a84452 | 2021-01-21 10:01:55 +0100 | [diff] [blame] | 1572 | changeNum, |
Dhruv Srivastava | 591b490 | 2021-03-10 11:48:12 +0100 | [diff] [blame] | 1573 | basePatchNum: convertToPatchSetNum(ctx.params[4]) as BasePatchSetNum, |
Dhruv Srivastava | e3430e2 | 2020-10-21 22:32:39 +0200 | [diff] [blame] | 1574 | patchNum: convertToPatchSetNum(ctx.params[6]), |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1575 | view: GerritView.CHANGE, |
Tao Zhou | 4fd32d5 | 2020-04-06 17:23:10 +0200 | [diff] [blame] | 1576 | queryMap: ctx.queryMap, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1577 | }; |
| 1578 | |
Milutin Kristofic | da88b33 | 2020-03-24 10:19:12 +0100 | [diff] [blame] | 1579 | this.reporting.setRepoName(params.project); |
Milutin Kristofic | 3a84452 | 2021-01-21 10:01:55 +0100 | [diff] [blame] | 1580 | this.reporting.setChangeId(changeNum); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1581 | this._redirectOrNavigate(params); |
| 1582 | } |
| 1583 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1584 | _handleCommentRoute(ctx: PageContextWithQueryMap) { |
Milutin Kristofic | 3a84452 | 2021-01-21 10:01:55 +0100 | [diff] [blame] | 1585 | const changeNum = Number(ctx.params[1]) as NumericChangeId; |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1586 | const params: GenerateUrlDiffViewParameters = { |
| 1587 | project: ctx.params[0] as RepoName, |
Milutin Kristofic | 3a84452 | 2021-01-21 10:01:55 +0100 | [diff] [blame] | 1588 | changeNum, |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1589 | commentId: ctx.params[2] as UrlEncodedCommentId, |
| 1590 | view: GerritView.DIFF, |
Dhruv Srivastava | 9024045 | 2020-07-02 15:51:53 +0200 | [diff] [blame] | 1591 | commentLink: true, |
| 1592 | }; |
| 1593 | this.reporting.setRepoName(params.project); |
Milutin Kristofic | 3a84452 | 2021-01-21 10:01:55 +0100 | [diff] [blame] | 1594 | this.reporting.setChangeId(changeNum); |
Dhruv Srivastava | 9024045 | 2020-07-02 15:51:53 +0200 | [diff] [blame] | 1595 | this._redirectOrNavigate(params); |
| 1596 | } |
| 1597 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1598 | _handleDiffRoute(ctx: PageContextWithQueryMap) { |
Milutin Kristofic | 3a84452 | 2021-01-21 10:01:55 +0100 | [diff] [blame] | 1599 | const changeNum = Number(ctx.params[1]) as NumericChangeId; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1600 | // Parameter order is based on the regex group number matched. |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1601 | const params: GenerateUrlDiffViewParameters = { |
| 1602 | project: ctx.params[0] as RepoName, |
Milutin Kristofic | 3a84452 | 2021-01-21 10:01:55 +0100 | [diff] [blame] | 1603 | changeNum, |
Dhruv Srivastava | 591b490 | 2021-03-10 11:48:12 +0100 | [diff] [blame] | 1604 | basePatchNum: convertToPatchSetNum(ctx.params[4]) as BasePatchSetNum, |
Dhruv Srivastava | e3430e2 | 2020-10-21 22:32:39 +0200 | [diff] [blame] | 1605 | patchNum: convertToPatchSetNum(ctx.params[6]), |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1606 | path: ctx.params[8], |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1607 | view: GerritView.DIFF, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1608 | }; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1609 | const address = this._parseLineAddress(ctx.hash); |
| 1610 | if (address) { |
| 1611 | params.leftSide = address.leftSide; |
| 1612 | params.lineNum = address.lineNum; |
| 1613 | } |
Milutin Kristofic | da88b33 | 2020-03-24 10:19:12 +0100 | [diff] [blame] | 1614 | this.reporting.setRepoName(params.project); |
Milutin Kristofic | 3a84452 | 2021-01-21 10:01:55 +0100 | [diff] [blame] | 1615 | this.reporting.setChangeId(changeNum); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1616 | this._redirectOrNavigate(params); |
| 1617 | } |
| 1618 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1619 | _handleChangeLegacyRoute(ctx: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1620 | // Parameter order is based on the regex group number matched. |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1621 | const params: GenerateUrlLegacyChangeViewParameters = { |
Ben Rohlfs | ebe4acc | 2020-12-11 21:16:10 +0100 | [diff] [blame] | 1622 | changeNum: Number(ctx.params[0]) as NumericChangeId, |
Dhruv Srivastava | 591b490 | 2021-03-10 11:48:12 +0100 | [diff] [blame] | 1623 | basePatchNum: convertToPatchSetNum(ctx.params[3]) as BasePatchSetNum, |
Dhruv Srivastava | e3430e2 | 2020-10-21 22:32:39 +0200 | [diff] [blame] | 1624 | patchNum: convertToPatchSetNum(ctx.params[5]), |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1625 | view: GerritView.CHANGE, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1626 | querystring: ctx.querystring, |
| 1627 | }; |
| 1628 | |
| 1629 | this._normalizeLegacyRouteParams(params); |
| 1630 | } |
| 1631 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1632 | _handleLegacyLinenum(ctx: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1633 | this._redirect(ctx.path.replace(LEGACY_LINENUM_PATTERN, '#$1')); |
| 1634 | } |
| 1635 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1636 | _handleDiffLegacyRoute(ctx: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1637 | // Parameter order is based on the regex group number matched. |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1638 | const params: GenerateUrlLegacyDiffViewParameters = { |
Ben Rohlfs | ebe4acc | 2020-12-11 21:16:10 +0100 | [diff] [blame] | 1639 | changeNum: Number(ctx.params[0]) as NumericChangeId, |
Dhruv Srivastava | 591b490 | 2021-03-10 11:48:12 +0100 | [diff] [blame] | 1640 | basePatchNum: convertToPatchSetNum(ctx.params[2]) as BasePatchSetNum, |
Dhruv Srivastava | e3430e2 | 2020-10-21 22:32:39 +0200 | [diff] [blame] | 1641 | patchNum: convertToPatchSetNum(ctx.params[4]), |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1642 | path: ctx.params[5], |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1643 | view: GerritView.DIFF, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1644 | }; |
| 1645 | |
| 1646 | const address = this._parseLineAddress(ctx.hash); |
| 1647 | if (address) { |
| 1648 | params.leftSide = address.leftSide; |
| 1649 | params.lineNum = address.lineNum; |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame] | 1650 | } |
Paladox none | 2be2d2a | 2017-07-27 16:36:58 +0000 | [diff] [blame] | 1651 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1652 | this._normalizeLegacyRouteParams(params); |
| 1653 | } |
Wyatt Allen | 089dfb3 | 2017-08-24 17:55:38 -0700 | [diff] [blame] | 1654 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1655 | _handleDiffEditRoute(ctx: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1656 | // Parameter order is based on the regex group number matched. |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1657 | const project = ctx.params[0] as RepoName; |
Milutin Kristofic | 3a84452 | 2021-01-21 10:01:55 +0100 | [diff] [blame] | 1658 | const changeNum = Number(ctx.params[1]) as NumericChangeId; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1659 | this._redirectOrNavigate({ |
| 1660 | project, |
Milutin Kristofic | 3a84452 | 2021-01-21 10:01:55 +0100 | [diff] [blame] | 1661 | changeNum, |
Dhruv Srivastava | e3430e2 | 2020-10-21 22:32:39 +0200 | [diff] [blame] | 1662 | // for edit view params, patchNum cannot be undefined |
| 1663 | patchNum: convertToPatchSetNum(ctx.params[2])!, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1664 | path: ctx.params[3], |
| 1665 | lineNum: ctx.hash, |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1666 | view: GerritView.EDIT, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1667 | }); |
Milutin Kristofic | da88b33 | 2020-03-24 10:19:12 +0100 | [diff] [blame] | 1668 | this.reporting.setRepoName(project); |
Milutin Kristofic | 3a84452 | 2021-01-21 10:01:55 +0100 | [diff] [blame] | 1669 | this.reporting.setChangeId(changeNum); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1670 | } |
Wyatt Allen | 089dfb3 | 2017-08-24 17:55:38 -0700 | [diff] [blame] | 1671 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1672 | _handleChangeEditRoute(ctx: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1673 | // Parameter order is based on the regex group number matched. |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1674 | const project = ctx.params[0] as RepoName; |
Milutin Kristofic | 3a84452 | 2021-01-21 10:01:55 +0100 | [diff] [blame] | 1675 | const changeNum = Number(ctx.params[1]) as NumericChangeId; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1676 | this._redirectOrNavigate({ |
| 1677 | project, |
Milutin Kristofic | 3a84452 | 2021-01-21 10:01:55 +0100 | [diff] [blame] | 1678 | changeNum, |
Dhruv Srivastava | e3430e2 | 2020-10-21 22:32:39 +0200 | [diff] [blame] | 1679 | patchNum: convertToPatchSetNum(ctx.params[3]), |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1680 | view: GerritView.CHANGE, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1681 | edit: true, |
| 1682 | }); |
Milutin Kristofic | da88b33 | 2020-03-24 10:19:12 +0100 | [diff] [blame] | 1683 | this.reporting.setRepoName(project); |
Milutin Kristofic | 3a84452 | 2021-01-21 10:01:55 +0100 | [diff] [blame] | 1684 | this.reporting.setChangeId(changeNum); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1685 | } |
Wyatt Allen | 089dfb3 | 2017-08-24 17:55:38 -0700 | [diff] [blame] | 1686 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1687 | /** |
| 1688 | * Normalize the patch range params for a the change or diff view and |
| 1689 | * redirect if URL upgrade is needed. |
| 1690 | */ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1691 | _redirectOrNavigate(params: GenerateUrlParameters & PatchRangeParams) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1692 | const needsRedirect = this._normalizePatchRangeParams(params); |
| 1693 | if (needsRedirect) { |
| 1694 | this._redirect(this._generateUrl(params)); |
| 1695 | } else { |
| 1696 | this._setParams(params); |
Dmitrii Filippov | 3fd2b10 | 2019-11-15 16:16:46 +0100 | [diff] [blame] | 1697 | } |
| 1698 | } |
| 1699 | |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1700 | _handleAgreementsRoute() { |
| 1701 | this._redirect('/settings/#Agreements'); |
| 1702 | } |
| 1703 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1704 | _handleNewAgreementsRoute(data: PageContextWithQueryMap) { |
| 1705 | data.params['view'] = GerritView.AGREEMENTS; |
| 1706 | // TODO(TS): create valid object |
| 1707 | this._setParams((data.params as unknown) as AppElementAgreementParam); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1708 | } |
| 1709 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1710 | _handleSettingsLegacyRoute(data: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1711 | // email tokens may contain '+' but no space. |
| 1712 | // The parameter parsing replaces all '+' with a space, |
| 1713 | // undo that to have valid tokens. |
| 1714 | const token = data.params[0].replace(/ /g, '+'); |
| 1715 | this._setParams({ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1716 | view: GerritView.SETTINGS, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1717 | emailToken: token, |
| 1718 | }); |
| 1719 | } |
| 1720 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1721 | _handleSettingsRoute(_: PageContextWithQueryMap) { |
| 1722 | this._setParams({view: GerritView.SETTINGS}); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1723 | } |
| 1724 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1725 | _handleRegisterRoute(ctx: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1726 | this._setParams({justRegistered: true}); |
| 1727 | let path = ctx.params[0] || '/'; |
| 1728 | |
| 1729 | // Prevent redirect looping. |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1730 | if (path.startsWith('/register')) { |
| 1731 | path = '/'; |
| 1732 | } |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1733 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1734 | if (path[0] !== '/') { |
| 1735 | return; |
| 1736 | } |
Dmitrii Filippov | 0049afe | 2020-07-08 14:08:17 +0200 | [diff] [blame] | 1737 | this._redirect(getBaseUrl() + path); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1738 | } |
| 1739 | |
| 1740 | /** |
| 1741 | * Handler for routes that should pass through the router and not be caught |
| 1742 | * by the catchall _handleDefaultRoute handler. |
| 1743 | */ |
| 1744 | _handlePassThroughRoute() { |
Ben Rohlfs | 5ae40eb | 2021-02-11 20:16:22 +0100 | [diff] [blame] | 1745 | windowLocationReload(); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1746 | } |
| 1747 | |
| 1748 | /** |
| 1749 | * URL may sometimes have /+/ encoded to / /. |
| 1750 | * Context: Issue 6888, Issue 7100 |
| 1751 | */ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1752 | _handleImproperlyEncodedPlusRoute(ctx: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1753 | let hash = this._getHashFromCanonicalPath(ctx.canonicalPath); |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1754 | if (hash.length) { |
| 1755 | hash = '#' + hash; |
| 1756 | } |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1757 | this._redirect(`/c/${ctx.params[0]}/+/${ctx.params[1]}${hash}`); |
| 1758 | } |
| 1759 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1760 | _handlePluginScreen(ctx: PageContextWithQueryMap) { |
| 1761 | const view = GerritView.PLUGIN_SCREEN; |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1762 | const plugin = ctx.params[0]; |
| 1763 | const screen = ctx.params[1]; |
| 1764 | this._setParams({view, plugin, screen}); |
| 1765 | } |
| 1766 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1767 | _handleDocumentationSearchRoute(data: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1768 | this._setParams({ |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1769 | view: GerritView.DOCUMENTATION_SEARCH, |
| 1770 | filter: data.params['filter'] || null, |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1771 | }); |
| 1772 | } |
| 1773 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1774 | _handleDocumentationSearchRedirectRoute(data: PageContextWithQueryMap) { |
| 1775 | this._redirect( |
| 1776 | '/Documentation/q/filter:' + encodeURIComponent(data.params[0]) |
| 1777 | ); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1778 | } |
| 1779 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1780 | _handleDocumentationRedirectRoute(data: PageContextWithQueryMap) { |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1781 | if (data.params[1]) { |
Ben Rohlfs | 5ae40eb | 2021-02-11 20:16:22 +0100 | [diff] [blame] | 1782 | windowLocationReload(); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1783 | } else { |
| 1784 | // Redirect /Documentation to /Documentation/index.html |
| 1785 | this._redirect('/Documentation/index.html'); |
| 1786 | } |
| 1787 | } |
| 1788 | |
| 1789 | /** |
| 1790 | * Catchall route for when no other route is matched. |
| 1791 | */ |
| 1792 | _handleDefaultRoute() { |
| 1793 | if (this._isInitialLoad) { |
| 1794 | // Server recognized this route as polygerrit, so we show 404. |
| 1795 | this._show404(); |
| 1796 | } else { |
| 1797 | // Route can be recognized by server, so we pass it to server. |
| 1798 | this._handlePassThroughRoute(); |
| 1799 | } |
| 1800 | } |
| 1801 | |
| 1802 | _show404() { |
| 1803 | // Note: the app's 404 display is tightly-coupled with catching 404 |
| 1804 | // network responses, so we simulate a 404 response status to display it. |
| 1805 | // TODO: Decouple the gr-app error view from network responses. |
Ben Rohlfs | a76c82f | 2021-01-22 22:22:32 +0100 | [diff] [blame] | 1806 | firePageError(new Response('', {status: 404})); |
Dmitrii Filippov | daf0ec9 | 2020-03-17 11:27:28 +0100 | [diff] [blame] | 1807 | } |
| 1808 | } |
| 1809 | |
Dmitrii Filippov | 252cddf | 2020-08-17 16:21:13 +0200 | [diff] [blame] | 1810 | declare global { |
| 1811 | interface HTMLElementTagNameMap { |
| 1812 | 'gr-router': GrRouter; |
| 1813 | } |
| 1814 | } |