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
|
@@ -379,12 +379,6 @@ interface ToolbarViewInput {
|
|
|
379
379
|
showChatActions: boolean;
|
|
380
380
|
showActiveConversationActions: boolean;
|
|
381
381
|
isLoading: boolean;
|
|
382
|
-
|
|
383
|
-
walkthrough: {
|
|
384
|
-
isExpanded: boolean,
|
|
385
|
-
isInlined: boolean,
|
|
386
|
-
onToggle: (isOpen: boolean) => void,
|
|
387
|
-
};
|
|
388
382
|
}
|
|
389
383
|
|
|
390
384
|
export const enum ViewState {
|
|
@@ -512,7 +506,7 @@ function defaultView(input: ViewInput, output: PanelViewOutput, target: HTMLElem
|
|
|
512
506
|
if (Root.Runtime.hostConfig.devToolsAiAssistanceV2?.enabled ||
|
|
513
507
|
Greendev.Prototypes.instance().isEnabled('breakpointDebuggerAgent')) {
|
|
514
508
|
|
|
515
|
-
const shouldShowWalkthrough = input.state === ViewState.CHAT_VIEW && input.walkthrough.isExpanded;
|
|
509
|
+
const shouldShowWalkthrough = input.state === ViewState.CHAT_VIEW && input.props.walkthrough.isExpanded;
|
|
516
510
|
/**
|
|
517
511
|
* We want to mark the walkthrough as loading only if it's showing the last
|
|
518
512
|
* message. Otherwise, a previous walkthrough will show as loading if we
|
|
@@ -521,7 +515,7 @@ function defaultView(input: ViewInput, output: PanelViewOutput, target: HTMLElem
|
|
|
521
515
|
let walkthroughIsForLastMessage = false;
|
|
522
516
|
if(input.state === ViewState.CHAT_VIEW) {
|
|
523
517
|
const lastMessage = input.props.messages.at(-1);
|
|
524
|
-
if(lastMessage && input.props.walkthrough.
|
|
518
|
+
if(lastMessage && input.props.walkthrough.activeSidebarMessage === lastMessage) {
|
|
525
519
|
walkthroughIsForLastMessage = true;
|
|
526
520
|
}
|
|
527
521
|
}
|
|
@@ -533,7 +527,7 @@ function defaultView(input: ViewInput, output: PanelViewOutput, target: HTMLElem
|
|
|
533
527
|
name="ai-assistance-split-view-state"
|
|
534
528
|
direction="column"
|
|
535
529
|
sidebar-position="second"
|
|
536
|
-
sidebar-visibility=${shouldShowWalkthrough && !input.walkthrough.isInlined ? 'visible' : 'hidden'}
|
|
530
|
+
sidebar-visibility=${shouldShowWalkthrough && !input.props.walkthrough.isInlined ? 'visible' : 'hidden'}
|
|
537
531
|
sidebar-initial-size=${WALKTHROUGH_SIDEBAR_INITIAL_WIDTH}
|
|
538
532
|
>
|
|
539
533
|
<div slot="main" class="main-view">
|
|
@@ -542,7 +536,7 @@ function defaultView(input: ViewInput, output: PanelViewOutput, target: HTMLElem
|
|
|
542
536
|
<div slot="sidebar" class="sidebar-view">
|
|
543
537
|
${shouldShowWalkthrough ? html`
|
|
544
538
|
<devtools-widget ${widget(WalkthroughView, {
|
|
545
|
-
message: input.props.walkthrough.
|
|
539
|
+
message: input.props.walkthrough.activeSidebarMessage,
|
|
546
540
|
isLoading: input.props.isLoading && walkthroughIsForLastMessage,
|
|
547
541
|
markdownRenderer: input.props.markdownRenderer,
|
|
548
542
|
onToggle: input.props.walkthrough.onToggle,
|
|
@@ -610,10 +604,15 @@ function createPerformanceTraceContext(focus: AiAssistanceModel.AIContext.AgentF
|
|
|
610
604
|
|
|
611
605
|
/**
|
|
612
606
|
* State relating to the visibility of the Walkthrough.
|
|
613
|
-
*
|
|
614
|
-
*
|
|
615
|
-
*
|
|
616
|
-
*
|
|
607
|
+
*
|
|
608
|
+
* We track both an `activeSidebarMessage` and a list of `inlineExpandedMessages` because:
|
|
609
|
+
* 1. In Narrow (inline) mode, multiple walkthroughs can be expanded at once,
|
|
610
|
+
* so we need to track them all to render them correctly in the chat.
|
|
611
|
+
* 2. In Wide (sidebar) mode, only one walkthrough can be visible at a time.
|
|
612
|
+
* The `activeSidebarMessage` tracks which one is shown in the sidebar.
|
|
613
|
+
* 3. When transitioning from Narrow to Wide, we use the last message in
|
|
614
|
+
* `inlineExpandedMessages` to determine which one should stay expanded
|
|
615
|
+
* in the sidebar.
|
|
617
616
|
*/
|
|
618
617
|
interface WalkthroughState {
|
|
619
618
|
/**
|
|
@@ -625,11 +624,15 @@ interface WalkthroughState {
|
|
|
625
624
|
*/
|
|
626
625
|
isExpanded: boolean;
|
|
627
626
|
/**
|
|
628
|
-
* The message that the walkthrough is showing all the steps for.
|
|
629
|
-
*
|
|
630
|
-
*
|
|
627
|
+
* The message that the walkthrough is showing all the steps for. In Wide mode,
|
|
628
|
+
* this is the message shown in the sidebar. In Narrow mode, it tracks the
|
|
629
|
+
* most recently interacted message.
|
|
630
|
+
*/
|
|
631
|
+
activeSidebarMessage: ModelChatMessage|null;
|
|
632
|
+
/**
|
|
633
|
+
* Tracks which messages are expanded in inline mode.
|
|
631
634
|
*/
|
|
632
|
-
|
|
635
|
+
inlineExpandedMessages: ModelChatMessage[];
|
|
633
636
|
}
|
|
634
637
|
|
|
635
638
|
let panelInstance: AiAssistancePanel;
|
|
@@ -667,7 +670,8 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
667
670
|
#walkthrough: WalkthroughState = {
|
|
668
671
|
isInlined: false,
|
|
669
672
|
isExpanded: false,
|
|
670
|
-
|
|
673
|
+
activeSidebarMessage: null,
|
|
674
|
+
inlineExpandedMessages: [],
|
|
671
675
|
};
|
|
672
676
|
|
|
673
677
|
constructor(private view: View = defaultView, {aidaClient, aidaAvailability}: {
|
|
@@ -704,11 +708,6 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
704
708
|
onSettingsClick: () => {
|
|
705
709
|
void UI.ViewManager.ViewManager.instance().showView('chrome-ai');
|
|
706
710
|
},
|
|
707
|
-
walkthrough: {
|
|
708
|
-
isExpanded: this.#walkthrough.isExpanded,
|
|
709
|
-
isInlined: this.#walkthrough.isInlined,
|
|
710
|
-
onToggle: this.#toggleWalkthrough.bind(this),
|
|
711
|
-
}
|
|
712
711
|
};
|
|
713
712
|
}
|
|
714
713
|
|
|
@@ -796,7 +795,8 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
796
795
|
onOpen: this.#openWalkthrough.bind(this),
|
|
797
796
|
isExpanded: this.#walkthrough.isExpanded,
|
|
798
797
|
isInlined: this.#walkthrough.isInlined,
|
|
799
|
-
|
|
798
|
+
activeSidebarMessage: this.#walkthrough.activeSidebarMessage,
|
|
799
|
+
inlineExpandedMessages: this.#walkthrough.inlineExpandedMessages,
|
|
800
800
|
},
|
|
801
801
|
}
|
|
802
802
|
};
|
|
@@ -820,20 +820,73 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
820
820
|
if (isNarrow === this.#walkthrough.isInlined) {
|
|
821
821
|
return;
|
|
822
822
|
}
|
|
823
|
-
|
|
824
|
-
this.#resetWalkthrough();
|
|
823
|
+
|
|
825
824
|
this.#walkthrough.isInlined = isNarrow;
|
|
825
|
+
|
|
826
|
+
if (!this.#walkthrough.isExpanded) {
|
|
827
|
+
// If nothing was expanded, we just ensure the state is clean.
|
|
828
|
+
this.#walkthrough.activeSidebarMessage = null;
|
|
829
|
+
this.#walkthrough.inlineExpandedMessages = [];
|
|
830
|
+
this.requestUpdate();
|
|
831
|
+
return;
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
if (isNarrow) {
|
|
835
|
+
// Wide -> Inline: the walkthrough that was open stays expanded
|
|
836
|
+
this.#walkthrough.inlineExpandedMessages =
|
|
837
|
+
this.#walkthrough.activeSidebarMessage ? [this.#walkthrough.activeSidebarMessage] : [];
|
|
838
|
+
} else {
|
|
839
|
+
// Inline -> Wide: the last walkthrough that the user opened stays expanded
|
|
840
|
+
this.#walkthrough.activeSidebarMessage = this.#walkthrough.inlineExpandedMessages.at(-1) ?? null;
|
|
841
|
+
}
|
|
842
|
+
|
|
826
843
|
this.requestUpdate();
|
|
827
844
|
}
|
|
828
845
|
|
|
829
846
|
#openWalkthrough(message: ModelChatMessage): void {
|
|
830
|
-
this.#walkthrough.
|
|
847
|
+
if (!this.#walkthrough.inlineExpandedMessages.includes(message)) {
|
|
848
|
+
this.#walkthrough.inlineExpandedMessages.push(message);
|
|
849
|
+
}
|
|
850
|
+
this.#walkthrough.activeSidebarMessage = message;
|
|
831
851
|
this.#walkthrough.isExpanded = true;
|
|
832
852
|
this.requestUpdate();
|
|
833
853
|
}
|
|
834
854
|
|
|
835
|
-
|
|
836
|
-
|
|
855
|
+
/**
|
|
856
|
+
* Toggles the expanded state of a walkthrough.
|
|
857
|
+
*
|
|
858
|
+
* In Wide (sidebar) mode:
|
|
859
|
+
* - Opening a message's walkthrough shows the sidebar for that message.
|
|
860
|
+
* - Closing the sidebar hides the walkthrough for the currently active message.
|
|
861
|
+
*
|
|
862
|
+
* In Narrow (inline) mode:
|
|
863
|
+
* - Any number of walkthroughs can be open at once.
|
|
864
|
+
* - Opening/closing a message's walkthrough only affects that message's inline display.
|
|
865
|
+
*/
|
|
866
|
+
#toggleWalkthrough(isOpen: boolean, message: ModelChatMessage): void {
|
|
867
|
+
if (isOpen) { // If we are opening a walkthrough, ensure it's in our list of expanded messages.
|
|
868
|
+
this.#openWalkthrough(message);
|
|
869
|
+
return;
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
// If we are closing a walkthrough, remove it from the list of expanded messages.
|
|
873
|
+
this.#walkthrough.inlineExpandedMessages = this.#walkthrough.inlineExpandedMessages.filter(m => m !== message);
|
|
874
|
+
|
|
875
|
+
if (this.#walkthrough.isInlined) {
|
|
876
|
+
// In Narrow mode, the global expanded state tracks if at least one walkthrough is open.
|
|
877
|
+
this.#walkthrough.isExpanded = this.#walkthrough.inlineExpandedMessages.length > 0;
|
|
878
|
+
// If the message we just closed was the active one, we pick a new active message
|
|
879
|
+
// from the remaining open ones (if any). This ensures that if the user
|
|
880
|
+
// re-opens the sidebar later, it shows the most recently opened walkthrough.
|
|
881
|
+
if (this.#walkthrough.activeSidebarMessage === message) {
|
|
882
|
+
this.#walkthrough.activeSidebarMessage = this.#walkthrough.inlineExpandedMessages.at(-1) ?? null;
|
|
883
|
+
}
|
|
884
|
+
} else {
|
|
885
|
+
// In Wide mode, closing the sidebar means we are no longer expanded globally.
|
|
886
|
+
this.#walkthrough.isExpanded = false;
|
|
887
|
+
this.#walkthrough.activeSidebarMessage = null;
|
|
888
|
+
}
|
|
889
|
+
|
|
837
890
|
this.requestUpdate();
|
|
838
891
|
}
|
|
839
892
|
|
|
@@ -1565,7 +1618,8 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
1565
1618
|
|
|
1566
1619
|
#resetWalkthrough(): void {
|
|
1567
1620
|
this.#walkthrough.isExpanded = false;
|
|
1568
|
-
this.#walkthrough.
|
|
1621
|
+
this.#walkthrough.activeSidebarMessage = null;
|
|
1622
|
+
this.#walkthrough.inlineExpandedMessages = [];
|
|
1569
1623
|
}
|
|
1570
1624
|
|
|
1571
1625
|
#onDeleteClicked(): void {
|
|
@@ -36,7 +36,7 @@ import * as TimelineUtils from '../../timeline/utils/utils.js';
|
|
|
36
36
|
import {PanelUtils} from '../../utils/utils.js';
|
|
37
37
|
|
|
38
38
|
import chatMessageStyles from './chatMessage.css.js';
|
|
39
|
-
import {walkthroughTitle, WalkthroughView} from './WalkthroughView.js';
|
|
39
|
+
import {walkthroughCloseTitle, walkthroughTitle, WalkthroughView} from './WalkthroughView.js';
|
|
40
40
|
|
|
41
41
|
const {html, Directives: {ref, ifDefined}} = Lit;
|
|
42
42
|
const lockedString = i18n.i18n.lockedString;
|
|
@@ -49,10 +49,6 @@ const SCROLL_ROUNDING_OFFSET = 1;
|
|
|
49
49
|
* Strings that don't need to be translated at this time.
|
|
50
50
|
*/
|
|
51
51
|
const UIStringsNotTranslate = {
|
|
52
|
-
/**
|
|
53
|
-
* @description Text used in the button to close an open walkthrough
|
|
54
|
-
*/
|
|
55
|
-
closeAgentWalkthrough: 'Close agent walkthrough',
|
|
56
52
|
/**
|
|
57
53
|
* @description The title of the button that allows submitting positive
|
|
58
54
|
* feedback about the response for AI assistance.
|
|
@@ -174,11 +170,6 @@ const UIStringsNotTranslate = {
|
|
|
174
170
|
* @description Alt text for image when it is not available.
|
|
175
171
|
*/
|
|
176
172
|
imageUnavailable: 'Image unavailable',
|
|
177
|
-
/**
|
|
178
|
-
* @description Title for the button that shows the thinking process (walkthrough).
|
|
179
|
-
*/
|
|
180
|
-
showThinking: 'Show thinking',
|
|
181
|
-
|
|
182
173
|
/**
|
|
183
174
|
* @description Title for the button that takes the user into other DevTools panels to reveal items the AI references.
|
|
184
175
|
*/
|
|
@@ -310,9 +301,10 @@ export interface MessageInput {
|
|
|
310
301
|
walkthrough: {
|
|
311
302
|
onOpen: (message: ModelChatMessage) => void,
|
|
312
303
|
isExpanded: boolean,
|
|
313
|
-
onToggle: (isOpen: boolean) => void,
|
|
304
|
+
onToggle: (isOpen: boolean, message: ModelChatMessage) => void,
|
|
314
305
|
isInlined: boolean,
|
|
315
|
-
|
|
306
|
+
activeSidebarMessage: ModelChatMessage|null,
|
|
307
|
+
inlineExpandedMessages: ModelChatMessage[],
|
|
316
308
|
};
|
|
317
309
|
}
|
|
318
310
|
|
|
@@ -350,12 +342,13 @@ export const DEFAULT_VIEW = (input: ChatMessageViewInput, output: ViewOutput, ta
|
|
|
350
342
|
class="chat-message answer ${input.isLastMessage ? 'is-last-message' : ''}"
|
|
351
343
|
jslog=${VisualLogging.section('answer')}
|
|
352
344
|
>
|
|
353
|
-
|
|
354
|
-
<
|
|
355
|
-
|
|
356
|
-
<
|
|
357
|
-
|
|
358
|
-
|
|
345
|
+
${aiAssistanceV2 ? Lit.nothing : html`
|
|
346
|
+
<div class="message-info">
|
|
347
|
+
<devtools-icon name=${icon}></devtools-icon>
|
|
348
|
+
<div class="message-name">
|
|
349
|
+
<h2>${AiAssistanceModel.AiUtils.isGeminiBranding() ? lockedString(UIStringsNotTranslate.gemini) : lockedString(UIStringsNotTranslate.ai)}</h2>
|
|
350
|
+
</div>
|
|
351
|
+
</div>`}
|
|
359
352
|
${aiAssistanceV2 ? renderWalkthroughUI(input, steps) : Lit.nothing}
|
|
360
353
|
${Lit.Directives.repeat(
|
|
361
354
|
message.parts,
|
|
@@ -516,9 +509,8 @@ function renderWalkthroughSidebarButton(
|
|
|
516
509
|
}
|
|
517
510
|
|
|
518
511
|
const hasOneStepWithWidget = steps.some(step => step.widgets?.length);
|
|
519
|
-
const
|
|
520
|
-
|
|
521
|
-
const title = isOpen ? lockedString(UIStringsNotTranslate.closeAgentWalkthrough) : walkthroughTitle({
|
|
512
|
+
const isExpanded = walkthrough.isExpanded && input.message === input.walkthrough.activeSidebarMessage;
|
|
513
|
+
const title = isExpanded ? walkthroughCloseTitle({hasWidgets: hasOneStepWithWidget}) : walkthroughTitle({
|
|
522
514
|
isLoading: input.isLoading,
|
|
523
515
|
hasWidgets: hasOneStepWithWidget,
|
|
524
516
|
lastStep,
|
|
@@ -528,20 +520,23 @@ function renderWalkthroughSidebarButton(
|
|
|
528
520
|
// want to change it visually at the end once everything has stopped
|
|
529
521
|
// loading.
|
|
530
522
|
const variant = hasOneStepWithWidget && !input.isLoading ? Buttons.Button.Variant.TONAL : Buttons.Button.Variant.TEXT;
|
|
523
|
+
const icon = AiAssistanceModel.AiUtils.getIconName();
|
|
531
524
|
|
|
532
525
|
// clang-format off
|
|
533
526
|
return html`
|
|
534
|
-
<div class="walkthrough-toggle-container">
|
|
535
|
-
${input.isLoading ?
|
|
527
|
+
<div class="walkthrough-toggle-container ${hasOneStepWithWidget ? 'has-widgets' : ''}">
|
|
528
|
+
${input.isLoading ?
|
|
529
|
+
html`<devtools-spinner></devtools-spinner>` :
|
|
530
|
+
html`<devtools-icon name=${icon}></devtools-icon>`}
|
|
536
531
|
<devtools-button
|
|
537
532
|
.variant=${variant}
|
|
538
533
|
.size=${Buttons.Button.Size.SMALL}
|
|
539
|
-
.title=${lastStep.isLoading ? titleForStep(lastStep) :
|
|
534
|
+
.title=${lastStep.isLoading ? titleForStep(lastStep) : title}
|
|
540
535
|
.jslogContext=${walkthrough.isExpanded ? 'ai-hide-walkthrough-sidebar' : 'ai-show-walkthrough-sidebar'}
|
|
541
536
|
data-show-walkthrough
|
|
542
537
|
@click=${() => {
|
|
543
|
-
if(walkthrough.
|
|
544
|
-
walkthrough.onToggle(false);
|
|
538
|
+
if(walkthrough.activeSidebarMessage === input.message && walkthrough.isExpanded) {
|
|
539
|
+
walkthrough.onToggle(false, message as ModelChatMessage);
|
|
545
540
|
} else {
|
|
546
541
|
// Can't just toggle the visibility here; we need to ensure we
|
|
547
542
|
// update the state with this message as the user could have had
|
|
@@ -549,8 +544,8 @@ function renderWalkthroughSidebarButton(
|
|
|
549
544
|
walkthrough.onOpen(message as ModelChatMessage);
|
|
550
545
|
}
|
|
551
546
|
}}
|
|
552
|
-
|
|
553
|
-
${title}<devtools-icon class="chevron" .name=${'chevron-right'}></devtools-icon>
|
|
547
|
+
>
|
|
548
|
+
${title}<devtools-icon class="chevron" .name=${isExpanded ? 'cross' : 'chevron-right'}></devtools-icon>
|
|
554
549
|
</devtools-button>
|
|
555
550
|
</div>
|
|
556
551
|
`;
|
|
@@ -577,7 +572,9 @@ function renderWalkthroughUI(input: ChatMessageViewInput, steps: Step[]): Lit.Li
|
|
|
577
572
|
// A message's walkthrough is considered expanded if the walkthrough is
|
|
578
573
|
// open and it is specifically targeting this message. This is necessary
|
|
579
574
|
// because the walkthrough state is shared across all messages in the chat.
|
|
580
|
-
const isExpanded =
|
|
575
|
+
const isExpanded = input.walkthrough.isInlined ?
|
|
576
|
+
input.walkthrough.inlineExpandedMessages.includes(input.message as ModelChatMessage) :
|
|
577
|
+
(input.walkthrough.isExpanded && input.walkthrough.activeSidebarMessage === input.message);
|
|
581
578
|
|
|
582
579
|
// When a side-effect step is present, it's shown in the main chat UI if the
|
|
583
580
|
// walkthrough is closed, allowing the user to approve it without opening
|
|
@@ -1238,11 +1235,12 @@ export class ChatMessage extends UI.Widget.Widget {
|
|
|
1238
1235
|
onToggle: () => {},
|
|
1239
1236
|
isInlined: false,
|
|
1240
1237
|
isExpanded: false,
|
|
1241
|
-
|
|
1238
|
+
activeSidebarMessage: null,
|
|
1239
|
+
inlineExpandedMessages: [],
|
|
1242
1240
|
};
|
|
1243
1241
|
|
|
1244
1242
|
#suggestionsResizeObserver = new ResizeObserver(() => this.#handleSuggestionsScrollOrResize());
|
|
1245
|
-
#suggestionsEvaluateLayoutThrottler = new Common.Throttler.Throttler(
|
|
1243
|
+
#suggestionsEvaluateLayoutThrottler = new Common.Throttler.Throttler(100);
|
|
1246
1244
|
|
|
1247
1245
|
#feedbackValue = '';
|
|
1248
1246
|
#currentRating: Host.AidaClient.Rating|undefined;
|
|
@@ -1252,6 +1250,8 @@ export class ChatMessage extends UI.Widget.Widget {
|
|
|
1252
1250
|
#view: View;
|
|
1253
1251
|
#viewOutput: ViewOutput = {};
|
|
1254
1252
|
|
|
1253
|
+
#isObservingSuggestions = false;
|
|
1254
|
+
|
|
1255
1255
|
constructor(element?: HTMLElement, view?: View) {
|
|
1256
1256
|
super(element);
|
|
1257
1257
|
this.#view = view ?? DEFAULT_VIEW;
|
|
@@ -1261,10 +1261,6 @@ export class ChatMessage extends UI.Widget.Widget {
|
|
|
1261
1261
|
super.wasShown();
|
|
1262
1262
|
void this.performUpdate();
|
|
1263
1263
|
this.#evaluateSuggestionsLayout();
|
|
1264
|
-
|
|
1265
|
-
if (this.#viewOutput.suggestionsScrollContainer) {
|
|
1266
|
-
this.#suggestionsResizeObserver.observe(this.#viewOutput.suggestionsScrollContainer);
|
|
1267
|
-
}
|
|
1268
1264
|
}
|
|
1269
1265
|
|
|
1270
1266
|
override performUpdate(): Promise<void>|void {
|
|
@@ -1303,6 +1299,11 @@ export class ChatMessage extends UI.Widget.Widget {
|
|
|
1303
1299
|
walkthrough: this.walkthrough,
|
|
1304
1300
|
},
|
|
1305
1301
|
this.#viewOutput, this.contentElement);
|
|
1302
|
+
|
|
1303
|
+
if (this.#viewOutput.suggestionsScrollContainer && !this.#isObservingSuggestions) {
|
|
1304
|
+
this.#suggestionsResizeObserver.observe(this.#viewOutput.suggestionsScrollContainer);
|
|
1305
|
+
this.#isObservingSuggestions = true;
|
|
1306
|
+
}
|
|
1306
1307
|
}
|
|
1307
1308
|
|
|
1308
1309
|
#handleInputChange(value: string): void {
|
|
@@ -1326,6 +1327,7 @@ export class ChatMessage extends UI.Widget.Widget {
|
|
|
1326
1327
|
const shouldShowRightButton = suggestionsScrollContainer.scrollLeft +
|
|
1327
1328
|
(suggestionsScrollContainer as HTMLElement).offsetWidth + SCROLL_ROUNDING_OFFSET <
|
|
1328
1329
|
suggestionsScrollContainer.scrollWidth;
|
|
1330
|
+
|
|
1329
1331
|
leftScrollButtonContainer.classList.toggle('hidden', !shouldShowLeftButton);
|
|
1330
1332
|
rightScrollButtonContainer.classList.toggle('hidden', !shouldShowRightButton);
|
|
1331
1333
|
};
|
|
@@ -1333,6 +1335,7 @@ export class ChatMessage extends UI.Widget.Widget {
|
|
|
1333
1335
|
override willHide(): void {
|
|
1334
1336
|
super.willHide();
|
|
1335
1337
|
this.#suggestionsResizeObserver.disconnect();
|
|
1338
|
+
this.#isObservingSuggestions = false;
|
|
1336
1339
|
}
|
|
1337
1340
|
|
|
1338
1341
|
#handleSuggestionsScrollOrResize(): void {
|
|
@@ -1416,8 +1419,8 @@ async function makeTimelineRangeSummaryWidget(widgetData: TimelineRangeSummaryAi
|
|
|
1416
1419
|
|
|
1417
1420
|
const thirdPartyTree = new Timeline.ThirdPartyTreeView.ThirdPartyTreeViewWidget();
|
|
1418
1421
|
const mapper = new Trace.EntityMapper.EntityMapper(parsedTrace);
|
|
1419
|
-
thirdPartyTree.
|
|
1420
|
-
thirdPartyTree.
|
|
1422
|
+
thirdPartyTree.model = {selectedEvents: eventsArray, parsedTrace, entityMapper: mapper};
|
|
1423
|
+
thirdPartyTree.activeSelection = Timeline.TimelineSelection.selectionFromRangeMicroSeconds(bounds.min, bounds.max);
|
|
1421
1424
|
thirdPartyTree.refreshTree(true);
|
|
1422
1425
|
|
|
1423
1426
|
// clang-format off
|
|
@@ -1429,9 +1432,16 @@ async function makeTimelineRangeSummaryWidget(widgetData: TimelineRangeSummaryAi
|
|
|
1429
1432
|
events,
|
|
1430
1433
|
startTime: Trace.Helpers.Timing.microToMilli(bounds.min),
|
|
1431
1434
|
endTime: Trace.Helpers.Timing.microToMilli(bounds.max),
|
|
1432
|
-
thirdPartyTreeTemplate: html
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
+
thirdPartyTreeTemplate: html`${
|
|
1436
|
+
widget(Timeline.ThirdPartyTreeView.ThirdPartyTreeViewWidget, {
|
|
1437
|
+
maxRows: 10,
|
|
1438
|
+
model: {
|
|
1439
|
+
selectedEvents: thirdPartyTree.selectedEvents() ?? null,
|
|
1440
|
+
parsedTrace,
|
|
1441
|
+
entityMapper: thirdPartyTree.entityMapper(),
|
|
1442
|
+
},
|
|
1443
|
+
activeSelection: { bounds },
|
|
1444
|
+
})}`,
|
|
1435
1445
|
} as TimelineComponents.TimelineRangeSummaryView.TimelineRangeSummaryViewData,
|
|
1436
1446
|
})}
|
|
1437
1447
|
></devtools-widget>`;
|
|
@@ -88,10 +88,11 @@ export interface Props {
|
|
|
88
88
|
generateConversationSummary: (markdown: string) => Promise<string>;
|
|
89
89
|
walkthrough: {
|
|
90
90
|
onOpen: (message: ModelChatMessage) => void,
|
|
91
|
-
onToggle: (isOpen: boolean) => void,
|
|
91
|
+
onToggle: (isOpen: boolean, message: ModelChatMessage) => void,
|
|
92
92
|
isExpanded: boolean,
|
|
93
93
|
isInlined: boolean,
|
|
94
|
-
|
|
94
|
+
activeSidebarMessage: ModelChatMessage|null,
|
|
95
|
+
inlineExpandedMessages: ModelChatMessage[],
|
|
95
96
|
};
|
|
96
97
|
}
|
|
97
98
|
|
|
@@ -36,6 +36,14 @@ const UIStrings = {
|
|
|
36
36
|
* @description Title for the button that shows the walkthrough when there are widgets in the walkthrough.
|
|
37
37
|
*/
|
|
38
38
|
showAgentWalkthrough: 'Show agent walkthrough',
|
|
39
|
+
/**
|
|
40
|
+
* @description Title for the button that hides the walkthrough when there are no widgets in the walkthrough.
|
|
41
|
+
*/
|
|
42
|
+
hideThinking: 'Hide thinking',
|
|
43
|
+
/**
|
|
44
|
+
* @description Title for the button that hides the walkthrough when there are widgets in the walkthrough.
|
|
45
|
+
*/
|
|
46
|
+
hideAgentWalkthrough: 'Hide agent walkthrough',
|
|
39
47
|
} as const;
|
|
40
48
|
const str_ = i18n.i18n.registerUIStrings('panels/ai_assistance/components/WalkthroughView.ts', UIStrings);
|
|
41
49
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
@@ -46,7 +54,7 @@ export interface ViewInput {
|
|
|
46
54
|
markdownRenderer: MarkdownLitRenderer;
|
|
47
55
|
isInlined: boolean;
|
|
48
56
|
isExpanded: boolean;
|
|
49
|
-
onToggle: (isOpen: boolean) => void;
|
|
57
|
+
onToggle: (isOpen: boolean, message: ModelChatMessage) => void;
|
|
50
58
|
onOpen: (message: ModelChatMessage) => void;
|
|
51
59
|
handleScroll: (ev: Event) => void;
|
|
52
60
|
}
|
|
@@ -70,6 +78,19 @@ export function walkthroughTitle(input: {
|
|
|
70
78
|
return lockedString(UIStrings.showThinking);
|
|
71
79
|
}
|
|
72
80
|
|
|
81
|
+
export function walkthroughCloseTitle(input: {
|
|
82
|
+
hasWidgets: boolean,
|
|
83
|
+
isInlined?: boolean,
|
|
84
|
+
}): string {
|
|
85
|
+
if (input.isInlined) {
|
|
86
|
+
return i18nString(UIStrings.title);
|
|
87
|
+
}
|
|
88
|
+
if (input.hasWidgets) {
|
|
89
|
+
return lockedString(UIStrings.hideAgentWalkthrough);
|
|
90
|
+
}
|
|
91
|
+
return lockedString(UIStrings.hideThinking);
|
|
92
|
+
}
|
|
93
|
+
|
|
73
94
|
function renderInlineWalkthrough(input: ViewInput, stepsOutput: Lit.LitTemplate, steps: Step[]): Lit.LitTemplate {
|
|
74
95
|
const lastStep = steps.at(-1);
|
|
75
96
|
if (!input.isInlined || !lastStep) {
|
|
@@ -78,10 +99,13 @@ function renderInlineWalkthrough(input: ViewInput, stepsOutput: Lit.LitTemplate,
|
|
|
78
99
|
|
|
79
100
|
function onToggle(event: Event): void {
|
|
80
101
|
const isOpen = (event.target as HTMLDetailsElement).open;
|
|
81
|
-
if (
|
|
102
|
+
if (!input.message) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (isOpen) {
|
|
82
106
|
input.onOpen(input.message);
|
|
83
107
|
} else {
|
|
84
|
-
input.onToggle(isOpen);
|
|
108
|
+
input.onToggle(isOpen, input.message);
|
|
85
109
|
}
|
|
86
110
|
}
|
|
87
111
|
|
|
@@ -92,7 +116,7 @@ function renderInlineWalkthrough(input: ViewInput, stepsOutput: Lit.LitTemplate,
|
|
|
92
116
|
<details class="walkthrough-inline" ?open=${input.isExpanded} @toggle=${onToggle}>
|
|
93
117
|
<summary ?data-has-widgets=${!input.isLoading && hasWidgets}>
|
|
94
118
|
${input.isLoading ? html`<devtools-spinner></devtools-spinner>` : Lit.nothing}
|
|
95
|
-
${walkthroughTitle({isLoading: input.isLoading, lastStep, hasWidgets})}
|
|
119
|
+
${input.isExpanded ? walkthroughCloseTitle({hasWidgets, isInlined: true}) : walkthroughTitle({isLoading: input.isLoading, lastStep, hasWidgets})}
|
|
96
120
|
<devtools-icon name="chevron-right"></devtools-icon>
|
|
97
121
|
</summary>
|
|
98
122
|
${stepsOutput}
|
|
@@ -118,7 +142,11 @@ function renderSidebarWalkthrough(input: ViewInput, stepsOutput: Lit.LitTemplate
|
|
|
118
142
|
title: i18nString(UIStrings.close),
|
|
119
143
|
jslogContext: 'close-walkthrough',
|
|
120
144
|
} as Buttons.Button.ButtonData}
|
|
121
|
-
@click=${() =>
|
|
145
|
+
@click=${() => {
|
|
146
|
+
if (input.message) {
|
|
147
|
+
input.onToggle(false, input.message);
|
|
148
|
+
}
|
|
149
|
+
}}
|
|
122
150
|
></devtools-button>
|
|
123
151
|
</div>
|
|
124
152
|
${stepsOutput}
|
|
@@ -184,7 +212,7 @@ export class WalkthroughView extends UI.Widget.Widget {
|
|
|
184
212
|
#message: ModelChatMessage|null = null;
|
|
185
213
|
#isLoading = false;
|
|
186
214
|
#markdownRenderer: MarkdownLitRenderer|null = null;
|
|
187
|
-
#onToggle: (isOpen: boolean) => void = () => {};
|
|
215
|
+
#onToggle: (isOpen: boolean, message: ModelChatMessage) => void = () => {};
|
|
188
216
|
#onOpen: (message: ModelChatMessage) => void = () => {};
|
|
189
217
|
#isInlined = false;
|
|
190
218
|
#isExpanded = false;
|
|
@@ -318,7 +346,7 @@ export class WalkthroughView extends UI.Widget.Widget {
|
|
|
318
346
|
this.requestUpdate();
|
|
319
347
|
}
|
|
320
348
|
|
|
321
|
-
set onToggle(onToggle: (isOpen: boolean) => void) {
|
|
349
|
+
set onToggle(onToggle: (isOpen: boolean, message: ModelChatMessage) => void) {
|
|
322
350
|
this.#onToggle = onToggle;
|
|
323
351
|
this.requestUpdate();
|
|
324
352
|
}
|
|
@@ -344,9 +344,13 @@
|
|
|
344
344
|
|
|
345
345
|
.walkthrough-toggle-container {
|
|
346
346
|
display: flex;
|
|
347
|
-
gap: var(--sys-size-
|
|
347
|
+
gap: var(--sys-size-2);
|
|
348
348
|
align-items: center;
|
|
349
349
|
|
|
350
|
+
&.has-widgets {
|
|
351
|
+
gap: var(--sys-size-6);
|
|
352
|
+
}
|
|
353
|
+
|
|
350
354
|
.chevron {
|
|
351
355
|
color: var(--sys-color-primary);
|
|
352
356
|
width: var(--sys-size-8);
|
|
@@ -92,6 +92,7 @@ import {SharedStorageTreeElement} from './SharedStorageTreeElement.js';
|
|
|
92
92
|
import {StorageBucketsTreeParentElement} from './StorageBucketsTreeElement.js';
|
|
93
93
|
import {StorageView} from './StorageView.js';
|
|
94
94
|
import {TrustTokensTreeElement} from './TrustTokensTreeElement.js';
|
|
95
|
+
import {WebMCPTreeElement} from './WebMCPTreeElement.js';
|
|
95
96
|
|
|
96
97
|
const UIStrings = {
|
|
97
98
|
/**
|
|
@@ -346,6 +347,7 @@ export class ApplicationPanelSidebar extends UI.Widget.VBox implements SDK.Targe
|
|
|
346
347
|
periodicBackgroundSyncTreeElement: BackgroundServiceTreeElement;
|
|
347
348
|
pushMessagingTreeElement: BackgroundServiceTreeElement;
|
|
348
349
|
reportingApiTreeElement: ReportingApiTreeElement;
|
|
350
|
+
webMcpTreeElement?: WebMCPTreeElement;
|
|
349
351
|
deviceBoundSessionsRootTreeElement: DeviceBoundSessionsRootTreeElement|undefined;
|
|
350
352
|
deviceBoundSessionsModel: DeviceBoundSessionsModel|undefined;
|
|
351
353
|
preloadingSummaryTreeElement: PreloadingSummaryTreeElement|undefined;
|
|
@@ -390,6 +392,10 @@ export class ApplicationPanelSidebar extends UI.Widget.VBox implements SDK.Targe
|
|
|
390
392
|
this.applicationTreeElement.appendChild(this.serviceWorkersTreeElement);
|
|
391
393
|
const clearStorageTreeElement = new ClearStorageTreeElement(panel);
|
|
392
394
|
this.applicationTreeElement.appendChild(clearStorageTreeElement);
|
|
395
|
+
if (Root.Runtime.hostConfig.devToolsWebMCPSupport?.enabled) {
|
|
396
|
+
this.webMcpTreeElement = new WebMCPTreeElement(panel);
|
|
397
|
+
this.applicationTreeElement.appendChild(this.webMcpTreeElement);
|
|
398
|
+
}
|
|
393
399
|
|
|
394
400
|
const storageSectionTitle = i18nString(UIStrings.storage);
|
|
395
401
|
const storageTreeElement = this.addSidebarSection(storageSectionTitle, 'storage');
|
|
@@ -321,27 +321,19 @@ export class IDBDataView extends UI.View.SimpleView {
|
|
|
321
321
|
const keyPath = this.isIndex && this.index ? this.index.keyPath : this.objectStore.keyPath;
|
|
322
322
|
|
|
323
323
|
const columns: DataGrid.DataGrid.ColumnDescriptor[] = [];
|
|
324
|
-
|
|
325
|
-
// Create column defaults so that we avoid repetition below.
|
|
326
|
-
const columnDefaults: Partial<DataGrid.DataGrid.ColumnDescriptor> = {
|
|
327
|
-
sortable: false,
|
|
328
|
-
};
|
|
329
324
|
columns.push({
|
|
330
|
-
...columnDefaults,
|
|
331
325
|
id: 'number',
|
|
332
326
|
title: '#' as Platform.UIString.LocalizedString,
|
|
333
327
|
sortable: false,
|
|
334
328
|
width: '50px',
|
|
335
329
|
});
|
|
336
330
|
columns.push({
|
|
337
|
-
...columnDefaults,
|
|
338
331
|
id: 'key',
|
|
339
332
|
titleDOMFragment: this.keyColumnHeaderFragment(i18nString(UIStrings.keyString), keyPath),
|
|
340
333
|
sortable: false,
|
|
341
334
|
});
|
|
342
335
|
if (this.isIndex) {
|
|
343
336
|
columns.push({
|
|
344
|
-
...columnDefaults,
|
|
345
337
|
id: 'primary-key',
|
|
346
338
|
titleDOMFragment: this.keyColumnHeaderFragment(i18nString(UIStrings.primaryKey), this.objectStore.keyPath),
|
|
347
339
|
sortable: false,
|
|
@@ -349,7 +341,6 @@ export class IDBDataView extends UI.View.SimpleView {
|
|
|
349
341
|
}
|
|
350
342
|
const title = i18nString(UIStrings.valueString);
|
|
351
343
|
columns.push({
|
|
352
|
-
...columnDefaults,
|
|
353
344
|
id: 'value',
|
|
354
345
|
title,
|
|
355
346
|
sortable: false,
|
|
@@ -0,0 +1,35 @@
|
|
|
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 * as Host from '../../core/host/host.js';
|
|
6
|
+
import type * as Platform from '../../core/platform/platform.js';
|
|
7
|
+
import {createIcon} from '../../ui/kit/kit.js';
|
|
8
|
+
|
|
9
|
+
import {ApplicationPanelTreeElement} from './ApplicationPanelTreeElement.js';
|
|
10
|
+
import type {ResourcesPanel} from './ResourcesPanel.js';
|
|
11
|
+
import {WebMCPView} from './WebMCPView.js';
|
|
12
|
+
|
|
13
|
+
export class WebMCPTreeElement extends ApplicationPanelTreeElement {
|
|
14
|
+
#view?: WebMCPView;
|
|
15
|
+
|
|
16
|
+
constructor(storagePanel: ResourcesPanel) {
|
|
17
|
+
super(storagePanel, 'WebMCP', false, 'web-mcp');
|
|
18
|
+
const icon = createIcon('document');
|
|
19
|
+
this.setLeadingIcons([icon]);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
override get itemURL(): Platform.DevToolsPath.UrlString {
|
|
23
|
+
return 'webMcp://' as Platform.DevToolsPath.UrlString;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
override onselect(selectedByUser?: boolean): boolean {
|
|
27
|
+
super.onselect(selectedByUser);
|
|
28
|
+
if (!this.#view) {
|
|
29
|
+
this.#view = new WebMCPView();
|
|
30
|
+
}
|
|
31
|
+
this.showView(this.#view);
|
|
32
|
+
Host.userMetrics.panelShown('web-mcp');
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|