chrome-devtools-frontend 1.0.1603822 → 1.0.1605219
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/AUTHORS +1 -0
- package/front_end/Tests.js +23 -7
- package/front_end/core/host/AidaClient.ts +153 -525
- package/front_end/core/host/AidaClientTypes.ts +470 -0
- package/front_end/core/host/AidaGcaTranslation.ts +231 -122
- package/front_end/core/host/GcaClient.ts +112 -0
- package/front_end/core/host/GcaTypes.ts +107 -155
- package/front_end/core/host/UserMetrics.ts +0 -1
- package/front_end/core/host/host.ts +2 -0
- package/front_end/core/protocol_client/DevToolsCDPConnection.ts +1 -1
- package/front_end/core/root/ExperimentNames.ts +0 -1
- package/front_end/core/root/Runtime.ts +5 -0
- package/front_end/core/sdk/AutofillModel.ts +3 -2
- package/front_end/core/sdk/CSSModel.ts +3 -4
- package/front_end/core/sdk/CSSProperty.ts +1 -1
- package/front_end/core/sdk/ConsoleModel.ts +15 -13
- package/front_end/core/sdk/CookieModel.ts +5 -4
- package/front_end/core/sdk/DOMDebuggerModel.ts +20 -14
- package/front_end/core/sdk/DOMModel.ts +24 -22
- package/front_end/core/sdk/DebuggerModel.ts +21 -36
- package/front_end/core/sdk/EmulationModel.ts +21 -23
- package/front_end/core/sdk/EventBreakpointsModel.ts +16 -6
- package/front_end/core/sdk/HeapProfilerModel.ts +4 -7
- package/front_end/core/sdk/IsolateManager.ts +12 -7
- package/front_end/core/sdk/NetworkManager.ts +35 -28
- package/front_end/core/sdk/OverlayModel.ts +10 -10
- package/front_end/core/sdk/PreloadingModel.ts +3 -4
- package/front_end/core/sdk/ServiceWorkerManager.ts +2 -3
- package/front_end/core/sdk/SourceMapScopesInfo.ts +93 -63
- package/front_end/entrypoints/formatter_worker/FormatterWorker.ts +1 -3
- package/front_end/entrypoints/heap_snapshot_worker/AllocationProfile.ts +22 -48
- package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshot.ts +1 -1
- package/front_end/entrypoints/main/MainImpl.ts +0 -4
- package/front_end/generated/InspectorBackendCommands.ts +4 -0
- package/front_end/generated/SupportedCSSProperties.js +68 -2
- package/front_end/generated/protocol-mapping.d.ts +7 -0
- package/front_end/generated/protocol-proxy-api.d.ts +14 -0
- package/front_end/generated/protocol.ts +22 -0
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +31 -17
- package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.snapshot.txt +1 -1
- package/front_end/models/bindings/TempFile.ts +1 -4
- package/front_end/models/emulation/DeviceModeModel.ts +21 -26
- package/front_end/models/extensions/ExtensionAPI.ts +1 -1
- package/front_end/models/heap_snapshot_model/HeapSnapshotModel.ts +34 -47
- package/front_end/models/javascript_metadata/NativeFunctions.js +6 -6
- package/front_end/models/trace/insights/LCPDiscovery.ts +14 -6
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +85 -31
- package/front_end/panels/ai_assistance/components/ChatMessage.ts +50 -40
- package/front_end/panels/ai_assistance/components/ChatView.ts +3 -2
- package/front_end/panels/ai_assistance/components/WalkthroughView.ts +35 -7
- package/front_end/panels/ai_assistance/components/chatMessage.css +5 -1
- package/front_end/panels/application/ApplicationPanelSidebar.ts +6 -0
- package/front_end/panels/application/IndexedDBViews.ts +0 -9
- package/front_end/panels/application/WebMCPTreeElement.ts +35 -0
- package/front_end/panels/application/WebMCPView.ts +118 -0
- package/front_end/panels/application/application.ts +4 -0
- package/front_end/panels/application/webMCPView.css +65 -0
- package/front_end/panels/common/aiCodeCompletionSummaryToolbar.css +1 -1
- package/front_end/panels/console/consoleView.css +4 -0
- package/front_end/panels/elements/ElementsTreeElement.ts +91 -13
- package/front_end/panels/elements/StylesAiCodeCompletionProvider.ts +23 -2
- package/front_end/panels/elements/StylesSidebarPane.ts +85 -20
- package/front_end/panels/elements/elementsPanel.css +14 -0
- package/front_end/panels/elements/elementsTreeOutline.css +18 -0
- package/front_end/panels/network/NetworkLogViewColumns.ts +3 -3
- package/front_end/panels/profiler/HeapSnapshotDataGrids.ts +15 -19
- package/front_end/panels/profiler/HeapSnapshotGridNodes.ts +4 -2
- package/front_end/panels/profiler/HeapSnapshotProxy.ts +12 -16
- package/front_end/panels/profiler/HeapSnapshotView.ts +3 -10
- package/front_end/panels/profiler/ProfilesPanel.ts +5 -7
- package/front_end/panels/recorder/components/recordingView.css +0 -6
- package/front_end/panels/sensors/SensorsView.ts +28 -61
- package/front_end/panels/timeline/EventsTimelineTreeView.ts +2 -2
- package/front_end/panels/timeline/ThirdPartyTreeView.ts +35 -36
- package/front_end/panels/timeline/TimelineDetailsView.ts +47 -41
- package/front_end/panels/timeline/TimelinePanel.ts +1 -3
- package/front_end/panels/timeline/TimelineTreeView.ts +13 -13
- package/front_end/panels/timeline/components/LiveMetricsView.ts +852 -824
- package/front_end/panels/timeline/components/liveMetricsView.css +4 -0
- package/front_end/panels/timeline/thirdPartyTreeView.css +2 -2
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/ui/components/buttons/button.css +2 -2
- package/front_end/ui/components/text_editor/AiCodeCompletionProvider.ts +0 -11
- package/front_end/ui/legacy/InspectorDrawerView.ts +206 -0
- package/front_end/ui/legacy/InspectorView.ts +41 -91
- package/front_end/ui/legacy/ViewManager.ts +14 -5
- package/front_end/ui/legacy/inspectorDrawerTabbedPane.css +5 -0
- package/front_end/ui/visual_logging/KnownContextValues.ts +2 -1
- package/package.json +1 -1
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// Copyright 2026 The Chromium Authors
|
|
2
|
+
// Use of this source code is governed by a BSD-style license that can be
|
|
3
|
+
// found in the LICENSE file.
|
|
4
|
+
|
|
5
|
+
import '../../ui/components/icon_button/icon_button.js';
|
|
6
|
+
import '../../ui/components/lists/lists.js';
|
|
7
|
+
import '../../ui/legacy/legacy.js';
|
|
8
|
+
|
|
9
|
+
import * as i18n from '../../core/i18n/i18n.js';
|
|
10
|
+
import * as SDK from '../../core/sdk/sdk.js';
|
|
11
|
+
import type * as Protocol from '../../generated/protocol.js';
|
|
12
|
+
import * as UI from '../../ui/legacy/legacy.js';
|
|
13
|
+
import {
|
|
14
|
+
html,
|
|
15
|
+
render,
|
|
16
|
+
} from '../../ui/lit/lit.js';
|
|
17
|
+
|
|
18
|
+
import webMCPViewStyles from './webMCPView.css.js';
|
|
19
|
+
|
|
20
|
+
const UIStrings = {
|
|
21
|
+
/**
|
|
22
|
+
* @description Text for the header of the tool registry section
|
|
23
|
+
*/
|
|
24
|
+
toolRegistry: 'Available Tools',
|
|
25
|
+
/**
|
|
26
|
+
* @description Title of text to display when no tools are registered
|
|
27
|
+
*/
|
|
28
|
+
noToolsPlaceholderTitle: 'Available `WebMCP` Tools',
|
|
29
|
+
/**
|
|
30
|
+
* @description Text to display when no tools are registered
|
|
31
|
+
*/
|
|
32
|
+
noToolsPlaceholder:
|
|
33
|
+
'Registered `WebMCP` tools for this page will appear here. No tools have been registered or detected yet.',
|
|
34
|
+
/**
|
|
35
|
+
* @description Title of text to display when no calls have been made
|
|
36
|
+
*/
|
|
37
|
+
noCallsPlaceholderTitle: 'Tool Activity',
|
|
38
|
+
/**
|
|
39
|
+
* @description Text to display when no calls have been made
|
|
40
|
+
*/
|
|
41
|
+
noCallsPlaceholder: 'Start interacting with your `WebMCP` agent to see real-time tool calls and executions here.'
|
|
42
|
+
} as const;
|
|
43
|
+
const str_ = i18n.i18n.registerUIStrings('panels/application/WebMCPView.ts', UIStrings);
|
|
44
|
+
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
45
|
+
|
|
46
|
+
export interface ViewInput {
|
|
47
|
+
tools: Protocol.WebMCP.Tool[];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export type View = (input: ViewInput, output: object, target: HTMLElement) => void;
|
|
51
|
+
export const DEFAULT_VIEW: View = (input, output, target) => {
|
|
52
|
+
const tools = input.tools;
|
|
53
|
+
// clang-format off
|
|
54
|
+
render(html`
|
|
55
|
+
<style>${webMCPViewStyles}</style>
|
|
56
|
+
<devtools-split-view class="webmcp-view" direction="row" sidebar-position="second" name="webmcp-split-view">
|
|
57
|
+
<div slot="main" class="call-log">
|
|
58
|
+
${UI.Widget.widget(UI.EmptyWidget.EmptyWidget, {header: i18nString(UIStrings.noCallsPlaceholderTitle),
|
|
59
|
+
text: i18nString(UIStrings.noCallsPlaceholder)})}
|
|
60
|
+
</div>
|
|
61
|
+
<div slot="sidebar" class="tool-list">
|
|
62
|
+
<div class="section-title">${i18nString(UIStrings.toolRegistry)}</div>
|
|
63
|
+
${tools.length === 0 ? html`
|
|
64
|
+
${UI.Widget.widget(UI.EmptyWidget.EmptyWidget, {header: i18nString(UIStrings.noToolsPlaceholderTitle),
|
|
65
|
+
text: i18nString(UIStrings.noToolsPlaceholder)})}
|
|
66
|
+
` : html`
|
|
67
|
+
<devtools-list>
|
|
68
|
+
${tools.map(tool => html`
|
|
69
|
+
<div class="tool-item">
|
|
70
|
+
<div class="tool-name-container">
|
|
71
|
+
<div class="tool-name source-code">${tool.name}</div>
|
|
72
|
+
</div>
|
|
73
|
+
<div class="tool-description">${tool.description}</div>
|
|
74
|
+
</div>
|
|
75
|
+
`)}
|
|
76
|
+
</devtools-list>
|
|
77
|
+
`}
|
|
78
|
+
</div>
|
|
79
|
+
</devtools-split-view>
|
|
80
|
+
`, target);
|
|
81
|
+
// clang-format on
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export class WebMCPView extends UI.Widget.VBox {
|
|
85
|
+
readonly #view: View;
|
|
86
|
+
|
|
87
|
+
constructor(target?: HTMLElement, view: View = DEFAULT_VIEW) {
|
|
88
|
+
super();
|
|
89
|
+
this.#view = view;
|
|
90
|
+
SDK.TargetManager.TargetManager.instance().observeModels(SDK.WebMCPModel.WebMCPModel, {
|
|
91
|
+
modelAdded: (model: SDK.WebMCPModel.WebMCPModel) => this.#webMCPModelAdded(model),
|
|
92
|
+
modelRemoved: (model: SDK.WebMCPModel.WebMCPModel) => this.#webMCPModelRemoved(model),
|
|
93
|
+
});
|
|
94
|
+
this.requestUpdate();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
#webMCPModelAdded(model: SDK.WebMCPModel.WebMCPModel): void {
|
|
98
|
+
model.addEventListener(SDK.WebMCPModel.Events.TOOLS_ADDED, this.requestUpdate, this);
|
|
99
|
+
model.addEventListener(SDK.WebMCPModel.Events.TOOLS_REMOVED, this.requestUpdate, this);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
#webMCPModelRemoved(model: SDK.WebMCPModel.WebMCPModel): void {
|
|
103
|
+
model.removeEventListener(SDK.WebMCPModel.Events.TOOLS_ADDED, this.requestUpdate, this);
|
|
104
|
+
model.removeEventListener(SDK.WebMCPModel.Events.TOOLS_REMOVED, this.requestUpdate, this);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
override performUpdate(): void {
|
|
108
|
+
const tools = SDK.TargetManager.TargetManager.instance()
|
|
109
|
+
.models(SDK.WebMCPModel.WebMCPModel)
|
|
110
|
+
.flatMap(m => m.tools.toArray())
|
|
111
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
112
|
+
this.#view(
|
|
113
|
+
{
|
|
114
|
+
tools,
|
|
115
|
+
},
|
|
116
|
+
{}, this.contentElement);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -40,6 +40,8 @@ import * as StorageBucketsTreeElement from './StorageBucketsTreeElement.js';
|
|
|
40
40
|
import * as StorageItemsToolbar from './StorageItemsToolbar.js';
|
|
41
41
|
import * as StorageView from './StorageView.js';
|
|
42
42
|
import * as TrustTokensTreeElement from './TrustTokensTreeElement.js';
|
|
43
|
+
import * as WebMCPTreeElement from './WebMCPTreeElement.js';
|
|
44
|
+
import * as WebMCPView from './WebMCPView.js';
|
|
43
45
|
|
|
44
46
|
export {
|
|
45
47
|
ApplicationPanelSidebar,
|
|
@@ -80,4 +82,6 @@ export {
|
|
|
80
82
|
StorageItemsToolbar,
|
|
81
83
|
StorageView,
|
|
82
84
|
TrustTokensTreeElement,
|
|
85
|
+
WebMCPTreeElement,
|
|
86
|
+
WebMCPView,
|
|
83
87
|
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026 The Chromium Authors
|
|
3
|
+
* Use of this source code is governed by a BSD-style license that can be
|
|
4
|
+
* found in the LICENSE file.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
@scope to (devtools-widget > *) {
|
|
8
|
+
.webmcp-view {
|
|
9
|
+
height: 100%;
|
|
10
|
+
width: 100%;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.call-log,
|
|
14
|
+
.tool-list {
|
|
15
|
+
height: 100%;
|
|
16
|
+
display: flex;
|
|
17
|
+
flex-direction: column;
|
|
18
|
+
overflow: auto;
|
|
19
|
+
padding: 0;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.empty-view-scroller {
|
|
23
|
+
flex: auto;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.section-title {
|
|
27
|
+
background-color: var(--sys-color-surface1);
|
|
28
|
+
padding: 0 5px;
|
|
29
|
+
line-height: 22px;
|
|
30
|
+
overflow: hidden;
|
|
31
|
+
align-items: center;
|
|
32
|
+
flex: none;
|
|
33
|
+
color: var(--sys-color-on-surface);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
devtools-list {
|
|
37
|
+
flex: 1 1 auto;
|
|
38
|
+
margin: var(--sys-size-4);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.tool-item {
|
|
42
|
+
display: flex;
|
|
43
|
+
flex-direction: column;
|
|
44
|
+
padding: 8px 0;
|
|
45
|
+
gap: 4px;
|
|
46
|
+
width: 100%;
|
|
47
|
+
border-bottom: 1px solid var(--sys-color-divider);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.tool-name-container {
|
|
51
|
+
display: flex;
|
|
52
|
+
justify-content: space-between;
|
|
53
|
+
align-items: center;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.tool-name.source-code {
|
|
57
|
+
color: var(--sys-color-token-string);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.tool-description {
|
|
61
|
+
color: var(--sys-color-on-surface);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
}
|
|
@@ -78,9 +78,25 @@ const {animateOn} = UI.UIUtils;
|
|
|
78
78
|
|
|
79
79
|
const UIStrings = {
|
|
80
80
|
/**
|
|
81
|
-
* @description Title for Ad adorner. This
|
|
81
|
+
* @description Title for Ad adorner. This element is marked as advertisement element.
|
|
82
82
|
*/
|
|
83
|
-
|
|
83
|
+
thisElementWasIdentifiedAsAnAd: 'This element was identified as an ad',
|
|
84
|
+
/**
|
|
85
|
+
* @description Title of a section in the Ad adorner tooltip. Lists the ad script(s) responsible for generating this element.
|
|
86
|
+
*/
|
|
87
|
+
creatorAdScriptAncestry: 'Creator ad script ancestry',
|
|
88
|
+
/**
|
|
89
|
+
* @description Title of a section in the Ad adorner tooltip. The filter list rule that flagged the root script in 'Creator ad script ancestry' as an ad.
|
|
90
|
+
*/
|
|
91
|
+
rootScriptFilterListRule: 'Root script filter list rule',
|
|
92
|
+
/**
|
|
93
|
+
* @description Title of a section in the Ad adorner tooltip. The filter list rule that flagged the element's current resource.
|
|
94
|
+
*/
|
|
95
|
+
filterListRule: 'Filter list rule',
|
|
96
|
+
/**
|
|
97
|
+
* @description Title of a section in the Ad adorner tooltip. This element was identified as an ad, but no provenance data is available.
|
|
98
|
+
*/
|
|
99
|
+
noProvenanceAvailable: 'No provenance data is available',
|
|
84
100
|
/**
|
|
85
101
|
* @description A context menu item in the Elements panel. Force is used as a verb, indicating intention to make the state change.
|
|
86
102
|
*/
|
|
@@ -399,7 +415,10 @@ export interface ViewInput {
|
|
|
399
415
|
gridAdornerActive: boolean;
|
|
400
416
|
popoverAdornerActive: boolean;
|
|
401
417
|
|
|
402
|
-
|
|
418
|
+
adProvenance?: Protocol.Network.AdProvenance;
|
|
419
|
+
target?: SDK.Target.Target;
|
|
420
|
+
adTooltipId: string;
|
|
421
|
+
|
|
403
422
|
showContainerAdorner: boolean;
|
|
404
423
|
containerType?: string;
|
|
405
424
|
showFlexAdorner: boolean;
|
|
@@ -851,8 +870,66 @@ function renderTag(
|
|
|
851
870
|
attributes.map(attr => html` ${renderAttribute(attr, updateRecord, false, node)}`)}></span>\u200B`;
|
|
852
871
|
}
|
|
853
872
|
|
|
873
|
+
function maybeRenderAdAdorner(input: ViewInput): Lit.TemplateResult|typeof nothing {
|
|
874
|
+
if (!input.adProvenance) {
|
|
875
|
+
return nothing;
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
// clang-format off
|
|
879
|
+
return html`
|
|
880
|
+
<devtools-adorner
|
|
881
|
+
aria-describedby=${input.adTooltipId}
|
|
882
|
+
aria-label=${i18nString(UIStrings.thisElementWasIdentifiedAsAnAd)}
|
|
883
|
+
.name=${ElementsComponents.AdornerManager.RegisteredAdorners.AD}
|
|
884
|
+
jslog=${VisualLogging.adorner(ElementsComponents.AdornerManager.RegisteredAdorners.AD)}
|
|
885
|
+
${adornerRef()}>
|
|
886
|
+
<span>${ElementsComponents.AdornerManager.RegisteredAdorners.AD}</span>
|
|
887
|
+
</devtools-adorner>
|
|
888
|
+
|
|
889
|
+
<!--
|
|
890
|
+
Prevent the copy event from bubbling up to the Elements tree outline. Otherwise, DevTools
|
|
891
|
+
copies the underlying DOM node's HTML instead of the user's highlighted text.
|
|
892
|
+
-->
|
|
893
|
+
<devtools-tooltip id=${input.adTooltipId} variant=rich @copy=${(e: Event) => e.stopPropagation()}>
|
|
894
|
+
<div class="ad-provenance-tooltip">
|
|
895
|
+
${input.adProvenance.filterlistRule ? html`
|
|
896
|
+
<div class="ad-provenance-tooltip-title">${i18nString(UIStrings.filterListRule)}</div>
|
|
897
|
+
<div class="ad-provenance-tooltip-content">${input.adProvenance.filterlistRule}</div>
|
|
898
|
+
` : nothing}
|
|
899
|
+
|
|
900
|
+
${input.adProvenance.adScriptAncestry && input.target ? html`
|
|
901
|
+
<div class="ad-provenance-tooltip-title">${i18nString(UIStrings.creatorAdScriptAncestry)}</div>
|
|
902
|
+
<div class="ad-provenance-tooltip-content">
|
|
903
|
+
${input.adProvenance.adScriptAncestry.ancestryChain.map(script => html`
|
|
904
|
+
<div>
|
|
905
|
+
${UI.Widget.widget(Components.Linkifier.ScriptLocationLink, {
|
|
906
|
+
target: input.target,
|
|
907
|
+
scriptId: script.scriptId,
|
|
908
|
+
options: { jslogContext: 'ad-script' },
|
|
909
|
+
})}
|
|
910
|
+
</div>
|
|
911
|
+
`)}
|
|
912
|
+
</div>
|
|
913
|
+
|
|
914
|
+
${input.adProvenance.adScriptAncestry.rootScriptFilterlistRule ? html`
|
|
915
|
+
<div class="ad-provenance-tooltip-title">${i18nString(UIStrings.rootScriptFilterListRule)}</div>
|
|
916
|
+
<div class="ad-provenance-tooltip-content">
|
|
917
|
+
${input.adProvenance.adScriptAncestry.rootScriptFilterlistRule}
|
|
918
|
+
</div>
|
|
919
|
+
` : nothing}
|
|
920
|
+
` : nothing}
|
|
921
|
+
|
|
922
|
+
${!input.adProvenance.adScriptAncestry && !input.adProvenance.filterlistRule ? html`
|
|
923
|
+
<div class="ad-provenance-tooltip-title">${i18nString(UIStrings.noProvenanceAvailable)}</div>
|
|
924
|
+
` : nothing}
|
|
925
|
+
</div>
|
|
926
|
+
</devtools-tooltip>
|
|
927
|
+
`;
|
|
928
|
+
// clang-format on
|
|
929
|
+
}
|
|
930
|
+
|
|
854
931
|
export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLElement): void => {
|
|
855
|
-
const hasAdorners = input.
|
|
932
|
+
const hasAdorners = !!input.adProvenance || input.showContainerAdorner || input.showFlexAdorner ||
|
|
856
933
|
input.showGridAdorner || input.showGridLanesAdorner || input.showMediaAdorner || input.showPopoverAdorner ||
|
|
857
934
|
input.showTopLayerAdorner || input.showViewSourceAdorner || input.showScrollAdorner ||
|
|
858
935
|
input.showScrollSnapAdorner || input.showSlotAdorner || input.showStartingStyleAdorner;
|
|
@@ -888,13 +965,7 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
|
|
|
888
965
|
</div>` : nothing}
|
|
889
966
|
</div>
|
|
890
967
|
${hasAdorners ? html`<div class="adorner-container ${!hasAdorners ? 'hidden' : ''}">
|
|
891
|
-
${input
|
|
892
|
-
aria-label=${i18nString(UIStrings.thisFrameWasIdentifiedAsAnAd)}
|
|
893
|
-
.name=${ElementsComponents.AdornerManager.RegisteredAdorners.AD}
|
|
894
|
-
jslog=${VisualLogging.adorner(ElementsComponents.AdornerManager.RegisteredAdorners.AD)}
|
|
895
|
-
${adornerRef()}>
|
|
896
|
-
<span>${ElementsComponents.AdornerManager.RegisteredAdorners.AD}</span>
|
|
897
|
-
</devtools-adorner>` : nothing}
|
|
968
|
+
${maybeRenderAdAdorner(input)}
|
|
898
969
|
${input.showViewSourceAdorner ? html`<devtools-adorner
|
|
899
970
|
.name=${ElementsComponents.AdornerManager.RegisteredAdorners.VIEW_SOURCE}
|
|
900
971
|
jslog=${VisualLogging.adorner(ElementsComponents.AdornerManager.RegisteredAdorners.VIEW_SOURCE)}
|
|
@@ -1102,6 +1173,9 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1102
1173
|
#descendantDecorations: Decoration[] = [];
|
|
1103
1174
|
#decorationsTooltip = '';
|
|
1104
1175
|
|
|
1176
|
+
static #adTooltipIdCounter = 0;
|
|
1177
|
+
#adTooltipId = `ad-tooltip-${++ElementsTreeElement.#adTooltipIdCounter}`;
|
|
1178
|
+
|
|
1105
1179
|
#updateRecord: Elements.ElementUpdateRecord.ElementUpdateRecord|null = null;
|
|
1106
1180
|
|
|
1107
1181
|
// Used to add the content to TreeElement's title element.
|
|
@@ -1230,7 +1304,9 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1230
1304
|
onExpand: () => this.expand(),
|
|
1231
1305
|
|
|
1232
1306
|
containerAdornerActive: this.#containerAdornerActive,
|
|
1233
|
-
|
|
1307
|
+
adProvenance: this.nodeInternal.adProvenance(),
|
|
1308
|
+
adTooltipId: this.#adTooltipId,
|
|
1309
|
+
target: this.nodeInternal.domModel().target(),
|
|
1234
1310
|
showContainerAdorner: Boolean(this.#layout?.containerType) && !this.isClosingTag(),
|
|
1235
1311
|
containerType: this.#layout?.containerType,
|
|
1236
1312
|
showFlexAdorner: Boolean(this.#layout?.isFlex) && !this.isClosingTag(),
|
|
@@ -1565,7 +1641,9 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1565
1641
|
onHighlightSearchResults: () => {},
|
|
1566
1642
|
onExpand: () => {},
|
|
1567
1643
|
containerAdornerActive: false,
|
|
1568
|
-
|
|
1644
|
+
adProvenance: undefined,
|
|
1645
|
+
target: undefined,
|
|
1646
|
+
adTooltipId: '',
|
|
1569
1647
|
showContainerAdorner: false,
|
|
1570
1648
|
containerType: this.#layout?.containerType,
|
|
1571
1649
|
showFlexAdorner: false,
|
|
@@ -16,6 +16,18 @@ export class StylesAiCodeCompletionProvider {
|
|
|
16
16
|
#aiCodeCompletion?: AiCodeCompletion.AiCodeCompletion.AiCodeCompletion;
|
|
17
17
|
#aiCodeCompletionConfig?: TextEditor.AiCodeCompletionProvider.AiCodeCompletionConfig;
|
|
18
18
|
|
|
19
|
+
getCompletionHint?: () => string | null;
|
|
20
|
+
setAiAutoCompletion?: (args: {
|
|
21
|
+
text: string,
|
|
22
|
+
from: number,
|
|
23
|
+
startTime: number,
|
|
24
|
+
onImpression: (rpcGlobalId: Host.AidaClient.RpcGlobalId, latency: number, sampleId?: number) => void,
|
|
25
|
+
clearCachedRequest: () => void,
|
|
26
|
+
citations: Host.AidaClient.Citation[],
|
|
27
|
+
rpcGlobalId?: Host.AidaClient.RpcGlobalId,
|
|
28
|
+
sampleId?: number,
|
|
29
|
+
}|null) => void;
|
|
30
|
+
|
|
19
31
|
#boundOnUpdateAiCodeCompletionState = this.#updateAiCodeCompletionState.bind(this);
|
|
20
32
|
|
|
21
33
|
private constructor(aiCodeCompletionConfig: TextEditor.AiCodeCompletionProvider.AiCodeCompletionConfig) {
|
|
@@ -123,7 +135,7 @@ export class StylesAiCodeCompletionProvider {
|
|
|
123
135
|
return;
|
|
124
136
|
}
|
|
125
137
|
|
|
126
|
-
this
|
|
138
|
+
this.setAiAutoCompletion?.({
|
|
127
139
|
text: currentPropertyString + aidaSuggestion.suggestionText,
|
|
128
140
|
from: cursorPosition,
|
|
129
141
|
rpcGlobalId: aidaSuggestion.rpcGlobalId,
|
|
@@ -131,6 +143,7 @@ export class StylesAiCodeCompletionProvider {
|
|
|
131
143
|
startTime,
|
|
132
144
|
clearCachedRequest: this.clearCache.bind(this),
|
|
133
145
|
onImpression: this.#aiCodeCompletion.registerUserImpression.bind(this.#aiCodeCompletion),
|
|
146
|
+
citations: aidaSuggestion.citations,
|
|
134
147
|
});
|
|
135
148
|
}
|
|
136
149
|
|
|
@@ -206,7 +219,7 @@ export class StylesAiCodeCompletionProvider {
|
|
|
206
219
|
return null;
|
|
207
220
|
}
|
|
208
221
|
|
|
209
|
-
const completionHint = this
|
|
222
|
+
const completionHint = this.getCompletionHint?.();
|
|
210
223
|
if (!completionHint) {
|
|
211
224
|
return response.generatedSamples[0];
|
|
212
225
|
}
|
|
@@ -216,4 +229,12 @@ export class StylesAiCodeCompletionProvider {
|
|
|
216
229
|
clearCache(): void {
|
|
217
230
|
this.#aiCodeCompletion?.clearCachedRequest();
|
|
218
231
|
}
|
|
232
|
+
|
|
233
|
+
onSuggestionAccepted(
|
|
234
|
+
citations: Host.AidaClient.Citation[], rpcGlobalId?: Host.AidaClient.RpcGlobalId, sampleId?: number): void {
|
|
235
|
+
this.#aiCodeCompletionConfig?.onSuggestionAccepted(citations);
|
|
236
|
+
if (rpcGlobalId) {
|
|
237
|
+
this.#aiCodeCompletion?.registerUserAcceptance(rpcGlobalId, sampleId);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
219
240
|
}
|
|
@@ -169,6 +169,10 @@ const HIGHLIGHTABLE_PROPERTIES = [
|
|
|
169
169
|
{mode: 'flexibility', properties: ['flex', 'flex-basis', 'flex-grow', 'flex-shrink']},
|
|
170
170
|
];
|
|
171
171
|
|
|
172
|
+
const DISCLAIMER_TOOLTIP_ID = 'styles-ai-code-completion-disclaimer-tooltip';
|
|
173
|
+
const SPINNER_TOOLTIP_ID = 'styles-ai-code-completion-spinner-tooltip';
|
|
174
|
+
const CITATIONS_TOOLTIP_ID = 'styles-ai-code-completion-citations-tooltip';
|
|
175
|
+
|
|
172
176
|
export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventTypes, typeof ElementsSidebarPane>(
|
|
173
177
|
ElementsSidebarPane) implements StylesContainer {
|
|
174
178
|
private matchedStyles: SDK.CSSMatchedStyles.CSSMatchedStyles|null = null;
|
|
@@ -214,6 +218,11 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
|
|
|
214
218
|
#updateAbortController?: AbortController;
|
|
215
219
|
#updateComputedStylesAbortController?: AbortController;
|
|
216
220
|
|
|
221
|
+
aiCodeCompletionConfig?: TextEditor.AiCodeCompletionProvider.AiCodeCompletionConfig;
|
|
222
|
+
aiCodeCompletionProvider?: StylesAiCodeCompletionProvider.StylesAiCodeCompletionProvider;
|
|
223
|
+
#aiCodeCompletionSummaryToolbarContainer?: HTMLElement;
|
|
224
|
+
#aiCodeCompletionSummaryToolbar?: PanelsCommon.AiCodeCompletionSummaryToolbar;
|
|
225
|
+
|
|
217
226
|
constructor(computedStyleModel: ComputedStyle.ComputedStyleModel.ComputedStyleModel) {
|
|
218
227
|
super(computedStyleModel, {delegatesFocus: true});
|
|
219
228
|
this.setMinimumSize(96, 26);
|
|
@@ -259,6 +268,26 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
|
|
|
259
268
|
this.#scheduleResetUpdateIfNotEditing();
|
|
260
269
|
}
|
|
261
270
|
});
|
|
271
|
+
|
|
272
|
+
const devtoolsLocale = i18n.DevToolsLocale.DevToolsLocale.instance();
|
|
273
|
+
if (AiCodeCompletion.AiCodeCompletion.AiCodeCompletion.isAiCodeCompletionStylesEnabled(devtoolsLocale.locale)) {
|
|
274
|
+
this.aiCodeCompletionConfig = {
|
|
275
|
+
completionContext: {},
|
|
276
|
+
generationContext: {},
|
|
277
|
+
onFeatureEnabled: () => {
|
|
278
|
+
this.#createAiCodeCompletionSummaryToolbar();
|
|
279
|
+
},
|
|
280
|
+
onFeatureDisabled: () => {
|
|
281
|
+
this.#cleanupAiCodeCompletion();
|
|
282
|
+
},
|
|
283
|
+
onSuggestionAccepted: this.#onAiCodeCompletionSuggestionAccepted.bind(this),
|
|
284
|
+
onRequestTriggered: this.#onAiCodeCompletionRequestTriggered.bind(this),
|
|
285
|
+
onResponseReceived: this.#onAiCodeCompletionResponseReceived.bind(this),
|
|
286
|
+
panel: AiCodeCompletion.AiCodeCompletion.ContextFlavor.STYLES,
|
|
287
|
+
};
|
|
288
|
+
this.aiCodeCompletionProvider =
|
|
289
|
+
StylesAiCodeCompletionProvider.StylesAiCodeCompletionProvider.createInstance(this.aiCodeCompletionConfig);
|
|
290
|
+
}
|
|
262
291
|
}
|
|
263
292
|
|
|
264
293
|
get webCustomData(): WebCustomData|undefined {
|
|
@@ -1528,6 +1557,45 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
|
|
|
1528
1557
|
|
|
1529
1558
|
return button;
|
|
1530
1559
|
}
|
|
1560
|
+
|
|
1561
|
+
#cleanupAiCodeCompletion(): void {
|
|
1562
|
+
this.#aiCodeCompletionSummaryToolbarContainer?.remove();
|
|
1563
|
+
this.#aiCodeCompletionSummaryToolbarContainer = undefined;
|
|
1564
|
+
this.#aiCodeCompletionSummaryToolbar = undefined;
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
#createAiCodeCompletionSummaryToolbar(): void {
|
|
1568
|
+
if (this.#aiCodeCompletionSummaryToolbar) {
|
|
1569
|
+
return;
|
|
1570
|
+
}
|
|
1571
|
+
this.#aiCodeCompletionSummaryToolbar = new PanelsCommon.AiCodeCompletionSummaryToolbar({
|
|
1572
|
+
citationsTooltipId: CITATIONS_TOOLTIP_ID,
|
|
1573
|
+
disclaimerTooltipId: DISCLAIMER_TOOLTIP_ID,
|
|
1574
|
+
spinnerTooltipId: SPINNER_TOOLTIP_ID,
|
|
1575
|
+
panel: AiCodeCompletion.AiCodeCompletion.ContextFlavor.STYLES,
|
|
1576
|
+
});
|
|
1577
|
+
const containingPane = this.contentElement.enclosingNodeOrSelfWithClass('style-panes-wrapper') as HTMLElement;
|
|
1578
|
+
this.#aiCodeCompletionSummaryToolbarContainer =
|
|
1579
|
+
containingPane.createChild('div', 'ai-code-completion-summary-toolbar-container');
|
|
1580
|
+
this.#aiCodeCompletionSummaryToolbarContainer.role = 'toolbar';
|
|
1581
|
+
this.#aiCodeCompletionSummaryToolbar.show(this.#aiCodeCompletionSummaryToolbarContainer, undefined, true);
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
#onAiCodeCompletionSuggestionAccepted(citations: Host.AidaClient.Citation[]): void {
|
|
1585
|
+
if (!this.#aiCodeCompletionSummaryToolbar || citations.length === 0) {
|
|
1586
|
+
return;
|
|
1587
|
+
}
|
|
1588
|
+
const citationsUri = citations.map(citation => citation.uri).filter((uri): uri is string => Boolean(uri));
|
|
1589
|
+
this.#aiCodeCompletionSummaryToolbar.updateCitations(citationsUri);
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
#onAiCodeCompletionRequestTriggered(): void {
|
|
1593
|
+
this.#aiCodeCompletionSummaryToolbar?.setLoading(true);
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
#onAiCodeCompletionResponseReceived(): void {
|
|
1597
|
+
this.#aiCodeCompletionSummaryToolbar?.setLoading(false);
|
|
1598
|
+
}
|
|
1531
1599
|
}
|
|
1532
1600
|
|
|
1533
1601
|
export const enum Events {
|
|
@@ -1757,8 +1825,9 @@ export class CSSPropertyPrompt extends UI.TextPrompt.TextPrompt {
|
|
|
1757
1825
|
private treeElement: StylePropertyTreeElement;
|
|
1758
1826
|
private isEditingName: boolean;
|
|
1759
1827
|
private readonly cssVariables: string[];
|
|
1760
|
-
aiCodeCompletionConfig?: TextEditor.AiCodeCompletionProvider.AiCodeCompletionConfig;
|
|
1761
1828
|
aiCodeCompletionProvider?: StylesAiCodeCompletionProvider.StylesAiCodeCompletionProvider;
|
|
1829
|
+
private activeAiSuggestionInfo?:
|
|
1830
|
+
{citations: Host.AidaClient.Citation[], rpcGlobalId?: Host.AidaClient.RpcGlobalId, sampleId?: number};
|
|
1762
1831
|
|
|
1763
1832
|
#debouncedTriggerAiCodeCompletion = Common.Debouncer.debounce(() => {
|
|
1764
1833
|
void this.triggerAiCodeCompletion();
|
|
@@ -1822,25 +1891,13 @@ export class CSSPropertyPrompt extends UI.TextPrompt.TextPrompt {
|
|
|
1822
1891
|
}
|
|
1823
1892
|
}
|
|
1824
1893
|
|
|
1825
|
-
const
|
|
1826
|
-
if (
|
|
1827
|
-
this.
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
onSuggestionAccepted: () => {},
|
|
1833
|
-
onRequestTriggered: () => {},
|
|
1834
|
-
onResponseReceived: () => {},
|
|
1835
|
-
panel: AiCodeCompletion.AiCodeCompletion.ContextFlavor.STYLES,
|
|
1836
|
-
getCompletionHint: this.getCompletionHint.bind(this),
|
|
1837
|
-
getCurrentText: () => {
|
|
1838
|
-
return this.text();
|
|
1839
|
-
},
|
|
1840
|
-
setAiAutoCompletion: this.setAiAutoCompletion.bind(this),
|
|
1841
|
-
};
|
|
1842
|
-
this.aiCodeCompletionProvider =
|
|
1843
|
-
StylesAiCodeCompletionProvider.StylesAiCodeCompletionProvider.createInstance(this.aiCodeCompletionConfig);
|
|
1894
|
+
const stylesContainer = this.treeElement.stylesContainer();
|
|
1895
|
+
if (stylesContainer instanceof StylesSidebarPane) {
|
|
1896
|
+
this.aiCodeCompletionProvider = stylesContainer.aiCodeCompletionProvider;
|
|
1897
|
+
if (this.aiCodeCompletionProvider) {
|
|
1898
|
+
this.aiCodeCompletionProvider.getCompletionHint = this.getCompletionHint.bind(this);
|
|
1899
|
+
this.aiCodeCompletionProvider.setAiAutoCompletion = this.setAiAutoCompletion.bind(this);
|
|
1900
|
+
}
|
|
1844
1901
|
}
|
|
1845
1902
|
}
|
|
1846
1903
|
|
|
@@ -2192,11 +2249,13 @@ export class CSSPropertyPrompt extends UI.TextPrompt.TextPrompt {
|
|
|
2192
2249
|
startTime: number,
|
|
2193
2250
|
onImpression: (rpcGlobalId: Host.AidaClient.RpcGlobalId, latency: number, sampleId?: number) => void,
|
|
2194
2251
|
clearCachedRequest: () => void,
|
|
2252
|
+
citations: Host.AidaClient.Citation[],
|
|
2195
2253
|
rpcGlobalId?: Host.AidaClient.RpcGlobalId,
|
|
2196
2254
|
sampleId?: number,
|
|
2197
2255
|
}|null): void {
|
|
2198
2256
|
if (!args) {
|
|
2199
2257
|
this.treeElement.section().activeAiSuggestion = undefined;
|
|
2258
|
+
this.activeAiSuggestionInfo = undefined;
|
|
2200
2259
|
return;
|
|
2201
2260
|
}
|
|
2202
2261
|
|
|
@@ -2207,6 +2266,7 @@ export class CSSPropertyPrompt extends UI.TextPrompt.TextPrompt {
|
|
|
2207
2266
|
clearCachedRequest: args.clearCachedRequest,
|
|
2208
2267
|
cssProperty: this.treeElement.property,
|
|
2209
2268
|
};
|
|
2269
|
+
this.activeAiSuggestionInfo = {citations: args.citations, rpcGlobalId: args.rpcGlobalId, sampleId: args.sampleId};
|
|
2210
2270
|
const latency = performance.now() - args.startTime;
|
|
2211
2271
|
if (args.rpcGlobalId) {
|
|
2212
2272
|
args.onImpression(args.rpcGlobalId, latency, args.sampleId);
|
|
@@ -2305,6 +2365,11 @@ export class CSSPropertyPrompt extends UI.TextPrompt.TextPrompt {
|
|
|
2305
2365
|
|
|
2306
2366
|
async commitAiSuggestion(): Promise<void> {
|
|
2307
2367
|
await this.treeElement.section().commitActiveAiSuggestion();
|
|
2368
|
+
if (this.activeAiSuggestionInfo) {
|
|
2369
|
+
this.aiCodeCompletionProvider?.onSuggestionAccepted(
|
|
2370
|
+
this.activeAiSuggestionInfo.citations, this.activeAiSuggestionInfo.rpcGlobalId,
|
|
2371
|
+
this.activeAiSuggestionInfo.sampleId);
|
|
2372
|
+
}
|
|
2308
2373
|
// Clear state and return
|
|
2309
2374
|
this.setAiAutoCompletion(null);
|
|
2310
2375
|
}
|
|
@@ -47,6 +47,20 @@
|
|
|
47
47
|
border-bottom: 1px solid var(--sys-color-divider);
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
.style-panes-wrapper > div:has(+ .ai-code-completion-summary-toolbar-container) {
|
|
51
|
+
border-bottom: 0;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.style-panes-wrapper .ai-code-completion-summary-toolbar-container {
|
|
55
|
+
container-type: inline-size;
|
|
56
|
+
flex-shrink: 0;
|
|
57
|
+
overflow: hidden;
|
|
58
|
+
position: fixed;
|
|
59
|
+
bottom: 0;
|
|
60
|
+
background-color: var(--sys-color-cdt-base-container);
|
|
61
|
+
width: 100%;
|
|
62
|
+
}
|
|
63
|
+
|
|
50
64
|
#elements-content:not(.elements-wrap) > div {
|
|
51
65
|
display: inline-block;
|
|
52
66
|
min-width: 100%;
|
|
@@ -384,3 +384,21 @@ li.hovered:not(.always-parent) + ol.children:not(.shadow-root) {
|
|
|
384
384
|
background-position: bottom;
|
|
385
385
|
padding-bottom: 1px;
|
|
386
386
|
}
|
|
387
|
+
|
|
388
|
+
/* Ad Provenance Tooltip */
|
|
389
|
+
.ad-provenance-tooltip {
|
|
390
|
+
user-select: text;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
.ad-provenance-tooltip-title {
|
|
394
|
+
color: var(--sys-color-on-surface-subtle);
|
|
395
|
+
margin-top: 4px;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
.ad-provenance-tooltip-title:first-child {
|
|
399
|
+
margin-top: 0;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
.ad-provenance-tooltip-content {
|
|
403
|
+
padding-left: 16px;
|
|
404
|
+
}
|
|
@@ -236,13 +236,13 @@ export class NetworkLogViewColumns {
|
|
|
236
236
|
const title = columnConfig.title instanceof Function ? columnConfig.title() : columnConfig.title;
|
|
237
237
|
return {
|
|
238
238
|
id: columnConfig.id,
|
|
239
|
-
title,
|
|
239
|
+
title: title as Common.UIString.LocalizedString,
|
|
240
240
|
sortable: columnConfig.sortable,
|
|
241
241
|
align: columnConfig.align,
|
|
242
242
|
nonSelectable: columnConfig.nonSelectable,
|
|
243
243
|
weight: columnConfig.weight,
|
|
244
244
|
allowInSortByEvenWhenHidden: columnConfig.allowInSortByEvenWhenHidden,
|
|
245
|
-
}
|
|
245
|
+
};
|
|
246
246
|
}
|
|
247
247
|
|
|
248
248
|
wasShown(): void {
|
|
@@ -1251,7 +1251,7 @@ export interface Descriptor {
|
|
|
1251
1251
|
hideableGroup: string|null;
|
|
1252
1252
|
nonSelectable: boolean;
|
|
1253
1253
|
sortable: boolean;
|
|
1254
|
-
align?:
|
|
1254
|
+
align?: DataGrid.DataGrid.Align|null;
|
|
1255
1255
|
isResponseHeader: boolean;
|
|
1256
1256
|
isRequestHeader: boolean;
|
|
1257
1257
|
sortingFunction: (arg0: NetworkNode, arg1: NetworkNode) => number | undefined;
|