UNPKG

@react-native/debugger-frontend

Version:
127 lines (126 loc) 33.4 kB
import*as e from"../../core/common/common.js";import*as t from"../../core/host/host.js";import*as r from"../../core/i18n/i18n.js";import*as o from"../../core/platform/platform.js";import*as i from"../../core/root/root.js";import*as n from"../../core/sdk/sdk.js";import*as s from"../../models/bindings/bindings.js";import*as a from"../../models/extensions/extensions.js";import*as c from"../common/common.js";import*as d from"../emulation/emulation.js";import*as l from"../timeline/timeline.js";import*as g from"../../services/tracing/tracing.js";import"../../ui/components/buttons/buttons.js";import*as h from"../../ui/components/helpers/helpers.js";import*as p from"../../ui/legacy/legacy.js";import*as u from"../../ui/lit/lit.js";import*as v from"../../ui/visual_logging/visual_logging.js";import*as m from"./components/components.js";import*as w from"./converters/converters.js";import*as R from"./extensions/extensions.js";import*as y from"./models/models.js";var f={cssText:`*{margin:0;padding:0;box-sizing:border-box;font-size:inherit}*:focus,\n*:focus-visible{outline:none}:host{overflow-x:auto}:host,\ndevtools-recording-view,\ndevtools-create-recording-view{display:flex;flex-direction:column;flex:1;min-height:0}.wrapper{display:flex;flex-direction:column;height:100%}.header{background-color:var(--sys-color-cdt-base-container);display:flex;flex-flow:row wrap;align-items:center;border-bottom:1px solid var(--sys-color-divider);padding:0 5px;gap:3px}.separator{background-color:var(--sys-color-divider);width:1px;height:17px;margin:0}select{appearance:none;user-select:none;border:none;border-radius:var(--sys-shape-corner-extra-small);height:var(--sys-size-9);max-width:140px;min-width:140px;padding:0 var(--sys-size-6) 0 var(--sys-size-5);position:relative;color:var(--sys-color-on-surface);background-color:transparent;text-overflow:ellipsis;background-image:var(--combobox-dropdown-arrow);background-position:right center;background-repeat:no-repeat;&:hover{background-color:var(--sys-color-state-hover-on-subtle)}&:active{background-color:var(--sys-color-state-ripple-neutral-on-subtle)}&:hover:active{background:var(--combobox-dropdown-arrow),linear-gradient(var(--sys-color-state-hover-on-subtle),var(--sys-color-state-hover-on-subtle)),linear-gradient(var(--sys-color-state-ripple-neutral-on-subtle),var(--sys-color-state-ripple-neutral-on-subtle));background-position:right center;background-repeat:no-repeat}&:disabled{pointer-events:none;color:var(--sys-color-state-disabled);background-color:var(--sys-color-state-disabled-container)}&:focus-visible{outline:var(--sys-size-2) solid var(--sys-color-state-focus-ring)}}select option{background-color:var(--sys-color-cdt-base-container);color:var(--sys-color-on-surface)}devtools-menu{width:0;height:0;position:absolute}devtools-recording-list-view{overflow:auto}.error{color:var(--sys-color-error);border:1px solid var(--sys-color-error);background-color:var(--sys-color-error-container);padding:4px}.feedback{margin-left:auto;margin-right:4px}.feedback .x-link{letter-spacing:0.03em;text-decoration-line:underline;font-size:9px;line-height:16px;color:var(--sys-color-on-surface-subtle);outline-offset:3px}.feedback .x-link:focus-visible,\n.empty-state-description .x-link:focus-visible{outline:-webkit-focus-ring-color auto 1px}.empty-state{margin:var(--sys-size-5);display:flex;flex-grow:1;justify-content:center;align-items:center;flex-direction:column;text-align:center;min-height:fit-content;min-width:fit-content;> *{max-width:var(--sys-size-29)}.empty-state-header{font:var(--sys-typescale-headline5);margin-bottom:var(--sys-size-3)}.empty-state-description{font:var(--sys-typescale-body4-regular);color:var(--sys-color-on-surface-subtle);> x-link{white-space:nowrap;margin-left:var(--sys-size-3);cursor:pointer;text-decoration:underline;color:var(--sys-color-primary);outline-offset:var(--sys-size-2)}}> devtools-button{margin-top:var(--sys-size-7)}}\n/*# sourceURL=${import.meta.resolve("./recorderController.css")} */\n`};class S extends Event{static eventName="replayfinished";constructor(){super(S.eventName,{bubbles:!0,composed:!0})}}class x extends Event{recording;static eventName="recordingstatechanged";constructor(e){super(x.eventName,{bubbles:!0,composed:!0}),this.recording=e}}var b=Object.freeze({__proto__:null,RecordingStateChangedEvent:x,ReplayFinishedEvent:S}),P=self&&self.__decorate||function(e,t,r,o){var i,n=arguments.length,s=n<3?t:null===o?o=Object.getOwnPropertyDescriptor(t,r):o;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,o);else for(var a=e.length-1;a>=0;a--)(i=e[a])&&(s=(n<3?i(s):n>3?i(t,r,s):i(t,r))||s);return n>3&&s&&Object.defineProperty(t,r,s),s};const C=new CSSStyleSheet;C.replaceSync(f.cssText);const{html:E,Decorators:k,LitElement:$}=u,{customElement:N,state:T}=k,I={createRecording:"Create recording",importRecording:"Import recording",deleteRecording:"Delete recording",noRecordings:"No recordings",numberOfRecordings:"recording(s)",continueReplay:"Continue",stepOverReplay:"Execute one step",exportRecording:"Export",startStopRecording:"Start/Stop recording",replayRecording:"Replay recording",copyShortcut:"Copy recording or selected step",toggleCode:"Toggle code view",export:"Export",exportViaExtensions:"Export via extensions",getExtensions:"Get extensions…",sendFeedback:"Send feedback",header:"Nothing recorded yet",recordingDescription:"Use recordings to create automated end-to-end tests or performance traces.",learnMore:"Learn more",doYouTrustThisCode:"Do you trust this recording?",doNotImport:"Don't import recordings you do not understand or have not reviewed yourself into DevTools. This could allow attackers to steal your identity or take control of your computer. Please type ''{PH1}'' below to allow importing.",allowImporting:"allow importing",typeAllowImporting:"Type ''{PH1}''"},M=r.i18n.registerUIStrings("panels/recorder/RecorderController.ts",I),F=r.i18n.getLocalizedString.bind(void 0,M),A="get-extensions-link",j={json:2,"@puppeteer/replay":3,puppeteer:1,"puppeteer-firefox":1,lighthouse:5};let B=class extends ${static styles=[C];#e=y.RecordingStorage.RecordingStorage.instance();#t=y.ScreenshotStorage.ScreenshotStorage.instance();#r=!0;#o={isPlaying:!1,isPausedOnBreakpoint:!1};#i;#n;#s=new Set;#a;#c=new y.RecorderSettings.RecorderSettings;#d=new y.RecorderShortcutHelper.RecorderShortcutHelper;#l=e.Settings.Settings.instance().createSetting("disable-recorder-import-warning",!1,"Synced");#g=e.Settings.Settings.instance().createSetting("disable-self-xss-warning",!1,"Synced");constructor(){super(),this.isRecording=!1,this.isToggling=!1,this.exportMenuExpanded=!1,this.currentPage="StartPage",this.#e.getRecordings().length&&this.#h("AllRecordingsPage");const t=e.Settings.Settings.instance().moduleSetting("text-editor-indent").get();this.#a=Object.freeze([new w.JSONConverter.JSONConverter(t),new w.PuppeteerReplayConverter.PuppeteerReplayConverter(t),new w.PuppeteerConverter.PuppeteerConverter(t),new w.PuppeteerFirefoxConverter.PuppeteerFirefoxConverter(t),new w.LighthouseConverter.LighthouseConverter(t)]);const r=R.ExtensionManager.ExtensionManager.instance();this.#p(r.extensions()),r.addEventListener("extensionsUpdated",(e=>{this.#p(e.data)})),this.addEventListener("setrecording",(e=>this.#u(e)))}disconnectedCallback(){super.disconnectedCallback(),this.currentRecordingSession&&this.currentRecordingSession.stop()}#p(e){this.extensionConverters=e.filter((e=>e.getCapabilities().includes("export"))).map(((e,t)=>new w.ExtensionConverter.ExtensionConverter(t,e))),this.replayExtensions=e.filter((e=>e.getCapabilities().includes("replay")))}setIsRecordingStateForTesting(e){this.isRecording=e}setRecordingStateForTesting(e){this.#o.isPlaying=e.isPlaying,this.#o.isPausedOnBreakpoint=e.isPausedOnBreakpoint}setCurrentPageForTesting(e){this.#h(e)}getCurrentPageForTesting(){return this.currentPage}getCurrentRecordingForTesting(){return this.currentRecording}getStepBreakpointIndexesForTesting(){return[...this.#s.values()]}#v(){this.importError=void 0}async#m(t){const r=new e.StringOutputStream.StringOutputStream,o=new s.FileUtils.ChunkedFileReader(t,1e7);if(!await o.read(r))throw o.error()??new Error("Unknown");let i;try{i=y.SchemaUtils.parse(JSON.parse(r.data()))}catch(e){return void(this.importError=e)}this.#w(await this.#e.saveRecording(i)),this.#h("RecordingPage"),this.#v()}setCurrentRecordingForTesting(e){this.#w(e)}getSectionsForTesting(){return this.sections}#w(e,t={}){const{keepBreakpoints:r=!1,updateSession:o=!1}=t;this.recordingPlayer?.abort(),this.currentStep=void 0,this.recordingError=void 0,this.lastReplayResult=void 0,this.recordingPlayer=void 0,this.#o.isPlaying=!1,this.#o.isPausedOnBreakpoint=!1,this.#s=r?this.#s:new Set,e?(this.currentRecording=e,this.sections=y.Section.buildSections(e.flow.steps),this.settings=this.#R(e.flow),o&&this.currentRecordingSession&&this.currentRecordingSession.overwriteUserFlow(e.flow)):(this.currentRecording=void 0,this.sections=void 0,this.settings=void 0),this.#y()}#h(e){e!==this.currentPage&&(this.previousPage=this.currentPage,this.currentPage=e)}#R(e){const t=e.steps,r=t.findIndex((e=>"navigate"===e.type)),o={timeout:e.timeout};for(let e=r-1;e>=0;e--){const r=t[e];if(o.viewportSettings||"setViewport"!==r.type||(o.viewportSettings=r),!o.networkConditionsSettings&&"emulateNetworkConditions"===r.type){o.networkConditionsSettings={...r};for(const e of[n.NetworkManager.OfflineConditions,n.NetworkManager.Slow3GConditions,n.NetworkManager.Slow4GConditions,n.NetworkManager.Fast4GConditions])n.NetworkManager.networkConditionsEqual({...e,title:e.i18nTitleKey||""},{...r,title:e.i18nTitleKey||""})&&(o.networkConditionsSettings.title=e.title instanceof Function?e.title():e.title,o.networkConditionsSettings.i18nTitleKey=e.i18nTitleKey)}}return o}#f(){const e=n.TargetManager.TargetManager.instance().primaryPageTarget();if(!e)throw new Error("Missing main page target");return e}#S(e){if(!this.sections)return null;for(const t of this.sections)if(-1!==t.steps.indexOf(e))return t;return null}#y(){if(!this.sections||!this.currentRecording)return;const e=this.currentRecording.storageName;for(let t=0;t<this.sections.length;t++){const r=this.#t.getScreenshotForSection(e,t);this.sections[t].screenshot=r||void 0}this.requestUpdate()}#x(){this.recordingPlayer?.abort()}async#b(e){if(!this.currentRecording||!this.#r)return;const r=a.RecorderPluginManager.RecorderPluginManager.instance().once("showViewRequested");e.replay(this.currentRecording.flow);const o=await r;this.viewDescriptor=o,t.userMetrics.recordingReplayStarted(3)}async#P(e){if(!this.currentRecording||!this.#r)return;if(this.viewDescriptor&&(this.viewDescriptor=void 0),e.data.extension)return await this.#b(e.data.extension);t.userMetrics.recordingReplayStarted("chrome-recorder"!==e.data.targetPanel?2:1),this.#o.isPlaying=!0,this.currentStep=void 0,this.recordingError=void 0,this.lastReplayResult=void 0;const r=this.currentRecording;this.#v(),await this.#C(),this.recordingPlayer=new y.RecordingPlayer.RecordingPlayer(this.currentRecording.flow,{speed:e.data.speed,breakpointIndexes:this.#s});const o="timeline"===e.data.targetPanel,i=new Set;this.recordingPlayer.addEventListener("Step",(async({data:{step:e,resolve:t}})=>{this.currentStep=e;const o=this.#S(e);if(this.sections&&o&&!i.has(o)){i.add(o);const e=this.sections.indexOf(o),t=await y.ScreenshotUtils.takeScreenshot();o.screenshot=t,y.ScreenshotStorage.ScreenshotStorage.instance().storeScreenshotForSection(r.storageName,e,t)}t()})),this.recordingPlayer.addEventListener("Stop",(()=>{this.#o.isPausedOnBreakpoint=!0,this.requestUpdate()})),this.recordingPlayer.addEventListener("Continue",(()=>{this.#o.isPausedOnBreakpoint=!1,this.requestUpdate()})),this.recordingPlayer.addEventListener("Error",(({data:e})=>{this.recordingError=e,o||(this.#o.isPlaying=!1,this.recordingPlayer=void 0),this.lastReplayResult="Failure";const r=e.message.toLowerCase();r.startsWith("could not find element")?t.userMetrics.recordingReplayFinished(2):r.startsWith("waiting for target failed")?t.userMetrics.recordingReplayFinished(3):t.userMetrics.recordingReplayFinished(4),this.dispatchEvent(new S)})),this.recordingPlayer.addEventListener("Done",(()=>{o||(this.#o.isPlaying=!1,this.recordingPlayer=void 0),this.lastReplayResult="Success",this.dispatchEvent(new S),t.userMetrics.recordingReplayFinished(1)})),this.recordingPlayer.addEventListener("Abort",(()=>{this.currentStep=void 0,this.recordingError=void 0,this.lastReplayResult=void 0,this.#o.isPlaying=!1}));let n=e=>{};const s=new Promise((e=>{n=e}));let a=null;if("timeline"===e.data?.targetPanel)a=new g.PerformanceTracing.PerformanceTracing(this.#f(),{tracingBufferUsage(){},eventsRetrievalProgress(){},tracingComplete(e){n(e)}});if(a&&await a.start(),this.#E(!1),await this.recordingPlayer.play(),this.#E(!0),a){await a.stop();const t=await s;if(this.#o.isPlaying=!1,this.recordingPlayer=void 0,await p.InspectorView.InspectorView.instance().showPanel(e.data?.targetPanel),"timeline"===e.data?.targetPanel)l.TimelinePanel.TimelinePanel.instance().loadFromEvents(t)}}async#C(){try{const e=d.DeviceModeWrapper.DeviceModeWrapper.instance();if(e.isDeviceModeOn()){e.toggleDeviceMode();const t=this.#f().model(n.EmulationModel.EmulationModel);await(t?.emulateDevice(null))}}catch{}}#E(e){const t=this.#f().model(n.EmulationModel.EmulationModel);t?.setTouchEmulationAllowed(e)}async#u(e){const t=JSON.parse(e.detail);this.#w(await this.#e.saveRecording(y.SchemaUtils.parse(t))),this.#h("RecordingPage"),this.#v()}getUserFlow(){return this.currentRecording?.flow}async#k(e){if(!this.currentRecording)throw new Error("Current recording expected to be defined.");const t={...this.currentRecording,flow:{...this.currentRecording.flow,steps:this.currentRecording.flow.steps.map((t=>t===e.currentStep?e.newStep:t))}};this.#w(await this.#e.updateRecording(t.storageName,t.flow),{keepBreakpoints:!0,updateSession:!0})}async#$(e){if(!this.currentRecording)throw new Error("Current recording expected to be defined.");const r=e.stepOrSection;let o,i=e.position;if("steps"in r){const t=this.sections?.indexOf(r);if(void 0===t||-1===t)throw new Error("There is no section to add a step to");if("after"===e.position)this.sections?.[t].steps.length?(o=this.sections?.[t].steps[0],i="before"):(o=this.sections?.[t].causingStep,i="after");else{if(t<=0)throw new Error("There is no section to add a step to");const e=this.sections?.[t-1];o=e?.steps[e.steps.length-1],i="after"}}else o=r;if(!o)throw new Error("Anchor step is not found when adding a step");const n=this.currentRecording.flow.steps,s=n.indexOf(o)+("before"===i?0:1);n.splice(s,0,{type:y.Schema.StepType.WaitForElement,selectors:["body"]});const a={...this.currentRecording,flow:{...this.currentRecording.flow,steps:n}};t.userMetrics.recordingEdited(2),this.#s=new Set([...this.#s.values()].map((e=>s>e?e:e+1))),this.#w(await this.#e.updateRecording(a.storageName,a.flow),{keepBreakpoints:!0,updateSession:!0})}async#N(e){if(!this.currentRecording)throw new Error("Current recording expected to be defined.");const t={...this.currentRecording.flow,title:e.title};this.#w(await this.#e.updateRecording(this.currentRecording.storageName,t))}async#T(e){if(!this.currentRecording)throw new Error("Current recording expected to be defined.");const r=this.currentRecording.flow.steps,o=r.indexOf(e.step);r.splice(o,1);const i={...this.currentRecording.flow,steps:r};t.userMetrics.recordingEdited(3),this.#s=new Set([...this.#s.values()].map((e=>o>e?e:o===e?-1:e-1)).filter((e=>e>=0))),this.#w(await this.#e.updateRecording(this.currentRecording.storageName,i),{keepBreakpoints:!0,updateSession:!0})}async#I(e){if(!this.currentRecording)throw new Error("Current recording expected to be defined.");const t=this.currentRecording.flow.steps.findIndex((e=>"navigate"===e.type));if(-1===t)throw new Error("Current recording does not have a navigate step");const r=this.currentRecording.flow.steps.findIndex(((e,r)=>!(r>=t)&&"emulateNetworkConditions"===e.type));if(e.data)if(-1===r)this.currentRecording.flow.steps.splice(0,0,y.SchemaUtils.createEmulateNetworkConditionsStep({download:e.data.download,upload:e.data.upload,latency:e.data.latency}));else{const t=this.currentRecording.flow.steps[r];t.download=e.data.download,t.upload=e.data.upload,t.latency=e.data.latency}else-1!==r&&this.currentRecording.flow.steps.splice(r,1);this.#w(await this.#e.updateRecording(this.currentRecording.storageName,this.currentRecording.flow))}async#M(e){if(!this.currentRecording)throw new Error("Current recording expected to be defined.");this.currentRecording.flow.timeout=e.data,this.#w(await this.#e.updateRecording(this.currentRecording.storageName,this.currentRecording.flow))}async#F(e){if(e.stopPropagation(),e instanceof m.RecordingListView.DeleteRecordingEvent)await this.#e.deleteRecording(e.storageName),this.#t.deleteScreenshotsForRecording(e.storageName),this.requestUpdate();else{if(!this.currentRecording)return;await this.#e.deleteRecording(this.currentRecording.storageName),this.#t.deleteScreenshotsForRecording(this.currentRecording.storageName)}(await this.#e.getRecordings()).length?this.#h("AllRecordingsPage"):this.#h("StartPage"),this.#w(void 0),this.#v()}#A(e){e?.stopPropagation(),this.#h("CreateRecordingPage"),this.#v()}async#j(e){await this.#C(),this.isToggling=!0,this.#v(),t.userMetrics.recordingToggled(1),this.currentRecordingSession=new y.RecordingSession.RecordingSession(this.#f(),{title:e.name,selectorAttribute:e.selectorAttribute,selectorTypesToRecord:e.selectorTypesToRecord.length?e.selectorTypesToRecord:Object.values(y.Schema.SelectorType)}),this.#w(await this.#e.saveRecording(this.currentRecordingSession.cloneUserFlow()));let r,o=-1;const i=async e=>{if(!this.sections)throw new Error("Could not find sections.");const t=this.sections.length-1,i=this.sections[t];if(r||o===t)return;r=y.ScreenshotUtils.takeScreenshot();const n=await r;r=void 0,i.screenshot=n,y.ScreenshotStorage.ScreenshotStorage.instance().storeScreenshotForSection(e.storageName,t,n),o=t,this.#y()};this.currentRecordingSession.addEventListener("recordingupdated",(async({data:e})=>{if(!this.currentRecording)throw new Error("No current recording found");this.#w(await this.#e.updateRecording(this.currentRecording.storageName,e));const t=this.shadowRoot?.querySelector("devtools-recording-view");t?.scrollToBottom(),await i(this.currentRecording)})),this.currentRecordingSession.addEventListener("recordingstopped",(async({data:e})=>{if(!this.currentRecording)throw new Error("No current recording found");t.userMetrics.keyboardShortcutFired("chrome-recorder.start-recording"),this.#w(await this.#e.updateRecording(this.currentRecording.storageName,e)),await this.#B()})),await this.currentRecordingSession.start(),this.isToggling=!1,this.isRecording=!0,this.#h("RecordingPage"),this.dispatchEvent(new x(this.currentRecording.flow))}async#B(){if(!this.currentRecording||!this.currentRecordingSession)throw new Error("Recording was never started");this.isToggling=!0,this.#v(),t.userMetrics.recordingToggled(2),await this.currentRecordingSession.stop(),this.currentRecordingSession=void 0,this.isToggling=!1,this.isRecording=!1,this.dispatchEvent(new x(this.currentRecording.flow))}async#D(){this.previousPage&&this.#h(this.previousPage)}async#O(e){const t=e instanceof m.RecordingListView.OpenRecordingEvent||e instanceof m.RecordingListView.PlayRecordingEvent?e.storageName:e.target?.value;this.#w(await this.#e.getRecording(t)),this.currentRecording?this.#h("RecordingPage"):"StartPage"===t?this.#h("StartPage"):"AllRecordingsPage"===t&&this.#h("AllRecordingsPage")}async#U(e){if("string"!=typeof e.itemValue)throw new Error("Invalid export option value");if(e.itemValue===A)return void t.InspectorFrontendHost.InspectorFrontendHostInstance.openInNewTab("https://goo.gle/recorder-extension-list");if(!this.currentRecording)throw new Error("No recording selected");const r=e.itemValue,o=e=>e.getId()===r,i=this.#a.find(o)||this.extensionConverters.find(o);if(!i)throw new Error("No recording selected");const[n]=await i.stringify(this.currentRecording.flow);await this.#V(i.getFilename(this.currentRecording.flow),n);const s=j[i.getId()];if(s)t.userMetrics.recordingExported(s);else{if(!i.getId().startsWith(w.ExtensionConverter.EXTENSION_PREFIX))throw new Error("Could not find a metric for the export option with id = "+r);t.userMetrics.recordingExported(4)}}async#V(e,t){try{const r=await window.showSaveFilePicker({suggestedName:e}),o=await r.createWritable();await o.write(t),await o.close()}catch(e){if("AbortError"===e.name)return;throw e}}async#L(){if(!this.currentRecordingSession||!this.currentRecording)return;const e=this.currentRecordingSession.cloneUserFlow();e.steps.push({type:"waitForElement",selectors:[[".cls"]]}),this.#w(await this.#e.updateRecording(this.currentRecording.storageName,e),{keepBreakpoints:!0,updateSession:!0}),t.userMetrics.recordingAssertion(1),await this.updateComplete,this.renderRoot.querySelector("devtools-recording-view")?.shadowRoot?.querySelector(".section:last-child devtools-step-view:last-of-type")?.shadowRoot?.querySelector(".action")?.click()}async#z(){if(this.#l.get())return!0;if(i.Runtime.Runtime.queryParam("isChromeForTesting")||i.Runtime.Runtime.queryParam("disableSelfXssWarnings")||this.#g.get())return!0;const e=await c.TypeToAllowDialog.show({jslogContext:{input:"confirm-import-recording-input",dialog:"confirm-import-recording-dialog"},message:F(I.doNotImport,{PH1:F(I.allowImporting)}),header:F(I.doYouTrustThisCode),typePhrase:F(I.allowImporting),inputPlaceholder:F(I.typeAllowImporting,{PH1:F(I.allowImporting)})});return e&&this.#l.set(!0),e}async#q(e){e.stopPropagation(),this.#v(),await this.#z()&&(this.#i=p.UIUtils.createFileSelectorElement(this.#m.bind(this)),this.#i.click())}async#_(e){await this.#O(e),await this.#P(new m.RecordingView.PlayRecordingEvent({targetPanel:"chrome-recorder",speed:this.#c.speed}))}#W=e=>{this.#s.add(e.index),this.recordingPlayer?.updateBreakpointIndexes(this.#s),this.requestUpdate()};#H=e=>{this.#s.delete(e.index),this.recordingPlayer?.updateBreakpointIndexes(this.#s),this.requestUpdate()};#X(){this.viewDescriptor=void 0}handleActions(e){if(this.isActionPossible(e))switch(e){case"chrome-recorder.create-recording":return void this.#A();case"chrome-recorder.start-recording":if("CreateRecordingPage"===this.currentPage||this.isRecording)if("CreateRecordingPage"===this.currentPage){const e=this.renderRoot.querySelector("devtools-create-recording-view");e&&this.#d.handleShortcut(e.startRecording.bind(e))}else this.isRecording&&this.#B();else this.#d.handleShortcut(this.#j.bind(this,new m.CreateRecordingView.RecordingStartedEvent(this.#c.defaultTitle,this.#c.defaultSelectors,this.#c.selectorAttribute)));return;case"chrome-recorder.replay-recording":return void this.#P(new m.RecordingView.PlayRecordingEvent({targetPanel:"chrome-recorder",speed:this.#c.speed}));case"chrome-recorder.toggle-code-view":{const e=this.renderRoot.querySelector("devtools-recording-view");return void(e&&e.showCodeToggle())}}}isActionPossible(e){switch(e){case"chrome-recorder.create-recording":return!this.isRecording&&!this.#o.isPlaying;case"chrome-recorder.start-recording":return!this.#o.isPlaying;case"chrome-recorder.replay-recording":return"RecordingPage"===this.currentPage&&!this.#o.isPlaying;case"chrome-recorder.toggle-code-view":return"RecordingPage"===this.currentPage;case"chrome-recorder.copy-recording-or-step":return!1}}#K(){const e=e=>p.ShortcutRegistry.ShortcutRegistry.instance().shortcutsForAction(e).map((e=>e.title().split(/[\s+]+/).map((e=>e.trim()))));return[{title:F(I.startStopRecording),bindings:e("chrome-recorder.start-recording")},{title:F(I.replayRecording),bindings:e("chrome-recorder.replay-recording")},{title:F(I.copyShortcut),bindings:t.Platform.isMac()?[["⌘","C"]]:[["Ctrl","C"]]},{title:F(I.toggleCode),bindings:e("chrome-recorder.toggle-code-view")}]}#G(){switch(this.currentPage){case"StartPage":return this.#J();case"AllRecordingsPage":return this.#Y();case"RecordingPage":return this.#Q();case"CreateRecordingPage":return this.#Z()}}#Y(){const e=this.#e.getRecordings();return E` <devtools-recording-list-view .recordings=${e.map((e=>({storageName:e.storageName,name:e.flow.title})))} .replayAllowed=${this.#r} @createrecording=${this.#A} @deleterecording=${this.#F} @openrecording=${this.#O} @playrecording=${this.#_} > </devtools-recording-list-view> `}#J(){return E` <div class="empty-state" jslog=${v.section().context("start-view")}> <div class="empty-state-header">${F(I.header)}</div> <div class="empty-state-description"> <span>${F(I.recordingDescription)}</span> ${p.XLink.XLink.create("https://developer.chrome.com/docs/devtools/recorder",F(I.learnMore),"x-link",void 0,"learn-more")} </div> <devtools-button .variant=${"tonal"} jslogContext=${"chrome-recorder.create-recording"} @click=${this.#A}>${F(I.createRecording)}</devtools-button> </div> `}#Q(){return E` <devtools-recording-view .data=${{recording:this.currentRecording?.flow,replayState:this.#o,isRecording:this.isRecording,recordingTogglingInProgress:this.isToggling,currentStep:this.currentStep,currentError:this.recordingError,sections:this.sections,settings:this.settings,recorderSettings:this.#c,lastReplayResult:this.lastReplayResult,replayAllowed:this.#r,breakpointIndexes:this.#s,builtInConverters:this.#a,extensionConverters:this.extensionConverters,replayExtensions:this.replayExtensions,extensionDescriptor:this.viewDescriptor}} @networkconditionschanged=${this.#I} @timeoutchanged=${this.#M} @requestselectorattribute=${e=>{e.send(this.currentRecording?.flow.selectorAttribute)}} @recordingfinished=${this.#B} @stepchanged=${this.#k.bind(this)} @recordingtitlechanged=${this.#N.bind(this)} @addstep=${this.#$.bind(this)} @removestep=${this.#T.bind(this)} @addbreakpoint=${this.#W} @removebreakpoint=${this.#H} @playrecording=${this.#P} @abortreplay=${this.#x} @recorderextensionviewclosed=${this.#X} @addassertion=${this.#L} ></devtools-recording-view> `}#Z(){return E` <devtools-create-recording-view .data=${{recorderSettings:this.#c}} @recordingstarted=${this.#j} @recordingcancelled=${this.#D} ></devtools-create-recording-view> `}#ee=()=>{if(!this.#n)throw new Error("#exportMenuButton not found");return this.#n};#te(e){e.stopPropagation(),this.#v(),this.exportMenuExpanded=!this.exportMenuExpanded}#re(){this.exportMenuExpanded=!1}render(){const e=this.#e.getRecordings(),t=this.currentRecording?this.currentRecording.storageName:this.currentPage,r=[0===e.length?{value:"StartPage",name:F(I.noRecordings),selected:"StartPage"===t}:{value:"AllRecordingsPage",name:`${e.length} ${F(I.numberOfRecordings)}`,selected:"AllRecordingsPage"===t},...e.map((e=>({value:e.storageName,name:e.flow.title,selected:t===e.storageName})))];return E` <div class="wrapper"> <div class="header" jslog=${v.toolbar()}> <devtools-button @click=${this.#A} .data=${{variant:"toolbar",iconName:"plus",disabled:this.#o.isPlaying||this.isRecording||this.isToggling,title:y.Tooltip.getTooltipForActions(F(I.createRecording),"chrome-recorder.create-recording"),jslogContext:"chrome-recorder.create-recording"}} ></devtools-button> <div class="separator"></div> <select .disabled=${0===e.length||this.#o.isPlaying||this.isRecording||this.isToggling} @click=${e=>e.stopPropagation()} @change=${this.#O} jslog=${v.dropDown("recordings").track({change:!0})} > ${u.Directives.repeat(r,(e=>e.value),(e=>E`<option .selected=${e.selected} value=${e.value}>${e.name}</option>`))} </select> <div class="separator"></div> <devtools-button @click=${this.#q} .data=${{variant:"toolbar",iconName:"import",title:F(I.importRecording),jslogContext:"import-recording"}} ></devtools-button> <devtools-button id='origin' @click=${this.#te} on-render=${h.Directives.nodeRenderedCallback((e=>{this.#n=e}))} .data=${{variant:"toolbar",iconName:"download",title:F(I.exportRecording),disabled:!this.currentRecording}} jslog=${v.dropDown("export-recording").track({click:!0})} ></devtools-button> <devtools-menu @menucloserequest=${this.#re} @menuitemselected=${this.#U} .origin=${this.#ee} .showDivider=${!1} .showSelectedItem=${!1} .open=${this.exportMenuExpanded} > <devtools-menu-group .name=${F(I.export)}> ${u.Directives.repeat(this.#a,(e=>E` <devtools-menu-item .value=${e.getId()} jslog=${v.item(`converter-${o.StringUtilities.toKebabCase(e.getId())}`).track({click:!0})}> ${e.getFormatName()} </devtools-menu-item> `))} </devtools-menu-group> <devtools-menu-group .name=${F(I.exportViaExtensions)}> ${u.Directives.repeat(this.extensionConverters,(e=>E` <devtools-menu-item .value=${e.getId()} jslog=${v.item("converter-extension").track({click:!0})}> ${e.getFormatName()} </devtools-menu-item> `))} <devtools-menu-item .value=${A}> ${F(I.getExtensions)} </devtools-menu-item> </devtools-menu-group> </devtools-menu> <devtools-button @click=${this.#F} .data=${{variant:"toolbar",iconName:"bin",disabled:!this.currentRecording||this.#o.isPlaying||this.isRecording||this.isToggling,title:F(I.deleteRecording),jslogContext:"delete-recording"}} ></devtools-button> <div class="separator"></div> <devtools-button @click=${()=>this.recordingPlayer?.continue()} .data=${{variant:"primary_toolbar",iconName:"resume",disabled:!this.recordingPlayer||!this.#o.isPausedOnBreakpoint,title:F(I.continueReplay),jslogContext:"continue-replay"}} ></devtools-button> <devtools-button @click=${()=>this.recordingPlayer?.stepOver()} .data=${{variant:"toolbar",iconName:"step-over",disabled:!this.recordingPlayer||!this.#o.isPausedOnBreakpoint,title:F(I.stepOverReplay),jslogContext:"step-over"}} ></devtools-button> <div class="feedback"> <x-link class="x-link" href=${"https://goo.gle/recorder-feedback"} jslog=${v.link("feedback").track({click:!0})}>${F(I.sendFeedback)}</x-link> </div> <div class="separator"></div> <devtools-shortcut-dialog .data=${{shortcuts:this.#K()}} jslog=${v.action("show-shortcuts").track({click:!0})} ></devtools-shortcut-dialog> </div> ${this.importError?E`<div class='error'>Import error: ${this.importError.message}</div>`:""} ${this.#G()} </div> `}};P([T()],B.prototype,"currentRecordingSession",void 0),P([T()],B.prototype,"currentRecording",void 0),P([T()],B.prototype,"currentStep",void 0),P([T()],B.prototype,"recordingError",void 0),P([T()],B.prototype,"isRecording",void 0),P([T()],B.prototype,"isToggling",void 0),P([T()],B.prototype,"recordingPlayer",void 0),P([T()],B.prototype,"lastReplayResult",void 0),P([T()],B.prototype,"currentPage",void 0),P([T()],B.prototype,"previousPage",void 0),P([T()],B.prototype,"sections",void 0),P([T()],B.prototype,"settings",void 0),P([T()],B.prototype,"importError",void 0),P([T()],B.prototype,"exportMenuExpanded",void 0),P([T()],B.prototype,"extensionConverters",void 0),P([T()],B.prototype,"replayExtensions",void 0),P([T()],B.prototype,"viewDescriptor",void 0),B=P([N("devtools-recorder-controller")],B);var D=Object.freeze({__proto__:null,get RecorderController(){return B}});let O;class U extends p.Panel.Panel{static panelName="chrome-recorder";#oe;constructor(){super(U.panelName),this.element.setAttribute("jslog",`${v.panel("chrome-recorder").track({resize:!0})}`),this.#oe=new B,this.contentElement.append(this.#oe)}static instance(e={forceNew:null}){const{forceNew:t}=e;return O&&!t||(O=new U),O}wasShown(){p.Context.Context.instance().setFlavor(U,this),this.#oe.focus()}willHide(){p.Context.Context.instance().setFlavor(U,null)}handleActions(e){this.#oe.handleActions(e)}isActionPossible(e){return this.#oe.isActionPossible(e)}}var V=Object.freeze({__proto__:null,ActionDelegate:class{handleAction(e,t){return(async()=>{await p.ViewManager.ViewManager.instance().showView(U.panelName);const e=p.ViewManager.ViewManager.instance().view(U.panelName);if(e){(await e.widget()).handleActions(t)}})(),!0}},RecorderPanel:U});export{D as RecorderController,b as RecorderEvents,V as RecorderPanel};