chrome-devtools-frontend 1.0.1534251 → 1.0.1535712
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/docs/contributing/infrastructure.md +32 -0
- package/docs/contributing/issues.md +15 -37
- package/eslint.config.mjs +1 -0
- package/front_end/core/host/InspectorFrontendHost.ts +2 -0
- package/front_end/core/host/InspectorFrontendHostAPI.ts +1 -0
- package/front_end/core/host/UserMetrics.ts +29 -1
- package/front_end/core/protocol_client/CDPConnection.ts +53 -5
- package/front_end/core/protocol_client/InspectorBackend.ts +0 -89
- package/front_end/core/protocol_client/protocol_client.ts +2 -0
- package/front_end/core/root/Runtime.ts +1 -0
- package/front_end/core/sdk/RehydratingConnection.ts +1 -1
- package/front_end/devtools_compatibility.js +230 -32
- package/front_end/generated/SupportedCSSProperties.js +38 -0
- package/front_end/models/ai_assistance/BuiltInAi.ts +141 -39
- package/front_end/panels/ai_assistance/PatchWidget.ts +39 -40
- package/front_end/panels/ai_assistance/components/ExploreWidget.ts +0 -2
- package/front_end/panels/autofill/AutofillView.ts +2 -3
- package/front_end/panels/changes/CombinedDiffView.ts +13 -14
- package/front_end/panels/common/BadgeNotification.ts +1 -3
- package/front_end/panels/console/ConsoleInsightTeaser.ts +8 -1
- package/front_end/panels/console/ConsoleView.ts +1 -0
- package/front_end/panels/console/consoleView.css +0 -1
- package/front_end/panels/elements/ElementsTreeOutline.ts +1 -1
- package/front_end/panels/network/components/DirectSocketConnectionView.ts +4 -6
- package/front_end/panels/network/components/ResponseHeaderSection.ts +1 -2
- package/front_end/panels/security/CookieControlsView.ts +72 -66
- package/front_end/panels/security/CookieReportView.ts +15 -14
- package/front_end/panels/security/IPProtectionView.ts +1 -2
- package/front_end/panels/security/SecurityPanel.ts +19 -19
- package/front_end/panels/timeline/TimelineSelectorStatsView.ts +36 -36
- package/front_end/panels/timeline/components/SidebarAnnotationsTab.ts +1 -2
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/ui/components/dialogs/Dialog.ts +7 -17
- package/front_end/ui/components/text_editor/TextEditor.ts +2 -3
- package/front_end/ui/components/text_editor/config.ts +1 -3
- package/front_end/ui/legacy/UIUtils.ts +5 -0
- package/front_end/ui/legacy/components/inline_editor/CSSAngle.ts +1 -1
- package/front_end/ui/legacy/components/perf_ui/BrickBreaker.ts +2 -2
- package/front_end/ui/legacy/components/perf_ui/Font.ts +1 -14
- package/front_end/ui/visual_logging/KnownContextValues.ts +2 -0
- package/inspector_overlay/testing/InspectorOverlayHelpers.ts +2 -10
- package/package.json +1 -1
- package/front_end/services/window_bounds/WindowBoundsService.ts +0 -27
- package/front_end/services/window_bounds/window_bounds.ts +0 -9
|
@@ -2,10 +2,13 @@
|
|
|
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 * as Host from '../../core/host/host.js';
|
|
5
6
|
import * as Root from '../../core/root/root.js';
|
|
6
7
|
|
|
7
8
|
let builtInAiInstance: BuiltInAi|undefined;
|
|
8
|
-
let availability
|
|
9
|
+
let availability: LanguageModelAvailability|undefined;
|
|
10
|
+
let hasGpu: boolean|undefined;
|
|
11
|
+
let isFirstRun = true;
|
|
9
12
|
|
|
10
13
|
export interface LanguageModel {
|
|
11
14
|
promptStreaming: (arg0: string, opts?: {
|
|
@@ -15,20 +18,62 @@ export interface LanguageModel {
|
|
|
15
18
|
destroy: () => void;
|
|
16
19
|
}
|
|
17
20
|
|
|
21
|
+
export const enum LanguageModelAvailability {
|
|
22
|
+
UNAVAILABLE = 'unavailable',
|
|
23
|
+
DOWNLOADABLE = 'downloadable',
|
|
24
|
+
DOWNLOADING = 'downloading',
|
|
25
|
+
AVAILABLE = 'available',
|
|
26
|
+
DISABLED = 'disabled',
|
|
27
|
+
}
|
|
28
|
+
|
|
18
29
|
export class BuiltInAi {
|
|
19
30
|
#consoleInsightsSession: LanguageModel;
|
|
20
31
|
|
|
21
|
-
static async
|
|
32
|
+
static async getLanguageModelAvailability(): Promise<LanguageModelAvailability> {
|
|
22
33
|
if (!Root.Runtime.hostConfig.devToolsAiPromptApi?.enabled) {
|
|
23
|
-
return
|
|
34
|
+
return LanguageModelAvailability.DISABLED;
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
// @ts-expect-error
|
|
38
|
+
availability = await window.LanguageModel.availability({expectedOutputs: [{type: 'text', languages: ['en']}]}) as
|
|
39
|
+
LanguageModelAvailability;
|
|
40
|
+
return availability;
|
|
41
|
+
} catch {
|
|
42
|
+
return LanguageModelAvailability.UNAVAILABLE;
|
|
24
43
|
}
|
|
25
|
-
// @ts-expect-error
|
|
26
|
-
availability = await window.LanguageModel.availability({expectedOutputs: [{type: 'text', languages: ['en']}]});
|
|
27
|
-
return availability === 'available';
|
|
28
44
|
}
|
|
29
45
|
|
|
30
46
|
static cachedIsAvailable(): boolean {
|
|
31
|
-
return availability ===
|
|
47
|
+
return availability === LanguageModelAvailability.AVAILABLE;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
static isGpuAvailable(): boolean {
|
|
51
|
+
const hasGpuHelper = (): boolean => {
|
|
52
|
+
const canvas = document.createElement('canvas');
|
|
53
|
+
try {
|
|
54
|
+
const webgl = canvas.getContext('webgl');
|
|
55
|
+
if (!webgl) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
const debugInfo = webgl.getExtension('WEBGL_debug_renderer_info');
|
|
59
|
+
if (!debugInfo) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
const renderer = webgl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL);
|
|
63
|
+
if (renderer.includes('SwiftShader')) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
} catch {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
return true;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
if (hasGpu !== undefined) {
|
|
73
|
+
return hasGpu;
|
|
74
|
+
}
|
|
75
|
+
hasGpu = hasGpuHelper();
|
|
76
|
+
return hasGpu;
|
|
32
77
|
}
|
|
33
78
|
|
|
34
79
|
private constructor(consoleInsightsSession: LanguageModel) {
|
|
@@ -37,40 +82,97 @@ export class BuiltInAi {
|
|
|
37
82
|
|
|
38
83
|
static async instance(): Promise<BuiltInAi|undefined> {
|
|
39
84
|
if (builtInAiInstance === undefined) {
|
|
40
|
-
if (
|
|
41
|
-
|
|
85
|
+
if (isFirstRun) {
|
|
86
|
+
const languageModelAvailability = await BuiltInAi.getLanguageModelAvailability();
|
|
87
|
+
const hasGpu = BuiltInAi.isGpuAvailable();
|
|
88
|
+
if (hasGpu) {
|
|
89
|
+
switch (languageModelAvailability) {
|
|
90
|
+
case LanguageModelAvailability.UNAVAILABLE:
|
|
91
|
+
Host.userMetrics.builtInAiAvailability(Host.UserMetrics.BuiltInAiAvailability.UNAVAILABLE_HAS_GPU);
|
|
92
|
+
break;
|
|
93
|
+
case LanguageModelAvailability.DOWNLOADABLE:
|
|
94
|
+
Host.userMetrics.builtInAiAvailability(Host.UserMetrics.BuiltInAiAvailability.DOWNLOADABLE_HAS_GPU);
|
|
95
|
+
break;
|
|
96
|
+
case LanguageModelAvailability.DOWNLOADING:
|
|
97
|
+
Host.userMetrics.builtInAiAvailability(Host.UserMetrics.BuiltInAiAvailability.DOWNLOADING_HAS_GPU);
|
|
98
|
+
break;
|
|
99
|
+
case LanguageModelAvailability.AVAILABLE:
|
|
100
|
+
Host.userMetrics.builtInAiAvailability(Host.UserMetrics.BuiltInAiAvailability.AVAILABLE_HAS_GPU);
|
|
101
|
+
break;
|
|
102
|
+
case LanguageModelAvailability.DISABLED:
|
|
103
|
+
Host.userMetrics.builtInAiAvailability(Host.UserMetrics.BuiltInAiAvailability.DISABLED_HAS_GPU);
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
} else {
|
|
107
|
+
switch (languageModelAvailability) {
|
|
108
|
+
case LanguageModelAvailability.UNAVAILABLE:
|
|
109
|
+
Host.userMetrics.builtInAiAvailability(Host.UserMetrics.BuiltInAiAvailability.UNAVAILABLE_NO_GPU);
|
|
110
|
+
break;
|
|
111
|
+
case LanguageModelAvailability.DOWNLOADABLE:
|
|
112
|
+
Host.userMetrics.builtInAiAvailability(Host.UserMetrics.BuiltInAiAvailability.DOWNLOADABLE_NO_GPU);
|
|
113
|
+
break;
|
|
114
|
+
case LanguageModelAvailability.DOWNLOADING:
|
|
115
|
+
Host.userMetrics.builtInAiAvailability(Host.UserMetrics.BuiltInAiAvailability.DOWNLOADING_NO_GPU);
|
|
116
|
+
break;
|
|
117
|
+
case LanguageModelAvailability.AVAILABLE:
|
|
118
|
+
Host.userMetrics.builtInAiAvailability(Host.UserMetrics.BuiltInAiAvailability.AVAILABLE_NO_GPU);
|
|
119
|
+
break;
|
|
120
|
+
case LanguageModelAvailability.DISABLED:
|
|
121
|
+
Host.userMetrics.builtInAiAvailability(Host.UserMetrics.BuiltInAiAvailability.DISABLED_NO_GPU);
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
isFirstRun = false;
|
|
126
|
+
if (!Root.Runtime.hostConfig.devToolsAiPromptApi?.allowWithoutGpu && !hasGpu) {
|
|
127
|
+
return undefined;
|
|
128
|
+
}
|
|
129
|
+
if (languageModelAvailability !== LanguageModelAvailability.AVAILABLE) {
|
|
130
|
+
return undefined;
|
|
131
|
+
}
|
|
132
|
+
} else {
|
|
133
|
+
if (!Root.Runtime.hostConfig.devToolsAiPromptApi?.allowWithoutGpu && !BuiltInAi.isGpuAvailable()) {
|
|
134
|
+
return undefined;
|
|
135
|
+
}
|
|
136
|
+
if ((await BuiltInAi.getLanguageModelAvailability()) !== LanguageModelAvailability.AVAILABLE) {
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
42
139
|
}
|
|
43
|
-
// @ts-expect-error
|
|
44
|
-
const consoleInsightsSession = await window.LanguageModel.create({
|
|
45
|
-
initialPrompts: [{
|
|
46
|
-
role: 'system',
|
|
47
|
-
content: `
|
|
48
|
-
You are an expert web developer. Your goal is to help a human web developer who
|
|
49
|
-
is using Chrome DevTools to debug a web site or web app. The Chrome DevTools
|
|
50
|
-
console is showing a message which is either an error or a warning. Please help
|
|
51
|
-
the user understand the problematic console message.
|
|
52
140
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
141
|
+
try {
|
|
142
|
+
// @ts-expect-error
|
|
143
|
+
const consoleInsightsSession = await window.LanguageModel.create({
|
|
144
|
+
initialPrompts: [{
|
|
145
|
+
role: 'system',
|
|
146
|
+
content: `
|
|
147
|
+
You are an expert web developer. Your goal is to help a human web developer who
|
|
148
|
+
is using Chrome DevTools to debug a web site or web app. The Chrome DevTools
|
|
149
|
+
console is showing a message which is either an error or a warning. Please help
|
|
150
|
+
the user understand the problematic console message.
|
|
151
|
+
|
|
152
|
+
Your instructions are as follows:
|
|
153
|
+
- Explain the reason why the error or warning is showing up.
|
|
154
|
+
- The explanation has a maximum length of 200 characters. Anything beyond this
|
|
155
|
+
length will be cut off. Make sure that your explanation is at most 200 characters long.
|
|
156
|
+
- Your explanation should not end in the middle of a sentence.
|
|
157
|
+
- Your explanation should consist of a single paragraph only. Do not include any
|
|
158
|
+
headings or code blocks. Only write a single paragraph of text.
|
|
159
|
+
- Your response should be concise and to the point. Avoid lengthy explanations
|
|
160
|
+
or unnecessary details.
|
|
161
|
+
`
|
|
162
|
+
}],
|
|
163
|
+
expectedInputs: [{
|
|
164
|
+
type: 'text',
|
|
165
|
+
languages: ['en'],
|
|
166
|
+
}],
|
|
167
|
+
expectedOutputs: [{
|
|
168
|
+
type: 'text',
|
|
169
|
+
languages: ['en'],
|
|
170
|
+
}],
|
|
171
|
+
}) as LanguageModel;
|
|
172
|
+
builtInAiInstance = new BuiltInAi(consoleInsightsSession);
|
|
173
|
+
} catch {
|
|
174
|
+
return undefined;
|
|
175
|
+
}
|
|
74
176
|
}
|
|
75
177
|
return builtInAiInstance;
|
|
76
178
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// Copyright 2025 The Chromium Authors
|
|
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
|
-
/* eslint-disable @devtools/no-lit-render-outside-of-view */
|
|
5
4
|
|
|
6
5
|
import '../../ui/legacy/legacy.js';
|
|
7
6
|
import '../../ui/components/markdown_view/markdown_view.js';
|
|
@@ -187,42 +186,8 @@ export interface ViewOutput {
|
|
|
187
186
|
}
|
|
188
187
|
|
|
189
188
|
type View = (input: ViewInput, output: ViewOutput, target: HTMLElement) => void;
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
changeSummary = '';
|
|
193
|
-
changeManager: AiAssistanceModel.ChangeManager.ChangeManager|undefined;
|
|
194
|
-
// Whether the user completed first run experience dialog or not.
|
|
195
|
-
#aiPatchingFreCompletedSetting =
|
|
196
|
-
Common.Settings.Settings.instance().createSetting('ai-assistance-patching-fre-completed', false);
|
|
197
|
-
#projectIdSetting =
|
|
198
|
-
Common.Settings.Settings.instance().createSetting('ai-assistance-patching-selected-project-id', '');
|
|
199
|
-
#view: View;
|
|
200
|
-
#viewOutput: ViewOutput = {};
|
|
201
|
-
#aidaClient: Host.AidaClient.AidaClient;
|
|
202
|
-
#applyPatchAbortController?: AbortController;
|
|
203
|
-
#project?: Workspace.Workspace.Project;
|
|
204
|
-
#patchSources?: string;
|
|
205
|
-
#savedToDisk?: boolean;
|
|
206
|
-
#noLogging: boolean; // Whether the enterprise setting is `ALLOW_WITHOUT_LOGGING` or not.
|
|
207
|
-
#patchSuggestionState = PatchSuggestionState.INITIAL;
|
|
208
|
-
#workspaceDiff = WorkspaceDiff.WorkspaceDiff.workspaceDiff();
|
|
209
|
-
#workspace = Workspace.Workspace.WorkspaceImpl.instance();
|
|
210
|
-
#automaticFileSystem =
|
|
211
|
-
Persistence.AutomaticFileSystemManager.AutomaticFileSystemManager.instance().automaticFileSystem;
|
|
212
|
-
#applyToDisconnectedAutomaticWorkspace = false;
|
|
213
|
-
// `rpcId` from the `applyPatch` request
|
|
214
|
-
#rpcId: Host.AidaClient.RpcGlobalId|null = null;
|
|
215
|
-
|
|
216
|
-
constructor(element?: HTMLElement, view?: View, opts?: {
|
|
217
|
-
aidaClient: Host.AidaClient.AidaClient,
|
|
218
|
-
}) {
|
|
219
|
-
super(element);
|
|
220
|
-
this.#aidaClient = opts?.aidaClient ?? new Host.AidaClient.AidaClient();
|
|
221
|
-
this.#noLogging = Root.Runtime.hostConfig.aidaAvailability?.enterprisePolicyValue ===
|
|
222
|
-
Root.Runtime.GenAiEnterprisePolicyValue.ALLOW_WITHOUT_LOGGING;
|
|
223
|
-
|
|
224
|
-
// clang-format off
|
|
225
|
-
this.#view = view ?? ((input, output, target) => {
|
|
189
|
+
const DEFAULT_VIEW: View =
|
|
190
|
+
(input, output, target) => {
|
|
226
191
|
if (!input.changeSummary && input.patchSuggestionState === PatchSuggestionState.INITIAL) {
|
|
227
192
|
return;
|
|
228
193
|
}
|
|
@@ -428,9 +393,43 @@ export class PatchWidget extends UI.Widget.Widget {
|
|
|
428
393
|
</details>
|
|
429
394
|
`;
|
|
430
395
|
|
|
431
|
-
render(template, target
|
|
432
|
-
}
|
|
433
|
-
|
|
396
|
+
render(template, target);
|
|
397
|
+
};
|
|
398
|
+
|
|
399
|
+
export class PatchWidget extends UI.Widget.Widget {
|
|
400
|
+
changeSummary = '';
|
|
401
|
+
changeManager: AiAssistanceModel.ChangeManager.ChangeManager|undefined;
|
|
402
|
+
// Whether the user completed first run experience dialog or not.
|
|
403
|
+
#aiPatchingFreCompletedSetting =
|
|
404
|
+
Common.Settings.Settings.instance().createSetting('ai-assistance-patching-fre-completed', false);
|
|
405
|
+
#projectIdSetting =
|
|
406
|
+
Common.Settings.Settings.instance().createSetting('ai-assistance-patching-selected-project-id', '');
|
|
407
|
+
#view: View;
|
|
408
|
+
#viewOutput: ViewOutput = {};
|
|
409
|
+
#aidaClient: Host.AidaClient.AidaClient;
|
|
410
|
+
#applyPatchAbortController?: AbortController;
|
|
411
|
+
#project?: Workspace.Workspace.Project;
|
|
412
|
+
#patchSources?: string;
|
|
413
|
+
#savedToDisk?: boolean;
|
|
414
|
+
#noLogging: boolean; // Whether the enterprise setting is `ALLOW_WITHOUT_LOGGING` or not.
|
|
415
|
+
#patchSuggestionState = PatchSuggestionState.INITIAL;
|
|
416
|
+
#workspaceDiff = WorkspaceDiff.WorkspaceDiff.workspaceDiff();
|
|
417
|
+
#workspace = Workspace.Workspace.WorkspaceImpl.instance();
|
|
418
|
+
#automaticFileSystem =
|
|
419
|
+
Persistence.AutomaticFileSystemManager.AutomaticFileSystemManager.instance().automaticFileSystem;
|
|
420
|
+
#applyToDisconnectedAutomaticWorkspace = false;
|
|
421
|
+
// `rpcId` from the `applyPatch` request
|
|
422
|
+
#rpcId: Host.AidaClient.RpcGlobalId|null = null;
|
|
423
|
+
|
|
424
|
+
constructor(element?: HTMLElement, view = DEFAULT_VIEW, opts?: {
|
|
425
|
+
aidaClient: Host.AidaClient.AidaClient,
|
|
426
|
+
}) {
|
|
427
|
+
super(element);
|
|
428
|
+
this.#aidaClient = opts?.aidaClient ?? new Host.AidaClient.AidaClient();
|
|
429
|
+
this.#noLogging = Root.Runtime.hostConfig.aidaAvailability?.enterprisePolicyValue ===
|
|
430
|
+
Root.Runtime.GenAiEnterprisePolicyValue.ALLOW_WITHOUT_LOGGING;
|
|
431
|
+
this.#view = view;
|
|
432
|
+
|
|
434
433
|
this.requestUpdate();
|
|
435
434
|
}
|
|
436
435
|
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
// Copyright 2025 The Chromium Authors
|
|
3
3
|
// Use of this source code is governed by a BSD-style license that can be
|
|
4
4
|
// found in the LICENSE file.
|
|
5
|
-
/* eslint-disable @devtools/no-lit-render-outside-of-view */
|
|
6
5
|
|
|
7
6
|
import * as i18n from '../../../core/i18n/i18n.js';
|
|
8
7
|
import * as Root from '../../../core/root/root.js';
|
|
@@ -105,7 +104,6 @@ export const DEFAULT_VIEW = (
|
|
|
105
104
|
</div>
|
|
106
105
|
`,
|
|
107
106
|
target,
|
|
108
|
-
{ host: target },
|
|
109
107
|
);
|
|
110
108
|
// clang-format on
|
|
111
109
|
};
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// Copyright 2023 The Chromium Authors
|
|
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
|
-
/* eslint-disable @devtools/no-lit-render-outside-of-view */
|
|
5
4
|
|
|
6
5
|
import '../../ui/components/adorners/adorners.js';
|
|
7
6
|
import '../../ui/legacy/components/data_grid/data_grid.js';
|
|
@@ -250,7 +249,7 @@ const DEFAULT_VIEW: View = (input: ViewInput, _output: ViewOutput, target: HTMLE
|
|
|
250
249
|
</div>
|
|
251
250
|
</div>
|
|
252
251
|
</main>
|
|
253
|
-
`, target
|
|
252
|
+
`, target);
|
|
254
253
|
// clang-format on
|
|
255
254
|
return;
|
|
256
255
|
}
|
|
@@ -287,7 +286,7 @@ const DEFAULT_VIEW: View = (input: ViewInput, _output: ViewOutput, target: HTMLE
|
|
|
287
286
|
${renderFilledFields()}
|
|
288
287
|
</div>
|
|
289
288
|
</main>
|
|
290
|
-
`, target
|
|
289
|
+
`, target);
|
|
291
290
|
// clang-format on
|
|
292
291
|
};
|
|
293
292
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// Copyright 2025 The Chromium Authors
|
|
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
|
-
/* eslint-disable @devtools/no-lit-render-outside-of-view */
|
|
5
4
|
|
|
6
5
|
import * as Common from '../../core/common/common.js';
|
|
7
6
|
import * as i18n from '../../core/i18n/i18n.js';
|
|
@@ -101,6 +100,18 @@ function renderSingleDiffView(singleDiffViewInput: SingleDiffViewInput): Lit.Tem
|
|
|
101
100
|
// clang-format on
|
|
102
101
|
}
|
|
103
102
|
|
|
103
|
+
const DEFAULT_VIEW: View = (input, output, target) => {
|
|
104
|
+
// clang-format off
|
|
105
|
+
Lit.render(
|
|
106
|
+
html`
|
|
107
|
+
<div class="combined-diff-view">
|
|
108
|
+
${input.singleDiffViewInputs.map(singleDiffViewInput => renderSingleDiffView(singleDiffViewInput))}
|
|
109
|
+
</div>
|
|
110
|
+
`,
|
|
111
|
+
target);
|
|
112
|
+
// clang-format on
|
|
113
|
+
};
|
|
114
|
+
|
|
104
115
|
export class CombinedDiffView extends UI.Widget.Widget {
|
|
105
116
|
/**
|
|
106
117
|
* Ignores urls that start with any in the list
|
|
@@ -113,19 +124,7 @@ export class CombinedDiffView extends UI.Widget.Widget {
|
|
|
113
124
|
#copiedFiles: Record<string, boolean> = {};
|
|
114
125
|
#view: View;
|
|
115
126
|
#viewOutput: ViewOutput = {};
|
|
116
|
-
constructor(element?: HTMLElement, view: View =
|
|
117
|
-
output.scrollToSelectedDiff = () => {
|
|
118
|
-
target.querySelector('details.selected')?.scrollIntoView();
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
Lit.render(
|
|
122
|
-
html`
|
|
123
|
-
<div class="combined-diff-view">
|
|
124
|
-
${input.singleDiffViewInputs.map(singleDiffViewInput => renderSingleDiffView(singleDiffViewInput))}
|
|
125
|
-
</div>
|
|
126
|
-
`,
|
|
127
|
-
target, {host: target});
|
|
128
|
-
}) {
|
|
127
|
+
constructor(element?: HTMLElement, view: View = DEFAULT_VIEW) {
|
|
129
128
|
super(element);
|
|
130
129
|
this.registerRequiredCSS(combinedDiffViewStyles);
|
|
131
130
|
this.#view = view;
|
|
@@ -6,7 +6,6 @@ import * as Common from '../../core/common/common.js';
|
|
|
6
6
|
import * as Host from '../../core/host/host.js';
|
|
7
7
|
import * as i18n from '../../core/i18n/i18n.js';
|
|
8
8
|
import * as Badges from '../../models/badges/badges.js';
|
|
9
|
-
import * as WindowBoundsService from '../../services/window_bounds/window_bounds.js';
|
|
10
9
|
import * as Buttons from '../../ui/components/buttons/buttons.js';
|
|
11
10
|
import * as UI from '../../ui/legacy/legacy.js';
|
|
12
11
|
import * as Lit from '../../ui/lit/lit.js';
|
|
@@ -166,8 +165,7 @@ export class BadgeNotification extends UI.Widget.Widget {
|
|
|
166
165
|
|
|
167
166
|
#positionNotification(): void {
|
|
168
167
|
const boundingRect = this.contentElement.getBoundingClientRect();
|
|
169
|
-
const container =
|
|
170
|
-
WindowBoundsService.WindowBoundsService.WindowBoundsServiceImpl.instance().getDevToolsBoundingElement();
|
|
168
|
+
const container = UI.UIUtils.getDevToolsBoundingElement();
|
|
171
169
|
this.contentElement.positionAt(
|
|
172
170
|
LEFT_OFFSET, container.clientHeight - boundingRect.height - BOTTOM_OFFSET, container);
|
|
173
171
|
}
|
|
@@ -124,6 +124,7 @@ export const DEFAULT_VIEW = (input: ViewInput, _output: undefined, target: HTMLE
|
|
|
124
124
|
variant="rich"
|
|
125
125
|
vertical-distance-increase=-6
|
|
126
126
|
prefer-span-left
|
|
127
|
+
jslogContext="console-insight-teaser"
|
|
127
128
|
>
|
|
128
129
|
<div class="teaser-tooltip-container">
|
|
129
130
|
${input.isError ? html`
|
|
@@ -177,7 +178,7 @@ export const DEFAULT_VIEW = (input: ViewInput, _output: undefined, target: HTMLE
|
|
|
177
178
|
aria-details=${'teaser-info-tooltip-' + input.uuid}
|
|
178
179
|
.accessibleLabel=${lockedString(UIStringsNotTranslate.learnDataUsage)}
|
|
179
180
|
></devtools-button>
|
|
180
|
-
<devtools-tooltip id=${'teaser-info-tooltip-' + input.uuid} variant="rich">
|
|
181
|
+
<devtools-tooltip id=${'teaser-info-tooltip-' + input.uuid} variant="rich" jslogContext="teaser-info-tooltip">
|
|
181
182
|
<div class="info-tooltip-text">${lockedString(UIStringsNotTranslate.infoTooltipText)}</div>
|
|
182
183
|
<div class="learn-more">
|
|
183
184
|
<x-link
|
|
@@ -322,6 +323,7 @@ export class ConsoleInsightTeaser extends UI.Widget.Widget {
|
|
|
322
323
|
}
|
|
323
324
|
if (this.#isGenerating) {
|
|
324
325
|
this.#mainText = '';
|
|
326
|
+
Host.userMetrics.actionTaken(Host.UserMetrics.Action.InsightTeaserGenerationAborted);
|
|
325
327
|
}
|
|
326
328
|
this.#isGenerating = false;
|
|
327
329
|
if (this.#timeoutId) {
|
|
@@ -345,7 +347,9 @@ export class ConsoleInsightTeaser extends UI.Widget.Widget {
|
|
|
345
347
|
async #generateTeaserText(): Promise<void> {
|
|
346
348
|
this.#headerText = this.#consoleViewMessage.toMessageTextString().substring(0, 70);
|
|
347
349
|
this.#isGenerating = true;
|
|
350
|
+
Host.userMetrics.actionTaken(Host.UserMetrics.Action.InsightTeaserGenerationStarted);
|
|
348
351
|
this.#timeoutId = setTimeout(this.#setSlow.bind(this), SLOW_GENERATION_CUTOFF_MILLISECONDS);
|
|
352
|
+
const startTime = performance.now();
|
|
349
353
|
let teaserText = '';
|
|
350
354
|
try {
|
|
351
355
|
for await (const chunk of this.#getOnDeviceInsight()) {
|
|
@@ -358,6 +362,7 @@ export class ConsoleInsightTeaser extends UI.Widget.Widget {
|
|
|
358
362
|
if (err.name !== 'AbortError') {
|
|
359
363
|
console.error(err.name, err.message);
|
|
360
364
|
this.#isError = true;
|
|
365
|
+
Host.userMetrics.actionTaken(Host.UserMetrics.Action.InsightTeaserGenerationErrored);
|
|
361
366
|
}
|
|
362
367
|
this.#isGenerating = false;
|
|
363
368
|
clearTimeout(this.#timeoutId);
|
|
@@ -366,8 +371,10 @@ export class ConsoleInsightTeaser extends UI.Widget.Widget {
|
|
|
366
371
|
}
|
|
367
372
|
|
|
368
373
|
clearTimeout(this.#timeoutId);
|
|
374
|
+
Host.userMetrics.consoleInsightTeaserGenerated(performance.now() - startTime);
|
|
369
375
|
this.#isGenerating = false;
|
|
370
376
|
this.#mainText = teaserText;
|
|
377
|
+
Host.userMetrics.actionTaken(Host.UserMetrics.Action.InsightTeaserGenerationCompleted);
|
|
371
378
|
this.requestUpdate();
|
|
372
379
|
}
|
|
373
380
|
|
|
@@ -505,6 +505,7 @@ export class ConsoleView extends UI.Widget.VBox implements
|
|
|
505
505
|
|
|
506
506
|
this.pinPane = new ConsolePinPane(liveExpressionButton, () => this.prompt.focus());
|
|
507
507
|
this.pinPane.element.classList.add('console-view-pinpane');
|
|
508
|
+
this.pinPane.element.classList.remove('flex-auto');
|
|
508
509
|
this.pinPane.show(this.contentsElement);
|
|
509
510
|
|
|
510
511
|
this.viewport = new ConsoleViewport(this);
|
|
@@ -422,7 +422,7 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
422
422
|
if (domModel.parentModel()) {
|
|
423
423
|
continue;
|
|
424
424
|
}
|
|
425
|
-
if (!this.rootDOMNode) {
|
|
425
|
+
if (!this.rootDOMNode || this.rootDOMNode.domModel() !== domModel) {
|
|
426
426
|
if (domModel.existingDocument()) {
|
|
427
427
|
this.rootDOMNode = domModel.existingDocument();
|
|
428
428
|
this.onDocumentUpdated(domModel);
|
|
@@ -2,8 +2,6 @@
|
|
|
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
|
-
/* eslint-disable @devtools/no-lit-render-outside-of-view */
|
|
6
|
-
|
|
7
5
|
import * as Common from '../../../core/common/common.js';
|
|
8
6
|
import * as Host from '../../../core/host/host.js';
|
|
9
7
|
import * as i18n from '../../../core/i18n/i18n.js';
|
|
@@ -112,9 +110,9 @@ export interface ViewInput {
|
|
|
112
110
|
onCopyRow: () => void;
|
|
113
111
|
}
|
|
114
112
|
|
|
115
|
-
export type View = (input: ViewInput, target: HTMLElement) => void;
|
|
113
|
+
export type View = (input: ViewInput, output: undefined, target: HTMLElement) => void;
|
|
116
114
|
|
|
117
|
-
export const DEFAULT_VIEW: View = (input, target) => {
|
|
115
|
+
export const DEFAULT_VIEW: View = (input, _output, target) => {
|
|
118
116
|
function isCategoryOpen(name: string): boolean {
|
|
119
117
|
return input.openCategories.includes(name);
|
|
120
118
|
}
|
|
@@ -203,7 +201,7 @@ export const DEFAULT_VIEW: View = (input, target) => {
|
|
|
203
201
|
${renderCategory(CATEGORY_NAME_GENERAL, i18nString(UIStrings.general), generalContent)}
|
|
204
202
|
${renderCategory(CATEGORY_NAME_OPTIONS, i18nString(UIStrings.options), optionsContent)}
|
|
205
203
|
${socketInfo.openInfo ? renderCategory(CATEGORY_NAME_OPEN_INFO, i18nString(UIStrings.openInfo), openInfoContent) : Lit.nothing}
|
|
206
|
-
`, target
|
|
204
|
+
`, target);
|
|
207
205
|
// clang-format on
|
|
208
206
|
};
|
|
209
207
|
|
|
@@ -278,7 +276,7 @@ export class DirectSocketConnectionView extends UI.Widget.Widget {
|
|
|
278
276
|
Host.userMetrics.actionTaken(Host.UserMetrics.Action.NetworkPanelCopyValue);
|
|
279
277
|
}
|
|
280
278
|
};
|
|
281
|
-
this.#view(viewInput, this.contentElement);
|
|
279
|
+
this.#view(viewInput, undefined, this.contentElement);
|
|
282
280
|
}
|
|
283
281
|
|
|
284
282
|
#setIsOpen(categoryName: string, open: boolean): void {
|
|
@@ -29,7 +29,6 @@ import {
|
|
|
29
29
|
type HeaderEditedEvent,
|
|
30
30
|
type HeaderEditorDescriptor,
|
|
31
31
|
type HeaderRemovedEvent,
|
|
32
|
-
type HeaderSectionRow,
|
|
33
32
|
type HeaderSectionRowData,
|
|
34
33
|
isValidHeaderName,
|
|
35
34
|
} from './HeaderSectionRow.js';
|
|
@@ -515,7 +514,7 @@ export class ResponseHeaderSection extends ResponseHeaderSectionBase {
|
|
|
515
514
|
this.#updateOverrides(this.#headerEditors[index].name, this.#headerEditors[index].value || '', index);
|
|
516
515
|
this.#render();
|
|
517
516
|
|
|
518
|
-
const rows = this.shadow.querySelectorAll
|
|
517
|
+
const rows = this.shadow.querySelectorAll('devtools-header-section-row');
|
|
519
518
|
const [lastRow] = Array.from(rows).slice(-1);
|
|
520
519
|
lastRow?.focus();
|
|
521
520
|
Host.userMetrics.actionTaken(Host.UserMetrics.Action.HeaderOverrideHeaderAdded);
|