import*as i18n from"../../../core/i18n/i18n.js";import*as Buttons from"../../../ui/components/buttons/buttons.js";import*as SDK from"../../../core/sdk/sdk.js";import*as LitHtml from"../../../ui/lit-html/lit-html.js";import*as Root from"../../../core/root/root.js";import*as ReportView from"../../../ui/components/report_view/report_view.js";import*as LegacyWrapper from"../../../ui/components/legacy_wrapper/legacy_wrapper.js";import*as IconButton from"../../../ui/components/icon_button/icon_button.js";import*as ComponentHelpers from"../../../ui/components/helpers/helpers.js";import*as Coordinator from"../../../ui/components/render_coordinator/render_coordinator.js";import*as ChromeLink from"../../../ui/components/chrome_link/chrome_link.js";import*as ExpandableList from"../../../ui/components/expandable_list/expandable_list.js";import*as TreeOutline from"../../../ui/components/tree_outline/tree_outline.js";import{NotRestoredReasonDescription}from"./BackForwardCacheStrings.js";import backForwardCacheViewStyles from"./backForwardCacheView.css.js";const UIStrings={mainFrame:"Main Frame",backForwardCacheTitle:"Back/forward cache",unavailable:"unavailable",url:"URL:",unknown:"Unknown Status",normalNavigation:"Not served from back/forward cache: to trigger back/forward cache, use Chrome's back/forward buttons, or use the test button below to automatically navigate away and back.",restoredFromBFCache:"Successfully served from back/forward cache.",pageSupportNeeded:"Actionable",pageSupportNeededExplanation:"These reasons are actionable i.e. they can be cleaned up to make the page eligible for back/forward cache.",circumstantial:"Not Actionable",circumstantialExplanation:"These reasons are not actionable i.e. caching was prevented by something outside of the direct control of the page.",supportPending:"Pending Support",runTest:"Test back/forward cache",runningTest:"Running test",learnMore:"Learn more: back/forward cache eligibility",neverUseUnload:"Learn more: Never use unload handler",supportPendingExplanation:"Chrome support for these reasons is pending i.e. they will not prevent the page from being eligible for back/forward cache in a future version of Chrome.",blockingExtensionId:"Extension id: ",framesTitle:"Frames",issuesInSingleFrame:"{n, plural, =1 {# issue found in 1 frame.} other {# issues found in 1 frame.}}",issuesInMultipleFrames:"{n, plural, =1 {# issue found in {m} frames.} other {# issues found in {m} frames.}}",framesPerIssue:"{n, plural, =1 {# frame} other {# frames}}",blankURLTitle:"Blank URL [{PH1}]"},str_=i18n.i18n.registerUIStrings("panels/application/components/BackForwardCacheView.ts",UIStrings),i18nString=i18n.i18n.getLocalizedString.bind(void 0,str_),coordinator=Coordinator.RenderCoordinator.RenderCoordinator.instance();export class BackForwardCacheView extends LegacyWrapper.LegacyWrapper.WrappableComponent{static litTagName=LitHtml.literal`devtools-resources-back-forward-cache-view`;#e=this.attachShadow({mode:"open"});#t="Result";#r=0;#n=0;constructor(){super(),this.#a()?.addEventListener(SDK.ResourceTreeModel.Events.PrimaryPageChanged,this.render,this),this.#a()?.addEventListener(SDK.ResourceTreeModel.Events.BackForwardCacheDetailsUpdated,this.render,this)}#a(){const e=SDK.TargetManager.TargetManager.instance().primaryPageTarget();return e?.model(SDK.ResourceTreeModel.ResourceTreeModel)||null}#i(){return this.#a()?.mainFrame||null}connectedCallback(){this.parentElement?.classList.add("overflow-auto"),this.#e.adoptedStyleSheets=[backForwardCacheViewStyles]}async render(){await coordinator.write("BackForwardCacheView render",(()=>{LitHtml.render(LitHtml.html`
        <${ReportView.ReportView.Report.litTagName} .data=${{reportTitle:i18nString(UIStrings.backForwardCacheTitle)}}>
          ${this.#o()}
        </${ReportView.ReportView.Report.litTagName}>
      `,this.#e,{host:this})}))}#s(){SDK.TargetManager.TargetManager.instance().removeModelListener(SDK.ResourceTreeModel.ResourceTreeModel,SDK.ResourceTreeModel.Events.FrameNavigated,this.#s,this),this.#t="Result",this.render()}async#l(){SDK.TargetManager.TargetManager.instance().removeModelListener(SDK.ResourceTreeModel.ResourceTreeModel,SDK.ResourceTreeModel.Events.FrameNavigated,this.#l,this),await this.#c(50)}async#c(e){const t=SDK.TargetManager.TargetManager.instance().primaryPageTarget(),r=t?.model(SDK.ResourceTreeModel.ResourceTreeModel),n=await(r?.navigationHistory());r&&n&&(n.currentIndex===this.#n?window.setTimeout(this.#c.bind(this,2*e),e):(SDK.TargetManager.TargetManager.instance().addModelListener(SDK.ResourceTreeModel.ResourceTreeModel,SDK.ResourceTreeModel.Events.FrameNavigated,this.#s,this),r.navigateToHistoryEntry(n.entries[n.currentIndex-1])))}async#d(){const e=SDK.TargetManager.TargetManager.instance().primaryPageTarget(),t=e?.model(SDK.ResourceTreeModel.ResourceTreeModel),r=await(t?.navigationHistory());t&&r&&(this.#n=r.currentIndex,this.#t="Running",this.render(),SDK.TargetManager.TargetManager.instance().addModelListener(SDK.ResourceTreeModel.ResourceTreeModel,SDK.ResourceTreeModel.Events.FrameNavigated,this.#l,this),t.navigate("chrome://terms"))}#o(){const e=this.#i();if(!e)return LitHtml.html`
        <${ReportView.ReportView.ReportKey.litTagName}>
          ${i18nString(UIStrings.mainFrame)}
        </${ReportView.ReportView.ReportKey.litTagName}>
        <${ReportView.ReportView.ReportValue.litTagName}>
          ${i18nString(UIStrings.unavailable)}
        </${ReportView.ReportView.ReportValue.litTagName}>
      `;const t="Running"===this.#t,r=e.url.startsWith("devtools://");return LitHtml.html`
      ${this.#m(e.backForwardCacheDetails.restoredFromCache)}
      <div class="report-line">
        <div class="report-key">
          ${i18nString(UIStrings.url)}
        </div>
        <div class="report-value" title=${e.url}>
          ${e.url}
        </div>
      </div>
      ${this.#p(e.backForwardCacheDetails.explanationsTree)}
      <${ReportView.ReportView.ReportSection.litTagName}>
        <${Buttons.Button.Button.litTagName}
          aria-label=${i18nString(UIStrings.runTest)}
          .disabled=${t||r}
          .spinner=${t}
          .variant=${"primary"}
          @click=${this.#d}>
          ${t?LitHtml.html`
            ${i18nString(UIStrings.runningTest)}`:`\n            ${i18nString(UIStrings.runTest)}\n          `}
        </${Buttons.Button.Button.litTagName}>
      </${ReportView.ReportView.ReportSection.litTagName}>
      <${ReportView.ReportView.ReportSectionDivider.litTagName}>
      </${ReportView.ReportView.ReportSectionDivider.litTagName}>
      ${this.#u(e.backForwardCacheDetails.explanations,e.backForwardCacheDetails.explanationsTree)}
      <${ReportView.ReportView.ReportSection.litTagName}>
        <x-link href="https://web.dev/bfcache/" class="link">
          ${i18nString(UIStrings.learnMore)}
        </x-link>
      </${ReportView.ReportView.ReportSection.litTagName}>
    `}#p(e){if(!e||0===e.explanations.length&&0===e.children.length||!Root.Runtime.experiments.isEnabled("bfcacheDisplayTree"))return LitHtml.nothing;const t=this.#g(e,{blankCount:1});t.node.treeNodeData.iconName="frame";let r="";r=1===t.frameCount?i18nString(UIStrings.issuesInSingleFrame,{n:t.issueCount}):i18nString(UIStrings.issuesInMultipleFrames,{n:t.issueCount,m:t.frameCount});const n={treeNodeData:{text:r},id:"root",children:()=>Promise.resolve([t.node])};return LitHtml.html`
      <div class="report-line">
        <div class="report-key">
          ${i18nString(UIStrings.framesTitle)}
        </div>
        <div class="report-value">
          <${TreeOutline.TreeOutline.TreeOutline.litTagName} .data=${{tree:[n],defaultRenderer:function(e){return LitHtml.html`
        <div class="text-ellipsis">
          ${e.treeNodeData.iconName?LitHtml.html`
            <${IconButton.Icon.Icon.litTagName} class="inline-icon" style="margin-bottom: -3px;" .data=${{iconName:e.treeNodeData.iconName,color:"var(--icon-default)",width:"20px",height:"20px"}}>
            </${IconButton.Icon.Icon.litTagName}>
          `:LitHtml.nothing}
          ${e.treeNodeData.text}
        </div>
      `},compact:!0}}>
          </${TreeOutline.TreeOutline.TreeOutline.litTagName}>
        </div>
      </div>
    `}#g(e,t){let r=1,n=0;const a=[];let i="";e.url.length?i=e.url:(i=i18nString(UIStrings.blankURLTitle,{PH1:t.blankCount}),t.blankCount+=1);for(const t of e.explanations){const e={treeNodeData:{text:t.reason},id:String(this.#r++)};n+=1,a.push(e)}for(const i of e.children){const e=this.#g(i,t);e.issueCount>0&&(a.push(e.node),n+=e.issueCount,r+=e.frameCount)}let o={treeNodeData:{text:`(${n}) ${i}`},id:String(this.#r++)};return a.length?(o={...o,children:()=>Promise.resolve(a)},o.treeNodeData.iconName="iframe"):e.url.length||(t.blankCount-=1),{node:o,frameCount:r,issueCount:n}}#m(e){switch(e){case!0:return LitHtml.html`
          <${ReportView.ReportView.ReportSection.litTagName}>
            <div class="status">
              <${IconButton.Icon.Icon.litTagName} class="inline-icon" .data=${{iconName:"check-circle",color:"var(--icon-checkmark-green)",width:"20px",height:"20px"}}>
              </${IconButton.Icon.Icon.litTagName}>
            </div>
            ${i18nString(UIStrings.restoredFromBFCache)}
          </${ReportView.ReportView.ReportSection.litTagName}>
        `;case!1:return LitHtml.html`
          <${ReportView.ReportView.ReportSection.litTagName}>
            <div class="status">
              <${IconButton.Icon.Icon.litTagName} class="inline-icon" .data=${{iconName:"clear",color:"var(--icon-default)",width:"20px",height:"20px"}}>
              </${IconButton.Icon.Icon.litTagName}>
            </div>
            ${i18nString(UIStrings.normalNavigation)}
          </${ReportView.ReportView.ReportSection.litTagName}>
        `}return LitHtml.html`
    <${ReportView.ReportView.ReportSection.litTagName}>
      ${i18nString(UIStrings.unknown)}
    </${ReportView.ReportView.ReportSection.litTagName}>
    `}#h(e,t,r){let n=e.url;0===n.length&&(n=i18nString(UIStrings.blankURLTitle,{PH1:t.blankCount}),t.blankCount+=1),e.explanations.forEach((e=>{let t=r.get(e.reason);void 0===t?(t=[n],r.set(e.reason,t)):t.push(n)})),e.children.map((e=>{this.#h(e,t,r)}))}#u(e,t){if(0===e.length)return LitHtml.nothing;const r=e.filter((e=>"PageSupportNeeded"===e.type)),n=e.filter((e=>"SupportPending"===e.type)),a=e.filter((e=>"Circumstantial"===e.type)),i=new Map;return t&&this.#h(t,{blankCount:1},i),LitHtml.html`
      ${this.#R(i18nString(UIStrings.pageSupportNeeded),i18nString(UIStrings.pageSupportNeededExplanation),r,i)}
      ${this.#R(i18nString(UIStrings.supportPending),i18nString(UIStrings.supportPendingExplanation),n,i)}
      ${this.#R(i18nString(UIStrings.circumstantial),i18nString(UIStrings.circumstantialExplanation),a,i)}
    `}#R(e,t,r,n){return LitHtml.html`
      ${r.length>0?LitHtml.html`
        <${ReportView.ReportView.ReportSectionHeader.litTagName}>
          ${e}
          <div class="help-outline-icon">
            <${IconButton.Icon.Icon.litTagName} class="inline-icon" .data=${{iconName:"help",color:"var(--icon-default)",width:"16px",height:"16px"}} title=${t}>
            </${IconButton.Icon.Icon.litTagName}>
          </div>
        </${ReportView.ReportView.ReportSectionHeader.litTagName}>
        ${r.map((e=>this.#w(e,n.get(e.reason))))}
      `:LitHtml.nothing}
    `}#T(e){if("EmbedderExtensionSentMessageToCachedFrame"===e.reason&&e.context){const t="chrome://extensions/?id="+e.context;return LitHtml.html`${i18nString(UIStrings.blockingExtensionId)}
      <${ChromeLink.ChromeLink.ChromeLink.litTagName} .href=${t}>${e.context}</${ChromeLink.ChromeLink.ChromeLink.litTagName}>`}return LitHtml.nothing}#S(e){if(void 0===e||0===e.length||!Root.Runtime.experiments.isEnabled("bfcacheDisplayTree"))return LitHtml.nothing;const t=[LitHtml.html`<div>${i18nString(UIStrings.framesPerIssue,{n:e.length})}</div>`];return t.push(...e.map((e=>LitHtml.html`<div class="text-ellipsis" title=${e}>${e}</div>`))),LitHtml.html`
      <div class="explanation-frames">
        <${ExpandableList.ExpandableList.ExpandableList.litTagName} .data=${{rows:t}}></${ExpandableList.ExpandableList.ExpandableList.litTagName}>
      </div>
    `}#v(e){return"UnloadHandlerExistsInMainFrame"===e.reason||"UnloadHandlerExistsInSubFrame"===e.reason?LitHtml.html`
        <x-link href="https://web.dev/bfcache/#never-use-the-unload-event" class="link">
          ${i18nString(UIStrings.neverUseUnload)}
        </x-link>`:LitHtml.nothing}#w(e,t){return LitHtml.html`
      <${ReportView.ReportView.ReportSection.litTagName}>
        ${e.reason in NotRestoredReasonDescription?LitHtml.html`
            <div class="circled-exclamation-icon">
              <${IconButton.Icon.Icon.litTagName} class="inline-icon" .data=${{iconName:"warning",color:"var(--icon-warning)",width:"16px",height:"16px"}}>
              </${IconButton.Icon.Icon.litTagName}>
            </div>
            <div>
              ${NotRestoredReasonDescription[e.reason].name()}
              ${this.#v(e)}
             ${this.#T(e)}
           </div>`:LitHtml.nothing}
      </${ReportView.ReportView.ReportSection.litTagName}>
      <div class="gray-text">
        ${e.reason}
      </div>
      ${this.#S(t)}
    `}}ComponentHelpers.CustomElements.defineComponent("devtools-resources-back-forward-cache-view",BackForwardCacheView);