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
|
@@ -251,8 +251,48 @@ html, body {
|
|
|
251
251
|
}
|
|
252
252
|
|
|
253
253
|
.green-dev-floaty-disclaimer {
|
|
254
|
-
font-size:
|
|
254
|
+
font-size: 16px;
|
|
255
255
|
color: #666;
|
|
256
256
|
text-align: center;
|
|
257
257
|
margin-top: 8px;
|
|
258
|
+
position: relative; /* For tooltip positioning */
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
.disclaimer-link {
|
|
262
|
+
color: #666; /* Match text color */
|
|
263
|
+
text-decoration: underline;
|
|
264
|
+
cursor: pointer;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
.disclaimer-tooltip {
|
|
268
|
+
display: none;
|
|
269
|
+
position: absolute;
|
|
270
|
+
bottom: 100%; /* Position above */
|
|
271
|
+
left: 50%;
|
|
272
|
+
transform: translateX(-50%);
|
|
273
|
+
width: 300px;
|
|
274
|
+
padding: 12px;
|
|
275
|
+
background-color: #fff;
|
|
276
|
+
border: 1px solid #ccc;
|
|
277
|
+
border-radius: 8px;
|
|
278
|
+
box-shadow: 0 2px 10px rgb(0 0 0 / 20%);
|
|
279
|
+
z-index: 1000;
|
|
280
|
+
text-align: left;
|
|
281
|
+
font-size: 14px;
|
|
282
|
+
line-height: 1.4;
|
|
283
|
+
color: #333;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.disclaimer-link:hover + .disclaimer-tooltip,
|
|
287
|
+
.disclaimer-tooltip:hover {
|
|
288
|
+
display: block;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
.learn-more-link {
|
|
292
|
+
color: #0b57d0;
|
|
293
|
+
text-decoration: none;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.learn-more-link:hover {
|
|
297
|
+
text-decoration: underline;
|
|
258
298
|
}
|
|
@@ -23,7 +23,14 @@
|
|
|
23
23
|
<input type="text" class="green-dev-floaty-dialog-text-field" placeholder="Why is this not centered?">
|
|
24
24
|
<button class="green-dev-floaty-dialog-play-button"></button>
|
|
25
25
|
</div>
|
|
26
|
-
<div class="green-dev-floaty-disclaimer">
|
|
26
|
+
<div class="green-dev-floaty-disclaimer">
|
|
27
|
+
<span class="disclaimer-link">Relevant data</span> is sent to Google
|
|
28
|
+
<div class="disclaimer-tooltip">
|
|
29
|
+
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.
|
|
30
|
+
<br><br>
|
|
31
|
+
<a href="https://developer.chrome.com/docs/devtools/ai-assistance" class="learn-more-link">Learn about AI in DevTools</a>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
27
34
|
</div>
|
|
28
35
|
</div>
|
|
29
36
|
</div>
|
|
@@ -66,8 +66,8 @@ class GreenDevFloaty {
|
|
|
66
66
|
// Refresh the anchor by re-sending the show command.
|
|
67
67
|
const msg = JSON.stringify({
|
|
68
68
|
id: 9999,
|
|
69
|
-
method: 'Overlay.
|
|
70
|
-
params: {
|
|
69
|
+
method: 'Overlay.setShowInspectedElementAnchor',
|
|
70
|
+
params: {inspectedElementAnchorConfig: {backendNodeId: this.#backendNodeId}}
|
|
71
71
|
});
|
|
72
72
|
Host.InspectorFrontendHost.InspectorFrontendHostInstance.sendMessageToBackend(msg);
|
|
73
73
|
}
|
|
@@ -403,8 +403,8 @@ async function init(): Promise<void> {
|
|
|
403
403
|
if (backendNodeId) {
|
|
404
404
|
const msg = JSON.stringify({
|
|
405
405
|
id: 9999,
|
|
406
|
-
method: 'Overlay.
|
|
407
|
-
params: {
|
|
406
|
+
method: 'Overlay.setShowInspectedElementAnchor',
|
|
407
|
+
params: {inspectedElementAnchorConfig: {backendNodeId}}
|
|
408
408
|
});
|
|
409
409
|
Host.InspectorFrontendHost.InspectorFrontendHostInstance.sendMessageToBackend(msg);
|
|
410
410
|
}
|
|
@@ -107,7 +107,7 @@ export class NodeChildTargetManager extends SDK.SDKModel.SDKModel<void> implemen
|
|
|
107
107
|
targetDestroyed(_event: Protocol.Target.TargetDestroyedEvent): void {
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
attachedToTarget({sessionId, targetInfo}: Protocol.Target.AttachedToTargetEvent): void {
|
|
110
|
+
async attachedToTarget({sessionId, targetInfo}: Protocol.Target.AttachedToTargetEvent): Promise<void> {
|
|
111
111
|
let target: SDK.Target.Target;
|
|
112
112
|
if (targetInfo.type === 'node_worker') {
|
|
113
113
|
target = this.#targetManager.createTarget(
|
|
@@ -124,6 +124,24 @@ export class NodeChildTargetManager extends SDK.SDKModel.SDKModel<void> implemen
|
|
|
124
124
|
}
|
|
125
125
|
this.#childTargets.set(sessionId, target);
|
|
126
126
|
void target.runtimeAgent().invoke_runIfWaitingForDebugger();
|
|
127
|
+
await this.#initializeStorage(target);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async #initializeStorage(target: SDK.Target.Target): Promise<void> {
|
|
131
|
+
const storageAgent = target.storageAgent();
|
|
132
|
+
const response = await storageAgent.invoke_getStorageKey({});
|
|
133
|
+
|
|
134
|
+
const storageKey = response.storageKey;
|
|
135
|
+
if (response.getError() || !storageKey) {
|
|
136
|
+
console.error(`Failed to get storage key for target ${target.id()}: ${response.getError()}`);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const storageKeyManager = target.model(SDK.StorageKeyManager.StorageKeyManager);
|
|
141
|
+
if (storageKeyManager) {
|
|
142
|
+
storageKeyManager.setMainStorageKey(storageKey);
|
|
143
|
+
storageKeyManager.updateStorageKeys(new Set([storageKey]));
|
|
144
|
+
}
|
|
127
145
|
}
|
|
128
146
|
|
|
129
147
|
detachedFromTarget({sessionId}: Protocol.Target.DetachedFromTargetEvent): void {
|
|
@@ -9,6 +9,7 @@ import '../../panels/network/network-meta.js';
|
|
|
9
9
|
import * as Common from '../../core/common/common.js';
|
|
10
10
|
import * as i18n from '../../core/i18n/i18n.js';
|
|
11
11
|
import * as Root from '../../core/root/root.js';
|
|
12
|
+
import type * as Resources from '../../panels/application/application.js';
|
|
12
13
|
import type * as Sources from '../../panels/sources/sources.js';
|
|
13
14
|
import * as UI from '../../ui/legacy/legacy.js';
|
|
14
15
|
import * as Main from '../main/main.js';
|
|
@@ -39,6 +40,14 @@ const UIStrings = {
|
|
|
39
40
|
* @description Command for showing the 'Node' tool in the Network Navigator View, which is part of the Sources tool
|
|
40
41
|
*/
|
|
41
42
|
showNode: 'Show Node',
|
|
43
|
+
/**
|
|
44
|
+
* @description Text in Application Panel Sidebar of the Application panel
|
|
45
|
+
*/
|
|
46
|
+
application: 'Application',
|
|
47
|
+
/**
|
|
48
|
+
* @description Command for showing the 'Application' tool
|
|
49
|
+
*/
|
|
50
|
+
showApplication: 'Show Application',
|
|
42
51
|
} as const;
|
|
43
52
|
|
|
44
53
|
const str_ = i18n.i18n.registerUIStrings('entrypoints/node_app/node_app.ts', UIStrings);
|
|
@@ -78,6 +87,31 @@ UI.ViewManager.registerViewExtension({
|
|
|
78
87
|
},
|
|
79
88
|
});
|
|
80
89
|
|
|
90
|
+
let loadedResourcesModule: (typeof Resources|undefined);
|
|
91
|
+
|
|
92
|
+
async function loadResourcesModule(): Promise<typeof Resources> {
|
|
93
|
+
if (!loadedResourcesModule) {
|
|
94
|
+
loadedResourcesModule = await import('../../panels/application/application.js');
|
|
95
|
+
}
|
|
96
|
+
return loadedResourcesModule;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
UI.ViewManager.registerViewExtension({
|
|
100
|
+
location: UI.ViewManager.ViewLocationValues.PANEL,
|
|
101
|
+
id: 'resources',
|
|
102
|
+
title: i18nLazyString(UIStrings.application),
|
|
103
|
+
commandPrompt: i18nLazyString(UIStrings.showApplication),
|
|
104
|
+
order: 70,
|
|
105
|
+
async loadView() {
|
|
106
|
+
const Resources = await loadResourcesModule();
|
|
107
|
+
return Resources.ResourcesPanel.ResourcesPanel.instance({
|
|
108
|
+
forceNew: true,
|
|
109
|
+
mode: 'node',
|
|
110
|
+
});
|
|
111
|
+
},
|
|
112
|
+
tags: [],
|
|
113
|
+
});
|
|
114
|
+
|
|
81
115
|
// @ts-expect-error Exposed for legacy layout tests
|
|
82
116
|
self.runtime = Root.Runtime.Runtime.instance({forceNew: true});
|
|
83
117
|
Common.Runnable.registerEarlyInitializationRunnable(NodeMainImpl.instance);
|
|
@@ -55,6 +55,7 @@ export class AiConversation {
|
|
|
55
55
|
undefined,
|
|
56
56
|
undefined,
|
|
57
57
|
serializedConversation.isExternal,
|
|
58
|
+
undefined,
|
|
58
59
|
);
|
|
59
60
|
}
|
|
60
61
|
|
|
@@ -74,6 +75,9 @@ export class AiConversation {
|
|
|
74
75
|
|
|
75
76
|
#contexts: Array<ConversationContext<unknown>> = [];
|
|
76
77
|
|
|
78
|
+
#performanceRecordAndReload?: () => Promise<Trace.TraceModel.ParsedTrace>;
|
|
79
|
+
#onInspectElement?: () => Promise<SDK.DOMModel.DOMNode|null>;
|
|
80
|
+
|
|
77
81
|
constructor(
|
|
78
82
|
type: ConversationType,
|
|
79
83
|
data: ResponseData[] = [],
|
|
@@ -82,9 +86,13 @@ export class AiConversation {
|
|
|
82
86
|
aidaClient: Host.AidaClient.AidaClient = new Host.AidaClient.AidaClient(),
|
|
83
87
|
changeManager?: ChangeManager,
|
|
84
88
|
isExternal = false,
|
|
89
|
+
performanceRecordAndReload?: () => Promise<Trace.TraceModel.ParsedTrace>,
|
|
90
|
+
onInspectElement?: () => Promise<SDK.DOMModel.DOMNode|null>,
|
|
85
91
|
) {
|
|
86
92
|
this.#changeManager = changeManager;
|
|
87
93
|
this.#aidaClient = aidaClient;
|
|
94
|
+
this.#performanceRecordAndReload = performanceRecordAndReload;
|
|
95
|
+
this.#onInspectElement = onInspectElement;
|
|
88
96
|
|
|
89
97
|
this.id = id;
|
|
90
98
|
this.#isReadOnly = isReadOnly;
|
|
@@ -278,6 +286,8 @@ export class AiConversation {
|
|
|
278
286
|
serverSideLoggingEnabled: isAiAssistanceServerSideLoggingEnabled(),
|
|
279
287
|
sessionId: this.id,
|
|
280
288
|
changeManager: this.#changeManager,
|
|
289
|
+
performanceRecordAndReload: this.#performanceRecordAndReload,
|
|
290
|
+
onInspectElement: this.#onInspectElement,
|
|
281
291
|
};
|
|
282
292
|
switch (type) {
|
|
283
293
|
case ConversationType.STYLING: {
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import * as Host from '../../../core/host/host.js';
|
|
6
6
|
import * as Root from '../../../core/root/root.js';
|
|
7
|
+
import type * as SDK from '../../../core/sdk/sdk.js';
|
|
7
8
|
import {debugLog, isStructuredLogEnabled} from '../debug.js';
|
|
8
9
|
|
|
9
10
|
export const enum ResponseType {
|
|
@@ -133,6 +134,7 @@ export interface AgentOptions {
|
|
|
133
134
|
serverSideLoggingEnabled?: boolean;
|
|
134
135
|
sessionId?: string;
|
|
135
136
|
confirmSideEffectForTest?: typeof Promise.withResolvers;
|
|
137
|
+
onInspectElement?: () => Promise<SDK.DOMModel.DOMNode|null>;
|
|
136
138
|
}
|
|
137
139
|
|
|
138
140
|
export interface ParsedAnswer {
|
|
@@ -88,6 +88,28 @@ Content:
|
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"name": "performanceRecordAndReload",
|
|
94
|
+
"description": "Start a new performance recording and reload the page.",
|
|
95
|
+
"parameters": {
|
|
96
|
+
"type": 6,
|
|
97
|
+
"description": "",
|
|
98
|
+
"nullable": true,
|
|
99
|
+
"required": [],
|
|
100
|
+
"properties": {}
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"name": "inspectDom",
|
|
105
|
+
"description": "Prompts user to select a DOM element from the page.",
|
|
106
|
+
"parameters": {
|
|
107
|
+
"type": 6,
|
|
108
|
+
"description": "",
|
|
109
|
+
"nullable": true,
|
|
110
|
+
"required": [],
|
|
111
|
+
"properties": {}
|
|
112
|
+
}
|
|
91
113
|
}
|
|
92
114
|
],
|
|
93
115
|
"options": {},
|
|
@@ -9,7 +9,9 @@ import * as Platform from '../../../core/platform/platform.js';
|
|
|
9
9
|
import * as Root from '../../../core/root/root.js';
|
|
10
10
|
import * as SDK from '../../../core/sdk/sdk.js';
|
|
11
11
|
import * as Logs from '../../logs/logs.js';
|
|
12
|
+
import type * as Trace from '../../trace/trace.js';
|
|
12
13
|
import * as Workspace from '../../workspace/workspace.js';
|
|
14
|
+
import {AgentFocus} from '../performance/AIContext.js';
|
|
13
15
|
|
|
14
16
|
import {
|
|
15
17
|
type AgentOptions,
|
|
@@ -71,8 +73,16 @@ export class ContextSelectionAgent extends AiAgent<never> {
|
|
|
71
73
|
};
|
|
72
74
|
}
|
|
73
75
|
|
|
74
|
-
|
|
76
|
+
readonly #performanceRecordAndReload?: () => Promise<Trace.TraceModel.ParsedTrace>;
|
|
77
|
+
readonly #onInspectElement?: () => Promise<SDK.DOMModel.DOMNode|null>;
|
|
78
|
+
|
|
79
|
+
constructor(opts: AgentOptions&{
|
|
80
|
+
performanceRecordAndReload?: () => Promise<Trace.TraceModel.ParsedTrace>,
|
|
81
|
+
onInspectElement?: () => Promise<SDK.DOMModel.DOMNode|null>,
|
|
82
|
+
}) {
|
|
75
83
|
super(opts);
|
|
84
|
+
this.#performanceRecordAndReload = opts.performanceRecordAndReload;
|
|
85
|
+
this.#onInspectElement = opts.onInspectElement;
|
|
76
86
|
|
|
77
87
|
this.declareFunction<Record<string, never>>('listNetworkRequests', {
|
|
78
88
|
description: `Gives a list of network requests including URL, status code, and duration in ms`,
|
|
@@ -213,6 +223,66 @@ export class ContextSelectionAgent extends AiAgent<never> {
|
|
|
213
223
|
return {error: 'Unable to find file.'};
|
|
214
224
|
},
|
|
215
225
|
});
|
|
226
|
+
|
|
227
|
+
this.declareFunction('performanceRecordAndReload', {
|
|
228
|
+
description: 'Start a new performance recording and reload the page.',
|
|
229
|
+
parameters: {
|
|
230
|
+
type: Host.AidaClient.ParametersTypes.OBJECT,
|
|
231
|
+
description: '',
|
|
232
|
+
nullable: true,
|
|
233
|
+
required: [],
|
|
234
|
+
properties: {},
|
|
235
|
+
},
|
|
236
|
+
displayInfoFromArgs: () => {
|
|
237
|
+
return {
|
|
238
|
+
title: 'Recording a performance trace…',
|
|
239
|
+
action: 'performanceRecordAndReload()',
|
|
240
|
+
};
|
|
241
|
+
},
|
|
242
|
+
handler: async () => {
|
|
243
|
+
if (!this.#performanceRecordAndReload) {
|
|
244
|
+
return {
|
|
245
|
+
error: 'Performance recording is not available.',
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
const result = await this.#performanceRecordAndReload();
|
|
249
|
+
|
|
250
|
+
return {
|
|
251
|
+
context: AgentFocus.fromParsedTrace(result),
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
this.declareFunction<Record<string, never>>('inspectDom', {
|
|
257
|
+
description: `Prompts user to select a DOM element from the page.`,
|
|
258
|
+
parameters: {
|
|
259
|
+
type: Host.AidaClient.ParametersTypes.OBJECT,
|
|
260
|
+
description: '',
|
|
261
|
+
nullable: true,
|
|
262
|
+
required: [],
|
|
263
|
+
properties: {},
|
|
264
|
+
},
|
|
265
|
+
displayInfoFromArgs: () => {
|
|
266
|
+
return {
|
|
267
|
+
title: lockedString('Please select an element on the page...'),
|
|
268
|
+
action: 'selectElement()',
|
|
269
|
+
};
|
|
270
|
+
},
|
|
271
|
+
handler: async () => {
|
|
272
|
+
if (!this.#onInspectElement) {
|
|
273
|
+
return {error: 'The inspect element action is not available.'};
|
|
274
|
+
}
|
|
275
|
+
const node = await this.#onInspectElement();
|
|
276
|
+
if (node) {
|
|
277
|
+
return {
|
|
278
|
+
context: node,
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
return {
|
|
282
|
+
error: 'Unable to select element.',
|
|
283
|
+
};
|
|
284
|
+
},
|
|
285
|
+
});
|
|
216
286
|
}
|
|
217
287
|
|
|
218
288
|
#getUISourceCodes = (): Iterable<Workspace.UISourceCode.UISourceCode> => {
|
|
@@ -137,6 +137,32 @@ export class ComputedStyleModel extends Common.ObjectWrapper.ObjectWrapper<Event
|
|
|
137
137
|
null as ComputedStyle | null;
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
|
+
|
|
141
|
+
private async fetchMatchedCascade(): Promise<SDK.CSSMatchedStyles.CSSMatchedStyles|null> {
|
|
142
|
+
const node = this.node;
|
|
143
|
+
if (!node || !this.cssModel()) {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const cssModel = this.cssModel();
|
|
148
|
+
if (!cssModel) {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const matchedStyles = await cssModel.cachedMatchedCascadeForNode(node);
|
|
153
|
+
if (!matchedStyles) {
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
return matchedStyles.node() === this.node ? matchedStyles : null;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async fetchAllComputedStyleInfo(): Promise<{
|
|
160
|
+
computedStyle: ComputedStyle | null,
|
|
161
|
+
matchedStyles: SDK.CSSMatchedStyles.CSSMatchedStyles|null,
|
|
162
|
+
}> {
|
|
163
|
+
const [computedStyle, matchedStyles] = await Promise.all([this.fetchComputedStyle(), this.fetchMatchedCascade()]);
|
|
164
|
+
return {computedStyle, matchedStyles};
|
|
165
|
+
}
|
|
140
166
|
}
|
|
141
167
|
|
|
142
168
|
export const enum Events {
|
|
@@ -8,7 +8,6 @@ import * as i18n from '../../core/i18n/i18n.js';
|
|
|
8
8
|
import type * as Platform from '../../core/platform/platform.js';
|
|
9
9
|
import * as SDK from '../../core/sdk/sdk.js';
|
|
10
10
|
import * as Protocol from '../../generated/protocol.js';
|
|
11
|
-
import * as ThirdPartyWeb from '../../third_party/third-party-web/third-party-web.js';
|
|
12
11
|
|
|
13
12
|
import {Issue, IssueCategory, IssueKind} from './Issue.js';
|
|
14
13
|
import {
|
|
@@ -55,15 +54,6 @@ export const enum CookieStatus {
|
|
|
55
54
|
ALLOWED_BY_HEURISTICS = 3,
|
|
56
55
|
}
|
|
57
56
|
|
|
58
|
-
export interface CookieReportInfo {
|
|
59
|
-
name: string;
|
|
60
|
-
domain: string;
|
|
61
|
-
type?: string;
|
|
62
|
-
platform?: string;
|
|
63
|
-
status: CookieStatus;
|
|
64
|
-
insight?: Protocol.Audits.CookieIssueInsight;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
57
|
export class CookieIssue extends Issue<Protocol.Audits.CookieIssueDetails> {
|
|
68
58
|
cookieId(): string {
|
|
69
59
|
const details = this.details();
|
|
@@ -246,24 +236,6 @@ export class CookieIssue extends Issue<Protocol.Audits.CookieIssueDetails> {
|
|
|
246
236
|
return IssueKind.BREAKING_CHANGE;
|
|
247
237
|
}
|
|
248
238
|
|
|
249
|
-
makeCookieReportEntry(): CookieReportInfo|undefined {
|
|
250
|
-
const status = CookieIssue.getCookieStatus(this.details());
|
|
251
|
-
const details = this.details();
|
|
252
|
-
if (details.cookie && details.cookieUrl && status !== undefined) {
|
|
253
|
-
const entity = ThirdPartyWeb.ThirdPartyWeb.getEntity(details.cookieUrl);
|
|
254
|
-
return {
|
|
255
|
-
name: details.cookie.name,
|
|
256
|
-
domain: details.cookie.domain,
|
|
257
|
-
type: entity?.category,
|
|
258
|
-
platform: entity?.name,
|
|
259
|
-
status,
|
|
260
|
-
insight: this.details().insight,
|
|
261
|
-
};
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
return;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
239
|
static getCookieStatus(cookieIssueDetails: Protocol.Audits.CookieIssueDetails): CookieStatus|undefined {
|
|
268
240
|
if (cookieIssueDetails.cookieExclusionReasons.includes(
|
|
269
241
|
Protocol.Audits.CookieExclusionReason.ExcludeThirdPartyPhaseout)) {
|
|
@@ -15,6 +15,7 @@ import * as Annotations from '../../models/annotations/annotations.js';
|
|
|
15
15
|
import * as Badges from '../../models/badges/badges.js';
|
|
16
16
|
import * as GreenDev from '../../models/greendev/greendev.js';
|
|
17
17
|
import * as TextUtils from '../../models/text_utils/text_utils.js';
|
|
18
|
+
import type * as Trace from '../../models/trace/trace.js';
|
|
18
19
|
import * as Workspace from '../../models/workspace/workspace.js';
|
|
19
20
|
import * as Buttons from '../../ui/components/buttons/buttons.js';
|
|
20
21
|
import * as Snackbars from '../../ui/components/snackbars/snackbars.js';
|
|
@@ -503,6 +504,7 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
503
504
|
#selectedRequest: AiAssistanceModel.NetworkAgent.RequestContext|null = null;
|
|
504
505
|
// Messages displayed in the `ChatView` component.
|
|
505
506
|
#messages: Message[] = [];
|
|
507
|
+
#isContextAutoSelectionSuspended = false;
|
|
506
508
|
|
|
507
509
|
// Whether the UI should show loading or not.
|
|
508
510
|
#isLoading = false;
|
|
@@ -672,6 +674,10 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
672
674
|
this.requestUpdate();
|
|
673
675
|
}
|
|
674
676
|
|
|
677
|
+
async #handlePerformanceRecordAndReload(): Promise<Trace.TraceModel.ParsedTrace> {
|
|
678
|
+
return await TimelinePanel.TimelinePanel.TimelinePanel.executeRecordAndReload();
|
|
679
|
+
}
|
|
680
|
+
|
|
675
681
|
#getDefaultConversationType(): AiAssistanceModel.AiHistoryStorage.ConversationType|undefined {
|
|
676
682
|
const {hostConfig} = Root.Runtime;
|
|
677
683
|
const viewManager = UI.ViewManager.ViewManager.instance();
|
|
@@ -715,7 +721,8 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
715
721
|
}
|
|
716
722
|
const conversation = targetConversationType ?
|
|
717
723
|
new AiAssistanceModel.AiConversation.AiConversation(
|
|
718
|
-
targetConversationType, [], undefined, false, this.#aidaClient, this.#changeManager
|
|
724
|
+
targetConversationType, [], undefined, false, this.#aidaClient, this.#changeManager, false,
|
|
725
|
+
this.#handlePerformanceRecordAndReload.bind(this), this.#handleInspectElement.bind(this)) :
|
|
719
726
|
undefined;
|
|
720
727
|
|
|
721
728
|
this.#updateConversationState(conversation);
|
|
@@ -735,16 +742,28 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
735
742
|
const conversationType = this.#getDefaultConversationType();
|
|
736
743
|
if (conversationType) {
|
|
737
744
|
conversation = new AiAssistanceModel.AiConversation.AiConversation(
|
|
738
|
-
conversationType,
|
|
745
|
+
conversationType,
|
|
746
|
+
[],
|
|
747
|
+
undefined,
|
|
748
|
+
false,
|
|
749
|
+
this.#aidaClient,
|
|
750
|
+
this.#changeManager,
|
|
751
|
+
false,
|
|
752
|
+
this.#handlePerformanceRecordAndReload.bind(this),
|
|
753
|
+
this.#handleInspectElement.bind(this),
|
|
754
|
+
);
|
|
739
755
|
}
|
|
740
756
|
}
|
|
741
757
|
|
|
742
758
|
this.#conversation = conversation;
|
|
759
|
+
this.#isContextAutoSelectionSuspended = false;
|
|
743
760
|
}
|
|
744
761
|
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
762
|
+
if (!this.#isContextAutoSelectionSuspended) {
|
|
763
|
+
this.#conversation?.setContext(this.#getConversationContext(
|
|
764
|
+
isAiAssistanceContextSelectionAgentEnabled() ? this.#getDefaultConversationType() :
|
|
765
|
+
(this.#conversation?.type ?? null)));
|
|
766
|
+
}
|
|
748
767
|
|
|
749
768
|
this.requestUpdate();
|
|
750
769
|
}
|
|
@@ -1116,10 +1135,12 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
1116
1135
|
|
|
1117
1136
|
#handleContextRemoved(): void {
|
|
1118
1137
|
this.#conversation?.setContext(null);
|
|
1138
|
+
this.#isContextAutoSelectionSuspended = true;
|
|
1119
1139
|
this.requestUpdate();
|
|
1120
1140
|
}
|
|
1121
1141
|
|
|
1122
1142
|
#handleContextAdd(): void {
|
|
1143
|
+
this.#isContextAutoSelectionSuspended = false;
|
|
1123
1144
|
this.#conversation?.setContext(this.#getConversationContext(this.#getDefaultConversationType()));
|
|
1124
1145
|
this.requestUpdate();
|
|
1125
1146
|
}
|
|
@@ -1141,6 +1162,7 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
1141
1162
|
return;
|
|
1142
1163
|
}
|
|
1143
1164
|
|
|
1165
|
+
this.#isContextAutoSelectionSuspended = false;
|
|
1144
1166
|
let targetConversationType: AiAssistanceModel.AiHistoryStorage.ConversationType|undefined;
|
|
1145
1167
|
switch (actionId) {
|
|
1146
1168
|
case 'freestyler.elements-floating-button': {
|
|
@@ -1187,7 +1209,16 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
1187
1209
|
let conversation = this.#conversation;
|
|
1188
1210
|
if (!this.#conversation || this.#conversation.type !== targetConversationType || this.#conversation.isEmpty) {
|
|
1189
1211
|
conversation = new AiAssistanceModel.AiConversation.AiConversation(
|
|
1190
|
-
targetConversationType,
|
|
1212
|
+
targetConversationType,
|
|
1213
|
+
[],
|
|
1214
|
+
undefined,
|
|
1215
|
+
false,
|
|
1216
|
+
this.#aidaClient,
|
|
1217
|
+
this.#changeManager,
|
|
1218
|
+
false,
|
|
1219
|
+
this.#handlePerformanceRecordAndReload.bind(this),
|
|
1220
|
+
this.#handleInspectElement.bind(this),
|
|
1221
|
+
);
|
|
1191
1222
|
}
|
|
1192
1223
|
this.#updateConversationState(conversation);
|
|
1193
1224
|
const predefinedPrompt = opts?.['prompt'];
|
|
@@ -1334,11 +1365,61 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
1334
1365
|
this.#conversation?.setContext(context);
|
|
1335
1366
|
}
|
|
1336
1367
|
|
|
1368
|
+
this.#isContextAutoSelectionSuspended = false;
|
|
1369
|
+
|
|
1337
1370
|
void VisualLogging.logFunctionCall(`context-change-${this.#conversation?.type}`);
|
|
1338
1371
|
|
|
1339
1372
|
this.requestUpdate();
|
|
1340
1373
|
};
|
|
1341
1374
|
|
|
1375
|
+
async #handleInspectElement(): Promise<SDK.DOMModel.DOMNode|null> {
|
|
1376
|
+
if (!this.#toggleSearchElementAction) {
|
|
1377
|
+
return null;
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1380
|
+
const result = new Promise<SDK.DOMModel.DOMNode|null>(resolve => {
|
|
1381
|
+
// Track the new flavor change for dom node.
|
|
1382
|
+
const handleDOMNodeFlavorChange = (ev: Common.EventTarget.EventTargetEvent<SDK.DOMModel.DOMNode>): void => {
|
|
1383
|
+
if (!ev.data) {
|
|
1384
|
+
return;
|
|
1385
|
+
}
|
|
1386
|
+
resolve(selectedElementFilter(ev.data));
|
|
1387
|
+
removeListeners();
|
|
1388
|
+
};
|
|
1389
|
+
|
|
1390
|
+
// If the inspect mode is toggled, we want to resolve null.
|
|
1391
|
+
const handleInspectModeToggled = (ev: Common.EventTarget.EventTargetEvent<boolean>): void => {
|
|
1392
|
+
if (!ev.data) {
|
|
1393
|
+
// The inspect element is toggled off
|
|
1394
|
+
// before the flavor change event fires
|
|
1395
|
+
// so we need to wait a bit to see if the flavor changed.
|
|
1396
|
+
window.setTimeout(() => {
|
|
1397
|
+
resolve((selectedElementFilter(UI.Context.Context.instance().flavor(SDK.DOMModel.DOMNode))));
|
|
1398
|
+
removeListeners();
|
|
1399
|
+
}, 50);
|
|
1400
|
+
}
|
|
1401
|
+
};
|
|
1402
|
+
|
|
1403
|
+
const removeListeners = (): void => {
|
|
1404
|
+
UI.Context.Context.instance().removeFlavorChangeListener(SDK.DOMModel.DOMNode, handleDOMNodeFlavorChange);
|
|
1405
|
+
this.#toggleSearchElementAction?.removeEventListener(
|
|
1406
|
+
UI.ActionRegistration.Events.TOGGLED, handleInspectModeToggled);
|
|
1407
|
+
};
|
|
1408
|
+
|
|
1409
|
+
UI.Context.Context.instance().addFlavorChangeListener(SDK.DOMModel.DOMNode, handleDOMNodeFlavorChange);
|
|
1410
|
+
this.#toggleSearchElementAction?.addEventListener(UI.ActionRegistration.Events.TOGGLED, handleInspectModeToggled);
|
|
1411
|
+
|
|
1412
|
+
// Clean-up listeners in case of abort.
|
|
1413
|
+
this.#runAbortController.signal.addEventListener('abort', () => {
|
|
1414
|
+
resolve(null);
|
|
1415
|
+
removeListeners();
|
|
1416
|
+
}, {once: true});
|
|
1417
|
+
});
|
|
1418
|
+
|
|
1419
|
+
void this.#toggleSearchElementAction.execute();
|
|
1420
|
+
return await result;
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1342
1423
|
async #startConversation(
|
|
1343
1424
|
text: string,
|
|
1344
1425
|
imageInput?: Host.AidaClient.Part,
|
|
@@ -392,7 +392,7 @@ export const
|
|
|
392
392
|
class="add-context"
|
|
393
393
|
.iconName=${'plus'}
|
|
394
394
|
.size=${Buttons.Button.Size.SMALL}
|
|
395
|
-
.jslogContext=${'context-
|
|
395
|
+
.jslogContext=${'context-added'}
|
|
396
396
|
.variant=${Buttons.Button.Variant.ICON}
|
|
397
397
|
@click=${input.onContextAdd}></devtools-button>` : Lit.nothing}
|
|
398
398
|
</div>
|
|
@@ -1916,17 +1916,19 @@ export class ResourcesSection implements SDK.TargetManager.Observer {
|
|
|
1916
1916
|
frameManager.addEventListener(
|
|
1917
1917
|
SDK.FrameManager.Events.RESOURCE_ADDED, event => this.resourceAdded(event.data.resource), this);
|
|
1918
1918
|
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1919
|
+
if (this.panel.mode !== 'node') {
|
|
1920
|
+
SDK.TargetManager.TargetManager.instance().addModelListener(
|
|
1921
|
+
SDK.ChildTargetManager.ChildTargetManager, SDK.ChildTargetManager.Events.TARGET_CREATED, this.windowOpened,
|
|
1922
|
+
this, {scoped: true});
|
|
1923
|
+
SDK.TargetManager.TargetManager.instance().addModelListener(
|
|
1924
|
+
SDK.ChildTargetManager.ChildTargetManager, SDK.ChildTargetManager.Events.TARGET_INFO_CHANGED,
|
|
1925
|
+
this.windowChanged, this, {scoped: true});
|
|
1926
|
+
SDK.TargetManager.TargetManager.instance().addModelListener(
|
|
1927
|
+
SDK.ChildTargetManager.ChildTargetManager, SDK.ChildTargetManager.Events.TARGET_DESTROYED,
|
|
1928
|
+
this.windowDestroyed, this, {scoped: true});
|
|
1929
|
+
|
|
1930
|
+
SDK.TargetManager.TargetManager.instance().observeTargets(this, {scoped: true});
|
|
1931
|
+
}
|
|
1930
1932
|
}
|
|
1931
1933
|
|
|
1932
1934
|
private initialize(): void {
|
|
@@ -250,7 +250,7 @@ export class DOMStorageModel extends SDK.SDKModel.SDKModel<EventTypes> {
|
|
|
250
250
|
}
|
|
251
251
|
}
|
|
252
252
|
|
|
253
|
-
SDK.SDKModel.SDKModel.register(DOMStorageModel, {capabilities: SDK.Target.Capability.
|
|
253
|
+
SDK.SDKModel.SDKModel.register(DOMStorageModel, {capabilities: SDK.Target.Capability.DOM_STORAGE, autostart: false});
|
|
254
254
|
|
|
255
255
|
export const enum Events {
|
|
256
256
|
DOM_STORAGE_ADDED = 'DOMStorageAdded',
|