Web Inspector: Show Resource Initiator in Network Tab detail views
authorjoepeck@webkit.org <joepeck@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 28 Mar 2019 18:47:05 +0000 (18:47 +0000)
committerjoepeck@webkit.org <joepeck@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 28 Mar 2019 18:47:05 +0000 (18:47 +0000)
https://bugs.webkit.org/show_bug.cgi?id=196316
<rdar://problem/49352679>

Reviewed by Devin Rousso.

* UserInterface/Controllers/NetworkManager.js:
(WI.NetworkManager.prototype.resourceRequestWillBeSent):
(WI.NetworkManager.prototype.resourceRequestWasServedFromMemoryCache):
(WI.NetworkManager.prototype._initiatorCallFramesFromPayload):
Initialize call frames from the initiator payload.

* UserInterface/Models/Resource.js:
(WI.Resource.prototype.get initiatorCallFrames):
Initialization and accessor.

* UserInterface/Views/CallFrameTreeElement.js:
(WI.CallFrameTreeElement):
Selecting a native element won't do anything so just don't allow selection.

* UserInterface/Views/ResourceHeadersContentView.css:
(.resource-headers .go-to-link):
(.resource-headers .call-stack):
(.resource-headers .call-stack:hover):
(@media (prefers-color-scheme: dark)):
* UserInterface/Views/ResourceHeadersContentView.js:
(WI.ResourceHeadersContentView):
(WI.ResourceHeadersContentView.prototype.hidden):
(WI.ResourceHeadersContentView.prototype._refreshSummarySection):
Add an "Initiator" line in the summary with a way to view the whole
initiator backtrace if one exists.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@243614 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/UserInterface/Controllers/NetworkManager.js
Source/WebInspectorUI/UserInterface/Images/CallStack.svg [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Models/Resource.js
Source/WebInspectorUI/UserInterface/Views/CallFrameTreeElement.js
Source/WebInspectorUI/UserInterface/Views/ResourceHeadersContentView.css
Source/WebInspectorUI/UserInterface/Views/ResourceHeadersContentView.js

index 97c277f..0042ac8 100644 (file)
@@ -1,3 +1,37 @@
+2019-03-28  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Web Inspector: Show Resource Initiator in Network Tab detail views
+        https://bugs.webkit.org/show_bug.cgi?id=196316
+        <rdar://problem/49352679>
+
+        Reviewed by Devin Rousso.
+
+        * UserInterface/Controllers/NetworkManager.js:
+        (WI.NetworkManager.prototype.resourceRequestWillBeSent):
+        (WI.NetworkManager.prototype.resourceRequestWasServedFromMemoryCache):
+        (WI.NetworkManager.prototype._initiatorCallFramesFromPayload):
+        Initialize call frames from the initiator payload.
+
+        * UserInterface/Models/Resource.js:
+        (WI.Resource.prototype.get initiatorCallFrames):
+        Initialization and accessor.
+
+        * UserInterface/Views/CallFrameTreeElement.js:
+        (WI.CallFrameTreeElement):
+        Selecting a native element won't do anything so just don't allow selection.
+
+        * UserInterface/Views/ResourceHeadersContentView.css:
+        (.resource-headers .go-to-link):
+        (.resource-headers .call-stack):
+        (.resource-headers .call-stack:hover):
+        (@media (prefers-color-scheme: dark)):
+        * UserInterface/Views/ResourceHeadersContentView.js:
+        (WI.ResourceHeadersContentView):
+        (WI.ResourceHeadersContentView.prototype.hidden):
+        (WI.ResourceHeadersContentView.prototype._refreshSummarySection):
+        Add an "Initiator" line in the summary with a way to view the whole
+        initiator backtrace if one exists.
+
 2019-03-26  Devin Rousso  <drousso@apple.com>
 
         Web Inspector: Sources: fix typo in CSS selector to always show add breakpoint button
index 2877240..59bfe8c 100644 (file)
@@ -306,6 +306,7 @@ WI.NetworkManager = class NetworkManager extends WI.Object
             requestData: request.postData,
             requestSentTimestamp: elapsedTime,
             requestSentWalltime: walltime,
+            initiatorCallFrames: this._initiatorCallFramesFromPayload(initiator),
             initiatorSourceCodeLocation: this._initiatorSourceCodeLocationFromPayload(initiator),
             initiatorNode: this._initiatorNodeFromPayload(initiator),
             originalRequestWillBeSentTimestamp,
@@ -450,6 +451,7 @@ WI.NetworkManager = class NetworkManager extends WI.Object
             requestIdentifier,
             requestMethod: "GET",
             requestSentTimestamp: elapsedTime,
+            initiatorCallFrames: this._initiatorCallFramesFromPayload(initiator),
             initiatorSourceCodeLocation: this._initiatorSourceCodeLocationFromPayload(initiator),
             initiatorNode: this._initiatorNodeFromPayload(initiator),
         });
@@ -762,6 +764,18 @@ WI.NetworkManager = class NetworkManager extends WI.Object
         target.addResource(resource);
     }
 
+    _initiatorCallFramesFromPayload(initiatorPayload)
+    {
+        if (!initiatorPayload)
+            return null;
+
+        let callFrames = initiatorPayload.stackTrace;
+        if (!callFrames)
+            return null;
+        
+        return callFrames.map((payload) => WI.CallFrame.fromPayload(WI.assumingMainTarget(), payload));
+    }
+
     _initiatorSourceCodeLocationFromPayload(initiatorPayload)
     {
         if (!initiatorPayload)
diff --git a/Source/WebInspectorUI/UserInterface/Images/CallStack.svg b/Source/WebInspectorUI/UserInterface/Images/CallStack.svg
new file mode 100644 (file)
index 0000000..ab5ff64
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright © 2019 Apple Inc. All rights reserved. -->
+<svg xmlns="http://www.w3.org/2000/svg" id="root" version="1.1" viewBox="0 0 16 13">
+    <path fill="currentColor" d="M 13 1 L 3 1 C 1.898438 1 1 1.898438 1 3 L 1 10 C 1 11.101562 1.898438 12 3 12 L 13 12 C 14.101562 12 15 11.101562 15 10 L 15 3 C 15 1.898438 14.101562 1 13 1 M 13 2 C 13.550781 2 14 2.449219 14 3 L 14 10 C 14 10.550781 13.550781 11 13 11 L 3 11 C 2.449219 11 2 10.550781 2 10 L 2 3 C 2 2.449219 2.449219 2 3 2 L 13 2"/>
+    <path fill="currentColor" d="M 12 6 L 7 6 L 7 4 L 12 4 Z"/>
+    <path fill="currentColor" d="M 12 9 L 7 9 L 7 7 L 12 7 Z"/>
+    <path fill="currentColor" fill-opacity="0.7" d="M 6 9 L 4 9 L 4 4 L 6 4 Z"/>
+</svg>
index fda06c2..dc75208 100644 (file)
@@ -26,7 +26,7 @@
 
 WI.Resource = class Resource extends WI.SourceCode
 {
-    constructor(url, {mimeType, type, loaderIdentifier, targetId, requestIdentifier, requestMethod, requestHeaders, requestData, requestSentTimestamp, requestSentWalltime, initiatorSourceCodeLocation, initiatorNode, originalRequestWillBeSentTimestamp} = {})
+    constructor(url, {mimeType, type, loaderIdentifier, targetId, requestIdentifier, requestMethod, requestHeaders, requestData, requestSentTimestamp, requestSentWalltime, initiatorCallFrames, initiatorSourceCodeLocation, initiatorNode, originalRequestWillBeSentTimestamp} = {})
     {
         super();
 
@@ -52,6 +52,7 @@ WI.Resource = class Resource extends WI.SourceCode
         this._responseCookies = null;
         this._serverTimingEntries = null;
         this._parentFrame = null;
+        this._initiatorCallFrames = initiatorCallFrames || null;
         this._initiatorSourceCodeLocation = initiatorSourceCodeLocation || null;
         this._initiatorNode = initiatorNode || null;
         this._initiatedResources = [];
@@ -301,6 +302,7 @@ WI.Resource = class Resource extends WI.SourceCode
     get requestIdentifier() { return this._requestIdentifier; }
     get requestMethod() { return this._requestMethod; }
     get requestData() { return this._requestData; }
+    get initiatorCallFrames() { return this._initiatorCallFrames; }
     get initiatorSourceCodeLocation() { return this._initiatorSourceCodeLocation; }
     get initiatorNode() { return this._initiatorNode; }
     get initiatedResources() { return this._initiatedResources; }
index 2ba42be..638b660 100644 (file)
@@ -44,6 +44,7 @@ WI.CallFrameTreeElement = class CallFrameTreeElement extends WI.GeneralTreeEleme
 
         if (this._callFrame.nativeCode || !this._callFrame.sourceCodeLocation) {
             this.subtitle = "";
+            this.selectable = false;
             return;
         }
 
index 601f8c3..047e7b6 100644 (file)
@@ -47,3 +47,32 @@ body[dir] .resource-headers > section:matches(.redirect, .headers) > .details {
 .resource-headers .h2-pseudo-header > .key {
     color: var(--network-pseudo-header-color);
 }
+
+.resource-headers .go-to-link {
+    -webkit-user-select: text;
+}
+
+.resource-headers .pair.initiator > .value {
+    display: inline-flex;
+    align-items: center;
+}
+
+.resource-headers .call-stack {
+    position: relative;
+    width: 16px;
+    height: 13px;
+    margin-left: 3px;
+    content: url(../Images/CallStack.svg);
+    opacity: 0.5;
+    -webkit-user-select: none;
+}
+
+.resource-headers .call-stack:hover {
+    opacity: 0.8;
+}
+
+@media (prefers-color-scheme: dark) {
+    .resource-headers .call-stack {
+        filter: invert();
+    }
+}
index bcc777f..397bd0f 100644 (file)
@@ -45,6 +45,8 @@ WI.ResourceHeadersContentView = class ResourceHeadersContentView extends WI.Cont
         this._searchIndex = -1;
         this._automaticallyRevealFirstSearchResult = false;
         this._bouncyHighlightElement = null;
+        this._popover = null;
+        this._popoverCallStackIconElement = null;
 
         this._redirectDetailsSections = [];
 
@@ -120,6 +122,14 @@ WI.ResourceHeadersContentView = class ResourceHeadersContentView extends WI.Cont
         }
     }
 
+    hidden()
+    {
+        super.hidden();
+
+        if (this._popover)
+            this._popover.dismiss();
+    }
+
     closed()
     {
         this._resource.removeEventListener(null, null, this);
@@ -251,6 +261,51 @@ WI.ResourceHeadersContentView = class ResourceHeadersContentView extends WI.Cont
 
         if (this._resource.remoteAddress)
             this._summarySection.appendKeyValuePair(WI.UIString("Address"), this._resource.remoteAddress);
+
+        let initiatorLocation = this._resource.initiatorSourceCodeLocation;
+        if (initiatorLocation) {
+
+            let fragment = document.createDocumentFragment();
+
+            const options = {
+                dontFloat: true,
+                ignoreSearchTab: true,
+            };
+            let link = WI.createSourceCodeLocationLink(initiatorLocation, options);
+            fragment.appendChild(link);
+
+            let callFrames = this._resource.initiatorCallFrames;
+            if (callFrames) {
+                this._popoverCallStackIconElement = document.createElement("img");
+                this._popoverCallStackIconElement.className = "call-stack";
+                fragment.appendChild(this._popoverCallStackIconElement);
+
+                this._popoverCallStackIconElement.addEventListener("click", (event) => {
+                    if (!this._popover) {
+                        this._popover = new WI.Popover(this);
+                        this._popover.windowResizeHandler = () => { this._presentPopoverBelowCallStackElement() };
+                    }
+
+                    const selectable = false;
+                    let callFramesTreeOutline = new WI.TreeOutline(selectable);
+                    callFramesTreeOutline.disclosureButtons = false;
+                    let callFrameTreeController = new WI.CallFrameTreeController(callFramesTreeOutline);
+                    callFrameTreeController.callFrames = callFrames;
+
+                    let popoverContent = document.createElement("div");
+                    popoverContent.appendChild(callFrameTreeController.treeOutline.element);
+                    this._popover.content = popoverContent;
+
+                    this._presentPopoverBelowCallStackElement();
+                });
+            }
+
+            let pair = this._summarySection.appendKeyValuePair(WI.UIString("Initiator"), fragment);
+            pair.classList.add("initiator");
+
+            if (this._popover && this._popover.visible)
+                this._presentPopoverBelowCallStackElement();
+        }
     }
 
     _refreshRedirectHeadersSections()
@@ -468,6 +523,12 @@ WI.ResourceHeadersContentView = class ResourceHeadersContentView extends WI.Cont
         this.element.appendChild(this._bouncyHighlightElement);
     }
 
+    _presentPopoverBelowCallStackElement()
+    {
+        let bounds = WI.Rect.rectFromClientRect(this._popoverCallStackIconElement.getBoundingClientRect());
+        this._popover.present(bounds.pad(2), [WI.RectEdge.MAX_Y, WI.RectEdge.MIN_Y, WI.RectEdge.MAX_X]);
+    }
+
     _resourceMetricsDidChange(event)
     {
         this._needsSummaryRefresh = true;