chrome-devtools-frontend 1.0.1571573 → 1.0.1572937

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 (140) hide show
  1. package/front_end/Images/geminiInDevTools.png +0 -0
  2. package/front_end/Images/geminiInDevTools_2x.png +0 -0
  3. package/front_end/Images/src/database-off.svg +1 -0
  4. package/front_end/Images/src/lock-person.svg +1 -1
  5. package/front_end/core/common/Debouncer.ts +10 -1
  6. package/front_end/core/common/SettingRegistration.ts +1 -1
  7. package/front_end/core/host/AidaClient.ts +8 -0
  8. package/front_end/core/host/InspectorFrontendHostAPI.ts +0 -6
  9. package/front_end/core/host/UserMetrics.ts +0 -30
  10. package/front_end/core/root/ExperimentNames.ts +30 -0
  11. package/front_end/core/root/Runtime.ts +12 -27
  12. package/front_end/core/root/root.ts +2 -0
  13. package/front_end/core/sdk/CSSModel.ts +36 -13
  14. package/front_end/core/sdk/CSSProperty.ts +1 -1
  15. package/front_end/core/sdk/CSSPropertyParserMatchers.ts +9 -0
  16. package/front_end/core/sdk/CookieModel.ts +2 -1
  17. package/front_end/core/sdk/DOMModel.ts +1 -1
  18. package/front_end/core/sdk/DebuggerModel.ts +1 -1
  19. package/front_end/core/sdk/OverlayModel.ts +1 -1
  20. package/front_end/core/sdk/SourceMap.ts +1 -1
  21. package/front_end/devtools_compatibility.js +0 -6
  22. package/front_end/entrypoints/main/MainImpl.ts +34 -25
  23. package/front_end/entrypoints/main/main-meta.ts +1 -1
  24. package/front_end/generated/SupportedCSSProperties.js +4 -8
  25. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +0 -180
  26. package/front_end/models/ai_assistance/ai_assistance.ts +0 -2
  27. package/front_end/models/breakpoints/BreakpointManager.ts +3 -3
  28. package/front_end/models/issues_manager/ContrastCheckTrigger.ts +2 -2
  29. package/front_end/models/source_map_scopes/NamesResolver.ts +1 -1
  30. package/front_end/models/trace/EventsSerializer.ts +5 -1
  31. package/front_end/models/trace/types/TraceEvents.ts +4 -0
  32. package/front_end/panels/accessibility/AXBreadcrumbsPane.ts +1 -1
  33. package/front_end/panels/accessibility/AccessibilitySidebarView.ts +1 -1
  34. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +8 -63
  35. package/front_end/panels/ai_assistance/aiAssistancePanel.css +0 -16
  36. package/front_end/panels/ai_assistance/ai_assistance.ts +0 -1
  37. package/front_end/panels/ai_assistance/components/ChatView.ts +123 -108
  38. package/front_end/panels/ai_assistance/components/PerformanceAgentMarkdownRenderer.ts +1 -145
  39. package/front_end/panels/application/DeviceBoundSessionsModel.ts +23 -1
  40. package/front_end/panels/application/DeviceBoundSessionsTreeElement.ts +23 -0
  41. package/front_end/panels/application/FrameDetailsView.ts +11 -10
  42. package/front_end/panels/application/components/BackForwardCacheView.ts +6 -8
  43. package/front_end/panels/application/components/BounceTrackingMitigationsView.ts +4 -3
  44. package/front_end/panels/application/components/ProtocolHandlersView.ts +5 -6
  45. package/front_end/panels/application/components/ReportsGrid.ts +8 -9
  46. package/front_end/panels/application/components/SharedStorageAccessGrid.ts +5 -4
  47. package/front_end/panels/application/components/TrustTokensView.ts +4 -6
  48. package/front_end/panels/application/preloading/PreloadingView.ts +9 -8
  49. package/front_end/panels/application/preloading/components/PreloadingDetailsReportView.ts +237 -230
  50. package/front_end/panels/application/preloading/components/PreloadingGrid.ts +3 -2
  51. package/front_end/panels/application/preloading/components/UsedPreloadingView.ts +6 -10
  52. package/front_end/panels/application/resourcesSidebar.css +8 -0
  53. package/front_end/panels/autofill/AutofillView.ts +4 -3
  54. package/front_end/panels/common/AiCodeGenerationTeaser.ts +35 -4
  55. package/front_end/panels/common/BadgeNotification.ts +17 -14
  56. package/front_end/panels/common/GdpSignUpDialog.ts +5 -6
  57. package/front_end/panels/common/GeminiRebrandPromoDialog.ts +192 -0
  58. package/front_end/panels/common/aiCodeGenerationTeaser.css +16 -1
  59. package/front_end/panels/common/common.ts +1 -0
  60. package/front_end/panels/common/geminiRebrandPromoDialog.css +47 -0
  61. package/front_end/panels/console/ErrorStackParser.ts +11 -16
  62. package/front_end/panels/css_overview/CSSOverviewCompletedView.ts +2 -2
  63. package/front_end/panels/css_overview/CSSOverviewModel.ts +1 -1
  64. package/front_end/panels/elements/ComputedStyleModel.ts +7 -54
  65. package/front_end/panels/elements/ElementsPanel.ts +33 -6
  66. package/front_end/panels/elements/ElementsTreeOutline.ts +1 -1
  67. package/front_end/panels/elements/StylePropertiesSection.ts +16 -8
  68. package/front_end/panels/elements/StylePropertyTreeElement.ts +67 -32
  69. package/front_end/panels/elements/StylesSidebarPane.ts +28 -11
  70. package/front_end/panels/elements/components/CSSHintDetailsView.ts +3 -2
  71. package/front_end/panels/elements/components/CSSPropertyDocsView.ts +3 -2
  72. package/front_end/panels/elements/elements-meta.ts +1 -1
  73. package/front_end/panels/issues/IssueView.ts +6 -6
  74. package/front_end/panels/network/RequestConditionsDrawer.ts +4 -3
  75. package/front_end/panels/network/RequestCookiesView.ts +3 -4
  76. package/front_end/panels/network/RequestTimingView.ts +2 -7
  77. package/front_end/panels/network/components/HeaderSectionRow.ts +3 -2
  78. package/front_end/panels/network/components/RequestHeaderSection.ts +3 -1
  79. package/front_end/panels/profiler/HeapProfileView.ts +3 -3
  80. package/front_end/panels/profiler/HeapSnapshotView.ts +1 -1
  81. package/front_end/panels/profiler/profiler-meta.ts +3 -3
  82. package/front_end/panels/protocol_monitor/protocol_monitor-meta.ts +1 -1
  83. package/front_end/panels/recorder/RecorderController.ts +2 -7
  84. package/front_end/panels/recorder/components/CreateRecordingView.ts +6 -6
  85. package/front_end/panels/recorder/components/RecordingView.ts +0 -38
  86. package/front_end/panels/recorder/components/ReplaySection.ts +0 -14
  87. package/front_end/panels/recorder/components/StepEditor.ts +2 -40
  88. package/front_end/panels/recorder/recorderController.css +3 -3
  89. package/front_end/panels/security/CookieReportView.ts +14 -14
  90. package/front_end/panels/security/cookieControlsView.css +1 -1
  91. package/front_end/panels/security/cookieReportView.css +1 -1
  92. package/front_end/panels/settings/AISettingsTab.ts +8 -10
  93. package/front_end/panels/settings/emulation/components/UserAgentClientHintsForm.ts +4 -12
  94. package/front_end/panels/settings/settings-meta.ts +1 -1
  95. package/front_end/panels/sources/BreakpointEditDialog.ts +4 -3
  96. package/front_end/panels/sources/FilteredUISourceCodeListProvider.ts +1 -1
  97. package/front_end/panels/sources/NavigatorView.ts +4 -4
  98. package/front_end/panels/sources/SourcesPanel.ts +5 -4
  99. package/front_end/panels/sources/components/HeadersView.ts +2 -2
  100. package/front_end/panels/timeline/CompatibilityTracksAppender.ts +3 -2
  101. package/front_end/panels/timeline/ThreadAppender.ts +2 -1
  102. package/front_end/panels/timeline/TimelineController.ts +3 -3
  103. package/front_end/panels/timeline/TimelinePanel.ts +6 -4
  104. package/front_end/panels/timeline/TimelineUIUtils.ts +2 -2
  105. package/front_end/panels/timeline/components/ExportTraceOptions.ts +4 -4
  106. package/front_end/panels/timeline/components/FieldSettingsDialog.ts +13 -6
  107. package/front_end/panels/timeline/components/LiveMetricsView.ts +13 -9
  108. package/front_end/panels/timeline/components/exportTraceOptions.css +1 -1
  109. package/front_end/panels/timeline/components/fieldSettingsDialog.css +1 -1
  110. package/front_end/panels/timeline/components/insights/BaseInsightComponent.ts +2 -19
  111. package/front_end/panels/timeline/components/insights/InsightRenderer.ts +3 -4
  112. package/front_end/panels/timeline/components/insights/baseInsightComponent.css +0 -5
  113. package/front_end/panels/timeline/components/liveMetricsView.css +1 -1
  114. package/front_end/third_party/chromium/README.chromium +1 -1
  115. package/front_end/ui/components/buttons/button.css +4 -0
  116. package/front_end/ui/components/panel_feedback/PreviewToggle.ts +5 -5
  117. package/front_end/ui/components/panel_feedback/previewToggle.css +2 -2
  118. package/front_end/ui/components/text_editor/AiCodeGenerationParser.ts +27 -8
  119. package/front_end/ui/components/text_editor/AiCodeGenerationProvider.ts +36 -6
  120. package/front_end/ui/legacy/ActionRegistration.ts +1 -1
  121. package/front_end/ui/legacy/ContextMenu.ts +2 -2
  122. package/front_end/ui/legacy/EmptyWidget.ts +3 -3
  123. package/front_end/ui/legacy/LinkContextMenuProvider.ts +42 -0
  124. package/front_end/ui/legacy/ViewRegistration.ts +1 -1
  125. package/front_end/ui/legacy/XLink.ts +0 -27
  126. package/front_end/ui/legacy/components/color_picker/ContrastDetails.ts +1 -1
  127. package/front_end/ui/legacy/components/color_picker/ContrastOverlay.ts +4 -4
  128. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +2 -2
  129. package/front_end/ui/legacy/components/perf_ui/perf_ui-meta.ts +1 -1
  130. package/front_end/ui/legacy/inspectorCommon.css +2 -1
  131. package/front_end/ui/legacy/legacy.ts +3 -1
  132. package/front_end/ui/visual_logging/KnownContextValues.ts +2 -0
  133. package/front_end/ui/visual_logging/LoggingDriver.ts +3 -0
  134. package/package.json +1 -1
  135. package/front_end/models/ai_assistance/ArtifactsManager.ts +0 -67
  136. package/front_end/panels/ai_assistance/components/ArtifactsViewer.ts +0 -183
  137. package/front_end/panels/ai_assistance/components/CollapsibleAssistanceContentWidget.ts +0 -89
  138. package/front_end/panels/ai_assistance/components/PerformanceAgentFlameChart.ts +0 -133
  139. package/front_end/panels/ai_assistance/components/artifactsViewer.css +0 -15
  140. package/front_end/panels/ai_assistance/components/collapsibleAssistanceContentWidget.css +0 -32
@@ -23,10 +23,22 @@ const UIStringsNotTranslate = {
23
23
  * @description Text for teaser to generate code in Mac.
24
24
  */
25
25
  cmdItoGenerateCode: 'Cmd+I to generate code',
26
+ /**
27
+ * @description Aria label for teaser to generate code.
28
+ */
29
+ pressCtrlPeriodToLearnHowYourDataIsBeingUsed: 'Press ctrl . (“period”) to learn how your data is being used.',
30
+ /**
31
+ * @description Aria label for teaser to generate code in Mac.
32
+ */
33
+ pressCmdPeriodToLearnHowYourDataIsBeingUsed: 'Press cmd . (“period”) to learn how your data is being used.',
26
34
  /**
27
35
  * @description Text for teaser when generating suggestion.
28
36
  */
29
37
  generating: 'Generating... (esc to cancel)',
38
+ /**
39
+ * @description Aria label for teaser when generating suggestion.
40
+ */
41
+ generatingAriaLabel: 'Generating. Press escape to cancel.',
30
42
  /**
31
43
  * @description Text for teaser for discoverability.
32
44
  */
@@ -103,6 +115,7 @@ export interface ViewInput {
103
115
 
104
116
  export interface ViewOutput {
105
117
  hideTooltip?: () => void;
118
+ showTooltip?: () => void;
106
119
  setTimerText?: (text: string) => void;
107
120
  }
108
121
 
@@ -123,11 +136,18 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
123
136
  }
124
137
  const toGenerateCode = Host.Platform.isMac() ? lockedString(UIStringsNotTranslate.cmdItoGenerateCode) :
125
138
  lockedString(UIStringsNotTranslate.ctrlItoGenerateCode);
139
+ const toLearnHowYourDataIsBeingUsed = Host.Platform.isMac() ?
140
+ lockedString(UIStringsNotTranslate.pressCmdPeriodToLearnHowYourDataIsBeingUsed) :
141
+ lockedString(UIStringsNotTranslate.pressCtrlPeriodToLearnHowYourDataIsBeingUsed);
126
142
  const tooltipDisclaimerText = getTooltipDisclaimerText(input.noLogging, input.panel);
127
143
  // TODO(b/472291834): Disclaimer icon should match the placeholder's color
128
144
  // clang-format off
129
145
  teaserLabel = html`<div class="ai-code-generation-teaser-trigger">
130
- ${toGenerateCode}&nbsp;<devtools-button
146
+ <span aria-atomic="true" aria-live="assertive">${toGenerateCode}&nbsp;</span>
147
+ <div class="ai-code-generation-teaser-screen-reader-only" aria-atomic="true" aria-live="assertive">
148
+ ${toLearnHowYourDataIsBeingUsed}
149
+ </div>
150
+ <devtools-button
131
151
  .data=${{
132
152
  title: lockedString(UIStringsNotTranslate.learnMoreAboutHowYourDataIsBeingUsed),
133
153
  size: Buttons.Button.Size.MICRO,
@@ -147,6 +167,11 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
147
167
  output.hideTooltip = () => {
148
168
  el.hidePopover();
149
169
  };
170
+ output.showTooltip = () => {
171
+ el.showPopover();
172
+ // Announce the content specifically for screen readers when triggered
173
+ UI.ARIAUtils.LiveAnnouncer.status(tooltipDisclaimerText);
174
+ };
150
175
  }
151
176
  })}>
152
177
  <div class="disclaimer-tooltip-container"><div class="tooltip-text">
@@ -175,10 +200,12 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
175
200
  }
176
201
 
177
202
  case AiCodeGenerationTeaserDisplayState.LOADING: {
203
+ const teaserAriaLabel = lockedString(UIStringsNotTranslate.generatingAriaLabel);
178
204
  // clang-format off
179
205
  teaserLabel = html`
180
- <span class="ai-code-generation-spinner"></span>&nbsp;${lockedString(UIStringsNotTranslate.generating)}&nbsp;
181
- <span class="ai-code-generation-timer" ${Directives.ref(el => {
206
+ <div class="ai-code-generation-teaser-screen-reader-only">${teaserAriaLabel}</div>
207
+ <span class="ai-code-generation-spinner" aria-hidden="true"></span>&nbsp;${lockedString(UIStringsNotTranslate.generating)}&nbsp;
208
+ <span class="ai-code-generation-timer" aria-hidden="true" ${Directives.ref(el => {
182
209
  if (el) {
183
210
  output.setTimerText = (text: string) => {
184
211
  el.textContent = text;
@@ -206,7 +233,7 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
206
233
  <style>${styles}</style>
207
234
  <style>@scope to (devtools-widget > *) { ${UI.inspectorCommonStyles} }</style>
208
235
  <div class="ai-code-generation-teaser">
209
- ${teaserLabel}
236
+ &nbsp;${teaserLabel}
210
237
  </div>
211
238
  `, target
212
239
  );
@@ -309,4 +336,8 @@ export class AiCodeGenerationTeaser extends UI.Widget.Widget {
309
336
  void UI.ViewManager.ViewManager.instance().showView('chrome-ai');
310
337
  event.consume(true);
311
338
  }
339
+
340
+ showTooltip(): void {
341
+ this.#viewOutput.showTooltip?.();
342
+ }
312
343
  }
@@ -2,6 +2,8 @@
2
2
  // Use of this source code is governed by a BSD-style license that can be
3
3
  // found in the LICENSE file.
4
4
 
5
+ import '../../ui/kit/kit.js';
6
+
5
7
  import * as Common from '../../core/common/common.js';
6
8
  import * as Host from '../../core/host/host.js';
7
9
  import * as i18n from '../../core/i18n/i18n.js';
@@ -11,6 +13,7 @@ import * as UIHelpers from '../../ui/helpers/helpers.js';
11
13
  import * as uiI18n from '../../ui/i18n/i18n.js';
12
14
  import * as UI from '../../ui/legacy/legacy.js';
13
15
  import * as Lit from '../../ui/lit/lit.js';
16
+ import {type LitTemplate, nothing} from '../../ui/lit/lit.js';
14
17
  import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
15
18
 
16
19
  import badgeNotificationStyles from './badgeNotification.css.js';
@@ -65,7 +68,7 @@ const UIStrings = {
65
68
 
66
69
  const str_ = i18n.i18n.registerUIStrings('panels/common/BadgeNotification.ts', UIStrings);
67
70
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
68
- const i18nFormatString = uiI18n.getFormatLocalizedString.bind(undefined, str_);
71
+ const i18nFormatStringTemplate = uiI18n.getFormatLocalizedStringTemplate.bind(undefined, str_);
69
72
  const lockedString = i18n.i18n.lockedString;
70
73
 
71
74
  const LEFT_OFFSET = 5;
@@ -80,7 +83,7 @@ export interface BadgeNotificationAction {
80
83
  }
81
84
 
82
85
  export interface BadgeNotificationProperties {
83
- message: HTMLElement|string;
86
+ message: LitTemplate;
84
87
  jslogContext: string;
85
88
  imageUri: string;
86
89
  actions: BadgeNotificationAction[];
@@ -141,7 +144,7 @@ function revealBadgeSettings(): void {
141
144
 
142
145
  export class BadgeNotification extends UI.Widget.Widget {
143
146
  jslogContext = '';
144
- message: HTMLElement|string = '';
147
+ message: LitTemplate = nothing;
145
148
  imageUri = '';
146
149
  actions: BadgeNotificationAction[] = [];
147
150
  isStarterBadge = false;
@@ -198,12 +201,12 @@ export class BadgeNotification extends UI.Widget.Widget {
198
201
  }
199
202
 
200
203
  #presentStarterBadgeSettingsNudge(badge: Badges.Badge): void {
201
- const googleDeveloperProgramLink = UI.XLink.XLink.create(
202
- 'https://developers.google.com/program', lockedString('Google Developer Program'), 'badge-link', undefined,
203
- 'program-link');
204
204
  this.#show({
205
- message: i18nFormatString(
206
- UIStrings.starterBadgeAwardMessageSettingDisabled, {PH1: badge.title, PH2: googleDeveloperProgramLink}),
205
+ message: i18nFormatStringTemplate(UIStrings.starterBadgeAwardMessageSettingDisabled, {
206
+ PH1: badge.title,
207
+ PH2: html`<devtools-link class="badge-link" href="https://developers.google.com/program" .jslogContext=${
208
+ 'program-link'}>${lockedString('Google Developer Program')}</devtools-link>`
209
+ }),
207
210
  jslogContext: badge.jslogContext,
208
211
  actions: [
209
212
  {
@@ -228,12 +231,12 @@ export class BadgeNotification extends UI.Widget.Widget {
228
231
  }
229
232
 
230
233
  #presentStarterBadgeProfileNudge(badge: Badges.Badge): void {
231
- const googleDeveloperProgramLink = UI.XLink.XLink.create(
232
- 'https://developers.google.com/program', lockedString('Google Developer Program'), 'badge-link', undefined,
233
- 'program-link');
234
234
  this.#show({
235
- message: i18nFormatString(
236
- UIStrings.starterBadgeAwardMessageNoGdpProfile, {PH1: badge.title, PH2: googleDeveloperProgramLink}),
235
+ message: i18nFormatStringTemplate(UIStrings.starterBadgeAwardMessageNoGdpProfile, {
236
+ PH1: badge.title,
237
+ PH2: html`<devtools-link class="badge-link" href="https://developers.google.com/program" .jslogContext=${
238
+ 'program-link'}>${lockedString('Google Developer Program')}</devtools-link>`
239
+ }),
237
240
  jslogContext: badge.jslogContext,
238
241
  actions: [
239
242
  {
@@ -262,7 +265,7 @@ export class BadgeNotification extends UI.Widget.Widget {
262
265
 
263
266
  #presentActivityBasedBadge(badge: Badges.Badge): void {
264
267
  this.#show({
265
- message: i18nString(UIStrings.activityBasedBadgeAwardMessage, {PH1: badge.title}),
268
+ message: i18nFormatStringTemplate(UIStrings.activityBasedBadgeAwardMessage, {PH1: badge.title}),
266
269
  jslogContext: badge.jslogContext,
267
270
  actions: [
268
271
  {
@@ -2,6 +2,7 @@
2
2
  // Use of this source code is governed by a BSD-style license that can be
3
3
  // found in the LICENSE file.
4
4
  import '../../ui/components/switch/switch.js';
5
+ import '../../ui/kit/kit.js';
5
6
 
6
7
  import * as Common from '../../core/common/common.js';
7
8
  import * as Host from '../../core/host/host.js';
@@ -152,12 +153,10 @@ export const DEFAULT_VIEW: View = (input, _output, target): void => {
152
153
  <h2 class="section-title">${i18nString(UIStrings.tailorProfile)}</h2>
153
154
  <div class="section-text">
154
155
  <div>${i18nString(UIStrings.tailorProfileBody)}</div><br/>
155
- <div>${uiI18n.getFormatLocalizedString(str_, UIStrings.tailorProfileBodyDisclaimer, {
156
- PH1: UI.XLink.XLink.create(CONTENT_POLICY_URL, i18nString(UIStrings.contentPolicy), 'link', undefined, 'content-policy'),
157
- PH2: UI.XLink.XLink.create(TERMS_OF_SERVICE_URL, i18nString(UIStrings.termsOfService), 'link',
158
- undefined, 'terms-of-service'),
159
- PH3: UI.XLink.XLink.create(PRIVACY_POLICY_URL, i18nString(UIStrings.privacyPolicy), 'link',
160
- undefined, 'privacy-policy'),
156
+ <div>${uiI18n.getFormatLocalizedStringTemplate(str_, UIStrings.tailorProfileBodyDisclaimer, {
157
+ PH1: html`<devtools-link href=${CONTENT_POLICY_URL} class="link" .jslogContext=${'content-policy'}>${i18nString(UIStrings.contentPolicy)}</devtools-link>`,
158
+ PH2: html`<devtools-link href=${TERMS_OF_SERVICE_URL} class="link" .jslogContext=${'terms-of-service'}>${i18nString(UIStrings.termsOfService)}</devtools-link>`,
159
+ PH3: html`<devtools-link href=${PRIVACY_POLICY_URL} class="link" .jslogContext=${'privacy-policy'}>${i18nString(UIStrings.privacyPolicy)}</devtools-link>`,
161
160
  })}</div>
162
161
  </div>
163
162
  </div>
@@ -0,0 +1,192 @@
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
+ // This dialog will be shown during M146 and removed by M147.
6
+ //
7
+ // To enable:
8
+ // --enable-features=DevToolsGeminiRebranding
9
+
10
+ import '../../ui/components/switch/switch.js';
11
+ import '../../ui/kit/kit.js';
12
+
13
+ import * as Common from '../../core/common/common.js';
14
+ import * as Host from '../../core/host/host.js';
15
+ import * as i18n from '../../core/i18n/i18n.js';
16
+ import * as Root from '../../core/root/root.js';
17
+ import * as Geometry from '../../models/geometry/geometry.js';
18
+ import * as Buttons from '../../ui/components/buttons/buttons.js';
19
+ import * as UI from '../../ui/legacy/legacy.js';
20
+ import {html, render} from '../../ui/lit/lit.js';
21
+ import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
22
+
23
+ import styles from './geminiRebrandPromoDialog.css.js';
24
+
25
+ const UIStrings = {
26
+ /**
27
+ * @description Aria label for the dialog
28
+ */
29
+ dialogAriaLabel: 'Gemini 3 Flash in DevTools',
30
+ /**
31
+ *
32
+ * @description Button text for dismissing the dialog.
33
+ */
34
+ dismiss: 'Dismiss',
35
+ /**
36
+ * @description Button text for getting started.
37
+ */
38
+ getStarted: 'Get started',
39
+ /**
40
+ * @description Detail message shown in the dialog.
41
+ */
42
+ detailAiCompanion: 'Meet your AI-powered companion for web dev',
43
+ /**
44
+ * @description Detail message shown in the dialog.
45
+ */
46
+ detailConsoleErrors: 'Get instant, accurate answers for console errors',
47
+ /**
48
+ * @description Detail message shown in the dialog.
49
+ */
50
+ detailGenerateCode: 'Generate CSS and JS snippets on the fly',
51
+ /**
52
+ * @description Detail message shown in the dialog.
53
+ */
54
+ detailPerformance: 'Automatically find issues in performance traces',
55
+ } as const;
56
+
57
+ const str_ = i18n.i18n.registerUIStrings('panels/common/GeminiRebrandPromoDialog.ts', UIStrings);
58
+ const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
59
+
60
+ interface ViewInput {
61
+ onGetStartedClick: () => void;
62
+ onCancelClick: () => void;
63
+ }
64
+
65
+ type View = (input: ViewInput, output: undefined, target: HTMLElement) => void;
66
+
67
+ const PROMO_IMAGE_1X = new URL('../../Images/geminiInDevTools.png', import.meta.url).toString();
68
+ const PROMO_IMAGE_2X = new URL('../../Images/geminiInDevTools_2x.png', import.meta.url).toString();
69
+
70
+ export const DEFAULT_VIEW: View = (input, _output, target): void => {
71
+ // clang-format off
72
+ render(
73
+ html`
74
+ <style>${styles}</style>
75
+
76
+ <div class="header">
77
+ <div class="title">Gemini 3 Flash in DevTools</div>
78
+ <div class="close-button">
79
+ <devtools-button
80
+ .iconName=${'cross'}
81
+ .variant=${Buttons.Button.Variant.ICON}
82
+ .size=${Buttons.Button.Size.REGULAR}
83
+ .title=${i18nString(UIStrings.dismiss)}
84
+ jslog=${VisualLogging.close().track({click: true})}
85
+ @click=${() => {}}
86
+ ></devtools-button>
87
+ </div>
88
+ </div>
89
+
90
+ <img class="banner-image" srcset=${`${PROMO_IMAGE_1X} 1x, ${PROMO_IMAGE_2X} 2x`}>
91
+
92
+ <div class="main-content">
93
+ <div class="detail-row">
94
+ <devtools-icon name="performance"></devtools-icon>
95
+ <div>${i18nString(UIStrings.detailAiCompanion)}</div>
96
+ </div>
97
+ <div class="detail-row">
98
+ <devtools-icon name="lightbulb-spark"></devtools-icon>
99
+ <div>${i18nString(UIStrings.detailConsoleErrors)}</div>
100
+ </div>
101
+ <div class="detail-row">
102
+ <devtools-icon name="text-analysis"></devtools-icon>
103
+ <div>${i18nString(UIStrings.detailGenerateCode)}</div>
104
+ </div>
105
+ <div class="detail-row">
106
+ <devtools-icon name="smart-assistant"></devtools-icon>
107
+ <div>${i18nString(UIStrings.detailPerformance)}</div>
108
+ </div>
109
+ </div>
110
+
111
+ <div class="buttons">
112
+ <devtools-button
113
+ .variant=${Buttons.Button.Variant.OUTLINED}
114
+ .jslogContext=${'cancel'}
115
+ @click=${input.onCancelClick}>${i18nString(UIStrings.dismiss)}</devtools-button>
116
+ <devtools-button
117
+ .variant=${Buttons.Button.Variant.PRIMARY}
118
+ .jslogContext=${'get-started'}
119
+ @click=${input.onGetStartedClick}>${i18nString(UIStrings.getStarted)}</devtools-button>
120
+ </div>
121
+ `,
122
+ target
123
+ );
124
+ // clang-format on
125
+ };
126
+
127
+ export class GeminiRebrandPromoDialog extends UI.Widget.VBox {
128
+ #view: View;
129
+ #dialog: UI.Dialog.Dialog;
130
+
131
+ constructor(
132
+ options: {
133
+ dialog: UI.Dialog.Dialog,
134
+ onSuccess?: () => void,
135
+ onCancel?: () => void,
136
+ },
137
+ view?: View) {
138
+ super();
139
+ this.#dialog = options.dialog;
140
+ this.#view = view ?? DEFAULT_VIEW;
141
+ this.requestUpdate();
142
+ }
143
+
144
+ async #onGetStartedClick(): Promise<void> {
145
+ this.#dialog.hide();
146
+ await UI.ViewManager.ViewManager.instance().showView('freestyler');
147
+ }
148
+
149
+ #onCancelClick(): void {
150
+ this.#dialog.hide();
151
+ }
152
+
153
+ override performUpdate(): void {
154
+ const viewInput: ViewInput = {
155
+ onGetStartedClick: this.#onGetStartedClick.bind(this),
156
+ onCancelClick: this.#onCancelClick.bind(this),
157
+ };
158
+
159
+ this.#view(viewInput, undefined, this.contentElement);
160
+ }
161
+
162
+ static show(): void {
163
+ const dialog = new UI.Dialog.Dialog('gemini-rebranding-dialog');
164
+ dialog.setAriaLabel(i18nString(UIStrings.dialogAriaLabel));
165
+ dialog.setMaxContentSize(new Geometry.Size(384, 500));
166
+ dialog.setSizeBehavior(UI.GlassPane.SizeBehavior.SET_EXACT_WIDTH_MAX_HEIGHT);
167
+ dialog.setDimmed(true);
168
+
169
+ new GeminiRebrandPromoDialog({dialog}).show(dialog.contentElement);
170
+ dialog.show(undefined, /* stack */ true);
171
+ }
172
+
173
+ static async maybeShow(): Promise<void> {
174
+ if (!Root.Runtime.hostConfig.aidaAvailability?.enabled) {
175
+ return;
176
+ }
177
+
178
+ const currentAidaAvailability = await Host.AidaClient.AidaClient.checkAccessPreconditions();
179
+ if (currentAidaAvailability !== Host.AidaClient.AidaAccessPreconditions.AVAILABLE) {
180
+ return;
181
+ }
182
+
183
+ const setting = Common.Settings.Settings.instance().createSetting<boolean>(
184
+ 'gemini-rebranding-dialog-shown', false, Common.Settings.SettingStorageType.SYNCED);
185
+ if (setting.get()) {
186
+ return;
187
+ }
188
+
189
+ setting.set(true);
190
+ GeminiRebrandPromoDialog.show();
191
+ }
192
+ }
@@ -5,15 +5,29 @@
5
5
  */
6
6
 
7
7
  @scope to (devtools-widget > *) {
8
+ .ai-code-generation-teaser-screen-reader-only {
9
+ position: absolute;
10
+ overflow: hidden;
11
+ clip-path: rect(0 0 0 0);
12
+ height: var(--sys-size-1);
13
+ width: var(--sys-size-1);
14
+ margin: -1 * var(--sys-size-1);;
15
+ padding: 0;
16
+ border: 0;
17
+ }
18
+
8
19
  .ai-code-generation-teaser {
9
20
  pointer-events: all;
10
21
  font-style: italic;
11
- padding-left: var(--sys-size-3);
12
22
  line-height: var(--sys-size-7);
13
23
 
14
24
  .ai-code-generation-teaser-trigger {
15
25
  display: inline-flex;
16
26
  align-items: center;
27
+
28
+ devtools-button {
29
+ --override-button-icon-color: var(--sys-color-token-subtle);
30
+ }
17
31
  }
18
32
 
19
33
  .ai-code-generation-teaser-generated {
@@ -53,6 +67,7 @@
53
67
  .link {
54
68
  margin: var(--sys-size-5) var(--sys-size-8) 0 var(--sys-size-5);
55
69
  display: inline-block;
70
+ color: var(--sys-color-on-surface-subtle);
56
71
  }
57
72
  }
58
73
  }
@@ -100,6 +100,7 @@ export {AiCodeGenerationUpgradeDialog} from './AiCodeGenerationUpgradeDialog.js'
100
100
  export {AnnotationManager} from './AnnotationManager.js';
101
101
  export {FreDialog} from './FreDialog.js';
102
102
  export {GdpSignUpDialog} from './GdpSignUpDialog.js';
103
+ export {GeminiRebrandPromoDialog} from './GeminiRebrandPromoDialog.js';
103
104
  export {AiCodeCompletionDisclaimer} from './AiCodeCompletionDisclaimer.js';
104
105
  export {AiCodeCompletionSummaryToolbar} from './AiCodeCompletionSummaryToolbar.js';
105
106
  export * from './BadgeNotification.js';
@@ -0,0 +1,47 @@
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
+ }
13
+
14
+ .header {
15
+ display: flex;
16
+ justify-content: space-between;
17
+ }
18
+
19
+ .title {
20
+ font-size: 20px;
21
+ }
22
+
23
+ .banner-image {
24
+ margin: 10px 0;
25
+ }
26
+
27
+ .main-content {
28
+ display: flex;
29
+ flex-direction: column;
30
+ margin: var(--sys-size-6) 0;
31
+ gap: var(--sys-size-3);
32
+ }
33
+
34
+ .detail-row {
35
+ display: flex;
36
+ align-items: center;
37
+ gap: 5px;
38
+ margin: 5px;
39
+ }
40
+
41
+ .buttons {
42
+ display: flex;
43
+ justify-content: flex-end;
44
+ align-items: center;
45
+ gap: 10px;
46
+ }
47
+ }
@@ -54,24 +54,19 @@ export function parseSourcePositionsFromErrorStack(
54
54
  let left = match[0].length;
55
55
  let right = line.length;
56
56
  let enclosedInBraces = false;
57
- while (line[right - 1] === ')') {
57
+ if (line[right - 1] === ')') {
58
58
  right--;
59
59
  enclosedInBraces = true;
60
- do {
61
- left = line.indexOf('(', left);
62
- if (left < 0) {
63
- return null;
64
- }
65
- left++;
66
- if (!line.substring(left).startsWith('eval at ')) {
67
- break;
68
- }
69
- left += 8;
70
- right = line.lastIndexOf(', ', right) - 1;
71
- if (right < 0) {
72
- return null;
73
- }
74
- } while (true);
60
+ left = line.lastIndexOf(' (', right);
61
+ if (left < 0) {
62
+ return null;
63
+ }
64
+ left += 2;
65
+ // Relevant in the `eval at ...` case.
66
+ const newRight = line.indexOf('), ', left);
67
+ if (newRight > left) {
68
+ right = newRight;
69
+ }
75
70
  }
76
71
 
77
72
  const linkCandidate = line.substring(left, right);
@@ -483,7 +483,7 @@ function renderContrastIssue(key: string, issues: ContrastIssue[]): TemplateResu
483
483
  const color = (minContrastIssue.textColor.asString(Common.Color.Format.HEXA));
484
484
  const backgroundColor = (minContrastIssue.backgroundColor.asString(Common.Color.Format.HEXA));
485
485
 
486
- const showAPCA = Root.Runtime.experiments.isEnabled(Root.Runtime.ExperimentName.APCA);
486
+ const showAPCA = Root.Runtime.experiments.isEnabled(Root.ExperimentNames.ExperimentName.APCA);
487
487
 
488
488
  const title = i18nString(UIStrings.textColorSOverSBackgroundResults, {
489
489
  PH1: color,
@@ -1041,7 +1041,7 @@ function renderContrastRatio(data: PopulateNodesEventNodeTypes): TemplateResult
1041
1041
  if (!('contrastRatio' in data)) {
1042
1042
  throw new Error('Contrast ratio entry is missing a contrast ratio.');
1043
1043
  }
1044
- const showAPCA = Root.Runtime.experiments.isEnabled(Root.Runtime.ExperimentName.APCA);
1044
+ const showAPCA = Root.Runtime.experiments.isEnabled(Root.ExperimentNames.ExperimentName.APCA);
1045
1045
  const contrastRatio = Platform.NumberUtilities.floor(data.contrastRatio, 2);
1046
1046
  const contrastRatioString = showAPCA ? contrastRatio + '%' : contrastRatio;
1047
1047
  const border = getBorderString(data.backgroundColor);
@@ -267,7 +267,7 @@ export class CSSOverviewModel extends SDK.SDKModel.SDKModel<void> {
267
267
  const formattedTextColor = formatColor(blendedTextColor);
268
268
  const formattedBackgroundColor = formatColor(blendedBackgroundColor.asLegacyColor());
269
269
  const key = `${formattedTextColor}_${formattedBackgroundColor}`;
270
- if (Root.Runtime.experiments.isEnabled(Root.Runtime.ExperimentName.APCA)) {
270
+ if (Root.Runtime.experiments.isEnabled(Root.ExperimentNames.ExperimentName.APCA)) {
271
271
  const contrastRatio = contrastInfo.contrastRatioAPCA();
272
272
  const threshold = contrastInfo.contrastRatioAPCAThreshold();
273
273
  const passes = contrastRatio && threshold ? Math.abs(contrastRatio) >= threshold : false;
@@ -3,38 +3,26 @@
3
3
  // found in the LICENSE file.
4
4
 
5
5
  import * as Common from '../../core/common/common.js';
6
- import * as Root from '../../core/root/root.js';
7
6
  import * as SDK from '../../core/sdk/sdk.js';
8
- import * as UI from '../../ui/legacy/legacy.js';
9
-
10
- import {ComputedStyleWidget} from './ComputedStyleWidget.js';
11
- import {StylesSidebarPane} from './StylesSidebarPane.js';
12
7
 
8
+ /**
9
+ * A thin wrapper around the CSS Model to gather up changes in CSS files that
10
+ * could impact a node's computed styles.
11
+ * Callers are expected to initiate tracking of the Node themselves via the CSS
12
+ * Model trackComputedStyleUpdatesForNode method.
13
+ */
13
14
  export class ComputedStyleModel extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
14
15
  #node: SDK.DOMModel.DOMNode|null;
15
16
  #cssModel: SDK.CSSModel.CSSModel|null;
16
17
  private eventListeners: Common.EventTarget.EventDescriptor[];
17
18
  private frameResizedTimer?: number;
18
19
  private computedStylePromise?: Promise<ComputedStyle|null>;
19
- private currentTrackedNodeId?: number;
20
20
 
21
21
  constructor(node?: SDK.DOMModel.DOMNode|null) {
22
22
  super();
23
23
  this.#cssModel = null;
24
24
  this.eventListeners = [];
25
25
  this.#node = node ?? null;
26
-
27
- UI.Context.Context.instance().addFlavorChangeListener(
28
- StylesSidebarPane, this.evaluateTrackingComputedStyleUpdatesForNode, this);
29
- UI.Context.Context.instance().addFlavorChangeListener(
30
- ComputedStyleWidget, this.evaluateTrackingComputedStyleUpdatesForNode, this);
31
- }
32
-
33
- dispose(): void {
34
- UI.Context.Context.instance().removeFlavorChangeListener(
35
- StylesSidebarPane, this.evaluateTrackingComputedStyleUpdatesForNode, this);
36
- UI.Context.Context.instance().removeFlavorChangeListener(
37
- ComputedStyleWidget, this.evaluateTrackingComputedStyleUpdatesForNode, this);
38
26
  }
39
27
 
40
28
  get node(): SDK.DOMModel.DOMNode|null {
@@ -45,48 +33,12 @@ export class ComputedStyleModel extends Common.ObjectWrapper.ObjectWrapper<Event
45
33
  this.#node = node;
46
34
  this.updateModel(this.#node ? this.#node.domModel().cssModel() : null);
47
35
  this.onCSSModelChanged(null);
48
- this.evaluateTrackingComputedStyleUpdatesForNode();
49
36
  }
50
37
 
51
38
  cssModel(): SDK.CSSModel.CSSModel|null {
52
39
  return this.#cssModel?.isEnabled() ? this.#cssModel : null;
53
40
  }
54
41
 
55
- // This is a debounced method because the user might be navigated from Styles tab to Computed Style tab and vice versa.
56
- // For that case, we want to only run this function once.
57
- private evaluateTrackingComputedStyleUpdatesForNode = Common.Debouncer.debounce((): void => {
58
- if (!this.#node) {
59
- // There isn't a node selected now, so let's stop tracking computed style updates for the previously tracked node.
60
- if (this.currentTrackedNodeId) {
61
- void this.cssModel()?.trackComputedStyleUpdatesForNode(undefined);
62
- this.currentTrackedNodeId = undefined;
63
- }
64
- return;
65
- }
66
-
67
- const isComputedStyleWidgetVisible = Boolean(UI.Context.Context.instance().flavor(ComputedStyleWidget));
68
- const isStylesTabVisible = Boolean(UI.Context.Context.instance().flavor(StylesSidebarPane));
69
- const shouldTrackComputedStyleUpdates = isComputedStyleWidgetVisible ||
70
- (isStylesTabVisible && Root.Runtime.hostConfig.devToolsAnimationStylesInStylesTab?.enabled);
71
- // There is a selected node but not the computed style widget nor the styles tab is visible.
72
- // If there is a previously tracked node let's stop tracking computed style updates for that node.
73
- if (!shouldTrackComputedStyleUpdates) {
74
- if (this.currentTrackedNodeId) {
75
- void this.cssModel()?.trackComputedStyleUpdatesForNode(undefined);
76
- this.currentTrackedNodeId = undefined;
77
- }
78
- return;
79
- }
80
-
81
- // Either computed style widget or styles tab is visible
82
- // if the currently tracked node id is not the same as the selected node
83
- // let's start tracking the currently selected node.
84
- if (this.currentTrackedNodeId !== this.#node.id) {
85
- void this.cssModel()?.trackComputedStyleUpdatesForNode(this.#node.id);
86
- this.currentTrackedNodeId = this.#node.id;
87
- }
88
- }, 100);
89
-
90
42
  private updateModel(cssModel: SDK.CSSModel.CSSModel|null): void {
91
43
  if (this.#cssModel === cssModel) {
92
44
  return;
@@ -95,6 +47,7 @@ export class ComputedStyleModel extends Common.ObjectWrapper.ObjectWrapper<Event
95
47
  this.#cssModel = cssModel;
96
48
  const domModel = cssModel ? cssModel.domModel() : null;
97
49
  const resourceTreeModel = cssModel ? cssModel.target().model(SDK.ResourceTreeModel.ResourceTreeModel) : null;
50
+
98
51
  if (cssModel && domModel && resourceTreeModel) {
99
52
  this.eventListeners = [
100
53
  cssModel.addEventListener(SDK.CSSModel.Events.StyleSheetAdded, this.onCSSModelChanged, this),