chrome-devtools-frontend 1.0.1643855 → 1.0.1646286
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/skills/devtools-source-maps/SKILL.md +124 -0
- package/docs/README.md +1 -0
- package/docs/using_source_maps.md +159 -0
- package/front_end/core/host/AidaClientTypes.ts +2 -0
- package/front_end/core/host/UserMetrics.ts +5 -3
- package/front_end/core/root/Runtime.ts +10 -0
- package/front_end/core/sdk/CSSPropertyParserMatchers.ts +2 -3
- package/front_end/core/sdk/DebuggerModel.ts +7 -9
- package/front_end/core/sdk/NetworkRequest.ts +0 -25
- package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshot.ts +37 -0
- package/front_end/generated/InspectorBackendCommands.ts +2 -2
- package/front_end/generated/SupportedCSSProperties.js +79 -2
- package/front_end/generated/protocol.ts +0 -5
- package/front_end/models/ai_assistance/AiAgent2.ts +52 -15
- package/front_end/models/ai_assistance/AiConversation.ts +4 -2
- package/front_end/models/ai_assistance/AiOrigins.ts +63 -2
- package/front_end/models/ai_assistance/README.md +20 -8
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +2 -2
- package/front_end/models/ai_assistance/agents/FileAgent.ts +9 -42
- package/front_end/models/ai_assistance/agents/NetworkAgent.snapshot.txt +2 -2
- package/front_end/models/ai_assistance/agents/NetworkAgent.ts +9 -133
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +25 -2
- package/front_end/models/ai_assistance/agents/README.md +64 -0
- package/front_end/models/ai_assistance/agents/StylingAgent.ts +26 -3
- package/front_end/models/ai_assistance/ai_assistance.ts +4 -0
- package/front_end/models/ai_assistance/contexts/FileContext.ts +45 -0
- package/front_end/models/ai_assistance/contexts/RequestContext.snapshot.txt +48 -0
- package/front_end/models/ai_assistance/contexts/RequestContext.ts +116 -0
- package/front_end/models/ai_assistance/data_formatters/NetworkRequestFormatter.ts +2 -1
- package/front_end/models/ai_assistance/tools/ExecuteJavaScript.ts +9 -12
- package/front_end/models/ai_assistance/tools/GetStyles.ts +19 -12
- package/front_end/models/ai_assistance/tools/README.md +45 -0
- package/front_end/models/ai_assistance/tools/Tool.ts +74 -11
- package/front_end/models/ai_assistance/tools/ToolRegistry.ts +21 -5
- package/front_end/models/heap_snapshot/HeapSnapshotModel.ts +18 -2
- package/front_end/models/heap_snapshot/HeapSnapshotProxy.ts +4 -0
- package/front_end/models/stack_trace/DetailedErrorStackParser.ts +17 -4
- package/front_end/models/stack_trace/StackTraceModel.ts +34 -1
- package/front_end/models/trace/Styles.ts +29 -7
- package/front_end/models/trace/handlers/NetworkRequestsHandler.ts +15 -11
- package/front_end/models/trace/handlers/PageLoadMetricsHandler.ts +33 -4
- package/front_end/models/trace/helpers/Timing.ts +10 -0
- package/front_end/models/trace/types/TraceEvents.ts +22 -2
- package/front_end/models/web_mcp/WebMCPModel.ts +8 -48
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +21 -15
- package/front_end/panels/ai_assistance/ai_assistance-meta.ts +16 -0
- package/front_end/panels/ai_assistance/components/ChatInput.ts +4 -4
- package/front_end/panels/application/ApplicationPanelSidebar.ts +69 -0
- package/front_end/panels/application/ServiceWorkersView.ts +2 -2
- package/front_end/panels/application/WebMCPView.ts +40 -71
- package/front_end/panels/application/components/AdsView.ts +31 -28
- package/front_end/panels/application/components/BackForwardCacheView.ts +1 -2
- package/front_end/panels/application/components/adsView.css +6 -0
- package/front_end/panels/common/ExtensionServer.ts +5 -0
- package/front_end/panels/console/ConsoleView.ts +6 -1
- package/front_end/panels/console/ConsoleViewMessage.ts +46 -213
- package/front_end/panels/console/SymbolizedErrorWidget.ts +4 -1
- package/front_end/panels/elements/AdoptedStyleSheetTreeElement.ts +0 -1
- package/front_end/panels/elements/ElementsTreeElement.ts +0 -2
- package/front_end/panels/elements/PropertyRenderer.ts +0 -1
- package/front_end/panels/elements/StylesSidebarPane.ts +9 -2
- package/front_end/panels/issues/AffectedResourcesView.ts +1 -1
- package/front_end/panels/issues/AffectedSourcesView.ts +1 -1
- package/front_end/panels/lighthouse/LighthouseReportRenderer.ts +0 -1
- package/front_end/panels/mobile_throttling/ThrottlingSettingsTab.ts +10 -0
- package/front_end/panels/network/NetworkDataGridNode.ts +1 -2
- package/front_end/panels/network/NetworkLogView.ts +34 -7
- package/front_end/panels/profiler/HeapProfileView.ts +0 -1
- package/front_end/panels/profiler/HeapSnapshotGridNodes.ts +0 -1
- package/front_end/panels/profiler/HeapSnapshotView.ts +1 -1
- package/front_end/panels/profiler/IsolateSelector.ts +4 -2
- package/front_end/panels/profiler/ProfileLauncherView.ts +194 -126
- package/front_end/panels/profiler/ProfilesPanel.ts +1 -3
- package/front_end/panels/settings/components/SyncSection.ts +1 -1
- package/front_end/panels/timeline/TimelineFlameChartView.ts +5 -4
- package/front_end/panels/timeline/TimelinePanel.ts +7 -0
- package/front_end/panels/timeline/TimelineUIUtils.ts +13 -14
- package/front_end/panels/timeline/TimingsTrackAppender.ts +7 -5
- package/front_end/panels/timeline/components/LayoutShiftDetails.ts +0 -1
- package/front_end/panels/timeline/components/NetworkRequestDetails.ts +0 -2
- package/front_end/panels/timeline/components/insights/ForcedReflow.ts +0 -1
- package/front_end/panels/timeline/components/insights/NodeLink.ts +0 -1
- package/front_end/panels/timeline/overlays/OverlaysImpl.ts +2 -0
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/ui/helpers/OpenInNewTab.ts +3 -3
- package/front_end/ui/kit/link/Link.ts +16 -2
- package/front_end/ui/legacy/InspectorDrawerView.ts +14 -5
- package/front_end/ui/legacy/InspectorView.ts +4 -1
- package/front_end/ui/legacy/PlusButton.ts +6 -1
- package/front_end/ui/legacy/Widget.ts +19 -1
- package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +95 -31
- package/front_end/ui/legacy/components/utils/JSPresentationUtils.ts +0 -1
- package/front_end/ui/legacy/components/utils/Linkifier.ts +2 -16
- package/front_end/ui/visual_logging/KnownContextValues.ts +6 -0
- package/package.json +1 -1
|
@@ -291,6 +291,10 @@ const UIStrings = {
|
|
|
291
291
|
* @description Text in Timeline UIUtils of the Performance panel
|
|
292
292
|
*/
|
|
293
293
|
frameStartedLoading: 'Frame started loading',
|
|
294
|
+
/**
|
|
295
|
+
* @description Text in Timeline UIUtils of the Performance panel
|
|
296
|
+
*/
|
|
297
|
+
softNavigationStart: 'Soft navigation start',
|
|
294
298
|
/**
|
|
295
299
|
* @description Text in Timeline UIUtils of the Performance panel
|
|
296
300
|
*/
|
|
@@ -307,6 +311,10 @@ const UIStrings = {
|
|
|
307
311
|
* @description Text in Timeline UIUtils of the Performance panel
|
|
308
312
|
*/
|
|
309
313
|
firstContentfulPaint: 'First Contentful Paint',
|
|
314
|
+
/**
|
|
315
|
+
* @description Text in Timeline UIUtils of the Performance panel
|
|
316
|
+
*/
|
|
317
|
+
softFirstContentfulPaint: 'Soft First Contentful Paint',
|
|
310
318
|
/**
|
|
311
319
|
* @description Text in Timeline UIUtils of the Performance panel
|
|
312
320
|
*/
|
|
@@ -866,6 +874,12 @@ export function maybeInitSylesMap(): EventStylesMap {
|
|
|
866
874
|
true,
|
|
867
875
|
),
|
|
868
876
|
|
|
877
|
+
[Types.Events.Name.SOFT_NAVIGATION_START]: new TimelineRecordStyle(
|
|
878
|
+
i18nString(UIStrings.softNavigationStart),
|
|
879
|
+
defaultCategoryStyles.loading,
|
|
880
|
+
true,
|
|
881
|
+
),
|
|
882
|
+
|
|
869
883
|
[Types.Events.Name.MARK_FIRST_PAINT]: new TimelineRecordStyle(
|
|
870
884
|
i18nString(UIStrings.firstPaint),
|
|
871
885
|
defaultCategoryStyles.painting,
|
|
@@ -878,6 +892,12 @@ export function maybeInitSylesMap(): EventStylesMap {
|
|
|
878
892
|
true,
|
|
879
893
|
),
|
|
880
894
|
|
|
895
|
+
[Types.Events.Name.MARK_SOFT_FCP]: new TimelineRecordStyle(
|
|
896
|
+
i18nString(UIStrings.softFirstContentfulPaint),
|
|
897
|
+
defaultCategoryStyles.rendering,
|
|
898
|
+
true,
|
|
899
|
+
),
|
|
900
|
+
|
|
881
901
|
[Types.Events.Name.MARK_LCP_CANDIDATE]: new TimelineRecordStyle(
|
|
882
902
|
i18nString(UIStrings.largestContentfulPaint),
|
|
883
903
|
defaultCategoryStyles.rendering,
|
|
@@ -1024,11 +1044,11 @@ export function maybeInitSylesMap(): EventStylesMap {
|
|
|
1024
1044
|
[Types.Events.Name.ASYNC_TASK]:
|
|
1025
1045
|
new TimelineRecordStyle(i18nString(UIStrings.asyncTask), defaultCategoryStyles.async),
|
|
1026
1046
|
|
|
1027
|
-
[Types.Events.Name.LAYOUT_SHIFT]:
|
|
1028
|
-
i18nString(UIStrings.layoutShift), defaultCategoryStyles.experience,
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1047
|
+
[Types.Events.Name.LAYOUT_SHIFT]:
|
|
1048
|
+
new TimelineRecordStyle(i18nString(UIStrings.layoutShift), defaultCategoryStyles.experience,
|
|
1049
|
+
/* Mark LayoutShifts as hidden; in the timeline we render
|
|
1050
|
+
* SyntheticLayoutShifts so those are the ones visible to the user */
|
|
1051
|
+
true),
|
|
1032
1052
|
|
|
1033
1053
|
[Types.Events.Name.SYNTHETIC_LAYOUT_SHIFT]:
|
|
1034
1054
|
new TimelineRecordStyle(i18nString(UIStrings.layoutShift), defaultCategoryStyles.experience),
|
|
@@ -1123,9 +1143,11 @@ export function markerDetailsForEvent(event: Types.Events.Event): {
|
|
|
1123
1143
|
} {
|
|
1124
1144
|
let title = '';
|
|
1125
1145
|
let color = 'var(--color-text-primary)';
|
|
1126
|
-
if (Types.Events.
|
|
1146
|
+
if (Types.Events.isAnyFirstContentfulPaint(event)) {
|
|
1127
1147
|
color = 'var(--sys-color-green-bright)';
|
|
1128
|
-
title =
|
|
1148
|
+
title = (Types.Events.isSoftFirstContentfulPaint(event)) ?
|
|
1149
|
+
Handlers.ModelHandlers.PageLoadMetrics.MetricName.SOFT_FCP :
|
|
1150
|
+
Handlers.ModelHandlers.PageLoadMetrics.MetricName.FCP;
|
|
1129
1151
|
}
|
|
1130
1152
|
if (Types.Events.isAnyLargestContentfulPaintCandidate(event)) {
|
|
1131
1153
|
color = 'var(--sys-color-green)';
|
|
@@ -213,6 +213,14 @@ export function handleEvent(event: Types.Events.Event): void {
|
|
|
213
213
|
|
|
214
214
|
export async function finalize(): Promise<void> {
|
|
215
215
|
const {rendererProcessesByFrame} = metaHandlerData();
|
|
216
|
+
|
|
217
|
+
const allowedProtocols = [
|
|
218
|
+
'blob:',
|
|
219
|
+
'file:',
|
|
220
|
+
'filesystem:',
|
|
221
|
+
'http:',
|
|
222
|
+
'https:',
|
|
223
|
+
];
|
|
216
224
|
for (const [requestId, request] of requestMap.entries()) {
|
|
217
225
|
// If we have an incomplete set of events here, we choose to drop the network
|
|
218
226
|
// request rather than attempt to synthesize the missing data.
|
|
@@ -248,7 +256,7 @@ export async function finalize(): Promise<void> {
|
|
|
248
256
|
}
|
|
249
257
|
|
|
250
258
|
redirects.push({
|
|
251
|
-
url: sendRequest.args.data.url,
|
|
259
|
+
url: allowedProtocols.some(p => sendRequest.args.data.url.startsWith(p)) ? sendRequest.args.data.url : '',
|
|
252
260
|
priority: sendRequest.args.data.priority,
|
|
253
261
|
requestMethod: sendRequest.args.data.requestMethod,
|
|
254
262
|
ts,
|
|
@@ -360,15 +368,7 @@ export async function finalize(): Promise<void> {
|
|
|
360
368
|
}
|
|
361
369
|
}
|
|
362
370
|
|
|
363
|
-
|
|
364
|
-
const allowedProtocols = [
|
|
365
|
-
'blob:',
|
|
366
|
-
'file:',
|
|
367
|
-
'filesystem:',
|
|
368
|
-
'http:',
|
|
369
|
-
'https:',
|
|
370
|
-
];
|
|
371
|
-
if (!allowedProtocols.some(p => firstSendRequest.args.data.url.startsWith(p))) {
|
|
371
|
+
if (!allowedProtocols.some(p => finalSendRequest.args.data.url.startsWith(p))) {
|
|
372
372
|
continue;
|
|
373
373
|
}
|
|
374
374
|
|
|
@@ -572,7 +572,11 @@ export async function finalize(): Promise<void> {
|
|
|
572
572
|
responseHeaders: request.receiveResponse?.args.data.headers ?? null,
|
|
573
573
|
fetchPriorityHint: finalSendRequest.args.data.fetchPriorityHint ?? 'auto',
|
|
574
574
|
initiator: finalSendRequest.args.data.initiator,
|
|
575
|
-
stackTrace: finalSendRequest.args.data.stackTrace
|
|
575
|
+
stackTrace: finalSendRequest.args.data.stackTrace?.map(
|
|
576
|
+
frame => ({
|
|
577
|
+
...frame,
|
|
578
|
+
url: allowedProtocols.some(p => frame.url.startsWith(p)) ? frame.url : '',
|
|
579
|
+
})),
|
|
576
580
|
timing,
|
|
577
581
|
lrServerResponseTime,
|
|
578
582
|
url,
|
|
@@ -75,6 +75,28 @@ export function handleEvent(event: Types.Events.Event): void {
|
|
|
75
75
|
return;
|
|
76
76
|
}
|
|
77
77
|
pageLoadEventsArray.push(event);
|
|
78
|
+
|
|
79
|
+
// A soft nav entry includes the Soft FCP details but we want to process both
|
|
80
|
+
// so push a separate Soft FCP event
|
|
81
|
+
if (Types.Events.isSoftNavigationStart(event) && event.args?.context?.firstContentfulPaint) {
|
|
82
|
+
const syntheticSoftFcpEvent = Helpers.SyntheticEvents.SyntheticEventsManager
|
|
83
|
+
.registerSyntheticEvent<Types.Events.SyntheticSoftFirstContentfulPaint>({
|
|
84
|
+
name: Types.Events.Name.MARK_SOFT_FCP,
|
|
85
|
+
ph: Types.Events.Phase.MARK,
|
|
86
|
+
rawSourceEvent: event,
|
|
87
|
+
pid: event.pid,
|
|
88
|
+
tid: event.tid,
|
|
89
|
+
ts: Types.Timing.Micro(event.args.context.firstContentfulPaint),
|
|
90
|
+
cat: event.cat,
|
|
91
|
+
args: {
|
|
92
|
+
frame: event.args.frame,
|
|
93
|
+
context: {
|
|
94
|
+
...event.args.context,
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
pageLoadEventsArray.push(syntheticSoftFcpEvent);
|
|
99
|
+
}
|
|
78
100
|
}
|
|
79
101
|
|
|
80
102
|
function storePageLoadMetricAgainstNavigationId(
|
|
@@ -101,7 +123,7 @@ function storePageLoadMetricAgainstNavigationId(
|
|
|
101
123
|
return;
|
|
102
124
|
}
|
|
103
125
|
|
|
104
|
-
if (Types.Events.
|
|
126
|
+
if (Types.Events.isAnyFirstContentfulPaint(event)) {
|
|
105
127
|
const fcpTime = Types.Timing.Micro(event.ts - navigation.ts);
|
|
106
128
|
const classification = scoreClassificationForFirstContentfulPaint(fcpTime);
|
|
107
129
|
const metricScore = {event, metricName: MetricName.FCP, classification, navigation, timing: fcpTime};
|
|
@@ -226,7 +248,7 @@ function storeMetricScore(frameId: string, navigation: AnyNavigationStart, metri
|
|
|
226
248
|
}
|
|
227
249
|
|
|
228
250
|
export function getFrameIdForPageLoadEvent(event: Types.Events.PageLoadEvent): string {
|
|
229
|
-
if (Types.Events.
|
|
251
|
+
if (Types.Events.isAnyFirstContentfulPaint(event) || Types.Events.isInteractiveTime(event) ||
|
|
230
252
|
Types.Events.isAnyLargestContentfulPaintCandidate(event) || Types.Events.isNavigationStart(event) ||
|
|
231
253
|
Types.Events.isSoftNavigationStart(event) || Types.Events.isLayoutShift(event) ||
|
|
232
254
|
Types.Events.isFirstPaint(event)) {
|
|
@@ -243,7 +265,7 @@ export function getFrameIdForPageLoadEvent(event: Types.Events.PageLoadEvent): s
|
|
|
243
265
|
}
|
|
244
266
|
|
|
245
267
|
function getNavigationForPageLoadEvent(event: Types.Events.PageLoadEvent): AnyNavigationStart|null {
|
|
246
|
-
if (Types.Events.
|
|
268
|
+
if (Types.Events.isAnyFirstContentfulPaint(event) || Types.Events.isAnyLargestContentfulPaintCandidate(event) ||
|
|
247
269
|
Types.Events.isFirstPaint(event)) {
|
|
248
270
|
const {navigationsByNavigationId, softNavigationsById} = metaHandlerData();
|
|
249
271
|
|
|
@@ -255,6 +277,12 @@ function getNavigationForPageLoadEvent(event: Types.Events.PageLoadEvent): AnyNa
|
|
|
255
277
|
// The most recent soft navigation must have been before the trace started.
|
|
256
278
|
return null;
|
|
257
279
|
}
|
|
280
|
+
} else if (Types.Events.isSoftFirstContentfulPaint(event) && event.args.context?.performanceTimelineNavigationId) {
|
|
281
|
+
navigation = softNavigationsById.get(event.args.context.performanceTimelineNavigationId);
|
|
282
|
+
if (!navigation) {
|
|
283
|
+
// The most recent soft navigation must have been before the trace started.
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
258
286
|
} else {
|
|
259
287
|
const navigationId = event.args.data?.navigationId;
|
|
260
288
|
if (!navigationId) {
|
|
@@ -428,7 +456,7 @@ export async function finalize(): Promise<void> {
|
|
|
428
456
|
// Filter out LCP candidates to use only definitive LCP values
|
|
429
457
|
const allEventsButLCP =
|
|
430
458
|
pageLoadEventsArray.filter(event => !Types.Events.isAnyLargestContentfulPaintCandidate(event));
|
|
431
|
-
const markerEvents = [...
|
|
459
|
+
const markerEvents = [...allEventsButLCP, ...allFinalLCPEvents].filter(Types.Events.isMarkerEvent);
|
|
432
460
|
// Filter by main frame and sort.
|
|
433
461
|
allMarkerEvents =
|
|
434
462
|
markerEvents.filter(event => getFrameIdForPageLoadEvent(event) === mainFrame).sort((a, b) => a.ts - b.ts);
|
|
@@ -495,6 +523,7 @@ export const enum MetricName {
|
|
|
495
523
|
NAV = 'Nav',
|
|
496
524
|
// Soft Navigation and Soft Metrics
|
|
497
525
|
SOFT_NAV = 'Nav*',
|
|
526
|
+
SOFT_FCP = 'FCP*',
|
|
498
527
|
SOFT_LCP = 'LCP*',
|
|
499
528
|
// Note: INP is handled in UserInteractionsHandler
|
|
500
529
|
}
|
|
@@ -32,6 +32,16 @@ export function timeStampForEventAdjustedByClosestNavigation(
|
|
|
32
32
|
if (navigationForEvent) {
|
|
33
33
|
eventTimeStamp = event.ts - navigationForEvent.ts;
|
|
34
34
|
}
|
|
35
|
+
} else if (Types.Events.isSoftFirstContentfulPaint(event) && event.args?.context?.performanceTimelineNavigationId) {
|
|
36
|
+
const navigationForEvent = softNavigationsById.get(event.args.context.performanceTimelineNavigationId);
|
|
37
|
+
if (navigationForEvent) {
|
|
38
|
+
eventTimeStamp = event.ts - navigationForEvent.ts;
|
|
39
|
+
}
|
|
40
|
+
} else if (Types.Events.isSoftNavigationStart(event)) {
|
|
41
|
+
const navigationForEvent = getNavigationForTraceEvent(event, event.args.frame, navigationsByFrameId);
|
|
42
|
+
if (navigationForEvent) {
|
|
43
|
+
eventTimeStamp = event.ts - navigationForEvent.ts;
|
|
44
|
+
}
|
|
35
45
|
} else if (event.args?.data?.navigationId) {
|
|
36
46
|
const navigationForEvent = navigationsByNavigationId.get(event.args.data.navigationId);
|
|
37
47
|
if (navigationForEvent) {
|
|
@@ -737,6 +737,16 @@ export interface FirstContentfulPaint extends Mark {
|
|
|
737
737
|
};
|
|
738
738
|
}
|
|
739
739
|
|
|
740
|
+
// Soft FCP is basically a copy of SoftNavigationStart but with a different name
|
|
741
|
+
// and a different ts.
|
|
742
|
+
export interface SyntheticSoftFirstContentfulPaint extends Omit<SoftNavigationStart, 'name'|'ph'>,
|
|
743
|
+
Omit<SyntheticBased, 'name'|'ph'|'args'> {
|
|
744
|
+
name: Name.MARK_SOFT_FCP;
|
|
745
|
+
ph: Phase.MARK;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
export type AnyFirstContentfulPaint = FirstContentfulPaint|SyntheticSoftFirstContentfulPaint;
|
|
749
|
+
|
|
740
750
|
export interface FirstPaint extends Mark {
|
|
741
751
|
name: Name.MARK_FIRST_PAINT;
|
|
742
752
|
args: Args&{
|
|
@@ -747,14 +757,14 @@ export interface FirstPaint extends Mark {
|
|
|
747
757
|
};
|
|
748
758
|
}
|
|
749
759
|
|
|
750
|
-
export type PageLoadEvent =
|
|
760
|
+
export type PageLoadEvent = AnyFirstContentfulPaint|MarkDOMContent|InteractiveTime|AnyLargestContentfulPaintCandidate|
|
|
751
761
|
LayoutShift|FirstPaint|MarkLoad|NavigationStart|SoftNavigationStart;
|
|
752
762
|
|
|
753
763
|
const markerTypeGuards = [
|
|
754
764
|
isMarkDOMContent,
|
|
755
765
|
isMarkLoad,
|
|
756
766
|
isFirstPaint,
|
|
757
|
-
|
|
767
|
+
isAnyFirstContentfulPaint,
|
|
758
768
|
isAnyLargestContentfulPaintCandidate,
|
|
759
769
|
isNavigationStart,
|
|
760
770
|
isSoftNavigationStart,
|
|
@@ -765,6 +775,7 @@ export const MarkerName = [
|
|
|
765
775
|
Name.MARK_LOAD,
|
|
766
776
|
Name.MARK_FIRST_PAINT,
|
|
767
777
|
Name.MARK_FCP,
|
|
778
|
+
Name.MARK_SOFT_FCP,
|
|
768
779
|
Name.MARK_LCP_CANDIDATE,
|
|
769
780
|
Name.MARK_LCP_CANDIDATE_FOR_SOFT_NAVIGATION,
|
|
770
781
|
Name.NAVIGATION_START,
|
|
@@ -2285,6 +2296,14 @@ export function isFirstContentfulPaint(event: Event): event is FirstContentfulPa
|
|
|
2285
2296
|
return event.name === Name.MARK_FCP;
|
|
2286
2297
|
}
|
|
2287
2298
|
|
|
2299
|
+
export function isSoftFirstContentfulPaint(event: Event): event is SyntheticSoftFirstContentfulPaint {
|
|
2300
|
+
return event.name === Name.MARK_SOFT_FCP;
|
|
2301
|
+
}
|
|
2302
|
+
|
|
2303
|
+
export function isAnyFirstContentfulPaint(event: Event): event is AnyFirstContentfulPaint {
|
|
2304
|
+
return event.name === Name.MARK_FCP || event.name === Name.MARK_SOFT_FCP;
|
|
2305
|
+
}
|
|
2306
|
+
|
|
2288
2307
|
export function isAnyLargestContentfulPaintCandidate(event: Event): event is AnyLargestContentfulPaintCandidate {
|
|
2289
2308
|
return event.name === Name.MARK_LCP_CANDIDATE || event.name === Name.MARK_LCP_CANDIDATE_FOR_SOFT_NAVIGATION;
|
|
2290
2309
|
}
|
|
@@ -3168,6 +3187,7 @@ export const enum Name {
|
|
|
3168
3187
|
MARK_DOM_CONTENT = 'MarkDOMContent',
|
|
3169
3188
|
MARK_FIRST_PAINT = 'firstPaint',
|
|
3170
3189
|
MARK_FCP = 'firstContentfulPaint',
|
|
3190
|
+
MARK_SOFT_FCP = 'SyntheticSoftFirstContentfulPaint',
|
|
3171
3191
|
MARK_LCP_CANDIDATE = 'largestContentfulPaint::Candidate',
|
|
3172
3192
|
MARK_LCP_CANDIDATE_FOR_SOFT_NAVIGATION = 'largestContentfulPaint::CandidateForSoftNavigation',
|
|
3173
3193
|
MARK_LCP_INVALIDATE = 'largestContentfulPaint::Invalidate',
|
|
@@ -9,7 +9,7 @@ import * as SDK from '../../core/sdk/sdk.js';
|
|
|
9
9
|
import type * as ProtocolProxyApi from '../../generated/protocol-proxy-api.js';
|
|
10
10
|
import type * as Protocol from '../../generated/protocol.js';
|
|
11
11
|
import * as Bindings from '../bindings/bindings.js';
|
|
12
|
-
import * as StackTrace from '../stack_trace/stack_trace.js';
|
|
12
|
+
import type * as StackTrace from '../stack_trace/stack_trace.js';
|
|
13
13
|
|
|
14
14
|
export const enum Events {
|
|
15
15
|
TOOLS_ADDED = 'ToolsAdded',
|
|
@@ -18,20 +18,13 @@ export const enum Events {
|
|
|
18
18
|
TOOL_RESPONDED = 'ToolResponded',
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
export interface ExceptionDetails {
|
|
22
|
-
readonly error: SDK.RemoteObject.RemoteObject;
|
|
23
|
-
readonly description: string;
|
|
24
|
-
readonly frames: StackTrace.ErrorStackParser.ParsedErrorFrame[];
|
|
25
|
-
readonly cause?: ExceptionDetails;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
21
|
export class Result {
|
|
29
22
|
readonly status: Protocol.WebMCP.InvocationStatus;
|
|
30
23
|
readonly output?: unknown;
|
|
31
24
|
readonly errorText?: string;
|
|
32
25
|
// TODO(crbug.com/494516094) Clean this up if the target disappears?
|
|
33
26
|
readonly #exception?: SDK.RemoteObject.RemoteObject;
|
|
34
|
-
#
|
|
27
|
+
#symbolizedError?: Promise<Bindings.SymbolizedError.SymbolizedError|null>;
|
|
35
28
|
|
|
36
29
|
constructor(
|
|
37
30
|
status: Protocol.WebMCP.InvocationStatus, output: unknown|undefined, errorText: string|undefined,
|
|
@@ -42,46 +35,13 @@ export class Result {
|
|
|
42
35
|
this.output = output;
|
|
43
36
|
}
|
|
44
37
|
|
|
45
|
-
get
|
|
46
|
-
if (!this.#
|
|
47
|
-
this.#
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
async #resolveExceptionDetails(errorObj: SDK.RemoteObject.RemoteObject|undefined):
|
|
53
|
-
Promise<ExceptionDetails|undefined> {
|
|
54
|
-
if (!errorObj) {
|
|
55
|
-
return undefined;
|
|
56
|
-
}
|
|
57
|
-
const error = SDK.RemoteObject.RemoteError.objectAsError(errorObj);
|
|
58
|
-
const [details, cause] = await Promise.all([error.exceptionDetails(), error.cause()]);
|
|
59
|
-
const description = error.errorStack;
|
|
60
|
-
|
|
61
|
-
const frames =
|
|
62
|
-
StackTrace.ErrorStackParser.parseSourcePositionsFromErrorStack(errorObj.runtimeModel(), error.errorStack) || [];
|
|
63
|
-
if (details?.stackTrace) {
|
|
64
|
-
StackTrace.ErrorStackParser.augmentErrorStackWithScriptIds(frames, details.stackTrace);
|
|
38
|
+
get symbolizedError(): Promise<Bindings.SymbolizedError.SymbolizedError|null>|undefined {
|
|
39
|
+
if (!this.#symbolizedError) {
|
|
40
|
+
this.#symbolizedError = this.#exception ?
|
|
41
|
+
Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance().createSymbolizedError(this.#exception) :
|
|
42
|
+
Promise.resolve(null);
|
|
65
43
|
}
|
|
66
|
-
|
|
67
|
-
if (cause?.subtype === 'error') {
|
|
68
|
-
return {error: errorObj, description, frames, cause: await this.#resolveExceptionDetails(cause)};
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
if (cause?.type === 'string') {
|
|
72
|
-
return {
|
|
73
|
-
error: errorObj,
|
|
74
|
-
description,
|
|
75
|
-
frames,
|
|
76
|
-
cause: {
|
|
77
|
-
error: cause,
|
|
78
|
-
description: cause.value as string,
|
|
79
|
-
frames: [],
|
|
80
|
-
}
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
return {error: errorObj, description, frames};
|
|
44
|
+
return this.#symbolizedError;
|
|
85
45
|
}
|
|
86
46
|
}
|
|
87
47
|
|
|
@@ -576,12 +576,12 @@ function createDOMNodeContext(node: SDK.DOMModel.DOMNode|null): AiAssistanceMode
|
|
|
576
576
|
return new AiAssistanceModel.DOMNodeContext.DOMNodeContext(node);
|
|
577
577
|
}
|
|
578
578
|
|
|
579
|
-
function createFileContext(file: Workspace.UISourceCode.UISourceCode|null): AiAssistanceModel.
|
|
579
|
+
function createFileContext(file: Workspace.UISourceCode.UISourceCode|null): AiAssistanceModel.FileContext.FileContext|
|
|
580
580
|
null {
|
|
581
581
|
if (!file) {
|
|
582
582
|
return null;
|
|
583
583
|
}
|
|
584
|
-
return new AiAssistanceModel.
|
|
584
|
+
return new AiAssistanceModel.FileContext.FileContext(file);
|
|
585
585
|
}
|
|
586
586
|
|
|
587
587
|
function createAccessibilityContext(report: LighthousePanel.LighthousePanel.ActiveLighthouseReport|null):
|
|
@@ -592,13 +592,13 @@ function createAccessibilityContext(report: LighthousePanel.LighthousePanel.Acti
|
|
|
592
592
|
return new AiAssistanceModel.AccessibilityAgent.AccessibilityContext(report.report);
|
|
593
593
|
}
|
|
594
594
|
|
|
595
|
-
function createRequestContext(request: SDK.NetworkRequest.NetworkRequest|
|
|
596
|
-
|
|
595
|
+
function createRequestContext(request: SDK.NetworkRequest.NetworkRequest|
|
|
596
|
+
null): AiAssistanceModel.RequestContext.RequestContext|null {
|
|
597
597
|
if (!request) {
|
|
598
598
|
return null;
|
|
599
599
|
}
|
|
600
600
|
const calculator = NetworkPanel.NetworkPanel.NetworkPanel.instance().networkLogView.timeCalculator();
|
|
601
|
-
return new AiAssistanceModel.
|
|
601
|
+
return new AiAssistanceModel.RequestContext.RequestContext(request, calculator);
|
|
602
602
|
}
|
|
603
603
|
|
|
604
604
|
function createPerformanceTraceContext(focus: AiAssistanceModel.AIContext.AgentFocus|null):
|
|
@@ -666,10 +666,10 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
666
666
|
|
|
667
667
|
#conversation?: AiAssistanceModel.AiConversation.AiConversation;
|
|
668
668
|
|
|
669
|
-
#selectedFile: AiAssistanceModel.
|
|
669
|
+
#selectedFile: AiAssistanceModel.FileContext.FileContext|null = null;
|
|
670
670
|
#selectedElement: AiAssistanceModel.DOMNodeContext.DOMNodeContext|null = null;
|
|
671
671
|
#selectedPerformanceTrace: AiAssistanceModel.PerformanceAgent.PerformanceTraceContext|null = null;
|
|
672
|
-
#selectedRequest: AiAssistanceModel.
|
|
672
|
+
#selectedRequest: AiAssistanceModel.RequestContext.RequestContext|null = null;
|
|
673
673
|
|
|
674
674
|
#selectedAccessibility: AiAssistanceModel.AccessibilityAgent.AccessibilityContext|null = null;
|
|
675
675
|
#selectedStorage: AiAssistanceModel.StorageAgent.StorageContext|null = null;
|
|
@@ -1254,7 +1254,7 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
1254
1254
|
|
|
1255
1255
|
if (Boolean(ev.data)) {
|
|
1256
1256
|
const calculator = NetworkPanel.NetworkPanel.NetworkPanel.instance().networkLogView.timeCalculator();
|
|
1257
|
-
this.#selectedRequest = new AiAssistanceModel.
|
|
1257
|
+
this.#selectedRequest = new AiAssistanceModel.RequestContext.RequestContext(ev.data, calculator);
|
|
1258
1258
|
} else {
|
|
1259
1259
|
this.#selectedRequest = null;
|
|
1260
1260
|
}
|
|
@@ -1280,7 +1280,7 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
1280
1280
|
if (!newFile || this.#selectedFile?.getItem() === newFile) {
|
|
1281
1281
|
return;
|
|
1282
1282
|
}
|
|
1283
|
-
this.#selectedFile = new AiAssistanceModel.
|
|
1283
|
+
this.#selectedFile = new AiAssistanceModel.FileContext.FileContext(ev.data);
|
|
1284
1284
|
this.#updateConversationState(this.#conversation);
|
|
1285
1285
|
};
|
|
1286
1286
|
|
|
@@ -1488,12 +1488,12 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
1488
1488
|
}
|
|
1489
1489
|
|
|
1490
1490
|
const context = this.#conversation.selectedContext;
|
|
1491
|
-
if (context instanceof AiAssistanceModel.
|
|
1491
|
+
if (context instanceof AiAssistanceModel.RequestContext.RequestContext) {
|
|
1492
1492
|
const requestLocation = NetworkForward.UIRequestLocation.UIRequestLocation.tab(
|
|
1493
1493
|
context.getItem(), NetworkForward.UIRequestLocation.UIRequestTabs.HEADERS_COMPONENT);
|
|
1494
1494
|
return Common.Revealer.reveal(requestLocation);
|
|
1495
1495
|
}
|
|
1496
|
-
if (context instanceof AiAssistanceModel.
|
|
1496
|
+
if (context instanceof AiAssistanceModel.FileContext.FileContext) {
|
|
1497
1497
|
return Common.Revealer.reveal(context.getItem().uiLocation(0, 0));
|
|
1498
1498
|
}
|
|
1499
1499
|
if (context instanceof AiAssistanceModel.PerformanceAgent.PerformanceTraceContext) {
|
|
@@ -1575,7 +1575,12 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
1575
1575
|
break;
|
|
1576
1576
|
}
|
|
1577
1577
|
case 'ai-assistance.storage-floating-button': {
|
|
1578
|
-
Host.userMetrics.actionTaken(Host.UserMetrics.Action.
|
|
1578
|
+
Host.userMetrics.actionTaken(Host.UserMetrics.Action.AiAssistanceOpenedFromApplicationPanelFloatingButton);
|
|
1579
|
+
targetConversationType = AiAssistanceModel.AiHistoryStorage.ConversationType.STORAGE;
|
|
1580
|
+
break;
|
|
1581
|
+
}
|
|
1582
|
+
case 'ai-assistance.application-panel-context': {
|
|
1583
|
+
Host.userMetrics.actionTaken(Host.UserMetrics.Action.AiAssistanceOpenedFromApplicationPanel);
|
|
1579
1584
|
targetConversationType = AiAssistanceModel.AiHistoryStorage.ConversationType.STORAGE;
|
|
1580
1585
|
break;
|
|
1581
1586
|
}
|
|
@@ -1728,11 +1733,11 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
1728
1733
|
}
|
|
1729
1734
|
|
|
1730
1735
|
#handleConversationContextChange = (data: unknown): void => {
|
|
1731
|
-
if (data instanceof AiAssistanceModel.
|
|
1736
|
+
if (data instanceof AiAssistanceModel.FileContext.FileContext) {
|
|
1732
1737
|
this.#selectedFile = data;
|
|
1733
1738
|
} else if (data instanceof AiAssistanceModel.DOMNodeContext.DOMNodeContext) {
|
|
1734
1739
|
this.#selectedElement = data;
|
|
1735
|
-
} else if (data instanceof AiAssistanceModel.
|
|
1740
|
+
} else if (data instanceof AiAssistanceModel.RequestContext.RequestContext) {
|
|
1736
1741
|
this.#selectedRequest = data;
|
|
1737
1742
|
} else if (data instanceof AiAssistanceModel.PerformanceAgent.PerformanceTraceContext) {
|
|
1738
1743
|
this.#selectedPerformanceTrace = data;
|
|
@@ -2116,7 +2121,8 @@ export class ActionDelegate implements UI.ActionRegistration.ActionDelegate {
|
|
|
2116
2121
|
case 'drjones.performance-panel-context':
|
|
2117
2122
|
case 'drjones.sources-floating-button':
|
|
2118
2123
|
case 'drjones.sources-panel-context':
|
|
2119
|
-
case 'ai-assistance.storage-floating-button':
|
|
2124
|
+
case 'ai-assistance.storage-floating-button':
|
|
2125
|
+
case 'ai-assistance.application-panel-context': {
|
|
2120
2126
|
void (async () => {
|
|
2121
2127
|
const view = UI.ViewManager.ViewManager.instance().view(
|
|
2122
2128
|
AiAssistancePanel.panelName,
|
|
@@ -313,3 +313,19 @@ UI.ActionRegistration.registerActionExtension({
|
|
|
313
313
|
condition: config =>
|
|
314
314
|
isStorageAgentFeatureAvailable(config) && !isPolicyRestricted(config) && !isGeoRestricted(config),
|
|
315
315
|
});
|
|
316
|
+
|
|
317
|
+
UI.ActionRegistration.registerActionExtension({
|
|
318
|
+
actionId: 'ai-assistance.application-panel-context',
|
|
319
|
+
contextTypes(): [] {
|
|
320
|
+
return [];
|
|
321
|
+
},
|
|
322
|
+
category: UI.ActionRegistration.ActionCategory.GLOBAL,
|
|
323
|
+
title: i18nAiBrandedString(UIStrings.debugWithGemini, UIStrings.debugWithAi),
|
|
324
|
+
configurableBindings: false,
|
|
325
|
+
async loadActionDelegate() {
|
|
326
|
+
const AiAssistance = await loadAiAssistanceModule();
|
|
327
|
+
return new AiAssistance.ActionDelegate();
|
|
328
|
+
},
|
|
329
|
+
condition: config =>
|
|
330
|
+
isStorageAgentFeatureAvailable(config) && !isPolicyRestricted(config) && !isGeoRestricted(config),
|
|
331
|
+
});
|
|
@@ -171,13 +171,13 @@ export type ViewOutput = undefined;
|
|
|
171
171
|
|
|
172
172
|
function getContextRemoveLabel(context: AiAssistanceModel.AiAgent.ConversationContext<unknown>):
|
|
173
173
|
Platform.UIString.LocalizedString {
|
|
174
|
-
if (context instanceof AiAssistanceModel.
|
|
174
|
+
if (context instanceof AiAssistanceModel.FileContext.FileContext) {
|
|
175
175
|
return lockedString(UIStringsNotTranslate.removeContextFile);
|
|
176
176
|
}
|
|
177
177
|
if (context instanceof AiAssistanceModel.DOMNodeContext.DOMNodeContext) {
|
|
178
178
|
return lockedString(UIStringsNotTranslate.removeContextElement);
|
|
179
179
|
}
|
|
180
|
-
if (context instanceof AiAssistanceModel.
|
|
180
|
+
if (context instanceof AiAssistanceModel.RequestContext.RequestContext) {
|
|
181
181
|
return lockedString(UIStringsNotTranslate.removeContextRequest);
|
|
182
182
|
}
|
|
183
183
|
if (context instanceof AiAssistanceModel.PerformanceAgent.PerformanceTraceContext) {
|
|
@@ -351,9 +351,9 @@ export const DEFAULT_VIEW = (input: ViewInput, _output: ViewOutput, target: HTML
|
|
|
351
351
|
})}
|
|
352
352
|
></devtools-widget>` :
|
|
353
353
|
html`
|
|
354
|
-
${input.context instanceof AiAssistanceModel.
|
|
354
|
+
${input.context instanceof AiAssistanceModel.RequestContext.RequestContext ?
|
|
355
355
|
PanelUtils.PanelUtils.getIconForNetworkRequest(input.context.getItem()) :
|
|
356
|
-
input.context instanceof AiAssistanceModel.
|
|
356
|
+
input.context instanceof AiAssistanceModel.FileContext.FileContext ?
|
|
357
357
|
PanelUtils.PanelUtils.getIconForSourceFile(input.context.getItem()) :
|
|
358
358
|
input.context instanceof AiAssistanceModel.AccessibilityAgent.AccessibilityContext ?
|
|
359
359
|
html`<devtools-icon class="icon" name="performance" title="Lighthouse"></devtools-icon>` :
|
|
@@ -52,6 +52,7 @@ import {BackForwardCacheTreeElement} from './BackForwardCacheTreeElement.js';
|
|
|
52
52
|
import {BackgroundServiceModel} from './BackgroundServiceModel.js';
|
|
53
53
|
import {BackgroundServiceView} from './BackgroundServiceView.js';
|
|
54
54
|
import {BounceTrackingMitigationsTreeElement} from './BounceTrackingMitigationsTreeElement.js';
|
|
55
|
+
import * as ApplicationComponents from './components/components.js';
|
|
55
56
|
import {DeviceBoundSessionsModel} from './DeviceBoundSessionsModel.js';
|
|
56
57
|
import {RootTreeElement as DeviceBoundSessionsRootTreeElement} from './DeviceBoundSessionsTreeElement.js';
|
|
57
58
|
import {
|
|
@@ -94,10 +95,26 @@ import {TrustTokensTreeElement} from './TrustTokensTreeElement.js';
|
|
|
94
95
|
import {WebMCPTreeElement} from './WebMCPTreeElement.js';
|
|
95
96
|
|
|
96
97
|
const UIStrings = {
|
|
98
|
+
/**
|
|
99
|
+
* @description Text of a context menu item to start a chat with AI
|
|
100
|
+
*/
|
|
101
|
+
startAChat: 'Start a chat',
|
|
102
|
+
/**
|
|
103
|
+
* @description Text of a context menu item to explain contents of a local/session storage bucket with AI
|
|
104
|
+
*/
|
|
105
|
+
explainStorage: 'Explain storage',
|
|
106
|
+
/**
|
|
107
|
+
* @description Text of a context menu item to explain web cookies with AI
|
|
108
|
+
*/
|
|
109
|
+
explainCookies: 'Explain cookies',
|
|
97
110
|
/**
|
|
98
111
|
* @description Text in Application Panel Sidebar of the Application panel
|
|
99
112
|
*/
|
|
100
113
|
application: 'Application',
|
|
114
|
+
/**
|
|
115
|
+
* @description Text in Application Panel Sidebar of the Application panel
|
|
116
|
+
*/
|
|
117
|
+
ads: 'Ads',
|
|
101
118
|
/**
|
|
102
119
|
* @description Text in Application Panel Sidebar of the Application panel
|
|
103
120
|
*/
|
|
@@ -342,6 +359,7 @@ export class ApplicationPanelSidebar extends UI.Widget.VBox implements SDK.Targe
|
|
|
342
359
|
pushMessagingTreeElement: BackgroundServiceTreeElement;
|
|
343
360
|
reportingApiTreeElement: ReportingApiTreeElement;
|
|
344
361
|
webMcpTreeElement?: WebMCPTreeElement;
|
|
362
|
+
adsTreeElement?: ApplicationPanelTreeElement;
|
|
345
363
|
deviceBoundSessionsRootTreeElement: DeviceBoundSessionsRootTreeElement|undefined;
|
|
346
364
|
deviceBoundSessionsModel: DeviceBoundSessionsModel|undefined;
|
|
347
365
|
preloadingSummaryTreeElement: PreloadingSummaryTreeElement|undefined;
|
|
@@ -391,6 +409,25 @@ export class ApplicationPanelSidebar extends UI.Widget.VBox implements SDK.Targe
|
|
|
391
409
|
this.applicationTreeElement.appendChild(this.webMcpTreeElement);
|
|
392
410
|
}
|
|
393
411
|
|
|
412
|
+
if (Root.Runtime.hostConfig.devToolsAdsPanel?.enabled) {
|
|
413
|
+
const adsTreeElement = new ApplicationPanelTreeElement(panel, i18nString(UIStrings.ads), false, 'ads');
|
|
414
|
+
const icon = createIcon('experiment');
|
|
415
|
+
adsTreeElement.setLeadingIcons([icon]);
|
|
416
|
+
adsTreeElement.itemURL = 'ads://' as Platform.DevToolsPath.UrlString;
|
|
417
|
+
let adsView: ApplicationComponents.AdsView.AdsView;
|
|
418
|
+
adsTreeElement.onselect = (selectedByUser?: boolean): boolean => {
|
|
419
|
+
ApplicationPanelTreeElement.prototype.onselect.call(adsTreeElement, selectedByUser);
|
|
420
|
+
if (!adsView) {
|
|
421
|
+
adsView = new ApplicationComponents.AdsView.AdsView();
|
|
422
|
+
}
|
|
423
|
+
adsTreeElement.showView(adsView);
|
|
424
|
+
UI.UIUserMetrics.UIUserMetrics.instance().panelShown('ads');
|
|
425
|
+
return false;
|
|
426
|
+
};
|
|
427
|
+
this.adsTreeElement = adsTreeElement;
|
|
428
|
+
this.applicationTreeElement.appendChild(this.adsTreeElement);
|
|
429
|
+
}
|
|
430
|
+
|
|
394
431
|
const storageSectionTitle = i18nString(UIStrings.storage);
|
|
395
432
|
const storageTreeElement = this.addSidebarSection(storageSectionTitle, 'storage');
|
|
396
433
|
this.localStorageListTreeElement = new ExpandableApplicationPanelTreeElement(
|
|
@@ -1792,6 +1829,22 @@ export class DOMStorageTreeElement extends ApplicationPanelTreeElement {
|
|
|
1792
1829
|
const contextMenu = new UI.ContextMenu.ContextMenu(event);
|
|
1793
1830
|
contextMenu.defaultSection().appendItem(
|
|
1794
1831
|
i18nString(UIStrings.clear), () => this.domStorage.clear(), {jslogContext: 'clear'});
|
|
1832
|
+
|
|
1833
|
+
const storageItem = this.#getStorageItem();
|
|
1834
|
+
if (storageItem) {
|
|
1835
|
+
const openAiAssistanceId = 'ai-assistance.application-panel-context';
|
|
1836
|
+
if (UI.ActionRegistry.ActionRegistry.instance().hasAction(openAiAssistanceId)) {
|
|
1837
|
+
UI.Context.Context.instance().setFlavor(AiAssistance.StorageItem.StorageItem, storageItem);
|
|
1838
|
+
const action = UI.ActionRegistry.ActionRegistry.instance().getAction(openAiAssistanceId);
|
|
1839
|
+
const submenu = contextMenu.footerSection().appendSubMenuItem(action.title(), false, openAiAssistanceId);
|
|
1840
|
+
submenu.defaultSection().appendAction(openAiAssistanceId, i18nString(UIStrings.startAChat));
|
|
1841
|
+
submenu.defaultSection().appendItem(
|
|
1842
|
+
i18nString(UIStrings.explainStorage),
|
|
1843
|
+
() => action.execute({prompt: 'What is the purpose of this storage bucket?'}),
|
|
1844
|
+
{disabled: !action.enabled(), jslogContext: openAiAssistanceId + '.storage'});
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1847
|
+
|
|
1795
1848
|
void contextMenu.show();
|
|
1796
1849
|
}
|
|
1797
1850
|
}
|
|
@@ -1900,6 +1953,22 @@ export class CookieTreeElement extends ApplicationPanelTreeElement {
|
|
|
1900
1953
|
contextMenu.defaultSection().appendItem(
|
|
1901
1954
|
i18nString(UIStrings.clear), () => this.resourcesPanel.clearCookies(this.target, this.#cookieDomain),
|
|
1902
1955
|
{jslogContext: 'clear'});
|
|
1956
|
+
|
|
1957
|
+
const storageItem = this.#getStorageItem();
|
|
1958
|
+
if (storageItem) {
|
|
1959
|
+
const openAiAssistanceId = 'ai-assistance.application-panel-context';
|
|
1960
|
+
if (UI.ActionRegistry.ActionRegistry.instance().hasAction(openAiAssistanceId)) {
|
|
1961
|
+
UI.Context.Context.instance().setFlavor(AiAssistance.StorageItem.StorageItem, storageItem);
|
|
1962
|
+
const action = UI.ActionRegistry.ActionRegistry.instance().getAction(openAiAssistanceId);
|
|
1963
|
+
const submenu = contextMenu.footerSection().appendSubMenuItem(action.title(), false, openAiAssistanceId);
|
|
1964
|
+
submenu.defaultSection().appendAction(openAiAssistanceId, i18nString(UIStrings.startAChat));
|
|
1965
|
+
submenu.defaultSection().appendItem(
|
|
1966
|
+
i18nString(UIStrings.explainCookies),
|
|
1967
|
+
() => action.execute({prompt: 'What is the purpose of these cookies?'}),
|
|
1968
|
+
{disabled: !action.enabled(), jslogContext: openAiAssistanceId + '.cookies'});
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
|
|
1903
1972
|
void contextMenu.show();
|
|
1904
1973
|
}
|
|
1905
1974
|
|