Port provisional headers warning to new RequestHeadersView

Screenshot: https://i.imgur.com/P0Rbvjg.png
Bug: 1297533
Change-Id: I0717360a7053a2cd7684cb98277a22e33a32f46c
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/3757783
Commit-Queue: Wolfgang Beyer <[email protected]>
Reviewed-by: Danil Somsikov <[email protected]>
diff --git a/front_end/panels/network/components/RequestHeadersView.css b/front_end/panels/network/components/RequestHeadersView.css
index 36693ea..200ebc4 100644
--- a/front_end/panels/network/components/RequestHeadersView.css
+++ b/front_end/panels/network/components/RequestHeadersView.css
@@ -161,6 +161,10 @@
   padding: 2px 0; /* adjust focus ring size */
 }
 
+.explanation .link {
+  font-weight: normal;
+}
+
 .inline-icon {
   vertical-align: middle;
 }
diff --git a/front_end/panels/network/components/RequestHeadersView.ts b/front_end/panels/network/components/RequestHeadersView.ts
index e422f8c..c6d9852 100644
--- a/front_end/panels/network/components/RequestHeadersView.ts
+++ b/front_end/panels/network/components/RequestHeadersView.ts
@@ -74,6 +74,19 @@
   onlyChooseThisOptionIfAn:
       'Only choose this option if an arbitrary website including this resource does not impose a security risk.',
   /**
+  *@description Message to explain lack of raw headers for a particular network request
+  */
+  provisionalHeadersAreShownDisableCache: 'Provisional headers are shown. Disable cache to see full headers.',
+  /**
+  *@description Tooltip to explain lack of raw headers for a particular network request
+  */
+  onlyProvisionalHeadersAre:
+      'Only provisional headers are available because this request was not sent over the network and instead was served from a local cache, which doesn’t store the original request headers. Disable cache to see full request headers.',
+  /**
+  *@description Message to explain lack of raw headers for a particular network request
+  */
+  provisionalHeadersAreShown: 'Provisional headers are shown.',
+  /**
   *@description Text in Request Headers View of the Network panel
   */
   referrerPolicy: 'Referrer Policy',
@@ -289,12 +302,44 @@
       >
         ${(this.#showRequestHeadersText && requestHeadersText) ?
             this.#renderRawHeaders(requestHeadersText, false) : html`
+          ${this.#maybeRenderProvisionalHeadersWarning()}
           ${headers.map(header => this.#renderHeader({...header, headerNotSet: false}))}
         `}
       </${Category.litTagName}>
     `;
   }
 
+  #maybeRenderProvisionalHeadersWarning(): LitHtml.LitTemplate {
+    assertNotNullOrUndefined(this.#request);
+    if (this.#request.requestHeadersText() !== undefined) {
+      return LitHtml.nothing;
+    }
+
+    let cautionText;
+    let cautionTitle = '';
+    if (this.#request.cachedInMemory() || this.#request.cached()) {
+      cautionText = i18nString(UIStrings.provisionalHeadersAreShownDisableCache);
+      cautionTitle = i18nString(UIStrings.onlyProvisionalHeadersAre);
+    } else {
+      cautionText = i18nString(UIStrings.provisionalHeadersAreShown);
+    }
+    return html`
+      <div class="call-to-action">
+        <div class="call-to-action-body">
+          <div class="explanation" title=${cautionTitle}>
+            <${IconButton.Icon.Icon.litTagName} class="inline-icon" .data=${{
+              iconName: 'warning_icon',
+              width: '12px',
+              height: '12px',
+              } as IconButton.Icon.IconData}>
+            </${IconButton.Icon.Icon.litTagName}>
+            ${cautionText} <x-link href="https://developer.chrome.com/docs/devtools/network/reference/#provisional-headers" class="link">${i18nString(UIStrings.learnMore)}</x-link>
+          </div>
+        </div>
+      </div>
+    `;
+  }
+
   #renderHeader(header: HeaderDescriptor): LitHtml.TemplateResult {
     return html`
       <div class="row">
@@ -310,20 +355,18 @@
       return LitHtml.nothing;
     }
     return html`
-      <div class="header-details">
-        <div class="call-to-action">
-          <div class="call-to-action-body">
-            <div class="explanation">${headerDetails.explanation()}</div>
-            ${headerDetails.examples.map(example => html`
-              <div class="example">
-                <code>${example.codeSnippet}</code>
-                ${example.comment ? html`
-                  <span class="comment">${example.comment()}</span>
-                ` : ''}
-              </div>
-            `)}
-            ${this.#maybeRenderHeaderDetailsLink(headerDetails)}
-          </div>
+      <div class="call-to-action">
+        <div class="call-to-action-body">
+          <div class="explanation">${headerDetails.explanation()}</div>
+          ${headerDetails.examples.map(example => html`
+            <div class="example">
+              <code>${example.codeSnippet}</code>
+              ${example.comment ? html`
+                <span class="comment">${example.comment()}</span>
+              ` : ''}
+            </div>
+          `)}
+          ${this.#maybeRenderHeaderDetailsLink(headerDetails)}
         </div>
       </div>
     `;