chrome-devtools-frontend 1.0.1611825 → 1.0.1613625

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 (56) hide show
  1. package/.agents/skills/verification/SKILL.md +5 -1
  2. package/front_end/Images/src/flowsheet.svg +1 -0
  3. package/front_end/core/common/Color.ts +3 -2
  4. package/front_end/core/common/MapWithDefault.ts +2 -2
  5. package/front_end/core/common/Object.ts +9 -6
  6. package/front_end/core/platform/StringUtilities.ts +5 -0
  7. package/front_end/core/sdk/NetworkManager.ts +7 -0
  8. package/front_end/generated/InspectorBackendCommands.ts +2 -2
  9. package/front_end/generated/protocol.ts +12 -2
  10. package/front_end/models/ai_assistance/agents/README.md +77 -0
  11. package/front_end/models/greendev/Prototypes.ts +7 -4
  12. package/front_end/models/har/HARFormat.ts +30 -0
  13. package/front_end/models/har/Importer.ts +12 -1
  14. package/front_end/models/har/Log.ts +28 -0
  15. package/front_end/models/heap_snapshot/HeapSnapshotProxy.ts +6 -4
  16. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +62 -22
  17. package/front_end/panels/ai_assistance/PatchWidget.ts +7 -23
  18. package/front_end/panels/ai_assistance/SelectWorkspaceDialog.ts +3 -3
  19. package/front_end/panels/ai_assistance/ai_assistance-meta.ts +7 -0
  20. package/front_end/panels/ai_assistance/ai_assistance.ts +1 -0
  21. package/front_end/panels/ai_assistance/components/ChatMessage.ts +13 -3
  22. package/front_end/panels/ai_assistance/components/ChatView.ts +4 -0
  23. package/front_end/panels/ai_assistance/components/ExportForAgentsDialog.ts +14 -7
  24. package/front_end/panels/ai_assistance/components/OptInChangeDialog.ts +179 -0
  25. package/front_end/panels/ai_assistance/components/WalkthroughView.ts +4 -3
  26. package/front_end/panels/ai_assistance/components/optInChangeDialog.css +95 -0
  27. package/front_end/panels/ai_assistance/components/walkthroughView.css +1 -1
  28. package/front_end/panels/application/CookieItemsView.ts +3 -2
  29. package/front_end/panels/changes/ChangesView.ts +0 -12
  30. package/front_end/panels/common/common.ts +0 -1
  31. package/front_end/panels/console/ConsolePrompt.ts +2 -2
  32. package/front_end/panels/elements/StylePropertyTreeElement.ts +2 -1
  33. package/front_end/panels/elements/StylesSidebarPane.ts +6 -2
  34. package/front_end/panels/elements/elements-meta.ts +14 -0
  35. package/front_end/panels/emulation/DeviceModeToolbar.ts +13 -4
  36. package/front_end/panels/network/NetworkLogView.ts +58 -28
  37. package/front_end/panels/profiler/HeapSnapshotDataGrids.ts +1 -1
  38. package/front_end/panels/profiler/HeapSnapshotGridNodes.ts +9 -17
  39. package/front_end/panels/protocol_monitor/JSONEditor.ts +30 -4
  40. package/front_end/panels/recorder/RecorderController.ts +4 -4
  41. package/front_end/panels/recorder/models/RecordingPlayer.ts +1 -1
  42. package/front_end/panels/settings/AISettingsTab.ts +53 -6
  43. package/front_end/panels/settings/SettingsScreen.ts +2 -2
  44. package/front_end/services/puppeteer/PuppeteerConnection.ts +1 -1
  45. package/front_end/third_party/chromium/README.chromium +1 -1
  46. package/front_end/ui/kit/icons/Icon.ts +1 -0
  47. package/front_end/ui/legacy/SplitWidget.ts +9 -6
  48. package/front_end/ui/legacy/TextPrompt.ts +1 -1
  49. package/front_end/ui/legacy/Treeoutline.ts +3 -2
  50. package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +4 -3
  51. package/front_end/ui/legacy/components/settings_ui/SettingsUI.ts +3 -3
  52. package/front_end/ui/legacy/components/source_frame/FontView.ts +101 -88
  53. package/front_end/ui/legacy/components/source_frame/SourceFrame.ts +4 -4
  54. package/front_end/ui/visual_logging/KnownContextValues.ts +13 -0
  55. package/package.json +2 -2
  56. package/front_end/panels/common/CopyChangesToPrompt.ts +0 -233
@@ -13,7 +13,6 @@ import * as i18n from '../../core/i18n/i18n.js';
13
13
  import * as Platform from '../../core/platform/platform.js';
14
14
  import * as Root from '../../core/root/root.js';
15
15
  import * as AiAssistanceModel from '../../models/ai_assistance/ai_assistance.js';
16
- import * as GreenDev from '../../models/greendev/greendev.js';
17
16
  import * as Persistence from '../../models/persistence/persistence.js';
18
17
  import * as Workspace from '../../models/workspace/workspace.js';
19
18
  import * as WorkspaceDiff from '../../models/workspace_diff/workspace_diff.js';
@@ -273,20 +272,6 @@ const DEFAULT_VIEW: View = (input, output, target) => {
273
272
  nothing}`;
274
273
  }
275
274
 
276
- function renderCopyPrompt(changedCode?: string): LitTemplate {
277
- if (!GreenDev.Prototypes.instance().isEnabled('copyToGemini') || !changedCode) {
278
- return nothing;
279
- }
280
-
281
- // clang-format off
282
- return html`<devtools-widget class="copy-to-prompt"
283
- ${widget(PanelCommon.CopyChangesToPrompt, {
284
- workspaceDiff: input.workspaceDiff,
285
- patchAgentCSSChange: changedCode,
286
- })}></devtools-widget>`;
287
- // clang-format on
288
- }
289
-
290
275
  function renderFooter(): LitTemplate {
291
276
  if (input.savedToDisk) {
292
277
  return nothing;
@@ -357,7 +342,6 @@ const DEFAULT_VIEW: View = (input, output, target) => {
357
342
  </div>
358
343
  ` :
359
344
  html`
360
- ${renderCopyPrompt(input.changeSummary)}
361
345
  <devtools-button
362
346
  @click=${input.onApplyToWorkspace}
363
347
  .jslogContext=${'patch-widget.apply-to-workspace'}
@@ -435,7 +419,7 @@ export class PatchWidget extends UI.Widget.Widget {
435
419
  #project?: Workspace.Workspace.Project;
436
420
  #patchSources?: string;
437
421
  #savedToDisk?: boolean;
438
- #noLogging: boolean; // Whether the enterprise setting is `ALLOW_WITHOUT_LOGGING` or not.
422
+ #loggingEnabled: boolean; // Whether the enterprise setting is `ALLOW_WITHOUT_LOGGING` or not.
439
423
  #patchSuggestionState = PatchSuggestionState.INITIAL;
440
424
  #workspaceDiff = WorkspaceDiff.WorkspaceDiff.workspaceDiff();
441
425
  #workspace = Workspace.Workspace.WorkspaceImpl.instance();
@@ -450,7 +434,7 @@ export class PatchWidget extends UI.Widget.Widget {
450
434
  }) {
451
435
  super(element);
452
436
  this.#aidaClient = opts?.aidaClient ?? new Host.AidaClient.AidaClient();
453
- this.#noLogging = Root.Runtime.hostConfig.aidaAvailability?.enterprisePolicyValue ===
437
+ this.#loggingEnabled = Root.Runtime.hostConfig.aidaAvailability?.enterprisePolicyValue !==
454
438
  Root.Runtime.GenAiEnterprisePolicyValue.ALLOW_WITHOUT_LOGGING;
455
439
  this.#view = view;
456
440
 
@@ -514,9 +498,9 @@ export class PatchWidget extends UI.Widget.Widget {
514
498
  projectPath,
515
499
  projectType: this.#getSelectedProjectType(projectPath),
516
500
  savedToDisk: this.#savedToDisk,
517
- applyToWorkspaceTooltipText: this.#noLogging ?
518
- lockedString(UIStringsNotTranslate.applyToWorkspaceTooltipNoLogging) :
519
- lockedString(UIStringsNotTranslate.applyToWorkspaceTooltip),
501
+ applyToWorkspaceTooltipText: this.#loggingEnabled ?
502
+ lockedString(UIStringsNotTranslate.applyToWorkspaceTooltip) :
503
+ lockedString(UIStringsNotTranslate.applyToWorkspaceTooltipNoLogging),
520
504
  onLearnMoreTooltipClick: this.#onLearnMoreTooltipClick.bind(this),
521
505
  onApplyToWorkspace: this.#onApplyToWorkspace.bind(this),
522
506
  onCancel: () => {
@@ -566,8 +550,8 @@ export class PatchWidget extends UI.Widget.Widget {
566
550
  },
567
551
  {
568
552
  iconName: 'google',
569
- content: this.#noLogging ? lockedString(UIStringsNotTranslate.freDisclaimerTextPrivacyNoLogging) :
570
- lockedString(UIStringsNotTranslate.freDisclaimerTextPrivacy),
553
+ content: this.#loggingEnabled ? lockedString(UIStringsNotTranslate.freDisclaimerTextPrivacy) :
554
+ lockedString(UIStringsNotTranslate.freDisclaimerTextPrivacyNoLogging),
571
555
  },
572
556
  {
573
557
  iconName: 'warning',
@@ -233,14 +233,14 @@ export class SelectWorkspaceDialog extends UI.Widget.VBox {
233
233
  }
234
234
 
235
235
  override performUpdate(): void {
236
- const noLogging = Root.Runtime.hostConfig.aidaAvailability?.enterprisePolicyValue ===
236
+ const loggingEnabled = Root.Runtime.hostConfig.aidaAvailability?.enterprisePolicyValue !==
237
237
  Root.Runtime.GenAiEnterprisePolicyValue.ALLOW_WITHOUT_LOGGING;
238
238
 
239
239
  const viewInput = {
240
240
  folders: this.#folders,
241
241
  selectedIndex: this.#selectedIndex,
242
- selectProjectRootText: noLogging ? lockedString(UIStringsNotTranslate.selectProjectRootNoLogging) :
243
- lockedString(UIStringsNotTranslate.selectProjectRoot),
242
+ selectProjectRootText: loggingEnabled ? lockedString(UIStringsNotTranslate.selectProjectRoot) :
243
+ lockedString(UIStringsNotTranslate.selectProjectRootNoLogging),
244
244
  showAutomaticWorkspaceNudge: this.#automaticFileSystemManager.automaticFileSystem === null &&
245
245
  this.#automaticFileSystemManager.availability === 'available',
246
246
  onProjectSelected: (index: number) => {
@@ -161,6 +161,13 @@ Common.Settings.registerSettingExtension({
161
161
  },
162
162
  });
163
163
 
164
+ Common.Settings.registerSettingExtension({
165
+ category: Common.Settings.SettingCategory.AI,
166
+ settingName: 'ai-assistance-v2-opt-in-change-dialog-seen',
167
+ settingType: Common.Settings.SettingType.BOOLEAN,
168
+ defaultValue: false,
169
+ });
170
+
164
171
  UI.ActionRegistration.registerActionExtension({
165
172
  actionId: 'freestyler.main-menu',
166
173
  contextTypes(): [] {
@@ -11,6 +11,7 @@ export * from './SelectWorkspaceDialog.js';
11
11
  export * as ChatMessage from './components/ChatMessage.js';
12
12
  export * as ExploreWidget from './components/ExploreWidget.js';
13
13
  export * as ExportForAgentsDialog from './components/ExportForAgentsDialog.js';
14
+ export * as OptInChangeDialog from './components/OptInChangeDialog.js';
14
15
  export * as PatchWidget from './PatchWidget.js';
15
16
  export * as DisabledWidget from './components/DisabledWidget.js';
16
17
  export * as WalkthroughView from './components/WalkthroughView.js';
@@ -729,7 +729,7 @@ export function renderStep({step, isLoading, markdownRenderer, isLast}: {
729
729
  // clang-format off
730
730
  return html`
731
731
  <details class=${stepClasses}
732
- jslog=${VisualLogging.section('step')}
732
+ jslog=${VisualLogging.expand('step').track({click: true})}
733
733
  .open=${Boolean(step.requestApproval)}>
734
734
  <summary>
735
735
  <div class="summary">
@@ -755,6 +755,7 @@ interface WidgetMakerResponse {
755
755
  customRevealTitle?: Platform.UIString.LocalizedString;
756
756
  // Can be null if the widget is only used to add the Reveal CTA.
757
757
  title: Lit.LitTemplate|Platform.UIString.LocalizedString|null;
758
+ jslogContext?: string;
758
759
  }
759
760
 
760
761
  const nodeCache = new Map<Protocol.DOM.BackendNodeId, SDK.DOMModel.DOMNode>();
@@ -823,6 +824,7 @@ async function makeComputedStyleWidget(widgetData: ComputedStyleAiWidget): Promi
823
824
  </span>
824
825
  </span>`,
825
826
  // clang-format on
827
+ jslogContext: 'computed-styles',
826
828
  };
827
829
  }
828
830
 
@@ -836,6 +838,7 @@ async function makeCoreWebVitalsWidget(widgetData: CoreVitalsAiWidget): Promise<
836
838
  renderedWidget,
837
839
  revealable: new TimelineUtils.Helpers.RevealableCoreVitals(widgetData.data.insightSetKey),
838
840
  title: lockedString(UIStringsNotTranslate.coreVitals),
841
+ jslogContext: 'core-web-vitals',
839
842
  };
840
843
  }
841
844
 
@@ -872,6 +875,7 @@ async function makeStylePropertiesWidget(widgetData: StylePropertiesAiWidget): P
872
875
  node: domNodeForId,
873
876
  })}
874
877
  ></devtools-widget>`,
878
+ jslogContext: 'standalone-styles',
875
879
  };
876
880
  }
877
881
 
@@ -894,6 +898,7 @@ async function makeLcpBreakdownWidget(widgetData: LcpBreakdownAiWidget): Promise
894
898
  renderedWidget,
895
899
  revealable: new TimelineUtils.Helpers.RevealableInsight(insight),
896
900
  title: lockedString(UIStringsNotTranslate.lcpBreakdown),
901
+ jslogContext: 'lcp-breakdown',
897
902
  };
898
903
  }
899
904
 
@@ -922,7 +927,8 @@ async function makeBottomUpTimelineTreeWidget(widgetData: BottomUpTreeAiWidget):
922
927
  return {
923
928
  renderedWidget,
924
929
  revealable: new TimelineUtils.Helpers.RevealableBottomUpProfile(widgetData.data.bounds),
925
- title: lockedString(UIStringsNotTranslate.bottomUpTree)
930
+ title: lockedString(UIStringsNotTranslate.bottomUpTree),
931
+ jslogContext: 'bottom-up',
926
932
  };
927
933
  }
928
934
 
@@ -947,6 +953,7 @@ function renderWidgetResponse(response: WidgetMakerResponse|null): Lit.LitTempla
947
953
  <devtools-button class="widget-reveal-button"
948
954
  .variant=${Buttons.Button.Variant.TEXT}
949
955
  .accessibleLabel=${lockedString(UIStringsNotTranslate.reveal)}
956
+ .jslogContext=${'reveal'}
950
957
  @click=${onReveal}
951
958
  >
952
959
  ${response.customRevealTitle ?? lockedString(UIStringsNotTranslate.reveal)}
@@ -956,7 +963,7 @@ function renderWidgetResponse(response: WidgetMakerResponse|null): Lit.LitTempla
956
963
 
957
964
  // clang-format off
958
965
  return html`
959
- <div class=${classes}>
966
+ <div class=${classes} jslog=${ifDefined(response.jslogContext ? VisualLogging.section(response.jslogContext) : undefined)}>
960
967
  ${response.title ? html`
961
968
  <div class="widget-header">
962
969
  <h3 class="widget-name">${response.title}</h3>
@@ -986,6 +993,7 @@ async function makePerformanceTraceWidget(widgetData: PerformanceTraceAiWidget):
986
993
  title: null,
987
994
  revealable: new Timeline.TimelinePanel.ParsedTraceRevealable(widgetData.data.parsedTrace),
988
995
  customRevealTitle: lockedString(UIStringsNotTranslate.revealTrace),
996
+ jslogContext: 'performance-trace',
989
997
  };
990
998
  }
991
999
 
@@ -1045,6 +1053,7 @@ async function makeDomTreeWidget(widgetData: DomTreeAiWidget): Promise<WidgetMak
1045
1053
  renderedWidget,
1046
1054
  revealable: new SDK.DOMModel.DeferredDOMNode(root.domModel().target(), root.backendNodeId()),
1047
1055
  title: lockedString(UIStringsNotTranslate.lcpElement),
1056
+ jslogContext: 'dom-snapshot',
1048
1057
  };
1049
1058
  }
1050
1059
 
@@ -1607,5 +1616,6 @@ async function makeTimelineRangeSummaryWidget(widgetData: TimelineRangeSummaryAi
1607
1616
  renderedWidget: template,
1608
1617
  revealable: new TimelineUtils.Helpers.RevealableTimeRange(bounds),
1609
1618
  title: lockedString(UIStringsNotTranslate.performanceSummary),
1619
+ jslogContext: 'timeline-range-summary',
1610
1620
  };
1611
1621
  }
@@ -282,6 +282,10 @@ export class ChatView extends HTMLElement {
282
282
  textArea.focus();
283
283
  }
284
284
 
285
+ setInputValue(text: string): void {
286
+ this.#output.input?.getWidget()?.setInputValue(text);
287
+ }
288
+
285
289
  restoreScrollPosition(): void {
286
290
  if (this.#scrollTop === undefined) {
287
291
  return;
@@ -10,6 +10,7 @@ import * as Buttons from '../../../ui/components/buttons/buttons.js';
10
10
  import * as Snackbars from '../../../ui/components/snackbars/snackbars.js';
11
11
  import * as UI from '../../../ui/legacy/legacy.js';
12
12
  import * as Lit from '../../../ui/lit/lit.js';
13
+ import * as VisualLogging from '../../../ui/visual_logging/visual_logging.js';
13
14
 
14
15
  import styles from './exportForAgentsDialog.css.js';
15
16
 
@@ -59,6 +60,8 @@ export const enum StateType {
59
60
  CONVERSATION = 'conversation',
60
61
  }
61
62
 
63
+ const DEFAULT_STATE_TYPE = StateType.PROMPT;
64
+
62
65
  export interface State {
63
66
  activeType: StateType;
64
67
  promptText: string;
@@ -78,14 +81,12 @@ type View = (input: ViewInput, output: undefined, target: HTMLElement) => void;
78
81
  export const DEFAULT_VIEW: View = (input, _output, target): void => {
79
82
  const isPrompt = input.state.activeType === StateType.PROMPT;
80
83
  const buttonText = isPrompt ? i18nString(UIStrings.copyToClipboard) : i18nString(UIStrings.saveAsMarkdown);
81
- const exportText = isPrompt && input.state.isPromptLoading ?
82
- i18nString(UIStrings.generatingSummary) :
83
- (isPrompt ? input.state.promptText : input.state.conversationText);
84
+ const exportText = isPrompt ? input.state.promptText : input.state.conversationText;
84
85
  // clang-format off
85
86
 
86
87
  render(html`
87
88
  <style>${styles}</style>
88
- <div class="export-for-agents-dialog">
89
+ <div class="export-for-agents-dialog" jslog=${VisualLogging.dialog('ai-export-for-agents')}>
89
90
  <header>
90
91
  <h1 id="export-for-agents-dialog-title" tabindex="-1">
91
92
  ${i18nString(UIStrings.exportForAgents)}
@@ -116,13 +117,13 @@ export const DEFAULT_VIEW: View = (input, _output, target): void => {
116
117
  </label>
117
118
  </div>
118
119
  <main>
119
- ${input.state.isPromptLoading ? html`
120
+ ${isPrompt && input.state.isPromptLoading ? html`
120
121
  <span class="prompt-loading">
121
122
  <devtools-spinner></devtools-spinner>
122
123
  ${i18nString(UIStrings.generatingSummary)}
123
124
  </span>
124
125
  ` : Lit.nothing}
125
- <textarea readonly .value=${input.state.isPromptLoading ? '' : exportText}></textarea>
126
+ <textarea readonly .value=${isPrompt && input.state.isPromptLoading ? '' : exportText}></textarea>
126
127
  </main>
127
128
  <div class="disclaimer">${i18nString(UIStrings.disclaimer)}</div>
128
129
  <footer>
@@ -144,6 +145,7 @@ export const DEFAULT_VIEW: View = (input, _output, target): void => {
144
145
  };
145
146
 
146
147
  export class ExportForAgentsDialog extends UI.Widget.VBox {
148
+ static #lastSelectedType: StateType = DEFAULT_STATE_TYPE;
147
149
  readonly #view: View;
148
150
  readonly #dialog: UI.Dialog.Dialog;
149
151
  #state: State;
@@ -160,7 +162,7 @@ export class ExportForAgentsDialog extends UI.Widget.VBox {
160
162
  super();
161
163
  this.#dialog = options.dialog;
162
164
  this.#state = {
163
- activeType: StateType.PROMPT,
165
+ activeType: ExportForAgentsDialog.#lastSelectedType,
164
166
  promptText: typeof options.promptText === 'string' ? options.promptText : '',
165
167
  conversationText: options.markdownText,
166
168
  isPromptLoading: typeof options.promptText !== 'string',
@@ -179,8 +181,13 @@ export class ExportForAgentsDialog extends UI.Widget.VBox {
179
181
  this.requestUpdate();
180
182
  }
181
183
 
184
+ static clearPersistedViewState(): void {
185
+ ExportForAgentsDialog.#lastSelectedType = DEFAULT_STATE_TYPE;
186
+ }
187
+
182
188
  #onStateChange = (newState: StateType): void => {
183
189
  this.#state.activeType = newState;
190
+ ExportForAgentsDialog.#lastSelectedType = newState;
184
191
  this.requestUpdate();
185
192
  };
186
193
 
@@ -0,0 +1,179 @@
1
+ // Copyright 2026 The Chromium Authors
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ import * as i18n from '../../../core/i18n/i18n.js';
6
+ import * as Root from '../../../core/root/root.js';
7
+ import * as Buttons from '../../../ui/components/buttons/buttons.js';
8
+ import * as UI from '../../../ui/legacy/legacy.js';
9
+ import * as Lit from '../../../ui/lit/lit.js';
10
+ import * as VisualLogging from '../../../ui/visual_logging/visual_logging.js';
11
+
12
+ import styles from './optInChangeDialog.css.js';
13
+
14
+ const {html, render} = Lit;
15
+
16
+ const UIStrings = {
17
+ /**
18
+ * @description Title for the opt-in change dialog.
19
+ */
20
+ title: 'AI assistance just got better',
21
+ /**
22
+ * @description First point in the opt-in change dialog, describing the new integration.
23
+ */
24
+ integrationPoint:
25
+ 'AI assistance is now integrated with Application and Lighthouse panels, and pulls context from data sources simultaneously',
26
+ /**
27
+ * @description Second point in the opt-in change dialog, describing the new widgets.
28
+ */
29
+ widgetPoint: 'Use widgets to verify results or jump to source data for select debugging cases',
30
+ /**
31
+ * @description Third point in the opt-in change dialog (disclaimer) for regular users.
32
+ */
33
+ privacyDisclaimer:
34
+ 'Chat messages, data accessible for this site via DevTools panels and Web APIs, and items you select such as network requests, files, and performance traces are sent to Google and may be seen by human reviewers to improve this feature. This is an experimental AI feature and won’t always get it right.',
35
+ /**
36
+ * @description Third point in the opt-in change dialog (disclaimer) for enterprise users with logging disabled.
37
+ */
38
+ privacyDisclaimerEnterpriseNoLogging:
39
+ 'Chat messages, data accessible for this site via DevTools panels and Web APIs, and items you select such as network requests, files, and performance traces are sent to Google. The content submitted to and generated by this feature will not be used to improve Google’s AI models. This is an experimental AI feature and won’t always get it right.',
40
+ /**
41
+ * @description Button text for managing settings.
42
+ */
43
+ manageSettings: 'Manage in settings',
44
+ /**
45
+ * @description Button text for acknowledging the changes.
46
+ */
47
+ gotIt: 'Got it',
48
+ } as const;
49
+
50
+ const str_ = i18n.i18n.registerUIStrings('panels/ai_assistance/components/OptInChangeDialog.ts', UIStrings);
51
+ const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
52
+
53
+ interface ViewInput {
54
+ onGotIt: () => void;
55
+ onManageSettings: () => void;
56
+ loggingEnabled: boolean;
57
+ }
58
+
59
+ type View = (input: ViewInput, output: undefined, target: HTMLElement) => void;
60
+
61
+ export const DEFAULT_VIEW: View = (input, _output, target): void => {
62
+ const disclaimer = input.loggingEnabled ? i18nString(UIStrings.privacyDisclaimer) :
63
+ i18nString(UIStrings.privacyDisclaimerEnterpriseNoLogging);
64
+ // clang-format off
65
+ render(html`
66
+ <style>${styles}</style>
67
+ <div class="opt-in-change-dialog" jslog=${VisualLogging.dialog('ai-v2-opt-in-change-dialog')}>
68
+ <header>
69
+ <div class="header-icon-container">
70
+ <devtools-icon name="smart-assistant" role="presentation"></devtools-icon>
71
+ </div>
72
+ <h1 tabindex="-1">
73
+ ${i18nString(UIStrings.title)}
74
+ </h1>
75
+ </header>
76
+ <main>
77
+ <div class="item">
78
+ <devtools-icon name="lightbulb-spark" role="presentation"></devtools-icon>
79
+ <div class="text">${i18nString(UIStrings.integrationPoint)}</div>
80
+ </div>
81
+ <div class="item">
82
+ <devtools-icon name="flowsheet" role="presentation"></devtools-icon>
83
+ <div class="text">${i18nString(UIStrings.widgetPoint)}</div>
84
+ </div>
85
+ <div class="item">
86
+ <devtools-icon name="google" role="presentation"></devtools-icon>
87
+ <div class="text">${disclaimer}</div>
88
+ </div>
89
+ </main>
90
+ <footer>
91
+ <div class="right-buttons">
92
+ <devtools-button
93
+ @click=${input.onManageSettings}
94
+ .jslogContext=${'ai-assistance-v2-opt-in.manage-settings'}
95
+ .variant=${Buttons.Button.Variant.OUTLINED}
96
+ .accessibleLabel=${i18nString(UIStrings.manageSettings)}
97
+ >
98
+ ${i18nString(UIStrings.manageSettings)}
99
+ </devtools-button>
100
+ <devtools-button
101
+ @click=${input.onGotIt}
102
+ .jslogContext=${'ai-assistance-v2-opt-in.got-it'}
103
+ .variant=${Buttons.Button.Variant.PRIMARY}
104
+ .accessibleLabel=${i18nString(UIStrings.gotIt)}
105
+ >
106
+ ${i18nString(UIStrings.gotIt)}
107
+ </devtools-button>
108
+ </div>
109
+ </footer>
110
+ </div>
111
+ `, target);
112
+ // clang-format on
113
+ };
114
+
115
+ export class OptInChangeDialog extends UI.Widget.VBox {
116
+ readonly #view: View;
117
+ readonly #onGotIt: () => void;
118
+ readonly #onManageSettings: () => void;
119
+
120
+ constructor(
121
+ options: {
122
+ onGotIt: () => void,
123
+ onManageSettings: () => void,
124
+ },
125
+ view: View = DEFAULT_VIEW) {
126
+ super();
127
+ this.#onGotIt = options.onGotIt;
128
+ this.#onManageSettings = options.onManageSettings;
129
+ this.#view = view;
130
+
131
+ this.requestUpdate();
132
+ }
133
+
134
+ override performUpdate(): void {
135
+ const loggingEnabled = Root.Runtime.hostConfig.aidaAvailability?.enterprisePolicyValue !==
136
+ Root.Runtime.GenAiEnterprisePolicyValue.ALLOW_WITHOUT_LOGGING;
137
+
138
+ const viewInput = {
139
+ onGotIt: this.#onGotIt,
140
+ onManageSettings: this.#onManageSettings,
141
+ loggingEnabled,
142
+ };
143
+
144
+ this.#view(viewInput, undefined, this.contentElement);
145
+ }
146
+
147
+ focusTitle(): void {
148
+ this.contentElement.querySelector('h1')?.focus();
149
+ }
150
+
151
+ static show(options: {
152
+ onGotIt: () => void,
153
+ onManageSettings: () => void,
154
+ }): void {
155
+ const dialog = new UI.Dialog.Dialog();
156
+ dialog.setAriaLabel(i18nString(UIStrings.title));
157
+ dialog.setOutsideClickCallback(event => event.consume(true));
158
+ dialog.setCloseOnEscape(false);
159
+ dialog.setSizeBehavior(UI.GlassPane.SizeBehavior.MEASURE_CONTENT);
160
+ dialog.setDimmed(true);
161
+
162
+ const optInChangeDialog = new OptInChangeDialog({
163
+ onGotIt: () => {
164
+ dialog.hide();
165
+ options.onGotIt();
166
+ },
167
+ onManageSettings: () => {
168
+ dialog.hide();
169
+ options.onManageSettings();
170
+ },
171
+ });
172
+ optInChangeDialog.show(dialog.contentElement);
173
+
174
+ void optInChangeDialog.updateComplete.then(() => {
175
+ dialog.show();
176
+ optInChangeDialog.focusTitle();
177
+ });
178
+ }
179
+ }
@@ -9,6 +9,7 @@ import * as Input from '../../../ui/components/input/input.js';
9
9
  import type {MarkdownLitRenderer} from '../../../ui/components/markdown_view/MarkdownView.js';
10
10
  import * as UI from '../../../ui/legacy/legacy.js';
11
11
  import * as Lit from '../../../ui/lit/lit.js';
12
+ import * as VisualLogging from '../../../ui/visual_logging/visual_logging.js';
12
13
 
13
14
  import chatMessageStyles from './chatMessage.css.js';
14
15
  import {type ModelChatMessage, renderStep, type Step, titleForStep} from './ChatMessage.js';
@@ -119,14 +120,14 @@ function renderInlineWalkthrough(input: ViewInput, stepsOutput: Lit.LitTemplate,
119
120
 
120
121
  // clang-format off
121
122
  return html`
122
- <div class="inline-wrapper" ?data-open=${input.isExpanded}>
123
+ <div class="inline-wrapper" ?data-open=${input.isExpanded} jslog=${VisualLogging.section('walkthrough-container')}>
123
124
  <span class="inline-icon">
124
125
  ${input.isLoading ?
125
126
  html`<devtools-spinner aria-label=${lockedString(UIStrings.inProgress)}></devtools-spinner>` :
126
127
  html`<devtools-icon name=${icon}></devtools-icon>`
127
128
  }
128
129
  </span>
129
- <details class="walkthrough-inline" ?open=${input.isExpanded} @toggle=${onToggle}>
130
+ <details class="walkthrough-inline" ?open=${input.isExpanded} @toggle=${onToggle} jslog=${VisualLogging.expand('walkthrough').track({click: true})}>
130
131
  <summary ?data-has-widgets=${!input.isLoading && hasWidgets}>
131
132
  <span class="walkthrough-inline-title">
132
133
  ${input.isExpanded ?
@@ -151,7 +152,7 @@ function renderSidebarWalkthrough(input: ViewInput, stepsOutput: Lit.LitTemplate
151
152
 
152
153
  // clang-format off
153
154
  return html`
154
- <div class="walkthrough-view">
155
+ <div class="walkthrough-view" jslog=${VisualLogging.section('walkthrough-container')}>
155
156
  <div class="walkthrough-header">
156
157
  <h2 class="walkthrough-title">${i18nString(UIStrings.title)}</h2>
157
158
  <devtools-button
@@ -0,0 +1,95 @@
1
+ /*
2
+ * Copyright 2026 The Chromium Authors
3
+ * Use of this source code is governed by a BSD-style license that can be
4
+ * found in the LICENSE file.
5
+ */
6
+
7
+ @scope to (devtools-widget > *) {
8
+ :scope {
9
+ width: 100%;
10
+ box-shadow: none;
11
+ padding: var(--sys-size-8);
12
+ background-color: var(--sys-color-surface);
13
+ border-radius: var(--sys-shape-corner-medium);
14
+ }
15
+
16
+ .opt-in-change-dialog {
17
+ width: var(--sys-size-33);
18
+ max-width: 100%;
19
+ }
20
+
21
+ header {
22
+ display: flex;
23
+ flex-direction: row;
24
+ align-items: center;
25
+ gap: var(--sys-size-8);
26
+ margin-bottom: var(--sys-size-8);
27
+
28
+ h2 {
29
+ margin: 0;
30
+ color: var(--sys-color-on-surface);
31
+ font: var(--sys-typescale-headline5);
32
+ }
33
+
34
+ .header-icon-container {
35
+ background: linear-gradient(
36
+ 135deg,
37
+ var(--sys-color-gradient-primary),
38
+ var(--sys-color-gradient-tertiary)
39
+ );
40
+ border-radius: var(--sys-size-4);
41
+ height: var(--sys-size-14);
42
+ width: var(--sys-size-14);
43
+ display: flex;
44
+ align-items: center;
45
+ justify-content: center;
46
+
47
+ devtools-icon {
48
+ width: var(--sys-size-9);
49
+ height: var(--sys-size-9);
50
+ color: var(--sys-color-on-primary);
51
+ }
52
+ }
53
+ }
54
+
55
+ main {
56
+ background-color: var(--sys-color-surface4);
57
+ border-radius: var(--sys-shape-corner-medium-small);
58
+ padding: var(--sys-size-8);
59
+ display: flex;
60
+ flex-direction: column;
61
+ gap: var(--sys-size-6);
62
+ margin-bottom: var(--sys-size-8);
63
+
64
+ .item {
65
+ display: flex;
66
+ flex-direction: row;
67
+ align-items: center;
68
+ gap: var(--sys-size-8);
69
+
70
+ devtools-icon {
71
+ width: var(--sys-size-8);
72
+ height: var(--sys-size-8);
73
+ flex-shrink: 0;
74
+ color: var(--sys-color-on-surface-subtle);
75
+ }
76
+
77
+ .text {
78
+ font: var(--sys-typescale-body4);
79
+ color: var(--sys-color-on-surface);
80
+ }
81
+ }
82
+ }
83
+
84
+ footer {
85
+ display: flex;
86
+ flex-direction: row;
87
+ align-items: center;
88
+ justify-content: flex-end;
89
+
90
+ .right-buttons {
91
+ display: flex;
92
+ gap: var(--sys-size-5);
93
+ }
94
+ }
95
+ }
@@ -99,7 +99,7 @@
99
99
 
100
100
  .inline-wrapper {
101
101
  display: flex;
102
- align-items: center;
102
+ align-items: flex-start;
103
103
  gap: var(--sys-size-2);
104
104
  justify-content: flex-start;
105
105
 
@@ -375,9 +375,10 @@ export class CookieItemsView extends UI.Widget.VBox {
375
375
  }
376
376
 
377
377
  deleteSelectedItem(): void {
378
- if (this.selectedCookie) {
378
+ const cookie = this.selectedCookie;
379
+ if (cookie) {
379
380
  this.showPreview(null);
380
- void this.model.deleteCookie(this.selectedCookie);
381
+ void this.model.deleteCookie(cookie);
381
382
  }
382
383
  }
383
384