Wolfgang Beyer | 760462e | 2020-07-13 15:01:35 | [diff] [blame] | 1 | // Copyright 2020 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Wolfgang Beyer | 309863f | 2021-01-21 09:01:21 | [diff] [blame] | 5 | /* eslint-disable rulesdir/no_underscored_properties */ |
| 6 | |
Wolfgang Beyer | 92395c9 | 2021-02-02 10:43:23 | [diff] [blame] | 7 | import type * as Components from '../ui/components/components.js'; |
| 8 | |
Wolfgang Beyer | 2ed11a4 | 2020-09-30 07:24:54 | [diff] [blame] | 9 | import * as Bindings from '../bindings/bindings.js'; |
Sigurd Schneider | 1e5ad28 | 2020-07-17 11:52:08 | [diff] [blame] | 10 | import * as Common from '../common/common.js'; |
Wolfgang Beyer | 92395c9 | 2021-02-02 10:43:23 | [diff] [blame] | 11 | import * as LitHtml from '../third_party/lit-html/lit-html.js'; |
Sigurd Schneider | fc2bd21 | 2020-08-12 12:58:41 | [diff] [blame] | 12 | import * as Network from '../network/network.js'; |
Wolfgang Beyer | 1525b1f | 2021-02-02 14:12:30 | [diff] [blame^] | 13 | import * as Platform from '../platform/platform.js'; |
Wolfgang Beyer | 95951c4d | 2020-10-23 08:00:06 | [diff] [blame] | 14 | import * as Root from '../root/root.js'; |
Wolfgang Beyer | 760462e | 2020-07-13 15:01:35 | [diff] [blame] | 15 | import * as SDK from '../sdk/sdk.js'; // eslint-disable-line no-unused-vars |
| 16 | import * as UI from '../ui/ui.js'; |
Sigurd Schneider | 1e5ad28 | 2020-07-17 11:52:08 | [diff] [blame] | 17 | import * as Workspace from '../workspace/workspace.js'; |
Wolfgang Beyer | 1525b1f | 2021-02-02 14:12:30 | [diff] [blame^] | 18 | import {ls} from '../platform/platform.js'; |
Wolfgang Beyer | 760462e | 2020-07-13 15:01:35 | [diff] [blame] | 19 | |
Wolfgang Beyer | 309863f | 2021-01-21 09:01:21 | [diff] [blame] | 20 | const booleanToYesNo = (b: boolean): Common.UIString.LocalizedString => b ? ls`Yes` : ls`No`; |
Sigurd Schneider | aef2982 | 2020-08-20 14:01:13 | [diff] [blame] | 21 | |
Sigurd Schneider | 1e5ad28 | 2020-07-17 11:52:08 | [diff] [blame] | 22 | export class FrameDetailsView extends UI.ThrottledWidget.ThrottledWidget { |
Wolfgang Beyer | 92395c9 | 2021-02-02 10:43:23 | [diff] [blame] | 23 | private readonly reportView = new FrameDetailsReportView(); |
| 24 | |
Wolfgang Beyer | 309863f | 2021-01-21 09:01:21 | [diff] [blame] | 25 | _protocolMonitorExperimentEnabled: boolean; |
| 26 | _frame: SDK.ResourceTreeModel.ResourceTreeFrame; |
| 27 | _reportView: UI.ReportView.ReportView; |
Wolfgang Beyer | 309863f | 2021-01-21 09:01:21 | [diff] [blame] | 28 | _isolationSection: UI.ReportView.Section; |
| 29 | _secureContext: HTMLElement; |
| 30 | _crossOriginIsolatedContext: HTMLElement; |
| 31 | _coepPolicy: HTMLElement; |
| 32 | _coopPolicy: HTMLElement; |
| 33 | _apiAvailability: UI.ReportView.Section; |
| 34 | _apiSharedArrayBuffer: HTMLElement; |
| 35 | _apiMeasureMemory: HTMLElement; |
| 36 | _additionalInfo: UI.ReportView.Section|undefined; |
Wolfgang Beyer | 92395c9 | 2021-02-02 10:43:23 | [diff] [blame] | 37 | |
Wolfgang Beyer | 309863f | 2021-01-21 09:01:21 | [diff] [blame] | 38 | constructor(frame: SDK.ResourceTreeModel.ResourceTreeFrame) { |
Wolfgang Beyer | 760462e | 2020-07-13 15:01:35 | [diff] [blame] | 39 | super(); |
Wolfgang Beyer | 95951c4d | 2020-10-23 08:00:06 | [diff] [blame] | 40 | this._protocolMonitorExperimentEnabled = Root.Runtime.experiments.isEnabled('protocolMonitor'); |
Wolfgang Beyer | 31b60b1 | 2020-11-27 13:16:03 | [diff] [blame] | 41 | this.registerRequiredCSS('resources/frameDetailsReportView.css', {enableLegacyPatching: false}); |
Sigurd Schneider | 1e5ad28 | 2020-07-17 11:52:08 | [diff] [blame] | 42 | this._frame = frame; |
Wolfgang Beyer | 5ac564d | 2020-09-28 13:49:35 | [diff] [blame] | 43 | this.contentElement.classList.add('frame-details-container'); |
| 44 | |
Wolfgang Beyer | 92395c9 | 2021-02-02 10:43:23 | [diff] [blame] | 45 | this.contentElement.appendChild(this.reportView); |
| 46 | |
Simon Zünd | 1edfa26 | 2020-12-09 08:30:05 | [diff] [blame] | 47 | // TODO(crbug.com/1156978): Replace UI.ReportView.ReportView with ReportView.ts web component. |
Wolfgang Beyer | 92395c9 | 2021-02-02 10:43:23 | [diff] [blame] | 48 | this._reportView = new UI.ReportView.ReportView(); |
Wolfgang Beyer | 31b60b1 | 2020-11-27 13:16:03 | [diff] [blame] | 49 | this._reportView.registerRequiredCSS('resources/frameDetailsReportView.css', {enableLegacyPatching: false}); |
Wolfgang Beyer | 760462e | 2020-07-13 15:01:35 | [diff] [blame] | 50 | this._reportView.show(this.contentElement); |
Wolfgang Beyer | 5ac564d | 2020-09-28 13:49:35 | [diff] [blame] | 51 | this._reportView.element.classList.add('frame-details-report-container'); |
Wolfgang Beyer | 760462e | 2020-07-13 15:01:35 | [diff] [blame] | 52 | |
Sigurd Schneider | 680531a | 2020-08-19 08:08:51 | [diff] [blame] | 53 | this._isolationSection = this._reportView.appendSection(ls`Security & Isolation`); |
Sigurd Schneider | aef2982 | 2020-08-20 14:01:13 | [diff] [blame] | 54 | this._secureContext = this._isolationSection.appendField(ls`Secure Context`); |
Sigurd Schneider | cea6576 | 2020-10-19 09:47:50 | [diff] [blame] | 55 | this._crossOriginIsolatedContext = this._isolationSection.appendField(ls`Cross-Origin Isolated`); |
Sigurd Schneider | 680531a | 2020-08-19 08:08:51 | [diff] [blame] | 56 | this._coepPolicy = this._isolationSection.appendField(ls`Cross-Origin Embedder Policy`); |
| 57 | this._coopPolicy = this._isolationSection.appendField(ls`Cross-Origin Opener Policy`); |
Sigurd Schneider | 3fa2f7f | 2020-10-19 14:36:02 | [diff] [blame] | 58 | |
| 59 | this._apiAvailability = this._reportView.appendSection(ls`API availablity`); |
| 60 | const summaryRow = this._apiAvailability.appendRow(); |
| 61 | const summaryText = ls`Availability of certain APIs depends on the document being cross-origin isolated.`; |
| 62 | const link = 'https://web.dev/why-coop-coep/'; |
| 63 | summaryRow.appendChild(UI.Fragment.html`<div>${summaryText} ${UI.XLink.XLink.create(link, ls`Learn more`)}</div>`); |
Sigurd Schneider | eabef96 | 2020-11-05 10:51:49 | [diff] [blame] | 64 | this._apiSharedArrayBuffer = this._apiAvailability.appendField(ls`Shared Array Buffers`); |
Sigurd Schneider | 12cf869 | 2021-01-11 15:21:00 | [diff] [blame] | 65 | this._apiMeasureMemory = this._apiAvailability.appendField(ls`Measure Memory`); |
Wolfgang Beyer | 95951c4d | 2020-10-23 08:00:06 | [diff] [blame] | 66 | |
| 67 | if (this._protocolMonitorExperimentEnabled) { |
| 68 | this._additionalInfo = this._reportView.appendSection(ls`Additional Information`); |
| 69 | this._additionalInfo.setTitle( |
| 70 | ls`Additional Information`, |
| 71 | ls`This additional (debugging) information is shown because the 'Protocol Monitor' experiment is enabled.`); |
| 72 | const frameIDField = this._additionalInfo.appendField(ls`Frame ID`); |
| 73 | frameIDField.textContent = frame.id; |
| 74 | } |
Sigurd Schneider | 1e5ad28 | 2020-07-17 11:52:08 | [diff] [blame] | 75 | this.update(); |
| 76 | } |
| 77 | |
Wolfgang Beyer | 309863f | 2021-01-21 09:01:21 | [diff] [blame] | 78 | async doUpdate(): Promise<void> { |
Wolfgang Beyer | 92395c9 | 2021-02-02 10:43:23 | [diff] [blame] | 79 | this.reportView.data = {frame: this._frame}; |
Sigurd Schneider | 680531a | 2020-08-19 08:08:51 | [diff] [blame] | 80 | await this._updateCoopCoepStatus(); |
Sigurd Schneider | aef2982 | 2020-08-20 14:01:13 | [diff] [blame] | 81 | this._updateContextStatus(); |
Sigurd Schneider | eabef96 | 2020-11-05 10:51:49 | [diff] [blame] | 82 | this._updateApiAvailability(); |
Sigurd Schneider | 680531a | 2020-08-19 08:08:51 | [diff] [blame] | 83 | } |
| 84 | |
Wolfgang Beyer | 309863f | 2021-01-21 09:01:21 | [diff] [blame] | 85 | static fillCrossOriginPolicy( |
| 86 | field: HTMLElement, |
| 87 | isEnabled: (value: Protocol.Network.CrossOriginEmbedderPolicyValue| |
| 88 | Protocol.Network.CrossOriginOpenerPolicyValue) => boolean, |
| 89 | info: Protocol.Network.CrossOriginEmbedderPolicyStatus|Protocol.Network.CrossOriginOpenerPolicyStatus|null| |
| 90 | undefined): void { |
Sigurd Schneider | a36cca5 | 2020-10-29 15:36:00 | [diff] [blame] | 91 | if (!info) { |
| 92 | field.textContent = ''; |
| 93 | return; |
| 94 | } |
Sigurd Schneider | 3cc78e2 | 2020-09-18 10:44:13 | [diff] [blame] | 95 | const enabled = isEnabled(info.value); |
| 96 | field.textContent = enabled ? info.value : info.reportOnlyValue; |
| 97 | if (!enabled && isEnabled(info.reportOnlyValue)) { |
| 98 | const reportOnly = document.createElement('span'); |
| 99 | reportOnly.classList.add('inline-comment'); |
| 100 | reportOnly.textContent = 'report-only'; |
| 101 | field.appendChild(reportOnly); |
| 102 | } |
| 103 | const endpoint = enabled ? info.reportingEndpoint : info.reportOnlyReportingEndpoint; |
| 104 | if (endpoint) { |
| 105 | const reportingEndpointPrefix = field.createChild('span', 'inline-name'); |
| 106 | reportingEndpointPrefix.textContent = ls`reporting to`; |
Wolfgang Beyer | 9a64fc6 | 2020-10-06 14:54:43 | [diff] [blame] | 107 | const reportingEndpointName = field.createChild('span'); |
Sigurd Schneider | 3cc78e2 | 2020-09-18 10:44:13 | [diff] [blame] | 108 | reportingEndpointName.textContent = endpoint; |
| 109 | } |
| 110 | } |
| 111 | |
Wolfgang Beyer | 309863f | 2021-01-21 09:01:21 | [diff] [blame] | 112 | async _updateCoopCoepStatus(): Promise<void> { |
Sigurd Schneider | 5a5b735 | 2020-10-05 11:13:05 | [diff] [blame] | 113 | const model = this._frame.resourceTreeModel().target().model(SDK.NetworkManager.NetworkManager); |
| 114 | const info = model && await model.getSecurityIsolationStatus(this._frame.id); |
Sigurd Schneider | 3cc78e2 | 2020-09-18 10:44:13 | [diff] [blame] | 115 | if (!info) { |
| 116 | return; |
| 117 | } |
Wolfgang Beyer | 309863f | 2021-01-21 09:01:21 | [diff] [blame] | 118 | const coepIsEnabled = |
| 119 | (value: Protocol.Network.CrossOriginEmbedderPolicyValue|Protocol.Network.CrossOriginOpenerPolicyValue): |
| 120 | boolean => value !== Protocol.Network.CrossOriginEmbedderPolicyValue.None; |
Sigurd Schneider | 3cc78e2 | 2020-09-18 10:44:13 | [diff] [blame] | 121 | FrameDetailsView.fillCrossOriginPolicy(this._coepPolicy, coepIsEnabled, info.coep); |
Tim van der Lippe | d7cfd14 | 2021-01-07 12:17:24 | [diff] [blame] | 122 | this._isolationSection.setFieldVisible(ls`Cross-Origin Embedder Policy`, Boolean(info.coep)); |
Sigurd Schneider | a36cca5 | 2020-10-29 15:36:00 | [diff] [blame] | 123 | |
Wolfgang Beyer | 309863f | 2021-01-21 09:01:21 | [diff] [blame] | 124 | const coopIsEnabled = |
| 125 | (value: Protocol.Network.CrossOriginEmbedderPolicyValue|Protocol.Network.CrossOriginOpenerPolicyValue): |
| 126 | boolean => value !== Protocol.Network.CrossOriginOpenerPolicyValue.UnsafeNone; |
Sigurd Schneider | 3cc78e2 | 2020-09-18 10:44:13 | [diff] [blame] | 127 | FrameDetailsView.fillCrossOriginPolicy(this._coopPolicy, coopIsEnabled, info.coop); |
Tim van der Lippe | d7cfd14 | 2021-01-07 12:17:24 | [diff] [blame] | 128 | this._isolationSection.setFieldVisible(ls`Cross-Origin Opener Policy`, Boolean(info.coop)); |
Wolfgang Beyer | 760462e | 2020-07-13 15:01:35 | [diff] [blame] | 129 | } |
Sigurd Schneider | f1aba72 | 2020-07-20 09:03:19 | [diff] [blame] | 130 | |
Wolfgang Beyer | 309863f | 2021-01-21 09:01:21 | [diff] [blame] | 131 | _explanationFromSecureContextType(type: Protocol.Page.SecureContextType|null): string|null { |
Sigurd Schneider | aef2982 | 2020-08-20 14:01:13 | [diff] [blame] | 132 | switch (type) { |
| 133 | case Protocol.Page.SecureContextType.Secure: |
| 134 | return null; |
| 135 | case Protocol.Page.SecureContextType.SecureLocalhost: |
| 136 | return ls`Localhost is always a secure context`; |
| 137 | case Protocol.Page.SecureContextType.InsecureAncestor: |
| 138 | return ls`A frame ancestor is an insecure context`; |
| 139 | case Protocol.Page.SecureContextType.InsecureScheme: |
| 140 | return ls`The frame's scheme is insecure`; |
| 141 | } |
| 142 | return null; |
| 143 | } |
| 144 | |
Wolfgang Beyer | 309863f | 2021-01-21 09:01:21 | [diff] [blame] | 145 | _updateContextStatus(): void { |
Sigurd Schneider | aef2982 | 2020-08-20 14:01:13 | [diff] [blame] | 146 | if (this._frame.unreachableUrl()) { |
| 147 | this._isolationSection.setFieldVisible(ls`Secure Context`, false); |
Sigurd Schneider | cea6576 | 2020-10-19 09:47:50 | [diff] [blame] | 148 | this._isolationSection.setFieldVisible(ls`Cross-Origin Isolated`, false); |
Sigurd Schneider | aef2982 | 2020-08-20 14:01:13 | [diff] [blame] | 149 | return; |
| 150 | } |
| 151 | this._isolationSection.setFieldVisible(ls`Secure Context`, true); |
Sigurd Schneider | cea6576 | 2020-10-19 09:47:50 | [diff] [blame] | 152 | this._isolationSection.setFieldVisible(ls`Cross-Origin Isolated`, true); |
| 153 | |
Sigurd Schneider | aef2982 | 2020-08-20 14:01:13 | [diff] [blame] | 154 | this._secureContext.textContent = booleanToYesNo(this._frame.isSecureContext()); |
| 155 | const secureContextExplanation = this._explanationFromSecureContextType(this._frame.getSecureContextType()); |
| 156 | if (secureContextExplanation) { |
Sigurd Schneider | cea6576 | 2020-10-19 09:47:50 | [diff] [blame] | 157 | const secureContextType = this._secureContext.createChild('span', 'inline-comment'); |
Sigurd Schneider | aef2982 | 2020-08-20 14:01:13 | [diff] [blame] | 158 | secureContextType.textContent = secureContextExplanation; |
| 159 | } |
Sigurd Schneider | cea6576 | 2020-10-19 09:47:50 | [diff] [blame] | 160 | this._crossOriginIsolatedContext.textContent = booleanToYesNo(this._frame.isCrossOriginIsolated()); |
Sigurd Schneider | aef2982 | 2020-08-20 14:01:13 | [diff] [blame] | 161 | } |
| 162 | |
Wolfgang Beyer | 309863f | 2021-01-21 09:01:21 | [diff] [blame] | 163 | _updateApiAvailability(): void { |
Sigurd Schneider | eabef96 | 2020-11-05 10:51:49 | [diff] [blame] | 164 | const features = this._frame.getGatedAPIFeatures(); |
Tim van der Lippe | d7cfd14 | 2021-01-07 12:17:24 | [diff] [blame] | 165 | this._apiAvailability.setFieldVisible(ls`Shared Array Buffers`, Boolean(features)); |
Sigurd Schneider | eabef96 | 2020-11-05 10:51:49 | [diff] [blame] | 166 | |
| 167 | if (!features) { |
| 168 | return; |
| 169 | } |
| 170 | const sabAvailable = features.includes(Protocol.Page.GatedAPIFeatures.SharedArrayBuffers); |
| 171 | if (sabAvailable) { |
| 172 | const sabTransferAvailable = features.includes(Protocol.Page.GatedAPIFeatures.SharedArrayBuffersTransferAllowed); |
| 173 | this._apiSharedArrayBuffer.textContent = |
| 174 | sabTransferAvailable ? ls`available, transferable` : ls`available, not transferable`; |
Tim van der Lippe | 420e5e3 | 2020-11-23 16:58:46 | [diff] [blame] | 175 | UI.Tooltip.Tooltip.install( |
| 176 | this._apiSharedArrayBuffer, |
| 177 | sabTransferAvailable ? |
| 178 | ls`SharedArrayBuffer constructor is available and SABs can be transferred via postMessage` : |
| 179 | ls`SharedArrayBuffer constructor is available but SABs cannot be transferred via postMessage`); |
Sigurd Schneider | eabef96 | 2020-11-05 10:51:49 | [diff] [blame] | 180 | if (!this._frame.isCrossOriginIsolated()) { |
| 181 | const reasonHint = this._apiSharedArrayBuffer.createChild('span', 'inline-span'); |
| 182 | reasonHint.textContent = ls`⚠️ will require cross-origin isolated context in the future`; |
| 183 | } |
| 184 | } else { |
| 185 | this._apiSharedArrayBuffer.textContent = ls`unavailable`; |
| 186 | if (!this._frame.isCrossOriginIsolated()) { |
| 187 | const reasonHint = this._apiSharedArrayBuffer.createChild('span', 'inline-comment'); |
| 188 | reasonHint.textContent = ls`requires cross-origin isolated context`; |
| 189 | } |
| 190 | } |
Sigurd Schneider | 12cf869 | 2021-01-11 15:21:00 | [diff] [blame] | 191 | |
| 192 | const measureMemoryAvailable = this._frame.isCrossOriginIsolated(); |
| 193 | UI.Tooltip.Tooltip.install( |
| 194 | this._apiMeasureMemory, |
Sigurd Schneider | bf1327b | 2021-01-22 14:25:48 | [diff] [blame] | 195 | measureMemoryAvailable ? ls`The performance.measureUserAgentSpecificMemory() API is available` : |
| 196 | ls`The performance.measureUserAgentSpecificMemory() API is not available`); |
Sigurd Schneider | 12cf869 | 2021-01-11 15:21:00 | [diff] [blame] | 197 | this._apiMeasureMemory.textContent = ''; |
Sigurd Schneider | 2d4d9af | 2021-01-25 12:12:27 | [diff] [blame] | 198 | const status = measureMemoryAvailable ? ls`available` : ls`unavailable`; |
Sigurd Schneider | 12cf869 | 2021-01-11 15:21:00 | [diff] [blame] | 199 | const link = 'https://web.dev/monitor-total-page-memory-usage/'; |
| 200 | this._apiMeasureMemory.appendChild( |
| 201 | UI.Fragment.html`<div>${status} ${UI.XLink.XLink.create(link, ls`Learn more`)}</div>`); |
Sigurd Schneider | eabef96 | 2020-11-05 10:51:49 | [diff] [blame] | 202 | } |
Wolfgang Beyer | 760462e | 2020-07-13 15:01:35 | [diff] [blame] | 203 | } |
Wolfgang Beyer | 3b4747f | 2020-08-12 07:30:46 | [diff] [blame] | 204 | |
Wolfgang Beyer | 92395c9 | 2021-02-02 10:43:23 | [diff] [blame] | 205 | export interface FrameDetailsReportViewData { |
| 206 | frame: SDK.ResourceTreeModel.ResourceTreeFrame; |
| 207 | } |
| 208 | |
| 209 | export class FrameDetailsReportView extends HTMLElement { |
| 210 | private readonly shadow = this.attachShadow({mode: 'open'}); |
| 211 | private frame?: SDK.ResourceTreeModel.ResourceTreeFrame; |
| 212 | |
| 213 | set data(data: FrameDetailsReportViewData) { |
| 214 | this.frame = data.frame; |
| 215 | this.render(); |
| 216 | } |
| 217 | |
| 218 | private async render(): Promise<void> { |
| 219 | if (!this.frame) { |
| 220 | return; |
| 221 | } |
| 222 | |
| 223 | // Disabled until https://crbug.com/1079231 is fixed. |
| 224 | // clang-format off |
| 225 | LitHtml.render(LitHtml.html` |
Wolfgang Beyer | 1525b1f | 2021-02-02 14:12:30 | [diff] [blame^] | 226 | <style> |
| 227 | .text-ellipsis { |
| 228 | overflow: hidden; |
| 229 | text-overflow: ellipsis; |
| 230 | white-space: nowrap; |
| 231 | } |
| 232 | |
| 233 | button ~ .text-ellipsis { |
| 234 | padding-left: 2px; |
| 235 | } |
| 236 | |
| 237 | .link { |
| 238 | color: var(--color-link); |
| 239 | text-decoration: underline; |
| 240 | cursor: pointer; |
| 241 | padding: 2px 0; /* adjust focus ring size */ |
| 242 | } |
| 243 | |
| 244 | button.link { |
| 245 | border: none; |
| 246 | background: none; |
| 247 | font-family: inherit; |
| 248 | font-size: inherit; |
| 249 | } |
| 250 | |
| 251 | .inline-items { |
| 252 | display: flex; |
| 253 | } |
| 254 | </style> |
Wolfgang Beyer | 92395c9 | 2021-02-02 10:43:23 | [diff] [blame] | 255 | <devtools-report .data=${{reportTitle: this.frame.displayName()} as Components.ReportView.ReportData}> |
Wolfgang Beyer | 1525b1f | 2021-02-02 14:12:30 | [diff] [blame^] | 256 | ${this.renderDocumentSection()} |
Wolfgang Beyer | 92395c9 | 2021-02-02 10:43:23 | [diff] [blame] | 257 | </devtools-report> |
| 258 | `, this.shadow); |
| 259 | // clang-format on |
| 260 | } |
Wolfgang Beyer | 1525b1f | 2021-02-02 14:12:30 | [diff] [blame^] | 261 | |
| 262 | private renderDocumentSection(): LitHtml.TemplateResult|{} { |
| 263 | if (!this.frame) { |
| 264 | return LitHtml.nothing; |
| 265 | } |
| 266 | |
| 267 | return LitHtml.html` |
| 268 | <devtools-report-section-header>${ls`Document`}</devtools-report-section-header> |
| 269 | <devtools-report-key>${ls`URL`}</devtools-report-key> |
| 270 | <devtools-report-value> |
| 271 | <div class="inline-items"> |
| 272 | ${this.maybeRenderSourcesLinkForURL()} |
| 273 | ${this.maybeRenderNetworkLinkForURL()} |
| 274 | <div class="text-ellipsis" title=${this.frame.url}>${this.frame.url}</div> |
| 275 | </div> |
| 276 | </devtools-report-value> |
| 277 | ${this.maybeRenderUnreachableURL()} |
| 278 | ${this.maybeRenderOrigin()} |
| 279 | ${LitHtml.Directives.until(this.renderOwnerElement(), LitHtml.nothing)} |
| 280 | ${this.maybeRenderAdStatus()} |
| 281 | <devtools-report-divider></devtools-report-divider> |
| 282 | `; |
| 283 | } |
| 284 | |
| 285 | private maybeRenderSourcesLinkForURL(): LitHtml.TemplateResult|{} { |
| 286 | if (!this.frame || this.frame.unreachableUrl()) { |
| 287 | return LitHtml.nothing; |
| 288 | } |
| 289 | const sourceCode = this.uiSourceCodeForFrame(this.frame); |
| 290 | return this.renderIconLink( |
| 291 | 'sources_panel_icon', |
| 292 | ls`Click to reveal in Sources panel`, |
| 293 | (): Promise<void> => Common.Revealer.reveal(sourceCode), |
| 294 | ); |
| 295 | } |
| 296 | |
| 297 | private maybeRenderNetworkLinkForURL(): LitHtml.TemplateResult|{} { |
| 298 | if (this.frame) { |
| 299 | const resource = this.frame.resourceForURL(this.frame.url); |
| 300 | if (resource && resource.request) { |
| 301 | const request = resource.request; |
| 302 | return this.renderIconLink( |
| 303 | 'network_panel_icon', |
| 304 | ls`Click to reveal in Network panel`, |
| 305 | (): Promise<void> => |
| 306 | Network.NetworkPanel.NetworkPanel.selectAndShowRequest(request, Network.NetworkItemView.Tabs.Headers), |
| 307 | ); |
| 308 | } |
| 309 | } |
| 310 | return LitHtml.nothing; |
| 311 | } |
| 312 | |
| 313 | private renderIconLink( |
| 314 | iconName: string, title: Platform.UIString.LocalizedString, |
| 315 | clickHandler: (() => void)|(() => Promise<void>)): LitHtml.TemplateResult { |
| 316 | // Disabled until https://crbug.com/1079231 is fixed. |
| 317 | // clang-format off |
| 318 | return LitHtml.html` |
| 319 | <button class="link" role="link" tabindex=0 @click=${clickHandler} title=${title}> |
| 320 | <devtools-icon .data=${{ |
| 321 | iconName: iconName, |
| 322 | color: 'var(--color-primary)', |
| 323 | width: '16px', |
| 324 | height: '16px', |
| 325 | } as Components.Icon.IconData}> |
| 326 | </button> |
| 327 | `; |
| 328 | // clang-format on |
| 329 | } |
| 330 | |
| 331 | private uiSourceCodeForFrame(frame: SDK.ResourceTreeModel.ResourceTreeFrame): Workspace.UISourceCode.UISourceCode |
| 332 | |null { |
| 333 | for (const project of Workspace.Workspace.WorkspaceImpl.instance().projects()) { |
| 334 | const projectTarget = Bindings.NetworkProject.NetworkProject.getTargetForProject(project); |
| 335 | if (projectTarget && projectTarget === frame.resourceTreeModel().target()) { |
| 336 | const uiSourceCode = project.uiSourceCodeForURL(frame.url); |
| 337 | if (uiSourceCode) { |
| 338 | return uiSourceCode; |
| 339 | } |
| 340 | } |
| 341 | } |
| 342 | return null; |
| 343 | } |
| 344 | |
| 345 | private maybeRenderUnreachableURL(): LitHtml.TemplateResult|{} { |
| 346 | if (!this.frame || !this.frame.unreachableUrl()) { |
| 347 | return LitHtml.nothing; |
| 348 | } |
| 349 | return LitHtml.html` |
| 350 | <devtools-report-key>${ls`Unreachable URL`}</devtools-report-key> |
| 351 | <devtools-report-value> |
| 352 | <div class="inline-items"> |
| 353 | ${this.renderNetworkLinkForUnreachableURL()} |
| 354 | <div class="text-ellipsis" title=${this.frame.unreachableUrl()}>${this.frame.unreachableUrl()}</div> |
| 355 | </div> |
| 356 | </devtools-report-value> |
| 357 | `; |
| 358 | } |
| 359 | |
| 360 | private renderNetworkLinkForUnreachableURL(): LitHtml.TemplateResult|{} { |
| 361 | if (this.frame) { |
| 362 | const unreachableUrl = Common.ParsedURL.ParsedURL.fromString(this.frame.unreachableUrl()); |
| 363 | if (unreachableUrl) { |
| 364 | return this.renderIconLink( |
| 365 | 'network_panel_icon', |
| 366 | ls`Click to reveal in Network panel (might require page reload)`, |
| 367 | (): |
| 368 | void => { |
| 369 | Network.NetworkPanel.NetworkPanel.revealAndFilter([ |
| 370 | { |
| 371 | filterType: 'domain', |
| 372 | filterValue: unreachableUrl.domain(), |
| 373 | }, |
| 374 | { |
| 375 | filterType: null, |
| 376 | filterValue: unreachableUrl.path, |
| 377 | }, |
| 378 | ]); |
| 379 | }, |
| 380 | ); |
| 381 | } |
| 382 | } |
| 383 | return LitHtml.nothing; |
| 384 | } |
| 385 | |
| 386 | private maybeRenderOrigin(): LitHtml.TemplateResult|{} { |
| 387 | if (this.frame && this.frame.securityOrigin && this.frame.securityOrigin !== '://') { |
| 388 | return LitHtml.html` |
| 389 | <devtools-report-key>${ls`Origin`}</devtools-report-key> |
| 390 | <devtools-report-value> |
| 391 | <div class="text-ellipsis" title=${this.frame.securityOrigin}>${this.frame.securityOrigin}</div> |
| 392 | </devtools-report-value> |
| 393 | `; |
| 394 | } |
| 395 | return LitHtml.nothing; |
| 396 | } |
| 397 | |
| 398 | private async renderOwnerElement(): Promise<LitHtml.TemplateResult|{}> { |
| 399 | if (this.frame) { |
| 400 | const openerFrame = this.frame instanceof SDK.ResourceTreeModel.ResourceTreeFrame ? |
| 401 | this.frame : |
| 402 | SDK.FrameManager.FrameManager.instance().getFrame(this.frame); |
| 403 | if (openerFrame) { |
| 404 | const linkTargetDOMNode = await openerFrame.getOwnerDOMNodeOrDocument(); |
| 405 | if (linkTargetDOMNode) { |
| 406 | // Disabled until https://crbug.com/1079231 is fixed. |
| 407 | // clang-format off |
| 408 | return LitHtml.html` |
| 409 | <style> |
| 410 | .button-icon-with-text { |
| 411 | vertical-align: sub; |
| 412 | } |
| 413 | </style> |
| 414 | <devtools-report-key>${ls`Owner Element`}</devtools-report-key> |
| 415 | <devtools-report-value> |
| 416 | <button class="link" role="link" tabindex=0 title=${ls`Click to reveal in Elements panel`} |
| 417 | @mouseenter=${(): Promise<void> => openerFrame.highlight()} |
| 418 | @mouseleave=${(): void => SDK.OverlayModel.OverlayModel.hideDOMNodeHighlight()} |
| 419 | @click=${(): Promise<void> => Common.Revealer.reveal(linkTargetDOMNode)} |
| 420 | > |
| 421 | <devtools-icon class="button-icon-with-text" .data=${{ |
| 422 | iconName: 'elements_panel_icon', |
| 423 | color: 'var(--color-primary)', |
| 424 | width: '16px', |
| 425 | height: '16px', |
| 426 | } as Components.Icon.IconData}></devtools-icon> |
| 427 | <${linkTargetDOMNode.nodeName().toLocaleLowerCase()}> |
| 428 | </a> |
| 429 | </devtools-report-value> |
| 430 | `; |
| 431 | // clang-format on |
| 432 | } |
| 433 | } |
| 434 | } |
| 435 | return LitHtml.nothing; |
| 436 | } |
| 437 | |
| 438 | private maybeRenderAdStatus(): LitHtml.TemplateResult|{} { |
| 439 | if (this.frame) { |
| 440 | if (this.frame.adFrameType() === Protocol.Page.AdFrameType.Root) { |
| 441 | return LitHtml.html` |
| 442 | <devtools-report-key>${ls`Ad Status`}</devtools-report-key> |
| 443 | <devtools-report-value title=${ls`This frame has been identified as the root frame of an ad`}>${ |
| 444 | ls`root`}</devtools-report-value> |
| 445 | `; |
| 446 | } |
| 447 | if (this.frame.adFrameType() === Protocol.Page.AdFrameType.Child) { |
| 448 | return LitHtml.html` |
| 449 | <devtools-report-key>${ls`Ad Status`}</devtools-report-key> |
| 450 | <devtools-report-value title=${ls`This frame has been identified as the a child frame of an ad`}>${ |
| 451 | ls`child`}</devtools-report-value> |
| 452 | `; |
| 453 | } |
| 454 | } |
| 455 | return LitHtml.nothing; |
| 456 | } |
Wolfgang Beyer | 92395c9 | 2021-02-02 10:43:23 | [diff] [blame] | 457 | } |
| 458 | |
| 459 | customElements.define('devtools-resources-frame-details-view', FrameDetailsReportView); |
| 460 | |
| 461 | declare global { |
| 462 | // eslint-disable-next-line @typescript-eslint/no-unused-vars |
| 463 | interface HTMLElementTagNameMap { |
| 464 | 'devtools-resources-frame-details-view': FrameDetailsReportView; |
| 465 | } |
| 466 | } |