chrome-devtools-frontend 1.0.1536371 → 1.0.1537268

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. package/front_end/core/host/AidaClient.ts +64 -5
  2. package/front_end/core/host/DispatchHttpRequestClient.ts +62 -0
  3. package/front_end/core/host/GdpClient.ts +8 -57
  4. package/front_end/core/host/host.ts +2 -0
  5. package/front_end/core/protocol_client/CDPConnection.ts +10 -8
  6. package/front_end/core/protocol_client/InspectorBackend.ts +36 -42
  7. package/front_end/core/sdk/EnhancedTracesParser.ts +20 -5
  8. package/front_end/core/sdk/RehydratingConnection.ts +112 -4
  9. package/front_end/core/sdk/RehydratingObject.ts +8 -0
  10. package/front_end/core/sdk/TraceObject.ts +5 -1
  11. package/front_end/models/javascript_metadata/NativeFunctions.js +1 -1
  12. package/front_end/models/trace/types/File.ts +9 -0
  13. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +5 -9
  14. package/front_end/panels/ai_assistance/components/ChatView.ts +58 -70
  15. package/front_end/panels/application/BackForwardCacheTreeElement.ts +2 -6
  16. package/front_end/panels/application/components/BackForwardCacheView.ts +74 -69
  17. package/front_end/panels/application/components/FrameDetailsView.ts +8 -11
  18. package/front_end/panels/application/components/OriginTrialTreeView.ts +65 -69
  19. package/front_end/panels/application/components/backForwardCacheView.css +4 -0
  20. package/front_end/panels/application/components/badge.css +1 -1
  21. package/front_end/panels/browser_debugger/CategorizedBreakpointsSidebarPane.ts +44 -53
  22. package/front_end/panels/recorder/RecorderController.ts +1 -2
  23. package/front_end/panels/recorder/components/CreateRecordingView.ts +153 -129
  24. package/front_end/panels/settings/AISettingsTab.ts +162 -171
  25. package/front_end/panels/settings/SettingsScreen.ts +3 -7
  26. package/front_end/panels/settings/aiSettingsTab.css +151 -148
  27. package/front_end/panels/settings/settings-meta.ts +1 -2
  28. package/front_end/panels/sources/AddSourceMapURLDialog.ts +23 -26
  29. package/front_end/panels/timeline/TimelinePanel.ts +60 -11
  30. package/front_end/panels/timeline/components/ExportTraceOptions.ts +33 -34
  31. package/front_end/third_party/chromium/README.chromium +2 -2
  32. package/front_end/third_party/puppeteer/README.chromium +2 -2
  33. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Browser.d.ts +9 -1
  34. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Browser.d.ts.map +1 -1
  35. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Browser.js.map +1 -1
  36. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/BrowserContext.d.ts +2 -2
  37. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/BrowserContext.d.ts.map +1 -1
  38. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/BrowserContext.js.map +1 -1
  39. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.d.ts +13 -1
  40. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.d.ts.map +1 -1
  41. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.js.map +1 -1
  42. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/BrowserContext.d.ts +2 -2
  43. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/BrowserContext.d.ts.map +1 -1
  44. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/BrowserContext.js +5 -2
  45. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/BrowserContext.js.map +1 -1
  46. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Page.d.ts +2 -2
  47. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Page.d.ts.map +1 -1
  48. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Page.js +3 -1
  49. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Page.js.map +1 -1
  50. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Realm.d.ts +1 -12
  51. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Realm.d.ts.map +1 -1
  52. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Accessibility.d.ts +6 -0
  53. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Accessibility.d.ts.map +1 -1
  54. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Accessibility.js +1 -0
  55. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Accessibility.js.map +1 -1
  56. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.d.ts +2 -2
  57. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.d.ts.map +1 -1
  58. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.js +6 -1
  59. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.js.map +1 -1
  60. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/BrowserContext.d.ts +2 -1
  61. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/BrowserContext.d.ts.map +1 -1
  62. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/BrowserContext.js +2 -2
  63. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/BrowserContext.js.map +1 -1
  64. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.d.ts +2 -2
  65. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.d.ts.map +1 -1
  66. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.js +3 -1
  67. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.js.map +1 -1
  68. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/injected/injected.d.ts +1 -1
  69. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.d.ts +3 -3
  70. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js +3 -3
  71. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js.map +1 -1
  72. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Mutex.d.ts +2 -2
  73. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/disposable.d.ts +2 -2
  74. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/disposable.d.ts.map +1 -1
  75. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/disposable.js +3 -1
  76. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/disposable.js.map +1 -1
  77. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/util.d.ts +1 -0
  78. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/util.d.ts.map +1 -1
  79. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/util.js +1 -0
  80. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/util.js.map +1 -1
  81. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.d.ts +1 -1
  82. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.js +1 -1
  83. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.d.ts +28 -3
  84. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +21 -10
  85. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Browser.d.ts +9 -1
  86. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Browser.d.ts.map +1 -1
  87. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Browser.js.map +1 -1
  88. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/BrowserContext.d.ts +2 -2
  89. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/BrowserContext.d.ts.map +1 -1
  90. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/BrowserContext.js.map +1 -1
  91. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Input.d.ts +1 -1
  92. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Input.d.ts.map +1 -1
  93. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.d.ts +13 -1
  94. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.d.ts.map +1 -1
  95. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.js.map +1 -1
  96. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/BrowserContext.d.ts +2 -2
  97. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/BrowserContext.d.ts.map +1 -1
  98. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/BrowserContext.js +5 -2
  99. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/BrowserContext.js.map +1 -1
  100. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Page.d.ts +2 -2
  101. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Page.d.ts.map +1 -1
  102. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Page.js +3 -1
  103. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Page.js.map +1 -1
  104. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/Realm.d.ts +1 -12
  105. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/Realm.d.ts.map +1 -1
  106. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Accessibility.d.ts +6 -0
  107. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Accessibility.d.ts.map +1 -1
  108. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Accessibility.js +1 -0
  109. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Accessibility.js.map +1 -1
  110. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.d.ts +2 -2
  111. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.d.ts.map +1 -1
  112. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.js +6 -1
  113. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.js.map +1 -1
  114. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/BrowserContext.d.ts +2 -1
  115. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/BrowserContext.d.ts.map +1 -1
  116. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/BrowserContext.js +2 -2
  117. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/BrowserContext.js.map +1 -1
  118. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.d.ts +2 -2
  119. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.d.ts.map +1 -1
  120. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.js +3 -1
  121. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.js.map +1 -1
  122. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.d.ts +3 -3
  123. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js +3 -3
  124. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js.map +1 -1
  125. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/disposable.d.ts +2 -2
  126. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/disposable.d.ts.map +1 -1
  127. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/disposable.js +2 -2
  128. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/disposable.js.map +1 -1
  129. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/util.d.ts +1 -0
  130. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/util.d.ts.map +1 -1
  131. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/util.js +1 -0
  132. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/util.js.map +1 -1
  133. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.d.ts +1 -1
  134. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.js +1 -1
  135. package/front_end/third_party/puppeteer/package/lib/types.d.ts +28 -3
  136. package/front_end/third_party/puppeteer/package/package.json +2 -2
  137. package/front_end/third_party/puppeteer/package/src/api/Browser.ts +13 -1
  138. package/front_end/third_party/puppeteer/package/src/api/BrowserContext.ts +7 -2
  139. package/front_end/third_party/puppeteer/package/src/api/Page.ts +14 -1
  140. package/front_end/third_party/puppeteer/package/src/bidi/BrowserContext.ts +8 -5
  141. package/front_end/third_party/puppeteer/package/src/bidi/Page.ts +5 -2
  142. package/front_end/third_party/puppeteer/package/src/cdp/Accessibility.ts +8 -0
  143. package/front_end/third_party/puppeteer/package/src/cdp/Browser.ts +11 -2
  144. package/front_end/third_party/puppeteer/package/src/cdp/BrowserContext.ts +3 -2
  145. package/front_end/third_party/puppeteer/package/src/cdp/Page.ts +5 -5
  146. package/front_end/third_party/puppeteer/package/src/revisions.ts +3 -3
  147. package/front_end/third_party/puppeteer/package/src/util/disposable.ts +2 -2
  148. package/front_end/third_party/puppeteer/package/src/util/util.ts +1 -0
  149. package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
  150. package/front_end/ui/components/text_editor/AiCodeCompletionProvider.ts +280 -0
  151. package/front_end/ui/components/text_editor/text_editor.ts +1 -0
  152. package/front_end/ui/components/tooltips/Tooltip.ts +1 -1
  153. package/front_end/ui/legacy/Dialog.ts +0 -1
  154. package/front_end/ui/legacy/SettingsUI.ts +0 -14
  155. package/front_end/ui/legacy/XLink.ts +0 -3
  156. package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +9 -0
  157. package/front_end/ui/legacy/components/utils/Linkifier.ts +9 -3
  158. package/front_end/ui/visual_logging/KnownContextValues.ts +1 -1
  159. package/mcp/mcp.ts +5 -0
  160. package/package.json +1 -1
  161. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatterBounds.snapshot.txt +0 -4
  162. package/front_end/ui/components/docs/breadcrumbs_perf/initial-breadcrumb-perf.html +0 -20
  163. package/front_end/ui/components/docs/breadcrumbs_perf/initial-breadcrumb-perf.ts +0 -25
  164. package/front_end/ui/components/docs/breadcrumbs_perf/nested-breadcrumbs-perf.html +0 -20
  165. package/front_end/ui/components/docs/breadcrumbs_perf/nested-breadcrumbs-perf.ts +0 -36
@@ -126,10 +126,9 @@ const str_ = i18n.i18n.registerUIStrings('panels/browser_debugger/CategorizedBre
126
126
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
127
127
  const i18nLazyString = i18n.i18n.getLazilyComputedLocalizedString.bind(undefined, str_);
128
128
 
129
- const {html, render, Directives: {ref}} = Lit;
129
+ const {html, render} = Lit;
130
130
 
131
131
  interface ViewOutput {
132
- defaultFocus: Element|undefined;
133
132
  userExpandedCategories: Set<SDK.CategorizedBreakpoint.Category>;
134
133
  }
135
134
  interface ViewInput {
@@ -211,53 +210,49 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
211
210
  style="flex: 1;"
212
211
  ></devtools-toolbar-input>
213
212
  </devtools-toolbar>
214
- <devtools-tree
215
- ${ref(e => { output.defaultFocus = e; })}
216
- .template=${html`
217
- <ul role="tree">
218
- ${filteredCategories.map(([category, breakpoints]) => html`
219
- <li @expand=${(e: UI.TreeOutline.TreeViewElement.ExpandEvent) => onExpand(category, e)}
220
- role="treeitem"
221
- jslog-context=${category}
222
- aria-checked=${breakpoints.some(breakpoint => breakpoint.enabled())
223
- ? breakpoints.some(breakpoint => !breakpoint.enabled()) ? 'mixed' : true
224
- : false}>
225
- <style>${categorizedBreakpointsSidebarPaneStyles}</style>
226
- <devtools-checkbox
227
- class="small"
228
- tabIndex=-1
229
- title=${getLocalizedCategory(category)}
230
- ?indeterminate=${breakpoints.some(breakpoint => !breakpoint.enabled()) &&
231
- breakpoints.some(breakpoint => breakpoint.enabled())}
232
- ?checked=${!breakpoints.some(breakpoint => !breakpoint.enabled())}
233
- @change=${(e: Event) => onCheckboxClicked(e, category)}
234
- >${getLocalizedCategory(category)}</devtools-checkbox>
235
- <ul
236
- role="group"
237
- ?hidden=${!shouldExpandCategory(breakpoints) && !input.userExpandedCategories.has(category)}>
238
- ${breakpoints.map(breakpoint => html`
239
- <li
240
- role="treeitem"
241
- aria-checked=${breakpoint.enabled()}
242
- jslog-context=${Platform.StringUtilities.toKebabCase(breakpoint.name)}>
243
- <div ?hidden=${breakpoint !== input.highlightedItem} class="breakpoint-hit-marker"></div>
244
- <devtools-checkbox
245
- class=${classes(breakpoint)}
246
- tabIndex=-1
247
- title=${Sources.CategorizedBreakpointL10n.getLocalizedBreakpointName(breakpoint.name)}
248
- ?checked=${breakpoint.enabled()}
249
- aria-description=${breakpoint === input.highlightedItem ? i18nString(UIStrings.breakpointHit)
250
- : Lit.nothing}
251
- @change=${(e: Event) => onCheckboxClicked(e, breakpoint)}
252
- >${Sources.CategorizedBreakpointL10n.getLocalizedBreakpointName(breakpoint.name)}</devtools-checkbox>
253
- </li>`)}
254
- </ul>
255
- </li>`)}
256
- </ul>
257
- `}>
258
- </devtools-tree>`,
259
- // clang-format on
260
- target);
213
+ <devtools-tree autofocus .template=${html`
214
+ <ul role="tree">
215
+ ${filteredCategories.map(([category, breakpoints]) => html`
216
+ <li @expand=${(e: UI.TreeOutline.TreeViewElement.ExpandEvent) => onExpand(category, e)}
217
+ role="treeitem"
218
+ jslog-context=${category}
219
+ aria-checked=${breakpoints.some(breakpoint => breakpoint.enabled())
220
+ ? breakpoints.some(breakpoint => !breakpoint.enabled()) ? 'mixed' : true
221
+ : false}>
222
+ <style>${categorizedBreakpointsSidebarPaneStyles}</style>
223
+ <devtools-checkbox
224
+ class="small"
225
+ tabIndex=-1
226
+ title=${getLocalizedCategory(category)}
227
+ ?indeterminate=${breakpoints.some(breakpoint => !breakpoint.enabled()) &&
228
+ breakpoints.some(breakpoint => breakpoint.enabled())}
229
+ ?checked=${!breakpoints.some(breakpoint => !breakpoint.enabled())}
230
+ @change=${(e: Event) => onCheckboxClicked(e, category)}
231
+ >${getLocalizedCategory(category)}</devtools-checkbox>
232
+ <ul
233
+ role="group"
234
+ ?hidden=${!shouldExpandCategory(breakpoints) && !input.userExpandedCategories.has(category)}>
235
+ ${breakpoints.map(breakpoint => html`
236
+ <li
237
+ role="treeitem"
238
+ aria-checked=${breakpoint.enabled()}
239
+ jslog-context=${Platform.StringUtilities.toKebabCase(breakpoint.name)}>
240
+ <div ?hidden=${breakpoint !== input.highlightedItem} class="breakpoint-hit-marker"></div>
241
+ <devtools-checkbox
242
+ class=${classes(breakpoint)}
243
+ tabIndex=-1
244
+ title=${Sources.CategorizedBreakpointL10n.getLocalizedBreakpointName(breakpoint.name)}
245
+ ?checked=${breakpoint.enabled()}
246
+ aria-description=${breakpoint === input.highlightedItem ? i18nString(UIStrings.breakpointHit)
247
+ : Lit.nothing}
248
+ @change=${(e: Event) => onCheckboxClicked(e, breakpoint)}
249
+ >${Sources.CategorizedBreakpointL10n.getLocalizedBreakpointName(breakpoint.name)}</devtools-checkbox>
250
+ </li>`)}
251
+ </ul>
252
+ </li>`)}
253
+ </ul>`}>
254
+ </devtools-tree>`, target);
255
+ // clang-format on
261
256
  };
262
257
 
263
258
  export abstract class CategorizedBreakpointsSidebarPane extends UI.Widget.VBox {
@@ -341,11 +336,7 @@ export abstract class CategorizedBreakpointsSidebarPane extends UI.Widget.VBox {
341
336
  highlightedItem: this.#highlightedItem,
342
337
  userExpandedCategories: this.#userExpandedCategories,
343
338
  };
344
- const that = this;
345
339
  const output: ViewOutput = {
346
- set defaultFocus(e: Element|undefined) {
347
- that.setDefaultFocusedElement(e ?? null);
348
- },
349
340
  userExpandedCategories: this.#userExpandedCategories,
350
341
  };
351
342
  this.#view(input, output, this.contentElement);
@@ -1072,7 +1072,7 @@ export class RecorderController extends LitElement {
1072
1072
  } else if (this.currentPage === Pages.CREATE_RECORDING_PAGE) {
1073
1073
  if (this.#createRecordingView) {
1074
1074
  this.#shortcutHelper.handleShortcut(() => {
1075
- this.#createRecordingView?.triggerFormSubmission();
1075
+ this.#createRecordingView?.startRecording();
1076
1076
  });
1077
1077
  }
1078
1078
  } else if (this.isRecording) {
@@ -1242,7 +1242,6 @@ export class RecorderController extends LitElement {
1242
1242
  class="recording-view"
1243
1243
  .widgetConfig=${UI.Widget.widgetConfig(Components.CreateRecordingView.CreateRecordingView, {
1244
1244
  recorderSettings: this.#recorderSettings,
1245
- defaultRecordingName: this.#recorderSettings.defaultTitle,
1246
1245
  onRecordingStarted: this.#onRecordingStarted.bind(this),
1247
1246
  onRecordingCancelled: this.onRecordingCancelled.bind(this),
1248
1247
  })}
@@ -17,7 +17,7 @@ import * as Actions from '../recorder-actions/recorder-actions.js';
17
17
 
18
18
  import createRecordingViewStyles from './createRecordingView.css.js';
19
19
 
20
- const {html, Directives: {ifDefined, ref, createRef}} = Lit;
20
+ const {html, Directives: {ref, createRef, repeat}} = Lit;
21
21
 
22
22
  const UIStrings = {
23
23
  /**
@@ -103,91 +103,74 @@ const str_ = i18n.i18n.registerUIStrings(
103
103
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
104
104
 
105
105
  export interface ViewInput {
106
- defaultRecordingName: string;
107
- recorderSettings?: Models.RecorderSettings.RecorderSettings;
106
+ name: string;
107
+ selectorAttribute: string;
108
+ selectorTypes: Array<{
109
+ selectorType: Models.Schema.SelectorType,
110
+ checked: boolean,
111
+ }>;
108
112
  error?: Error;
109
- startRecording: (name: string, selectorTypes: Models.Schema.SelectorType[], selectorAttribute?: string) => void;
113
+ onRecordingStarted: () => void;
110
114
  onRecordingCancelled: () => void;
111
- resetError: () => void;
115
+ onErrorReset: () => void;
116
+ onUpdate: (update: {
117
+ selectorType: Models.Schema.SelectorType,
118
+ checked: boolean,
119
+ }|{
120
+ name: string,
121
+ }|{
122
+ selectorAttribute: string,
123
+ }) => void;
112
124
  }
113
125
 
114
126
  export interface ViewOutput {
115
127
  focusInput?: () => void;
116
- triggerFormSubmission?: () => void;
117
128
  }
118
129
 
119
130
  export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLElement): void => {
120
- const {defaultRecordingName, recorderSettings, error, startRecording, onRecordingCancelled, resetError} = input;
121
-
122
- // TODO(crbug.com/455531160): move state from input elements into the presenter widget.
123
- const selectorTypeToLabel = new Map([
124
- [Models.Schema.SelectorType.ARIA, i18nString(UIStrings.selectorTypeARIA)],
125
- [Models.Schema.SelectorType.CSS, i18nString(UIStrings.selectorTypeCSS)],
126
- [Models.Schema.SelectorType.Text, i18nString(UIStrings.selectorTypeText)],
127
- [
128
- Models.Schema.SelectorType.XPath,
129
- i18nString(UIStrings.selectorTypeXPath),
130
- ],
131
- [
132
- Models.Schema.SelectorType.Pierce,
133
- i18nString(UIStrings.selectorTypePierce),
134
- ],
135
- ]);
136
- function getSelectorTypes(): Models.Schema.SelectorType[] {
137
- const selectorTypeElements = target.querySelectorAll(
138
- '.selector-type input[type=checkbox]',
139
- );
140
- const selectorTypesToRecord: Models.Schema.SelectorType[] = [];
141
- for (const selectorType of selectorTypeElements) {
142
- const checkbox = selectorType as HTMLInputElement;
143
- const checkboxValue = checkbox.value as Models.Schema.SelectorType;
144
- if (checkbox.checked) {
145
- selectorTypesToRecord.push(checkboxValue);
146
- }
147
- }
148
- return selectorTypesToRecord;
149
- }
150
-
151
- const selectorAttributeInputRef = createRef<HTMLInputElement>();
152
-
153
- function getSelectorAttribute(): string|undefined {
154
- const selectorAttribute = selectorAttributeInputRef.value?.value.trim();
155
- if (!selectorAttribute) {
156
- return undefined;
157
- }
158
- return selectorAttribute;
159
- }
131
+ const {
132
+ name,
133
+ selectorAttribute,
134
+ selectorTypes,
135
+ error,
136
+ onUpdate,
137
+ onRecordingStarted,
138
+ onRecordingCancelled,
139
+ onErrorReset
140
+ } = input;
160
141
 
161
142
  const nameInputRef = createRef<HTMLInputElement>();
162
143
 
163
- function handleStartRecording(): void {
164
- startRecording(nameInputRef.value?.value ?? '', getSelectorTypes(), getSelectorAttribute());
165
- }
166
-
167
144
  const onKeyDown = (event: KeyboardEvent): void => {
168
145
  if (error) {
169
- resetError();
146
+ onErrorReset();
170
147
  }
171
148
 
172
149
  const keyboardEvent = event;
173
150
  if (keyboardEvent.key === 'Enter') {
174
- handleStartRecording();
151
+ onRecordingStarted();
175
152
  event.stopPropagation();
176
153
  event.preventDefault();
177
154
  }
178
155
  };
179
156
 
180
- const onInputFocus = (): void => {
181
- nameInputRef.value?.select();
182
- };
183
-
184
157
  output.focusInput = () => {
185
158
  nameInputRef.value?.focus();
186
159
  };
187
160
 
188
- output.triggerFormSubmission = () => {
189
- handleStartRecording();
190
- };
161
+ const selectorTypeToLabel = new Map([
162
+ [Models.Schema.SelectorType.ARIA, i18nString(UIStrings.selectorTypeARIA)],
163
+ [Models.Schema.SelectorType.CSS, i18nString(UIStrings.selectorTypeCSS)],
164
+ [Models.Schema.SelectorType.Text, i18nString(UIStrings.selectorTypeText)],
165
+ [
166
+ Models.Schema.SelectorType.XPath,
167
+ i18nString(UIStrings.selectorTypeXPath),
168
+ ],
169
+ [
170
+ Models.Schema.SelectorType.Pierce,
171
+ i18nString(UIStrings.selectorTypePierce),
172
+ ],
173
+ ]);
191
174
 
192
175
  // clang-format off
193
176
  Lit.render(
@@ -215,13 +198,16 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
215
198
  UIStrings.recordingName,
216
199
  )}</label>
217
200
  <input
218
- value=${defaultRecordingName}
219
- @focus=${onInputFocus}
201
+ value=${name}
202
+ @focus=${() => nameInputRef.value?.select()}
220
203
  @keydown=${onKeyDown}
221
204
  jslog=${VisualLogging.textField('user-flow-name').track({change: true})}
222
205
  class="devtools-text-input"
223
206
  id="user-flow-name"
224
207
  ${ref(nameInputRef)}
208
+ @input=${(e:Event) => onUpdate({
209
+ name: (e.target as HTMLInputElement).value.trim()
210
+ })}
225
211
  />
226
212
  <label class="row-label" for="selector-attribute">
227
213
  <span>${i18nString(UIStrings.selectorAttribute)}</span>
@@ -234,13 +220,15 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
234
220
  </x-link>
235
221
  </label>
236
222
  <input
237
- value=${ifDefined(recorderSettings?.selectorAttribute)}
223
+ value=${selectorAttribute}
238
224
  placeholder="data-testid"
239
225
  @keydown=${onKeyDown}
240
226
  jslog=${VisualLogging.textField('selector-attribute').track({change: true})}
241
227
  class="devtools-text-input"
242
228
  id="selector-attribute"
243
- ${ref(selectorAttributeInputRef)}
229
+ @input=${(e:Event) => onUpdate({
230
+ selectorAttribute: (e.target as HTMLInputElement).value.trim()
231
+ })}
244
232
  />
245
233
  <label class="row-label">
246
234
  <span>${i18nString(UIStrings.selectorTypes)}</span>
@@ -253,37 +241,34 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
253
241
  </x-link>
254
242
  </label>
255
243
  <div class="checkbox-container">
256
- ${Object.values(Models.Schema.SelectorType).map(selectorType => {
257
- const checked =
258
- recorderSettings?.getSelectorByType(selectorType);
244
+ ${repeat(selectorTypes, item => {
259
245
  return html`
260
- <label class="checkbox-label selector-type">
261
- <input
262
- @keydown=${onKeyDown}
263
- .value=${selectorType}
264
- jslog=${VisualLogging.toggle().track({click: true}).context(`selector-${selectorType}`)}
265
- ?checked=${checked}
266
- type="checkbox"
267
- />
268
- ${selectorTypeToLabel.get(selectorType) || selectorType}
269
- </label>
270
- `;
246
+ <label class="checkbox-label selector-type">
247
+ <input
248
+ @keydown=${onKeyDown}
249
+ .value=${item.selectorType}
250
+ jslog=${VisualLogging.toggle().track({click: true}).context(`selector-${item.selectorType}`)}
251
+ ?checked=${item.checked}
252
+ type="checkbox"
253
+ @change=${(e:Event) => onUpdate({
254
+ selectorType: item.selectorType,
255
+ checked: (e.target as HTMLInputElement).checked
256
+ })}
257
+ />
258
+ ${selectorTypeToLabel.get(item.selectorType) || item.selectorType}
259
+ </label>
260
+ `;
271
261
  })}
272
262
  </div>
273
-
274
263
  ${
275
264
  error &&
276
- html`
277
- <div class="error" role="alert">
278
- ${error.message}
279
- </div>
280
- `
265
+ html` <div class="error" role="alert"> ${error.message} </div>`
281
266
  }
282
267
  </div>
283
268
  <div class="footer">
284
269
  <div class="controls">
285
270
  <devtools-control-button
286
- @click=${handleStartRecording}
271
+ @click=${onRecordingStarted}
287
272
  .label=${i18nString(UIStrings.startRecording)}
288
273
  .shape=${'circle'}
289
274
  jslog=${VisualLogging.action(Actions.RecorderActions.START_RECORDING).track({click: true})}
@@ -302,15 +287,33 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
302
287
 
303
288
  export class CreateRecordingView extends UI.Widget.Widget {
304
289
  #error?: Error;
290
+ #name = '';
291
+ #selectorAttribute = '';
292
+ #selectorTypes: Array<{
293
+ selectorType: Models.Schema.SelectorType,
294
+ checked: boolean,
295
+ }> = [];
305
296
  #view: typeof DEFAULT_VIEW;
306
297
  #output: ViewOutput = {};
298
+ #recorderSettings?: Models.RecorderSettings.RecorderSettings;
307
299
 
308
300
  onRecordingStarted:
309
301
  (data: {name: string, selectorTypesToRecord: Models.Schema.SelectorType[], selectorAttribute?: string}) => void =
310
302
  () => {};
311
303
  onRecordingCancelled = (): void => {};
312
- recorderSettings?: Models.RecorderSettings.RecorderSettings;
313
- defaultRecordingName = '';
304
+
305
+ set recorderSettings(value: Models.RecorderSettings.RecorderSettings) {
306
+ this.#recorderSettings = value;
307
+ this.#name = this.#recorderSettings.defaultTitle;
308
+ this.#selectorAttribute = this.#recorderSettings.selectorAttribute;
309
+ this.#selectorTypes = Object.values(Models.Schema.SelectorType).map(selectorType => {
310
+ return {
311
+ selectorType,
312
+ checked: this.#recorderSettings?.getSelectorByType(selectorType) ?? true,
313
+ };
314
+ }),
315
+ this.requestUpdate();
316
+ }
314
317
 
315
318
  constructor(element?: HTMLElement, view?: typeof DEFAULT_VIEW) {
316
319
  super(element, {useShadowDom: true});
@@ -323,57 +326,78 @@ export class CreateRecordingView extends UI.Widget.Widget {
323
326
  void this.updateComplete.then(() => this.#output.focusInput?.());
324
327
  }
325
328
 
326
- triggerFormSubmission(): void {
327
- this.#output.triggerFormSubmission?.();
329
+ startRecording(): void {
330
+ if (!this.#recorderSettings) {
331
+ throw new Error('settings not set');
332
+ }
333
+
334
+ if (!this.#name.trim()) {
335
+ this.#error = new Error(i18nString(UIStrings.recordingNameIsRequired));
336
+ this.requestUpdate();
337
+ return;
338
+ }
339
+
340
+ const selectorTypesToRecord = this.#selectorTypes.filter(item => item.checked).map(item => item.selectorType);
341
+
342
+ if (!selectorTypesToRecord.includes(Models.Schema.SelectorType.CSS) &&
343
+ !selectorTypesToRecord.includes(Models.Schema.SelectorType.XPath) &&
344
+ !selectorTypesToRecord.includes(Models.Schema.SelectorType.Pierce)) {
345
+ this.#error = new Error(i18nString(UIStrings.includeNecessarySelectors));
346
+ this.requestUpdate();
347
+ return;
348
+ }
349
+
350
+ for (const selectorType of Object.values(Models.Schema.SelectorType)) {
351
+ this.#recorderSettings.setSelectorByType(
352
+ selectorType,
353
+ selectorTypesToRecord.includes(selectorType),
354
+ );
355
+ }
356
+
357
+ const selectorAttribute = this.#selectorAttribute.trim();
358
+ if (selectorAttribute) {
359
+ this.#recorderSettings.selectorAttribute = selectorAttribute;
360
+ }
361
+
362
+ this.onRecordingStarted({
363
+ name: this.#name,
364
+ selectorTypesToRecord,
365
+ selectorAttribute: this.#selectorAttribute ? this.#selectorAttribute : undefined,
366
+ });
367
+
368
+ Badges.UserBadges.instance().recordAction(Badges.BadgeAction.RECORDER_RECORDING_STARTED);
328
369
  }
329
370
 
330
371
  override performUpdate(): void {
331
372
  this.#view(
332
373
  {
333
- defaultRecordingName: this.defaultRecordingName,
334
- recorderSettings: this.recorderSettings,
374
+ name: this.#name,
375
+ selectorAttribute: this.#selectorAttribute,
376
+ selectorTypes: this.#selectorTypes,
335
377
  error: this.#error,
336
378
  onRecordingCancelled: this.onRecordingCancelled,
337
- startRecording:
338
- (name: string, selectorTypesToRecord: Models.Schema.SelectorType[], selectorAttribute?: string): void => {
339
- if (!this.recorderSettings) {
340
- throw new Error('settings not set');
341
- }
342
-
343
- if (!name.trim()) {
344
- this.#error = new Error(i18nString(UIStrings.recordingNameIsRequired));
345
- this.requestUpdate();
346
- return;
347
- }
348
-
349
- if (!selectorTypesToRecord.includes(Models.Schema.SelectorType.CSS) &&
350
- !selectorTypesToRecord.includes(Models.Schema.SelectorType.XPath) &&
351
- !selectorTypesToRecord.includes(Models.Schema.SelectorType.Pierce)) {
352
- this.#error = new Error(i18nString(UIStrings.includeNecessarySelectors));
353
- this.requestUpdate();
354
- return;
355
- }
356
-
357
- for (const selectorType of Object.values(Models.Schema.SelectorType)) {
358
- this.recorderSettings.setSelectorByType(
359
- selectorType,
360
- selectorTypesToRecord.includes(selectorType),
361
- );
379
+ onUpdate: update => {
380
+ if ('name' in update) {
381
+ this.#name = update.name;
382
+ } else if ('selectorAttribute' in update) {
383
+ this.#selectorAttribute = update.selectorAttribute;
384
+ } else {
385
+ this.#selectorTypes = this.#selectorTypes.map(item => {
386
+ if (item.selectorType === update.selectorType) {
387
+ return {
388
+ ...item,
389
+ checked: update.checked,
390
+ };
362
391
  }
363
-
364
- if (selectorAttribute) {
365
- this.recorderSettings.selectorAttribute = selectorAttribute;
366
- }
367
-
368
- this.onRecordingStarted({
369
- name,
370
- selectorTypesToRecord,
371
- selectorAttribute,
372
- });
373
-
374
- Badges.UserBadges.instance().recordAction(Badges.BadgeAction.RECORDER_RECORDING_STARTED);
375
- },
376
- resetError: () => {
392
+ return item;
393
+ });
394
+ }
395
+ this.requestUpdate();
396
+ },
397
+ onRecordingStarted: (): void => {
398
+ this.startRecording();
399
+ },
400
+ onErrorReset: () => {
377
401
  this.#error = undefined;
378
402
  this.requestUpdate();
379
403
  },