chrome-devtools-frontend 1.0.1581449 → 1.0.1581708
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.
- package/agents/prompts/merging-devtools-module.md +144 -0
- package/agents/prompts/ui-widgets.md +351 -0
- package/agents/prompts/verification.md +2 -1
- package/docs/contributing/README.md +5 -6
- package/docs/contributing/changes.md +1 -2
- package/docs/styleguide/ux/README.md +1 -1
- package/front_end/core/sdk/OverlayModel.ts +4 -2
- package/front_end/core/sdk/StorageKeyManager.ts +6 -1
- package/front_end/core/sdk/Target.ts +4 -2
- package/front_end/entrypoints/greendev_floaty/FloatyEntrypoint.ts +22 -16
- package/front_end/entrypoints/greendev_floaty/floaty.css +41 -1
- package/front_end/entrypoints/greendev_floaty/floaty.html +8 -1
- package/front_end/entrypoints/greendev_floaty/greendev_floaty.ts +4 -4
- package/front_end/entrypoints/node_app/app/NodeMain.ts +19 -1
- package/front_end/entrypoints/node_app/node_app.ts +34 -0
- package/front_end/models/ai_assistance/AiConversation.ts +10 -0
- package/front_end/models/ai_assistance/agents/AiAgent.ts +2 -0
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.snapshot.txt +22 -0
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +71 -1
- package/front_end/models/computed_style/ComputedStyleModel.ts +26 -0
- package/front_end/models/issues_manager/CookieIssue.ts +0 -28
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +87 -6
- package/front_end/panels/ai_assistance/components/ChatInput.ts +1 -1
- package/front_end/panels/application/ApplicationPanelSidebar.ts +13 -11
- package/front_end/panels/application/DOMStorageModel.ts +1 -1
- package/front_end/panels/application/ResourcesPanel.ts +10 -5
- package/front_end/panels/common/AiCodeCompletionTeaser.ts +13 -3
- package/front_end/panels/common/aiCodeCompletionTeaser.css +6 -0
- package/front_end/panels/console_counters/WarningErrorCounter.ts +16 -10
- package/front_end/panels/elements/ComputedStyleWidget.ts +55 -37
- package/front_end/panels/elements/PlatformFontsWidget.ts +23 -10
- package/front_end/panels/greendev/GreenDevPanel.css +42 -1
- package/front_end/panels/greendev/GreenDevPanel.ts +30 -1
- package/front_end/panels/network/RequestInitiatorView.ts +8 -11
- package/front_end/panels/network/RequestTimingView.ts +1 -1
- package/front_end/panels/settings/KeybindsSettingsTab.ts +4 -3
- package/front_end/panels/sources/OutlineQuickOpen.ts +19 -0
- package/front_end/panels/timeline/TimelinePanel.ts +25 -0
- package/front_end/third_party/lighthouse/README.chromium +2 -2
- package/front_end/third_party/lighthouse/lighthouse-dt-bundle.js +145 -144
- package/front_end/third_party/lighthouse/report/bundle.js +12 -5
- package/front_end/third_party/lighthouse/report-assets/report-generator.mjs +2 -2
- package/front_end/ui/legacy/ListControl.ts +28 -1
- package/front_end/ui/legacy/Treeoutline.ts +1 -1
- package/front_end/ui/legacy/UIUtils.ts +17 -7
- package/front_end/ui/legacy/components/utils/JSPresentationUtils.ts +4 -2
- package/front_end/ui/visual_logging/KnownContextValues.ts +2 -0
- package/inspector_overlay/main.ts +18 -3
- package/inspector_overlay/tool_green_dev_anchors.css +54 -0
- package/inspector_overlay/tool_green_dev_anchors.ts +164 -0
- package/inspector_overlay/tool_persistent.ts +14 -0
- package/package.json +1 -1
- package/docs/contributing/design.md +0 -166
- package/docs/design_guidelines.md +0 -1
|
@@ -37,9 +37,13 @@ export class ResourcesPanel extends UI.Panel.PanelWithSidebar {
|
|
|
37
37
|
private cookieView: CookieItemsView|null;
|
|
38
38
|
private deviceBoundSessionsView: DeviceBoundSessionsView|null;
|
|
39
39
|
private readonly sidebar: ApplicationPanelSidebar;
|
|
40
|
+
mode: 'default'|'node' = 'default';
|
|
40
41
|
|
|
41
|
-
private constructor(
|
|
42
|
+
private constructor(
|
|
43
|
+
mode: 'default'|'node' = 'default',
|
|
44
|
+
) {
|
|
42
45
|
super('resources');
|
|
46
|
+
this.mode = mode;
|
|
43
47
|
this.registerRequiredCSS(resourcesPanelStyles);
|
|
44
48
|
|
|
45
49
|
this.resourcesLastSelectedItemSetting =
|
|
@@ -68,11 +72,12 @@ export class ResourcesPanel extends UI.Panel.PanelWithSidebar {
|
|
|
68
72
|
}
|
|
69
73
|
|
|
70
74
|
static instance(opts: {
|
|
71
|
-
forceNew
|
|
72
|
-
|
|
73
|
-
|
|
75
|
+
forceNew?: boolean|null,
|
|
76
|
+
mode?: 'default'|'node',
|
|
77
|
+
} = {forceNew: null, mode: 'default'}): ResourcesPanel {
|
|
78
|
+
const {forceNew, mode} = opts;
|
|
74
79
|
if (!resourcesPanelInstance || forceNew) {
|
|
75
|
-
resourcesPanelInstance = new ResourcesPanel();
|
|
80
|
+
resourcesPanelInstance = new ResourcesPanel(mode);
|
|
76
81
|
}
|
|
77
82
|
|
|
78
83
|
return resourcesPanelInstance;
|
|
@@ -73,12 +73,12 @@ const UIStringsNotTranslate = {
|
|
|
73
73
|
* @description Code generation disclaimer item text for the fre dialog.
|
|
74
74
|
*/
|
|
75
75
|
freDisclaimerDescribeCodeInComment:
|
|
76
|
-
'In Console or Sources, describe the code you need in a comment, then press
|
|
76
|
+
'In Console or Sources, describe the code you need in a comment, then press ctrl+i to generate it.',
|
|
77
77
|
/**
|
|
78
78
|
* @description Code generation disclaimer item text for the fre dialog.
|
|
79
79
|
*/
|
|
80
80
|
freDisclaimerDescribeCodeInCommentForMacOs:
|
|
81
|
-
'In Console or Sources, describe the code you need in a comment, then press
|
|
81
|
+
'In Console or Sources, describe the code you need in a comment, then press cmd+i to generate it.',
|
|
82
82
|
/**
|
|
83
83
|
* @description Privacy disclaimer item text for the fre dialog.
|
|
84
84
|
*/
|
|
@@ -140,7 +140,17 @@ export const DEFAULT_VIEW: View = (input, _output, target) => {
|
|
|
140
140
|
<span>${lockedString(UIStringsNotTranslate.i)}</span>
|
|
141
141
|
</span>
|
|
142
142
|
</span> ${lockedString(UIStringsNotTranslate.toTurnOnCodeSuggestions)}
|
|
143
|
-
<span role="button" class="ai-code-completion-teaser-dismiss"
|
|
143
|
+
<span role="button" class="ai-code-completion-teaser-dismiss"
|
|
144
|
+
tabindex="0"
|
|
145
|
+
@click=${input.onDismiss}
|
|
146
|
+
@keydown=${(e: KeyboardEvent) => {
|
|
147
|
+
// Handle Enter and Space events to make dismiss button accessible for only keyboard users.
|
|
148
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
149
|
+
input.onDismiss(e);
|
|
150
|
+
e.stopPropagation();
|
|
151
|
+
e.preventDefault();
|
|
152
|
+
}
|
|
153
|
+
}}
|
|
144
154
|
jslog=${VisualLogging.action('ai-code-completion-teaser.dismiss').track({click: true})}>
|
|
145
155
|
${lockedString(UIStringsNotTranslate.dontShowAgain)}
|
|
146
156
|
</span>
|
|
@@ -26,6 +26,12 @@
|
|
|
26
26
|
.ai-code-completion-teaser-dismiss {
|
|
27
27
|
text-decoration: underline;
|
|
28
28
|
cursor: pointer;
|
|
29
|
+
|
|
30
|
+
&:focus-visible {
|
|
31
|
+
border-radius: var(--sys-shape-corner-extra-small);
|
|
32
|
+
outline: var(--sys-size-2) solid var(--sys-color-state-focus-ring);
|
|
33
|
+
outline-offset: 0;
|
|
34
|
+
}
|
|
29
35
|
}
|
|
30
36
|
|
|
31
37
|
.ai-code-completion-teaser-action {
|
|
@@ -12,9 +12,11 @@ import * as IssuesManager from '../../models/issues_manager/issues_manager.js';
|
|
|
12
12
|
import type * as IconButton from '../../ui/components/icon_button/icon_button.js';
|
|
13
13
|
import * as IssueCounter from '../../ui/components/issue_counter/issue_counter.js';
|
|
14
14
|
import * as UI from '../../ui/legacy/legacy.js';
|
|
15
|
-
import
|
|
15
|
+
import * as Lit from '../../ui/lit/lit.js';
|
|
16
16
|
import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
|
|
17
17
|
|
|
18
|
+
const {html, nothing, render} = Lit;
|
|
19
|
+
|
|
18
20
|
const UIStrings = {
|
|
19
21
|
/**
|
|
20
22
|
* @description The console error count in the Warning Error Counter shown in the main toolbar (top-left in DevTools). The error count refers to the number of errors currently present in the JavaScript console.
|
|
@@ -95,21 +97,25 @@ const DEFAULT_VIEW: View = (input, _output, target) => {
|
|
|
95
97
|
|
|
96
98
|
render(
|
|
97
99
|
html`<div class="status-buttons"
|
|
98
|
-
|
|
100
|
+
>${
|
|
101
|
+
errors + warnings ? html`<icon-button
|
|
99
102
|
.data=${iconData}
|
|
100
103
|
title=${consoleTitle}
|
|
101
|
-
class=${'small'
|
|
104
|
+
class=${'small'}
|
|
102
105
|
jslog=${VisualLogging.counter('console').track({
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
></icon-button
|
|
106
|
-
|
|
106
|
+
click: true
|
|
107
|
+
})}
|
|
108
|
+
></icon-button>` :
|
|
109
|
+
nothing}${
|
|
110
|
+
issues ? html`<devtools-issue-counter
|
|
111
|
+
class=${'main-toolbar'}
|
|
107
112
|
title=${issuesTitle}
|
|
108
113
|
.data=${issueCounterData}
|
|
109
114
|
jslog=${VisualLogging.counter('issue').track({
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
></devtools-issue-counter
|
|
115
|
+
click: true
|
|
116
|
+
})}
|
|
117
|
+
></devtools-issue-counter>` :
|
|
118
|
+
nothing}</div>`,
|
|
113
119
|
target);
|
|
114
120
|
};
|
|
115
121
|
|
|
@@ -53,7 +53,7 @@ import {categorizePropertyName, type Category, DefaultCategoryOrder} from './Pro
|
|
|
53
53
|
import {Renderer, rendererBase, type RenderingContext, StringRenderer, URLRenderer} from './PropertyRenderer.js';
|
|
54
54
|
import {StylePropertiesSection} from './StylePropertiesSection.js';
|
|
55
55
|
|
|
56
|
-
const {html} = Lit;
|
|
56
|
+
const {html, render} = Lit;
|
|
57
57
|
|
|
58
58
|
const UIStrings = {
|
|
59
59
|
/**
|
|
@@ -197,7 +197,7 @@ const createTraceElement =
|
|
|
197
197
|
return trace;
|
|
198
198
|
};
|
|
199
199
|
|
|
200
|
-
|
|
200
|
+
// clang-format off
|
|
201
201
|
class ColorRenderer extends rendererBase(SDK.CSSPropertyParserMatchers.ColorMatch) {
|
|
202
202
|
// clang-format on
|
|
203
203
|
override render(match: SDK.CSSPropertyParserMatchers.ColorMatch, context: RenderingContext): Node[] {
|
|
@@ -261,21 +261,47 @@ type ComputedStyleData = {
|
|
|
261
261
|
name: string,
|
|
262
262
|
};
|
|
263
263
|
|
|
264
|
+
interface ComputedStyleWidgetInput {
|
|
265
|
+
computedStylesTree: TreeOutline.TreeOutline.TreeOutline<ComputedStyleData>;
|
|
266
|
+
toolbar: HTMLElement;
|
|
267
|
+
hasMatches: boolean;
|
|
268
|
+
computedStyleModel: ComputedStyleModule.ComputedStyleModel.ComputedStyleModel;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
type View = (input: ComputedStyleWidgetInput, output: null, target: HTMLElement) => void;
|
|
272
|
+
|
|
273
|
+
export const DEFAULT_VIEW: View = (input, _output, target) => {
|
|
274
|
+
// clang-format off
|
|
275
|
+
render(html`
|
|
276
|
+
<div class="styles-sidebar-pane-toolbar">${input.toolbar}</div>
|
|
277
|
+
<div class="computed-style-tree-outline-container">
|
|
278
|
+
${input.computedStylesTree}
|
|
279
|
+
</div>
|
|
280
|
+
${!input.hasMatches ? html`<div class="gray-info-message">${i18nString(UIStrings.noMatchingProperty)}</div>` : ''}
|
|
281
|
+
<div class="platform-fonts-widget-container">
|
|
282
|
+
<devtools-widget .widgetConfig=${UI.Widget.widgetConfig(PlatformFontsWidget, { sharedModel: input.computedStyleModel})}></devtools-widget>
|
|
283
|
+
</div>
|
|
284
|
+
`, target);
|
|
285
|
+
// clang-format on
|
|
286
|
+
};
|
|
287
|
+
|
|
264
288
|
export class ComputedStyleWidget extends UI.Widget.VBox {
|
|
265
289
|
private computedStyleModel: ComputedStyleModule.ComputedStyleModel.ComputedStyleModel;
|
|
266
290
|
private readonly showInheritedComputedStylePropertiesSetting: Common.Settings.Setting<boolean>;
|
|
267
291
|
private readonly groupComputedStylesSetting: Common.Settings.Setting<boolean>;
|
|
268
292
|
input: UI.Toolbar.ToolbarInput;
|
|
269
293
|
private filterRegex: RegExp|null;
|
|
270
|
-
private readonly noMatchesElement: HTMLElement;
|
|
271
294
|
private readonly linkifier: Components.Linkifier.Linkifier;
|
|
272
295
|
private readonly imagePreviewPopover: ImagePreviewPopover;
|
|
273
296
|
|
|
274
297
|
#computedStylesTree = new TreeOutline.TreeOutline.TreeOutline<ComputedStyleData>();
|
|
275
298
|
#treeData?: TreeOutline.TreeOutline.TreeOutlineData<ComputedStyleData>;
|
|
299
|
+
readonly #view: View;
|
|
300
|
+
private readonly toolbarElement: HTMLElement;
|
|
276
301
|
|
|
277
302
|
constructor(computedStyleModel: ComputedStyleModule.ComputedStyleModel.ComputedStyleModel) {
|
|
278
303
|
super({useShadowDom: true});
|
|
304
|
+
this.#view = DEFAULT_VIEW;
|
|
279
305
|
this.registerRequiredCSS(computedStyleSidebarPaneStyles);
|
|
280
306
|
|
|
281
307
|
this.contentElement.classList.add('styles-sidebar-computed-style-widget');
|
|
@@ -295,8 +321,12 @@ export class ComputedStyleWidget extends UI.Widget.VBox {
|
|
|
295
321
|
this.requestUpdate();
|
|
296
322
|
});
|
|
297
323
|
|
|
298
|
-
|
|
299
|
-
|
|
324
|
+
this.toolbarElement = document.createElement('div');
|
|
325
|
+
this.toolbarElement.classList.add('hbox', 'styles-sidebar-pane-toolbar');
|
|
326
|
+
const toolbar = document.createElement('devtools-toolbar');
|
|
327
|
+
toolbar.classList.add('styles-pane-toolbar');
|
|
328
|
+
this.toolbarElement.appendChild(toolbar);
|
|
329
|
+
|
|
300
330
|
const filterInput = new UI.Toolbar.ToolbarFilter(undefined, 1, 1, undefined, undefined, false);
|
|
301
331
|
filterInput.addEventListener(UI.Toolbar.ToolbarInput.Event.TEXT_CHANGED, this.onFilterChanged, this);
|
|
302
332
|
toolbar.appendToolbarItem(filterInput);
|
|
@@ -308,11 +338,6 @@ export class ComputedStyleWidget extends UI.Widget.VBox {
|
|
|
308
338
|
toolbar.appendToolbarItem(
|
|
309
339
|
new UI.Toolbar.ToolbarSettingCheckbox(this.groupComputedStylesSetting, undefined, i18nString(UIStrings.group)));
|
|
310
340
|
|
|
311
|
-
this.noMatchesElement = this.contentElement.createChild('div', 'gray-info-message');
|
|
312
|
-
this.noMatchesElement.textContent = i18nString(UIStrings.noMatchingProperty);
|
|
313
|
-
|
|
314
|
-
this.contentElement.appendChild(this.#computedStylesTree);
|
|
315
|
-
|
|
316
341
|
this.linkifier = new Components.Linkifier.Linkifier(maxLinkLength);
|
|
317
342
|
|
|
318
343
|
this.imagePreviewPopover = new ImagePreviewPopover(this.contentElement, event => {
|
|
@@ -323,8 +348,7 @@ export class ComputedStyleWidget extends UI.Widget.VBox {
|
|
|
323
348
|
return null;
|
|
324
349
|
}, () => this.computedStyleModel.node);
|
|
325
350
|
|
|
326
|
-
|
|
327
|
-
fontsWidget.show(this.contentElement);
|
|
351
|
+
this.#updateView({hasMatches: true});
|
|
328
352
|
}
|
|
329
353
|
|
|
330
354
|
override onResize(): void {
|
|
@@ -342,11 +366,24 @@ export class ComputedStyleWidget extends UI.Widget.VBox {
|
|
|
342
366
|
UI.Context.Context.instance().setFlavor(ComputedStyleWidget, null);
|
|
343
367
|
}
|
|
344
368
|
|
|
369
|
+
/**
|
|
370
|
+
* @param input.hasMatches Whether any properties matched the current filter (or if any properties exist at all).
|
|
371
|
+
*/
|
|
372
|
+
#updateView({hasMatches}: {hasMatches: boolean}): void {
|
|
373
|
+
this.#view(
|
|
374
|
+
{
|
|
375
|
+
computedStylesTree: this.#computedStylesTree,
|
|
376
|
+
toolbar: this.toolbarElement,
|
|
377
|
+
hasMatches,
|
|
378
|
+
computedStyleModel: this.computedStyleModel,
|
|
379
|
+
},
|
|
380
|
+
null, this.contentElement);
|
|
381
|
+
}
|
|
382
|
+
|
|
345
383
|
override async performUpdate(): Promise<void> {
|
|
346
|
-
const
|
|
347
|
-
await Promise.all([this.computedStyleModel.fetchComputedStyle(), this.fetchMatchedCascade()]);
|
|
384
|
+
const {computedStyle: nodeStyles, matchedStyles} = await this.computedStyleModel.fetchAllComputedStyleInfo();
|
|
348
385
|
if (!nodeStyles || !matchedStyles) {
|
|
349
|
-
this
|
|
386
|
+
this.#updateView({hasMatches: false});
|
|
350
387
|
return;
|
|
351
388
|
}
|
|
352
389
|
const shouldGroupComputedStyles = this.groupComputedStylesSetting.get();
|
|
@@ -357,25 +394,6 @@ export class ComputedStyleWidget extends UI.Widget.VBox {
|
|
|
357
394
|
}
|
|
358
395
|
}
|
|
359
396
|
|
|
360
|
-
private async fetchMatchedCascade(): Promise<SDK.CSSMatchedStyles.CSSMatchedStyles|null> {
|
|
361
|
-
const node = this.computedStyleModel.node;
|
|
362
|
-
if (!node || !this.computedStyleModel.cssModel()) {
|
|
363
|
-
return null;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
const cssModel = this.computedStyleModel.cssModel();
|
|
367
|
-
if (!cssModel) {
|
|
368
|
-
return null;
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
return await cssModel.cachedMatchedCascadeForNode(node).then(validateStyles.bind(this));
|
|
372
|
-
|
|
373
|
-
function validateStyles(this: ComputedStyleWidget, matchedStyles: SDK.CSSMatchedStyles.CSSMatchedStyles|null):
|
|
374
|
-
SDK.CSSMatchedStyles.CSSMatchedStyles|null {
|
|
375
|
-
return matchedStyles && matchedStyles.node() === this.computedStyleModel.node ? matchedStyles : null;
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
|
|
379
397
|
private async rebuildAlphabeticalList(
|
|
380
398
|
nodeStyle: ComputedStyleModule.ComputedStyleModel.ComputedStyle,
|
|
381
399
|
matchedStyles: SDK.CSSMatchedStyles.CSSMatchedStyles): Promise<void> {
|
|
@@ -426,7 +444,7 @@ export class ComputedStyleWidget extends UI.Widget.VBox {
|
|
|
426
444
|
this.linkifier.reset();
|
|
427
445
|
const cssModel = this.computedStyleModel.cssModel();
|
|
428
446
|
if (!nodeStyle || !matchedStyles || !cssModel) {
|
|
429
|
-
this
|
|
447
|
+
this.#updateView({hasMatches: false});
|
|
430
448
|
return;
|
|
431
449
|
}
|
|
432
450
|
|
|
@@ -648,7 +666,7 @@ export class ComputedStyleWidget extends UI.Widget.VBox {
|
|
|
648
666
|
defaultRenderer: this.#treeData.defaultRenderer,
|
|
649
667
|
compact: this.#treeData.compact,
|
|
650
668
|
};
|
|
651
|
-
this
|
|
669
|
+
this.#updateView({hasMatches: Boolean(tree.length)});
|
|
652
670
|
}
|
|
653
671
|
|
|
654
672
|
private async filterGroupLists(): Promise<void> {
|
|
@@ -675,7 +693,7 @@ export class ComputedStyleWidget extends UI.Widget.VBox {
|
|
|
675
693
|
compact: this.#treeData.compact,
|
|
676
694
|
};
|
|
677
695
|
await this.#computedStylesTree.expandRecursively(0);
|
|
678
|
-
this
|
|
696
|
+
this.#updateView({hasMatches: Boolean(tree.length)});
|
|
679
697
|
}
|
|
680
698
|
}
|
|
681
699
|
|
|
@@ -78,24 +78,37 @@ export const DEFAULT_VIEW: View = (input, _output, target) => {
|
|
|
78
78
|
};
|
|
79
79
|
|
|
80
80
|
export class PlatformFontsWidget extends UI.Widget.VBox {
|
|
81
|
-
private readonly sharedModel: ComputedStyle.ComputedStyleModel.ComputedStyleModel;
|
|
82
81
|
readonly #view: View;
|
|
82
|
+
#sharedModel: ComputedStyle.ComputedStyleModel.ComputedStyleModel|null = null;
|
|
83
83
|
|
|
84
|
-
constructor(
|
|
85
|
-
super({useShadowDom: true});
|
|
84
|
+
constructor(element?: HTMLElement, view: View = DEFAULT_VIEW) {
|
|
85
|
+
super(element, {useShadowDom: true});
|
|
86
86
|
this.#view = view;
|
|
87
87
|
this.registerRequiredCSS(platformFontsWidgetStyles);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
get sharedModel(): ComputedStyle.ComputedStyleModel.ComputedStyleModel|null {
|
|
91
|
+
return this.#sharedModel;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
set sharedModel(model: ComputedStyle.ComputedStyleModel.ComputedStyleModel) {
|
|
95
|
+
if (model !== this.sharedModel) {
|
|
96
|
+
this.sharedModel?.removeEventListener(
|
|
97
|
+
ComputedStyle.ComputedStyleModel.Events.CSS_MODEL_CHANGED, this.requestUpdate, this);
|
|
98
|
+
this.sharedModel?.removeEventListener(
|
|
99
|
+
ComputedStyle.ComputedStyleModel.Events.COMPUTED_STYLE_CHANGED, this.requestUpdate, this);
|
|
100
|
+
|
|
101
|
+
model.addEventListener(ComputedStyle.ComputedStyleModel.Events.CSS_MODEL_CHANGED, this.requestUpdate, this);
|
|
102
|
+
model.addEventListener(ComputedStyle.ComputedStyleModel.Events.COMPUTED_STYLE_CHANGED, this.requestUpdate, this);
|
|
103
|
+
}
|
|
88
104
|
|
|
89
|
-
this
|
|
90
|
-
this.
|
|
91
|
-
ComputedStyle.ComputedStyleModel.Events.CSS_MODEL_CHANGED, this.requestUpdate, this);
|
|
92
|
-
this.sharedModel.addEventListener(
|
|
93
|
-
ComputedStyle.ComputedStyleModel.Events.COMPUTED_STYLE_CHANGED, this.requestUpdate, this);
|
|
105
|
+
this.#sharedModel = model;
|
|
106
|
+
void this.requestUpdate();
|
|
94
107
|
}
|
|
95
108
|
|
|
96
109
|
override async performUpdate(): Promise<void> {
|
|
97
|
-
const cssModel = this
|
|
98
|
-
const node = this
|
|
110
|
+
const cssModel = this.#sharedModel?.cssModel();
|
|
111
|
+
const node = this.#sharedModel?.node;
|
|
99
112
|
if (!node || !cssModel) {
|
|
100
113
|
this.#view({platformFonts: null}, {}, this.contentElement);
|
|
101
114
|
return;
|
|
@@ -234,8 +234,49 @@
|
|
|
234
234
|
}
|
|
235
235
|
|
|
236
236
|
.green-dev-floaty-disclaimer {
|
|
237
|
-
font-size:
|
|
237
|
+
font-size: 15px;
|
|
238
238
|
color: #666;
|
|
239
239
|
text-align: center;
|
|
240
240
|
margin-top: 8px;
|
|
241
|
+
position: relative; /* For tooltip positioning */
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.disclaimer-link {
|
|
245
|
+
color: #666; /* Match text color */
|
|
246
|
+
text-decoration: underline;
|
|
247
|
+
cursor: pointer;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
.disclaimer-tooltip {
|
|
251
|
+
display: none;
|
|
252
|
+
position: absolute;
|
|
253
|
+
bottom: 100%; /* Position above */
|
|
254
|
+
left: 50%;
|
|
255
|
+
transform: translateX(-50%);
|
|
256
|
+
width: 300px;
|
|
257
|
+
padding: 12px;
|
|
258
|
+
background-color: #fff;
|
|
259
|
+
border: 1px solid #ccc;
|
|
260
|
+
border-radius: 8px;
|
|
261
|
+
box-shadow: 0 2px 10px rgb(0 0 0 / 20%);
|
|
262
|
+
z-index: 1000;
|
|
263
|
+
text-align: left;
|
|
264
|
+
font-size: 16px;
|
|
265
|
+
line-height: 1.4;
|
|
266
|
+
color: #333;
|
|
267
|
+
white-space: normal; /* Ensure text wraps */
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.disclaimer-link:hover + .disclaimer-tooltip,
|
|
271
|
+
.disclaimer-tooltip:hover {
|
|
272
|
+
display: block;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.learn-more-link {
|
|
276
|
+
color: #0b57d0;
|
|
277
|
+
text-decoration: none;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
.learn-more-link:hover {
|
|
281
|
+
text-decoration: underline;
|
|
241
282
|
}
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
/* eslint-disable @devtools/no-imperative-dom-api */
|
|
5
5
|
|
|
6
6
|
import type * as Common from '../../core/common/common.js';
|
|
7
|
+
import * as Host from '../../core/host/host.js';
|
|
8
|
+
import type * as Platform from '../../core/platform/platform.js';
|
|
7
9
|
import * as SDK from '../../core/sdk/sdk.js';
|
|
8
10
|
import type * as Protocol from '../../generated/protocol.js';
|
|
9
11
|
import * as UI from '../../ui/legacy/legacy.js';
|
|
@@ -186,7 +188,34 @@ export class GreenDevPanel extends UI.Panel.Panel {
|
|
|
186
188
|
|
|
187
189
|
const disclaimer = document.createElement('div');
|
|
188
190
|
disclaimer.className = 'green-dev-floaty-disclaimer';
|
|
189
|
-
|
|
191
|
+
|
|
192
|
+
const link = document.createElement('span');
|
|
193
|
+
link.className = 'disclaimer-link';
|
|
194
|
+
link.textContent = 'Relevant data';
|
|
195
|
+
disclaimer.appendChild(link);
|
|
196
|
+
|
|
197
|
+
disclaimer.appendChild(document.createTextNode(' is sent to Google'));
|
|
198
|
+
|
|
199
|
+
const tooltip = document.createElement('div');
|
|
200
|
+
tooltip.className = 'disclaimer-tooltip';
|
|
201
|
+
|
|
202
|
+
tooltip.appendChild(document.createTextNode(
|
|
203
|
+
'Chat messages and any data the inspected page can access via Web APIs 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.'));
|
|
204
|
+
tooltip.appendChild(document.createElement('br'));
|
|
205
|
+
tooltip.appendChild(document.createElement('br'));
|
|
206
|
+
|
|
207
|
+
const learnMore = document.createElement('a');
|
|
208
|
+
const href = 'https://developer.chrome.com/docs/devtools/ai-assistance' as Platform.DevToolsPath.UrlString;
|
|
209
|
+
learnMore.href = href;
|
|
210
|
+
learnMore.className = 'learn-more-link';
|
|
211
|
+
learnMore.textContent = 'Learn about AI in DevTools';
|
|
212
|
+
learnMore.addEventListener('click', event => {
|
|
213
|
+
event.preventDefault();
|
|
214
|
+
Host.InspectorFrontendHost.InspectorFrontendHostInstance.openInNewTab(href);
|
|
215
|
+
});
|
|
216
|
+
tooltip.appendChild(learnMore);
|
|
217
|
+
|
|
218
|
+
disclaimer.appendChild(tooltip);
|
|
190
219
|
blueCard.appendChild(disclaimer);
|
|
191
220
|
|
|
192
221
|
content.appendChild(blueCard);
|
|
@@ -184,21 +184,18 @@ export class RequestInitiatorView extends UI.Widget.VBox {
|
|
|
184
184
|
if (!initiator?.stack) {
|
|
185
185
|
return null;
|
|
186
186
|
}
|
|
187
|
+
const targetManager = SDK.TargetManager.TargetManager.instance();
|
|
187
188
|
const networkManager = SDK.NetworkManager.NetworkManager.forRequest(request);
|
|
188
|
-
const target = networkManager
|
|
189
|
+
const target = networkManager?.target() ?? targetManager.primaryPageTarget() ?? targetManager.rootTarget();
|
|
190
|
+
let stackTrace: StackTrace.StackTrace.StackTrace|null = null;
|
|
191
|
+
const preview = new Components.JSPresentationUtils.StackTracePreviewContent(
|
|
192
|
+
undefined, target ?? undefined, linkifier, {tabStops: focusableLink});
|
|
189
193
|
if (target) {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
const preview = new Components.JSPresentationUtils.StackTracePreviewContent(
|
|
193
|
-
undefined, target, linkifier, {tabStops: focusableLink});
|
|
194
|
+
stackTrace = await Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance()
|
|
195
|
+
.createStackTraceFromProtocolRuntime(initiator.stack, target);
|
|
194
196
|
preview.stackTrace = stackTrace;
|
|
195
|
-
return {preview, stackTrace};
|
|
196
197
|
}
|
|
197
|
-
return {
|
|
198
|
-
preview: new Components.JSPresentationUtils.StackTracePreviewContent(
|
|
199
|
-
undefined, target, linkifier, {runtimeStackTrace: initiator.stack, tabStops: focusableLink}),
|
|
200
|
-
stackTrace: null
|
|
201
|
-
};
|
|
198
|
+
return {preview, stackTrace};
|
|
202
199
|
}
|
|
203
200
|
|
|
204
201
|
override performUpdate(): void {
|
|
@@ -576,7 +576,7 @@ export class RequestTimingView extends UI.Widget.VBox {
|
|
|
576
576
|
calculator: this.#calculator,
|
|
577
577
|
requestStartTime: this.#request.startTime,
|
|
578
578
|
requestIssueTime: this.#request.issueTime(),
|
|
579
|
-
requestUnfinished:
|
|
579
|
+
requestUnfinished: !this.#request.finished,
|
|
580
580
|
fetchDetails: this.#fetchDetailsTree(),
|
|
581
581
|
routerDetails: this.#routerDetailsTree(),
|
|
582
582
|
wasThrottled: conditions?.urlPattern ? conditions : undefined,
|
|
@@ -222,8 +222,9 @@ export class KeybindsSettingsTab extends UI.Widget.VBox implements UI.ListContro
|
|
|
222
222
|
return 0;
|
|
223
223
|
}
|
|
224
224
|
|
|
225
|
-
isItemSelectable(
|
|
226
|
-
|
|
225
|
+
isItemSelectable(item: KeybindsItem): boolean {
|
|
226
|
+
// Category headers (UI.ActionRegistration.ActionCategory) should not be selectable
|
|
227
|
+
return item instanceof UI.ActionRegistration.Action;
|
|
227
228
|
}
|
|
228
229
|
|
|
229
230
|
selectedItemChanged(
|
|
@@ -314,7 +315,7 @@ export class KeybindsSettingsTab extends UI.Widget.VBox implements UI.ListContro
|
|
|
314
315
|
}
|
|
315
316
|
this.list.refreshAllItems();
|
|
316
317
|
if (!this.list.selectedItem()) {
|
|
317
|
-
this.list.
|
|
318
|
+
this.list.selectFirstItem();
|
|
318
319
|
}
|
|
319
320
|
}
|
|
320
321
|
|
|
@@ -179,6 +179,25 @@ export function outline(state: CodeMirror.EditorState): OutlineItem[] {
|
|
|
179
179
|
])) {
|
|
180
180
|
let title = state.sliceDoc(cursor.from, cursor.to);
|
|
181
181
|
const {lineNumber, columnNumber} = toLineColumn(cursor.from);
|
|
182
|
+
let hasEquals = false;
|
|
183
|
+
let node: CodeMirror.SyntaxNode|null = cursor.node;
|
|
184
|
+
while (node && node.name !== 'AssignmentExpression' && node.name !== 'VariableDeclaration') {
|
|
185
|
+
let sibling = node.nextSibling;
|
|
186
|
+
while (sibling) {
|
|
187
|
+
if (sibling.name === 'Equals') {
|
|
188
|
+
hasEquals = true;
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
sibling = sibling.nextSibling;
|
|
192
|
+
}
|
|
193
|
+
if (hasEquals) {
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
node = node.parent;
|
|
197
|
+
}
|
|
198
|
+
if (!hasEquals) {
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
182
201
|
while (cursor.name as string !== 'Equals') {
|
|
183
202
|
if (!cursor.next()) {
|
|
184
203
|
return items;
|
|
@@ -3041,6 +3041,31 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
|
|
|
3041
3041
|
this.#setActiveInsight({model: insightModel, insightSetKey}, {highlightInsight: true});
|
|
3042
3042
|
}
|
|
3043
3043
|
|
|
3044
|
+
static async executeRecordAndReload(): Promise<Trace.TraceModel.ParsedTrace> {
|
|
3045
|
+
await UI.ViewManager.ViewManager.instance().showView('timeline');
|
|
3046
|
+
const panelInstance = TimelinePanel.instance();
|
|
3047
|
+
|
|
3048
|
+
const result: EventTypes[Events.RECORDING_COMPLETED] = await new Promise(resolve => {
|
|
3049
|
+
function listener(e: Common.EventTarget.EventTargetEvent<EventTypes[Events.RECORDING_COMPLETED]>): void {
|
|
3050
|
+
resolve(e.data);
|
|
3051
|
+
panelInstance.removeEventListener(Events.RECORDING_COMPLETED, listener);
|
|
3052
|
+
}
|
|
3053
|
+
panelInstance.addEventListener(Events.RECORDING_COMPLETED, listener);
|
|
3054
|
+
panelInstance.recordReload();
|
|
3055
|
+
});
|
|
3056
|
+
|
|
3057
|
+
if ('errorText' in result) {
|
|
3058
|
+
throw new Error(result.errorText);
|
|
3059
|
+
}
|
|
3060
|
+
|
|
3061
|
+
const trace = panelInstance.model.parsedTrace(result.traceIndex);
|
|
3062
|
+
if (!trace) {
|
|
3063
|
+
throw new Error('Failed to parse trace');
|
|
3064
|
+
}
|
|
3065
|
+
|
|
3066
|
+
return trace;
|
|
3067
|
+
}
|
|
3068
|
+
|
|
3044
3069
|
static async *
|
|
3045
3070
|
handleExternalRecordRequest(): AsyncGenerator<
|
|
3046
3071
|
AiAssistanceModel.AiAgent.ExternalRequestResponse, AiAssistanceModel.AiAgent.ExternalRequestResponse> {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Name: Lighthouse
|
|
2
2
|
Short Name: lighthouse
|
|
3
|
-
Version: 13.0.
|
|
4
|
-
Revision:
|
|
3
|
+
Version: 13.0.2
|
|
4
|
+
Revision: 440f8bf87117ef61dc970c3ce4cebf91d46eb181
|
|
5
5
|
Update Mechanism: Manual
|
|
6
6
|
URL: https://github.com/GoogleChrome/lighthouse
|
|
7
7
|
License: Apache-2.0
|