@react-native/debugger-frontend
Version:
Debugger frontend for React Native based on Chrome DevTools
121 lines (120 loc) • 30.8 kB
JavaScript
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 i from"../../core/sdk/sdk.js";import*as o from"../../models/bindings/bindings.js";import*as n from"../../models/extensions/extensions.js";import*as s from"../emulation/emulation.js";import*as a from"../timeline/timeline.js";import*as c from"../../services/tracing/tracing.js";import*as d from"../../ui/components/buttons/buttons.js";import*as l from"../../ui/components/dialogs/dialogs.js";import*as g from"../../ui/components/helpers/helpers.js";import*as h from"../../ui/components/menus/menus.js";import*as p from"../../ui/legacy/legacy.js";import*as u from"../../ui/lit-html/lit-html.js";import*as R from"../../ui/visual_logging/visual_logging.js";import*as m from"./components/components.js";import*as w from"./converters/converters.js";import*as v from"./extensions/extensions.js";import*as y from"./models/models.js";const S=new CSSStyleSheet;S.replaceSync("*{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-direction:row;align-items:center;border-bottom:1px solid var(--sys-color-divider);padding:0 5px;min-height:29px;max-height:29px;gap:3px}.separator{background-color:var(--sys-color-divider);width:1px;height:17px;margin:0}select{border-radius:2px;border:1px solid transparent;height:24px;max-width:180px;min-width:140px;padding:0 5px;position:relative;color:var(--sys-color-on-surface);background-color:var(--sys-color-cdt-base-container);text-overflow:ellipsis}select:disabled{color:var(--sys-color-state-disabled)}select:not([disabled]):hover,\nselect:not([disabled]):focus-visible,\nselect:not([disabled]):active{background-color:var(--sys-color-state-hover-on-subtle)}select:not([disabled]):focus-visible{box-shadow:0 0 0 2px 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{outline:-webkit-focus-ring-color auto 1px}devtools-shortcut-dialog{padding-right:6px}\n/*# sourceURL=recorderController.css */\n");class f extends Event{static eventName="replayfinished";constructor(){super(f.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 P=Object.freeze({__proto__:null,ReplayFinishedEvent:f,RecordingStateChangedEvent:x}),C=self&&self.__decorate||function(e,t,r,i){var o,n=arguments.length,s=n<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,r):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,r,i);else for(var a=e.length-1;a>=0;a--)(o=e[a])&&(s=(n<3?o(s):n>3?o(t,r,s):o(t,r))||s);return n>3&&s&&Object.defineProperty(t,r,s),s};const{html:b,Decorators:E,LitElement:$}=u,{customElement:k,state:N}=E,T={createRecording:"Create a new 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"},M=r.i18n.registerUIStrings("panels/recorder/RecorderController.ts",T),B=r.i18n.getLocalizedString.bind(void 0,M),I="get-extensions-link",F={json:2,"@puppeteer/replay":3,puppeteer:1,lighthouse:5};let A=class extends ${static styles=[S];#e=y.RecordingStorage.RecordingStorage.instance();#t=y.ScreenshotStorage.ScreenshotStorage.instance();#r=!0;#i={isPlaying:!1,isPausedOnBreakpoint:!1};#o;#n;#s=new Set;#a;#c=new y.RecorderSettings.RecorderSettings;#d=new y.RecorderShortcutHelper.RecorderShortcutHelper;constructor(){super(),this.isRecording=!1,this.isToggling=!1,this.exportMenuExpanded=!1,this.currentPage="StartPage",this.#e.getRecordings().length&&this.#l("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.LighthouseConverter.LighthouseConverter(t)]);const r=v.ExtensionManager.ExtensionManager.instance();this.#g(r.extensions()),r.addEventListener("extensionsUpdated",(e=>{this.#g(e.data)})),this.addEventListener("setrecording",(e=>this.#h(e)))}disconnectedCallback(){super.disconnectedCallback(),this.currentRecordingSession&&this.currentRecordingSession.stop()}#g(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.#i.isPlaying=e.isPlaying,this.#i.isPausedOnBreakpoint=e.isPausedOnBreakpoint}setCurrentPageForTesting(e){this.#l(e)}getCurrentPageForTesting(){return this.currentPage}getCurrentRecordingForTesting(){return this.currentRecording}getStepBreakpointIndexesForTesting(){return[...this.#s.values()]}#p(){this.importError=void 0}async#u(t){const r=new e.StringOutputStream.StringOutputStream,i=new o.FileUtils.ChunkedFileReader(t,1e7);if(!await i.read(r))throw i.error();let n;try{n=y.SchemaUtils.parse(JSON.parse(r.data()))}catch(e){return void(this.importError=e)}this.#R(await this.#e.saveRecording(n)),this.#l("RecordingPage"),this.#p()}setCurrentRecordingForTesting(e){this.#R(e)}getSectionsForTesting(){return this.sections}#R(e,t={}){const{keepBreakpoints:r=!1,updateSession:i=!1}=t;this.recordingPlayer?.abort(),this.currentStep=void 0,this.recordingError=void 0,this.lastReplayResult=void 0,this.recordingPlayer=void 0,this.#i.isPlaying=!1,this.#i.isPausedOnBreakpoint=!1,this.#s=r?this.#s:new Set,e?(this.currentRecording=e,this.sections=y.Section.buildSections(e.flow.steps),this.settings=this.#m(e.flow),i&&this.currentRecordingSession&&this.currentRecordingSession.overwriteUserFlow(e.flow)):(this.currentRecording=void 0,this.sections=void 0,this.settings=void 0),this.#w()}#l(e){e!==this.currentPage&&(this.previousPage=this.currentPage,this.currentPage=e)}#m(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[i.NetworkManager.OfflineConditions,i.NetworkManager.Slow3GConditions,i.NetworkManager.Slow4GConditions,i.NetworkManager.Fast4GConditions])i.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}#v(){const e=i.TargetManager.TargetManager.instance().primaryPageTarget();if(!e)throw new Error("Missing main page target");return e}#y(e){if(!this.sections)return null;for(const t of this.sections)if(-1!==t.steps.indexOf(e))return t;return null}#w(){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()}#S(){this.recordingPlayer?.abort()}async#f(e){if(!this.currentRecording||!this.#r)return;const r=n.RecorderPluginManager.RecorderPluginManager.instance().once("showViewRequested");e.replay(this.currentRecording.flow);const i=await r;this.viewDescriptor=i,t.userMetrics.recordingReplayStarted(3)}async#x(e){if(!this.currentRecording||!this.#r)return;if(this.viewDescriptor&&(this.viewDescriptor=void 0),e.data.extension)return this.#f(e.data.extension);t.userMetrics.recordingReplayStarted("chrome-recorder"!==e.data.targetPanel?2:1),this.#i.isPlaying=!0,this.currentStep=void 0,this.recordingError=void 0,this.lastReplayResult=void 0;const r=this.currentRecording;this.#p(),await this.#P(),this.recordingPlayer=new y.RecordingPlayer.RecordingPlayer(this.currentRecording.flow,{speed:e.data.speed,breakpointIndexes:this.#s});const i="timeline"===e.data.targetPanel,o=new Set;this.recordingPlayer.addEventListener("Step",(async({data:{step:e,resolve:t}})=>{this.currentStep=e;const i=this.#y(e);if(this.sections&&i&&!o.has(i)){o.add(i);const e=this.sections.indexOf(i),t=await y.ScreenshotUtils.takeScreenshot();i.screenshot=t,y.ScreenshotStorage.ScreenshotStorage.instance().storeScreenshotForSection(r.storageName,e,t)}t()})),this.recordingPlayer.addEventListener("Stop",(()=>{this.#i.isPausedOnBreakpoint=!0,this.requestUpdate()})),this.recordingPlayer.addEventListener("Continue",(()=>{this.#i.isPausedOnBreakpoint=!1,this.requestUpdate()})),this.recordingPlayer.addEventListener("Error",(({data:e})=>{this.recordingError=e,i||(this.#i.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.recordingPlayer.addEventListener("Done",(()=>{i||(this.#i.isPlaying=!1,this.recordingPlayer=void 0),this.lastReplayResult="Success",this.dispatchEvent(new f),t.userMetrics.recordingReplayFinished(1)})),this.recordingPlayer.addEventListener("Abort",(()=>{this.currentStep=void 0,this.recordingError=void 0,this.lastReplayResult=void 0,this.#i.isPlaying=!1}));let n=e=>{};const s=new Promise((e=>{n=e}));let d=null;if("timeline"===e.data?.targetPanel)d=new c.PerformanceTracing.PerformanceTracing(this.#v(),{tracingBufferUsage(){},eventsRetrievalProgress(){},tracingComplete(e){n(e)}});if(d&&await d.start(),this.#C(!1),await this.recordingPlayer.play(),this.#C(!0),d){await d.stop();const t=await s;if(this.#i.isPlaying=!1,this.recordingPlayer=void 0,await p.InspectorView.InspectorView.instance().showPanel(e.data?.targetPanel),"timeline"===e.data?.targetPanel)a.TimelinePanel.TimelinePanel.instance().loadFromEvents(t)}}async#P(){try{const e=s.DeviceModeWrapper.DeviceModeWrapper.instance();if(e.isDeviceModeOn()){e.toggleDeviceMode();const t=this.#v().model(i.EmulationModel.EmulationModel);await(t?.emulateDevice(null))}}catch{}}#C(e){const t=this.#v().model(i.EmulationModel.EmulationModel);t?.setTouchEmulationAllowed(e)}async#h(e){const t=JSON.parse(e.detail);this.#R(await this.#e.saveRecording(y.SchemaUtils.parse(t))),this.#l("RecordingPage"),this.#p()}getUserFlow(){return this.currentRecording?.flow}async#b(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.#R(await this.#e.updateRecording(t.storageName,t.flow),{keepBreakpoints:!0,updateSession:!0})}async#E(e){if(!this.currentRecording)throw new Error("Current recording expected to be defined.");const r=e.stepOrSection;let i,o=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?(i=this.sections?.[t].steps[0],o="before"):(i=this.sections?.[t].causingStep,o="after");else{if(t<=0)throw new Error("There is no section to add a step to");const e=this.sections?.[t-1];i=e?.steps[e.steps.length-1],o="after"}}else i=r;if(!i)throw new Error("Anchor step is not found when adding a step");const n=this.currentRecording.flow.steps,s=n.indexOf(i)+("before"===o?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.#R(await this.#e.updateRecording(a.storageName,a.flow),{keepBreakpoints:!0,updateSession:!0})}async#$(e){if(!this.currentRecording)throw new Error("Current recording expected to be defined.");const t={...this.currentRecording.flow,title:e.title};this.#R(await this.#e.updateRecording(this.currentRecording.storageName,t))}async#k(e){if(!this.currentRecording)throw new Error("Current recording expected to be defined.");const r=this.currentRecording.flow.steps,i=r.indexOf(e.step);r.splice(i,1);const o={...this.currentRecording.flow,steps:r};t.userMetrics.recordingEdited(3),this.#s=new Set([...this.#s.values()].map((e=>i>e?e:i===e?-1:e-1)).filter((e=>e>=0))),this.#R(await this.#e.updateRecording(this.currentRecording.storageName,o),{keepBreakpoints:!0,updateSession:!0})}async#N(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.#R(await this.#e.updateRecording(this.currentRecording.storageName,this.currentRecording.flow))}async#T(e){if(!this.currentRecording)throw new Error("Current recording expected to be defined.");this.currentRecording.flow.timeout=e.data,this.#R(await this.#e.updateRecording(this.currentRecording.storageName,this.currentRecording.flow))}async#M(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.#l("AllRecordingsPage"):this.#l("StartPage"),this.#R(void 0),this.#p()}#B(e){e?.stopPropagation(),this.#l("CreateRecordingPage"),this.#p()}async#I(e){await this.#P(),this.isToggling=!0,this.#p(),t.userMetrics.recordingToggled(1),this.currentRecordingSession=new y.RecordingSession.RecordingSession(this.#v(),{title:e.name,selectorAttribute:e.selectorAttribute,selectorTypesToRecord:e.selectorTypesToRecord.length?e.selectorTypesToRecord:Object.values(y.Schema.SelectorType)}),this.#R(await this.#e.saveRecording(this.currentRecordingSession.cloneUserFlow()));let r,i=-1;const o=async e=>{if(!this.sections)throw new Error("Could not find sections.");const t=this.sections.length-1,o=this.sections[t];if(r||i===t)return;r=y.ScreenshotUtils.takeScreenshot();const n=await r;r=void 0,o.screenshot=n,y.ScreenshotStorage.ScreenshotStorage.instance().storeScreenshotForSection(e.storageName,t,n),i=t,this.#w()};this.currentRecordingSession.addEventListener("recordingupdated",(async({data:e})=>{if(!this.currentRecording)throw new Error("No current recording found");this.#R(await this.#e.updateRecording(this.currentRecording.storageName,e));const t=this.shadowRoot?.querySelector("devtools-recording-view");t?.scrollToBottom(),await o(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.#R(await this.#e.updateRecording(this.currentRecording.storageName,e)),await this.#F()})),await this.currentRecordingSession.start(),this.isToggling=!1,this.isRecording=!0,this.#l("RecordingPage"),this.dispatchEvent(new x(this.currentRecording.flow))}async#F(){if(!this.currentRecording||!this.currentRecordingSession)throw new Error("Recording was never started");this.isToggling=!0,this.#p(),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#A(){this.previousPage&&this.#l(this.previousPage)}async#j(e){const t=e instanceof m.RecordingListView.OpenRecordingEvent||e instanceof m.RecordingListView.PlayRecordingEvent?e.storageName:e.target?.value;this.#R(await this.#e.getRecording(t)),this.currentRecording?this.#l("RecordingPage"):"StartPage"===t?this.#l("StartPage"):"AllRecordingsPage"===t&&this.#l("AllRecordingsPage")}async#V(e){if("string"!=typeof e.itemValue)throw new Error("Invalid export option value");if(e.itemValue===I)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,i=e=>e.getId()===r,o=this.#a.find(i)||this.extensionConverters.find(i);if(!o)throw new Error("No recording selected");const[n]=await o.stringify(this.currentRecording.flow);await this.#O(o.getFilename(this.currentRecording.flow),n);const s=F[o.getId()];if(s)t.userMetrics.recordingExported(s);else{if(!o.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#O(e,t){try{const r=await window.showSaveFilePicker({suggestedName:e}),i=await r.createWritable();await i.write(t),await i.close()}catch(e){if("AbortError"===e.name)return;throw e}}async#D(){if(!this.currentRecordingSession||!this.currentRecording)return;const e=this.currentRecordingSession.cloneUserFlow();e.steps.push({type:"waitForElement",selectors:[[".cls"]]}),this.#R(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()}#L(e){e.stopPropagation(),this.#p(),this.#o=p.UIUtils.createFileSelectorElement(this.#u.bind(this)),this.#o.click()}async#U(e){await this.#j(e),await this.#x(new m.RecordingView.PlayRecordingEvent({targetPanel:"chrome-recorder",speed:this.#c.speed}))}#_=e=>{this.#s.add(e.index),this.recordingPlayer?.updateBreakpointIndexes(this.#s),this.requestUpdate()};#q=e=>{this.#s.delete(e.index),this.recordingPlayer?.updateBreakpointIndexes(this.#s),this.requestUpdate()};#z(){this.viewDescriptor=void 0}handleActions(e){if(this.isActionPossible(e))switch(e){case"chrome-recorder.create-recording":return void this.#B();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.#F();else this.#d.handleShortcut(this.#I.bind(this,new m.CreateRecordingView.RecordingStartedEvent(this.#c.defaultTitle,this.#c.defaultSelectors,this.#c.selectorAttribute)));return;case"chrome-recorder.replay-recording":return void this.#x(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.#i.isPlaying;case"chrome-recorder.start-recording":return!this.#i.isPlaying;case"chrome-recorder.replay-recording":return"RecordingPage"===this.currentPage&&!this.#i.isPlaying;case"chrome-recorder.toggle-code-view":return"RecordingPage"===this.currentPage;case"chrome-recorder.copy-recording-or-step":return!1}}#G(){const e=e=>p.ShortcutRegistry.ShortcutRegistry.instance().shortcutsForAction(e).map((e=>e.title()));return[{title:B(T.startStopRecording),bindings:e("chrome-recorder.start-recording")},{title:B(T.replayRecording),bindings:e("chrome-recorder.replay-recording")},{title:B(T.copyShortcut),bindings:[""+(t.Platform.isMac()?"⌘ C":"Ctrl+C")]},{title:B(T.toggleCode),bindings:e("chrome-recorder.toggle-code-view")}]}#H(){switch(this.currentPage){case"StartPage":return this.#W();case"AllRecordingsPage":return this.#K();case"RecordingPage":return this.#J();case"CreateRecordingPage":return this.#X()}}#K(){const e=this.#e.getRecordings();return b`
<${m.RecordingListView.RecordingListView.litTagName}
.recordings=${e.map((e=>({storageName:e.storageName,name:e.flow.title})))}
.replayAllowed=${this.#r}
=${this.#B}
=${this.#M}
=${this.#j}
=${this.#U}
>
</${m.RecordingListView.RecordingListView.litTagName}>
`}#W(){return b`
<${m.StartView.StartView.litTagName}
=${this.#B}
></${m.StartView.StartView.litTagName}>
`}#J(){return b`
<${m.RecordingView.RecordingView.litTagName}
.data=${{recording:this.currentRecording?.flow,replayState:this.#i,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}}
=${this.#N}
=${this.#T}
=${e=>{e.send(this.currentRecording?.flow.selectorAttribute)}}
=${this.#F}
=${this.#b.bind(this)}
=${this.#$.bind(this)}
=${this.#E.bind(this)}
=${this.#k.bind(this)}
=${this.#_}
=${this.#q}
=${this.#x}
=${this.#S}
=${this.#z}
=${this.#D}
></${m.RecordingView.RecordingView.litTagName}>
`}#X(){return b`
<${m.CreateRecordingView.CreateRecordingView.litTagName}
.data=${{recorderSettings:this.#c}}
=${this.#I}
=${this.#A}
></${m.CreateRecordingView.CreateRecordingView.litTagName}>
`}#Q=()=>{if(!this.#n)throw new Error("#exportMenuButton not found");return this.#n};#Y(e){e.stopPropagation(),this.#p(),this.exportMenuExpanded=!this.exportMenuExpanded}#Z(){this.exportMenuExpanded=!1}render(){const e=this.#e.getRecordings(),t=this.currentRecording?this.currentRecording.storageName:this.currentPage,r=[0===e.length?{value:"StartPage",name:B(T.noRecordings),selected:"StartPage"===t}:{value:"AllRecordingsPage",name:`${e.length} ${B(T.numberOfRecordings)}`,selected:"AllRecordingsPage"===t},...e.map((e=>({value:e.storageName,name:e.flow.title,selected:t===e.storageName})))];return b`
<div class="wrapper">
<div class="header" jslog=${R.toolbar()}>
<${d.Button.Button.litTagName}
=${this.#B}
.data=${{variant:"toolbar",iconName:"plus",disabled:this.#i.isPlaying||this.isRecording||this.isToggling,title:y.Tooltip.getTooltipForActions(B(T.createRecording),"chrome-recorder.create-recording"),jslogContext:"chrome-recorder.create-recording"}}
></${d.Button.Button.litTagName}>
<div class="separator"></div>
<select
.disabled=${0===e.length||this.#i.isPlaying||this.isRecording||this.isToggling}
=${e=>e.stopPropagation()}
=${this.#j}
jslog=${R.dropDown("recordings").track({change:!0})}
>
${u.Directives.repeat(r,(e=>e.value),(e=>b`<option .selected=${e.selected} value=${e.value}>${e.name}</option>`))}
</select>
<div class="separator"></div>
<${d.Button.Button.litTagName}
=${this.#L}
.data=${{variant:"toolbar",iconName:"import",title:B(T.importRecording),jslogContext:"import-recording"}}
></${d.Button.Button.litTagName}>
<${d.Button.Button.litTagName}
id='origin'
=${this.#Y}
on-render=${g.Directives.nodeRenderedCallback((e=>{this.#n=e}))}
.data=${{variant:"toolbar",iconName:"download",title:B(T.exportRecording),disabled:!this.currentRecording}}
jslog=${R.dropDown("export-recording").track({click:!0})}
></${d.Button.Button.litTagName}>
<${h.Menu.Menu.litTagName}
=${this.#Z}
=${this.#V}
.origin=${this.#Q}
.showDivider=${!1}
.showSelectedItem=${!1}
.showConnector=${!1}
.open=${this.exportMenuExpanded}
>
<${h.Menu.MenuGroup.litTagName} .name=${B(T.export)}>
${u.Directives.repeat(this.#a,(e=>b`
<${h.Menu.MenuItem.litTagName} .value=${e.getId()}
jslog=${R.item(`converter-${e.getFormatName()}`).track({click:!0})}>
${e.getFormatName()}
</${h.Menu.MenuItem.litTagName}>
`))}
</${h.Menu.MenuGroup.litTagName}>
<${h.Menu.MenuGroup.litTagName} .name=${B(T.exportViaExtensions)}>
${u.Directives.repeat(this.extensionConverters,(e=>b`
<${h.Menu.MenuItem.litTagName} .value=${e.getId()}
jslog=${R.item(`converter-${e.getFormatName()}`).track({click:!0})}>
${e.getFormatName()}
</${h.Menu.MenuItem.litTagName}>
`))}
<${h.Menu.MenuItem.litTagName} .value=${I}>
${B(T.getExtensions)}
</${h.Menu.MenuItem.litTagName}>
</${h.Menu.MenuGroup.litTagName}>
</${h.Menu.Menu.litTagName}>
<${d.Button.Button.litTagName}
=${this.#M}
.data=${{variant:"toolbar",iconName:"bin",disabled:!this.currentRecording||this.#i.isPlaying||this.isRecording||this.isToggling,title:B(T.deleteRecording),jslogContext:"delete-recording"}}
></${d.Button.Button.litTagName}>
<div class="separator"></div>
<${d.Button.Button.litTagName}
=${()=>this.recordingPlayer?.continue()}
.data=${{variant:"primary_toolbar",iconName:"resume",disabled:!this.recordingPlayer||!this.#i.isPausedOnBreakpoint,title:B(T.continueReplay),jslogContext:"continue-replay"}}
></${d.Button.Button.litTagName}>
<${d.Button.Button.litTagName}
=${()=>this.recordingPlayer?.stepOver()}
.data=${{variant:"toolbar",iconName:"step-over",disabled:!this.recordingPlayer||!this.#i.isPausedOnBreakpoint,title:B(T.stepOverReplay),jslogContext:"step-over"}}
></${d.Button.Button.litTagName}>
<div class="feedback">
<x-link class="x-link" href=${m.StartView.FEEDBACK_URL} jslog=${R.link("feedback").track({click:!0})}>${B(T.sendFeedback)}</x-link>
</div>
<div class="separator"></div>
<${l.ShortcutDialog.ShortcutDialog.litTagName}
.data=${{shortcuts:this.#G()}} jslog=${R.action("show-shortcuts").track({click:!0})}
></${l.ShortcutDialog.ShortcutDialog.litTagName}>
</div>
${this.importError?b`<div class='error'>Import error: ${this.importError.message}</div>`:""}
${this.#H()}
</div>
`}};C([N()],A.prototype,"currentRecordingSession",void 0),C([N()],A.prototype,"currentRecording",void 0),C([N()],A.prototype,"currentStep",void 0),C([N()],A.prototype,"recordingError",void 0),C([N()],A.prototype,"isRecording",void 0),C([N()],A.prototype,"isToggling",void 0),C([N()],A.prototype,"recordingPlayer",void 0),C([N()],A.prototype,"lastReplayResult",void 0),C([N()],A.prototype,"currentPage",void 0),C([N()],A.prototype,"previousPage",void 0),C([N()],A.prototype,"sections",void 0),C([N()],A.prototype,"settings",void 0),C([N()],A.prototype,"importError",void 0),C([N()],A.prototype,"exportMenuExpanded",void 0),C([N()],A.prototype,"extensionConverters",void 0),C([N()],A.prototype,"replayExtensions",void 0),C([N()],A.prototype,"viewDescriptor",void 0),A=C([k("devtools-recorder-controller")],A);var j=Object.freeze({__proto__:null,get RecorderController(){return A}});let V;class O extends p.Panel.Panel{static panelName="chrome-recorder";#ee;constructor(){super(O.panelName),this.element.setAttribute("jslog",`${R.panel("chrome-recorder").track({resize:!0})}`),this.#ee=new A,this.contentElement.append(this.#ee),this.contentElement.style.minWidth="400px"}static instance(e={forceNew:null}){const{forceNew:t}=e;return V&&!t||(V=new O),V}wasShown(){p.Context.Context.instance().setFlavor(O,this),this.#ee.focus()}willHide(){p.Context.Context.instance().setFlavor(O,null)}handleActions(e){this.#ee.handleActions(e)}isActionPossible(e){return this.#ee.isActionPossible(e)}}var D=Object.freeze({__proto__:null,RecorderPanel:O,ActionDelegate:class{handleAction(e,t){return(async()=>{await p.ViewManager.ViewManager.instance().showView(O.panelName);const e=p.ViewManager.ViewManager.instance().view(O.panelName);if(e){(await e.widget()).handleActions(t)}})(),!0}}});export{j as RecorderController,P as RecorderEvents,D as RecorderPanel};