chrome-devtools-frontend 1.0.1597448 → 1.0.1598808
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/ui_engineering.md +6 -6
- package/front_end/core/host/AidaClient.ts +6 -0
- package/front_end/core/sdk/CPUThrottlingManager.ts +5 -1
- package/front_end/core/sdk/CSSMatchedStyles.ts +2 -0
- package/front_end/core/sdk/CSSPropertyParserMatchers.ts +28 -0
- package/front_end/models/ai_assistance/AiConversation.ts +40 -22
- package/front_end/models/ai_assistance/ChangeManager.ts +16 -0
- package/front_end/models/ai_assistance/ExtensionScope.ts +11 -3
- package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +127 -0
- package/front_end/models/ai_assistance/agents/AiAgent.ts +35 -6
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.snapshot.txt +1 -1
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +11 -8
- package/front_end/models/ai_assistance/agents/ConversationSummaryAgent.ts +109 -0
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +30 -1
- package/front_end/models/ai_assistance/agents/StylingAgent.ts +34 -4
- package/front_end/models/ai_assistance/ai_assistance.ts +4 -0
- package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +27 -0
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +21 -0
- package/front_end/models/trace/Processor.ts +1 -0
- package/front_end/models/trace/handlers/PageLoadMetricsHandler.ts +33 -0
- package/front_end/models/trace/insights/CharacterSet.ts +172 -0
- package/front_end/models/trace/insights/Models.ts +1 -0
- package/front_end/models/trace/insights/types.ts +1 -0
- package/front_end/models/trace/types/TraceEvents.ts +17 -0
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +22 -12
- package/front_end/panels/ai_assistance/PatchWidget.ts +1 -1
- package/front_end/panels/ai_assistance/components/ChatMessage.ts +131 -63
- package/front_end/panels/ai_assistance/components/ChatView.ts +1 -1
- package/front_end/panels/ai_assistance/components/MarkdownRendererWithCodeBlock.ts +18 -9
- package/front_end/panels/ai_assistance/components/chatMessage.css +11 -0
- package/front_end/panels/application/AppManifestView.ts +4 -5
- package/front_end/panels/application/CookieItemsView.ts +9 -15
- package/front_end/panels/application/DeviceBoundSessionsView.ts +20 -26
- package/front_end/panels/application/FrameDetailsView.ts +10 -16
- package/front_end/panels/application/OriginTrialTreeView.ts +2 -3
- package/front_end/panels/application/ReportingApiView.ts +14 -18
- package/front_end/panels/application/components/BackForwardCacheView.ts +3 -3
- package/front_end/panels/application/preloading/PreloadingView.ts +18 -3
- package/front_end/panels/application/preloading/components/UsedPreloadingView.ts +2 -3
- package/front_end/panels/browser_debugger/DOMBreakpointsSidebarPane.ts +3 -2
- package/front_end/panels/changes/ChangesView.ts +13 -15
- package/front_end/panels/console/ConsolePinPane.ts +3 -3
- package/front_end/panels/coverage/CoverageListView.ts +1 -1
- package/front_end/panels/coverage/CoverageView.ts +4 -4
- package/front_end/panels/css_overview/CSSOverviewCompletedView.ts +3 -3
- package/front_end/panels/css_overview/CSSOverviewPanel.ts +11 -15
- package/front_end/panels/developer_resources/DeveloperResourcesView.ts +3 -5
- package/front_end/panels/elements/ElementsTreeOutline.ts +34 -8
- package/front_end/panels/elements/EventListenersWidget.ts +3 -2
- package/front_end/panels/elements/StandaloneStylesContainer.ts +21 -6
- package/front_end/panels/elements/StylePropertiesSection.ts +129 -1
- package/front_end/panels/elements/StylePropertyHighlighter.ts +3 -0
- package/front_end/panels/elements/StylePropertyTreeElement.ts +49 -4
- package/front_end/panels/elements/stylesSidebarPane.css +34 -0
- package/front_end/panels/issues/AffectedSelectivePermissionsInterventionView.ts +3 -5
- package/front_end/panels/layer_viewer/LayerDetailsView.ts +2 -1
- package/front_end/panels/layer_viewer/Layers3DView.ts +5 -4
- package/front_end/panels/linear_memory_inspector/components/LinearMemoryInspector.ts +5 -6
- package/front_end/panels/linear_memory_inspector/components/LinearMemoryValueInterpreter.ts +6 -11
- package/front_end/panels/network/RequestConditionsDrawer.ts +4 -4
- package/front_end/panels/network/RequestCookiesView.ts +5 -6
- package/front_end/panels/network/RequestHeadersView.ts +4 -4
- package/front_end/panels/network/RequestInitiatorView.ts +7 -5
- package/front_end/panels/network/RequestResponseView.ts +10 -15
- package/front_end/panels/performance_monitor/PerformanceMonitor.ts +2 -2
- package/front_end/panels/protocol_monitor/ProtocolMonitor.ts +5 -6
- package/front_end/panels/recorder/components/RecordingView.ts +31 -36
- package/front_end/panels/recorder/components/StepEditor.ts +6 -7
- package/front_end/panels/recorder/components/StepView.ts +2 -1
- package/front_end/panels/search/SearchView.ts +3 -4
- package/front_end/panels/settings/WorkspaceSettingsTab.ts +2 -5
- package/front_end/panels/timeline/TimelineDetailsView.ts +8 -6
- package/front_end/panels/timeline/components/LiveMetricsView.ts +5 -8
- package/front_end/panels/timeline/components/SidebarSingleInsightSet.ts +2 -7
- package/front_end/panels/timeline/components/insights/Cache.ts +8 -10
- package/front_end/panels/timeline/components/insights/CharacterSet.ts +34 -0
- package/front_end/panels/timeline/components/insights/DOMSize.ts +16 -20
- package/front_end/panels/timeline/components/insights/DocumentLatency.ts +2 -6
- package/front_end/panels/timeline/components/insights/DuplicatedJavaScript.ts +3 -4
- package/front_end/panels/timeline/components/insights/EventRef.ts +2 -2
- package/front_end/panels/timeline/components/insights/FontDisplay.ts +3 -4
- package/front_end/panels/timeline/components/insights/ForcedReflow.ts +5 -7
- package/front_end/panels/timeline/components/insights/INPBreakdown.ts +3 -4
- package/front_end/panels/timeline/components/insights/ImageDelivery.ts +3 -4
- package/front_end/panels/timeline/components/insights/ImageRef.ts +2 -4
- package/front_end/panels/timeline/components/insights/InsightRenderer.ts +2 -0
- package/front_end/panels/timeline/components/insights/LCPBreakdown.ts +5 -7
- package/front_end/panels/timeline/components/insights/LCPDiscovery.ts +2 -4
- package/front_end/panels/timeline/components/insights/LegacyJavaScript.ts +3 -4
- package/front_end/panels/timeline/components/insights/ModernHTTP.ts +3 -4
- package/front_end/panels/timeline/components/insights/NetworkDependencyTree.ts +7 -11
- package/front_end/panels/timeline/components/insights/NodeLink.ts +2 -4
- package/front_end/panels/timeline/components/insights/RenderBlocking.ts +3 -4
- package/front_end/panels/timeline/components/insights/SlowCSSSelector.ts +7 -10
- package/front_end/panels/timeline/components/insights/ThirdParties.ts +5 -7
- package/front_end/panels/timeline/components/insights/insights.ts +2 -0
- package/front_end/panels/web_audio/WebAudioView.ts +3 -4
- package/front_end/panels/webauthn/WebauthnPane.ts +2 -2
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/third_party/puppeteer/README.chromium +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Realm.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Realm.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/util.d.ts +4 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/util.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/util.js +13 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/util.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/injected/injected.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.d.ts +3 -3
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js +3 -3
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Mutex.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/third_party/mitt/mitt.js +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/third_party/parsel-js/parsel-js.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/third_party/rxjs/rxjs.js +446 -446
- package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +166 -167
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Realm.js +2 -2
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Realm.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/util.d.ts +4 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/util.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/util.js +12 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/util.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.d.ts +3 -3
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js +3 -3
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/third_party/mitt/mitt.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/third_party/parsel-js/parsel-js.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/third_party/rxjs/rxjs.js +97 -97
- package/front_end/third_party/puppeteer/package/package.json +1 -1
- package/front_end/third_party/puppeteer/package/src/bidi/Realm.ts +2 -2
- package/front_end/third_party/puppeteer/package/src/bidi/util.ts +17 -0
- package/front_end/third_party/puppeteer/package/src/revisions.ts +3 -3
- package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
- package/front_end/ui/components/settings/SettingCheckbox.ts +2 -0
- package/front_end/ui/legacy/Widget.ts +42 -6
- package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +3 -3
- package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +8 -8
- package/front_end/ui/visual_logging/Debugging.ts +0 -32
- package/front_end/ui/visual_logging/KnownContextValues.ts +2 -0
- package/package.json +1 -1
|
@@ -0,0 +1,172 @@
|
|
|
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 i18n from '../../../core/i18n/i18n.js';
|
|
6
|
+
import type * as Handlers from '../handlers/handlers.js';
|
|
7
|
+
import type * as Types from '../types/types.js';
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
type Checklist,
|
|
11
|
+
InsightCategory,
|
|
12
|
+
InsightKeys,
|
|
13
|
+
type InsightModel,
|
|
14
|
+
type InsightSetContext,
|
|
15
|
+
InsightWarning,
|
|
16
|
+
type PartialInsightModel,
|
|
17
|
+
} from './types.js';
|
|
18
|
+
|
|
19
|
+
export const UIStrings = {
|
|
20
|
+
/**
|
|
21
|
+
* @description Title of an insight that checks whether the page declares a character encoding early enough.
|
|
22
|
+
*/
|
|
23
|
+
title: 'Declare a character encoding',
|
|
24
|
+
/**
|
|
25
|
+
* @description Description of an insight that checks whether the page has a proper character encoding declaration via HTTP header or early meta tag.
|
|
26
|
+
*/
|
|
27
|
+
description:
|
|
28
|
+
'A character encoding declaration is required. It can be done with a meta charset tag in the first 1024 bytes of the HTML or in the Content-Type HTTP response header. [Learn more about declaring the character encoding](https://developer.chrome.com/docs/insights/charset/).',
|
|
29
|
+
/**
|
|
30
|
+
* @description Text to tell the user that the charset is declared in the Content-Type HTTP response header.
|
|
31
|
+
*/
|
|
32
|
+
passingHttpHeader: 'Declares charset in HTTP header',
|
|
33
|
+
/**
|
|
34
|
+
* @description Text to tell the user that the charset is NOT declared in the Content-Type HTTP response header.
|
|
35
|
+
*/
|
|
36
|
+
failedHttpHeader: 'Does not declare charset in HTTP header',
|
|
37
|
+
/**
|
|
38
|
+
* @description Text to tell the user that a meta charset tag was found in the first 1024 bytes of the HTML.
|
|
39
|
+
*/
|
|
40
|
+
passingMetaCharsetEarly: 'Declares charset using a meta tag in the first 1024 bytes',
|
|
41
|
+
/**
|
|
42
|
+
* @description Text to tell the user that a meta charset tag was found, but too late in the HTML.
|
|
43
|
+
*/
|
|
44
|
+
failedMetaCharsetLate: 'Declares charset using a meta tag after the first 1024 bytes',
|
|
45
|
+
/**
|
|
46
|
+
* @description Text to tell the user that no meta charset tag was found in the HTML.
|
|
47
|
+
*/
|
|
48
|
+
failedMetaCharsetMissing: 'Does not declare charset using a meta tag',
|
|
49
|
+
/**
|
|
50
|
+
* @description Text to tell the user that trace data did not include the Blink signal for meta charset.
|
|
51
|
+
*/
|
|
52
|
+
failedMetaCharsetUnknown: 'Could not determine meta charset declaration from trace',
|
|
53
|
+
} as const;
|
|
54
|
+
|
|
55
|
+
const str_ = i18n.i18n.registerUIStrings('models/trace/insights/CharacterSet.ts', UIStrings);
|
|
56
|
+
export const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
57
|
+
|
|
58
|
+
const CHARSET_HTTP_REGEX = /charset\s*=\s*[a-zA-Z0-9\-_:.()]{2,}/i;
|
|
59
|
+
|
|
60
|
+
export type CharacterSetInsightModel = InsightModel<typeof UIStrings, {
|
|
61
|
+
data?: {
|
|
62
|
+
hasHttpCharset: boolean,
|
|
63
|
+
checklist: Checklist<'httpCharset'|'metaCharset'>,
|
|
64
|
+
metaCharsetDisposition?: Types.Events.MetaCharsetDisposition,
|
|
65
|
+
documentRequest?: Types.Events.SyntheticNetworkRequest,
|
|
66
|
+
},
|
|
67
|
+
}>;
|
|
68
|
+
|
|
69
|
+
export function isCharacterSetInsight(model: InsightModel): model is CharacterSetInsightModel {
|
|
70
|
+
return model.insightKey === InsightKeys.CHARACTER_SET;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function finalize(partialModel: PartialInsightModel<CharacterSetInsightModel>): CharacterSetInsightModel {
|
|
74
|
+
let hasFailure = false;
|
|
75
|
+
if (partialModel.data) {
|
|
76
|
+
hasFailure = !partialModel.data.checklist.httpCharset.value && !partialModel.data.checklist.metaCharset.value;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
insightKey: InsightKeys.CHARACTER_SET,
|
|
81
|
+
strings: UIStrings,
|
|
82
|
+
title: i18nString(UIStrings.title),
|
|
83
|
+
description: i18nString(UIStrings.description),
|
|
84
|
+
docs: 'https://developer.chrome.com/docs/insights/charset/',
|
|
85
|
+
category: InsightCategory.ALL,
|
|
86
|
+
state: hasFailure ? 'fail' : 'pass',
|
|
87
|
+
...partialModel,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function hasCharsetInContentType(request: Types.Events.SyntheticNetworkRequest): boolean {
|
|
92
|
+
if (!request.args.data.responseHeaders) {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
for (const header of request.args.data.responseHeaders) {
|
|
96
|
+
if (header.name.toLowerCase() === 'content-type') {
|
|
97
|
+
return CHARSET_HTTP_REGEX.test(header.value);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function findMetaCharsetDisposition(
|
|
104
|
+
data: Handlers.Types.HandlerData,
|
|
105
|
+
context: InsightSetContext,
|
|
106
|
+
): Types.Events.MetaCharsetDisposition|undefined {
|
|
107
|
+
if (!context.navigation) {
|
|
108
|
+
return undefined;
|
|
109
|
+
}
|
|
110
|
+
return data.PageLoadMetrics.metaCharsetCheckEventsByNavigation.get(context.navigation)
|
|
111
|
+
?.at(-1)
|
|
112
|
+
?.args.data?.disposition;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function metaCharsetLabel(disposition: Types.Events.MetaCharsetDisposition|undefined): ReturnType<typeof i18nString> {
|
|
116
|
+
switch (disposition) {
|
|
117
|
+
case 'found-in-first-1024-bytes':
|
|
118
|
+
return i18nString(UIStrings.passingMetaCharsetEarly);
|
|
119
|
+
case 'found-after-first-1024-bytes':
|
|
120
|
+
return i18nString(UIStrings.failedMetaCharsetLate);
|
|
121
|
+
case 'not-found':
|
|
122
|
+
return i18nString(UIStrings.failedMetaCharsetMissing);
|
|
123
|
+
default:
|
|
124
|
+
return i18nString(UIStrings.failedMetaCharsetUnknown);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function generateInsight(
|
|
129
|
+
data: Handlers.Types.HandlerData, context: InsightSetContext): CharacterSetInsightModel {
|
|
130
|
+
if (!context.navigation) {
|
|
131
|
+
return finalize({});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const documentRequest = data.NetworkRequests.byId.get(context.navigationId);
|
|
135
|
+
if (!documentRequest) {
|
|
136
|
+
return finalize({warnings: [InsightWarning.NO_DOCUMENT_REQUEST]});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const hasHttpCharset = hasCharsetInContentType(documentRequest);
|
|
140
|
+
const metaCharsetDisposition = findMetaCharsetDisposition(data, context);
|
|
141
|
+
const hasMetaCharsetInFirst1024Bytes = metaCharsetDisposition === 'found-in-first-1024-bytes';
|
|
142
|
+
|
|
143
|
+
return finalize({
|
|
144
|
+
relatedEvents: [documentRequest],
|
|
145
|
+
data: {
|
|
146
|
+
hasHttpCharset,
|
|
147
|
+
metaCharsetDisposition,
|
|
148
|
+
documentRequest,
|
|
149
|
+
checklist: {
|
|
150
|
+
httpCharset: {
|
|
151
|
+
label: hasHttpCharset ? i18nString(UIStrings.passingHttpHeader) : i18nString(UIStrings.failedHttpHeader),
|
|
152
|
+
value: hasHttpCharset,
|
|
153
|
+
},
|
|
154
|
+
metaCharset: {
|
|
155
|
+
label: metaCharsetLabel(metaCharsetDisposition),
|
|
156
|
+
value: hasMetaCharsetInFirst1024Bytes,
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export function createOverlays(model: CharacterSetInsightModel): Types.Overlays.Overlay[] {
|
|
164
|
+
if (!model.data?.documentRequest) {
|
|
165
|
+
return [];
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return [{
|
|
169
|
+
type: 'ENTRY_SELECTED',
|
|
170
|
+
entry: model.data.documentRequest,
|
|
171
|
+
}];
|
|
172
|
+
}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
|
|
5
5
|
export * as Cache from './Cache.js';
|
|
6
|
+
export * as CharacterSet from './CharacterSet.js';
|
|
6
7
|
export * as CLSCulprits from './CLSCulprits.js';
|
|
7
8
|
export * as DocumentLatency from './DocumentLatency.js';
|
|
8
9
|
export * as DOMSize from './DOMSize.js';
|
|
@@ -1360,6 +1360,22 @@ export function isParseMetaViewport(event: Event): event is ParseMetaViewport {
|
|
|
1360
1360
|
return event.name === Name.PARSE_META_VIEWPORT;
|
|
1361
1361
|
}
|
|
1362
1362
|
|
|
1363
|
+
export type MetaCharsetDisposition = 'found-in-first-1024-bytes'|'found-after-first-1024-bytes'|'not-found';
|
|
1364
|
+
|
|
1365
|
+
export interface MetaCharsetCheck extends Instant {
|
|
1366
|
+
name: Name.META_CHARSET_CHECK;
|
|
1367
|
+
args: Args&{
|
|
1368
|
+
data: {
|
|
1369
|
+
frame: string,
|
|
1370
|
+
disposition: MetaCharsetDisposition,
|
|
1371
|
+
},
|
|
1372
|
+
};
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
export function isMetaCharsetCheck(event: Event): event is MetaCharsetCheck {
|
|
1376
|
+
return event.name === Name.META_CHARSET_CHECK;
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1363
1379
|
export interface LinkPreconnect extends Instant {
|
|
1364
1380
|
name: Name.LINK_PRECONNECT;
|
|
1365
1381
|
args: Args&{
|
|
@@ -3110,6 +3126,7 @@ export const enum Name {
|
|
|
3110
3126
|
SELECTOR_STATS = 'SelectorStats',
|
|
3111
3127
|
BEGIN_COMMIT_COMPOSITOR_FRAME = 'BeginCommitCompositorFrame',
|
|
3112
3128
|
PARSE_META_VIEWPORT = 'ParseMetaViewport',
|
|
3129
|
+
META_CHARSET_CHECK = 'MetaCharsetCheck',
|
|
3113
3130
|
|
|
3114
3131
|
/* Paint */
|
|
3115
3132
|
SCROLL_LAYER = 'ScrollLayer',
|
|
@@ -50,6 +50,7 @@ import {
|
|
|
50
50
|
import {isAiAssistancePatchingEnabled} from './PatchWidget.js';
|
|
51
51
|
|
|
52
52
|
const {html} = Lit;
|
|
53
|
+
const {widget} = UI.Widget;
|
|
53
54
|
|
|
54
55
|
const AI_ASSISTANCE_SEND_FEEDBACK = 'https://crbug.com/364805393' as Platform.DevToolsPath.UrlString;
|
|
55
56
|
const AI_ASSISTANCE_HELP =
|
|
@@ -465,16 +466,12 @@ function defaultView(input: ViewInput, output: PanelViewOutput, target: HTMLElem
|
|
|
465
466
|
></devtools-ai-chat-view>`;
|
|
466
467
|
}
|
|
467
468
|
case ViewState.EXPLORE_VIEW:
|
|
468
|
-
return html`<devtools-widget
|
|
469
|
-
|
|
470
|
-
.widgetConfig=${UI.Widget.widgetConfig(ExploreWidget)}
|
|
471
|
-
></devtools-widget>`;
|
|
469
|
+
return html`<devtools-widget class="fill-panel" ${widget(ExploreWidget)}>
|
|
470
|
+
</devtools-widget>`;
|
|
472
471
|
|
|
473
472
|
case ViewState.DISABLED_VIEW:
|
|
474
|
-
return html`<devtools-widget
|
|
475
|
-
|
|
476
|
-
.widgetConfig=${UI.Widget.widgetConfig(DisabledWidget, input.props)}
|
|
477
|
-
></devtools-widget>`;
|
|
473
|
+
return html`<devtools-widget class="fill-panel" ${widget(DisabledWidget, input.props)}>
|
|
474
|
+
</devtools-widget>`;
|
|
478
475
|
}
|
|
479
476
|
}
|
|
480
477
|
|
|
@@ -510,7 +507,7 @@ function defaultView(input: ViewInput, output: PanelViewOutput, target: HTMLElem
|
|
|
510
507
|
</div>
|
|
511
508
|
<div slot="sidebar" class="sidebar-view">
|
|
512
509
|
${shouldShowWalkthrough ? html`
|
|
513
|
-
<devtools-widget
|
|
510
|
+
<devtools-widget ${widget(WalkthroughView, {
|
|
514
511
|
message: input.props.walkthrough.activeMessage,
|
|
515
512
|
isLoading: input.props.isLoading && walkthroughIsForLastMessage,
|
|
516
513
|
markdownRenderer: input.props.markdownRenderer,
|
|
@@ -1699,8 +1696,14 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
1699
1696
|
parts: [],
|
|
1700
1697
|
};
|
|
1701
1698
|
this.#messages.push(systemMessage);
|
|
1702
|
-
|
|
1703
|
-
|
|
1699
|
+
// If the walkthrough is currently expanded in the sidebar, we want to
|
|
1700
|
+
// automatically swap it to the newly created message's walkthrough.
|
|
1701
|
+
// This ensures that when a user asks a new question, the sidebar updates
|
|
1702
|
+
// immediately to show the "loading" state of the new walkthrough.
|
|
1703
|
+
const isSidebarWalkthroughOpen = this.#walkthrough.isExpanded && !this.#walkthrough.isInlined;
|
|
1704
|
+
if (isSidebarWalkthroughOpen ||
|
|
1705
|
+
(Greendev.Prototypes.instance().isEnabled('breakpointDebuggerAgent') &&
|
|
1706
|
+
this.#conversation?.type === AiAssistanceModel.AiHistoryStorage.ConversationType.BREAKPOINT)) {
|
|
1704
1707
|
this.#openWalkthrough(systemMessage);
|
|
1705
1708
|
}
|
|
1706
1709
|
break;
|
|
@@ -1788,6 +1791,13 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
1788
1791
|
systemMessage.parts.push(newPart);
|
|
1789
1792
|
}
|
|
1790
1793
|
|
|
1794
|
+
if (data.widgets && Root.Runtime.hostConfig.devToolsAiAssistanceV2?.enabled) {
|
|
1795
|
+
systemMessage.parts.push({
|
|
1796
|
+
type: 'widget',
|
|
1797
|
+
widgets: data.widgets,
|
|
1798
|
+
});
|
|
1799
|
+
}
|
|
1800
|
+
|
|
1791
1801
|
// When there is an answer without any thinking steps, we don't want to show the thinking step.
|
|
1792
1802
|
// TODO(crbug.com/463323934): Remove specially handling this case.
|
|
1793
1803
|
if (systemMessage.parts.length > 1) {
|
|
@@ -1881,7 +1891,7 @@ export function getResponseMarkdown(message: ModelChatMessage): string {
|
|
|
1881
1891
|
for (const part of message.parts) {
|
|
1882
1892
|
if (part.type === 'answer') {
|
|
1883
1893
|
contentParts.push(`### Answer\n\n${part.text}`);
|
|
1884
|
-
} else {
|
|
1894
|
+
} else if (part.type === 'step') {
|
|
1885
1895
|
const step = part.step;
|
|
1886
1896
|
if (step.title) {
|
|
1887
1897
|
contentParts.push(`### ${step.title}`);
|
|
@@ -280,7 +280,7 @@ const DEFAULT_VIEW: View = (input, output, target) => {
|
|
|
280
280
|
|
|
281
281
|
// clang-format off
|
|
282
282
|
return html`<devtools-widget class="copy-to-prompt"
|
|
283
|
-
|
|
283
|
+
${widget(PanelCommon.CopyChangesToPrompt, {
|
|
284
284
|
workspaceDiff: input.workspaceDiff,
|
|
285
285
|
patchAgentCSSChange: changedCode,
|
|
286
286
|
})}></devtools-widget>`;
|
|
@@ -13,7 +13,8 @@ import * as Root from '../../../core/root/root.js';
|
|
|
13
13
|
import * as SDK from '../../../core/sdk/sdk.js';
|
|
14
14
|
import type * as Protocol from '../../../generated/protocol.js';
|
|
15
15
|
import type {
|
|
16
|
-
AiWidget, ComputedStyleAiWidget, CoreVitalsAiWidget} from
|
|
16
|
+
AiWidget, ComputedStyleAiWidget, CoreVitalsAiWidget, DomTreeAiWidget, StylePropertiesAiWidget} from
|
|
17
|
+
'../../../models/ai_assistance/agents/AiAgent.js';
|
|
17
18
|
import * as AiAssistanceModel from '../../../models/ai_assistance/ai_assistance.js';
|
|
18
19
|
import * as ComputedStyle from '../../../models/computed_style/computed_style.js';
|
|
19
20
|
import * as Marked from '../../../third_party/marked/marked.js';
|
|
@@ -101,6 +102,10 @@ const UIStringsNotTranslate = {
|
|
|
101
102
|
* @description The error message when the LLM gets stuck in a loop (max steps reached).
|
|
102
103
|
*/
|
|
103
104
|
maxStepsError: 'Seems like I am stuck with the investigation. It would be better if you start over.',
|
|
105
|
+
/**
|
|
106
|
+
* @description The error message when the LLM selects context from a different origin.
|
|
107
|
+
*/
|
|
108
|
+
crossOriginError: 'I have selected the new context but you will have to start a new chat.',
|
|
104
109
|
/**
|
|
105
110
|
* @description Displayed when the user stop the response
|
|
106
111
|
*/
|
|
@@ -205,7 +210,12 @@ export interface StepPart {
|
|
|
205
210
|
step: Step;
|
|
206
211
|
}
|
|
207
212
|
|
|
208
|
-
export
|
|
213
|
+
export interface WidgetPart {
|
|
214
|
+
type: 'widget';
|
|
215
|
+
widgets: AiWidget[];
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export type ModelMessagePart = AnswerPart|StepPart|WidgetPart;
|
|
209
219
|
|
|
210
220
|
export interface UserChatMessage {
|
|
211
221
|
entity: ChatMessageEntity.USER;
|
|
@@ -327,6 +337,9 @@ export const DEFAULT_VIEW = (input: ChatMessageViewInput, output: ViewOutput, ta
|
|
|
327
337
|
if (part.type === 'answer') {
|
|
328
338
|
return html`<p>${renderTextAsMarkdown(part.text, input.markdownRenderer, { animate: !input.isReadOnly && input.isLoading && isLastPart && input.isLastMessage })}</p>`;
|
|
329
339
|
}
|
|
340
|
+
if (part.type === 'widget') {
|
|
341
|
+
return html`${Lit.Directives.until(renderWidgets(part.widgets, {wrapperClass: 'main-widgets-wrapper'}))}`;
|
|
342
|
+
}
|
|
330
343
|
if (!aiAssistanceV2 && part.type === 'step') {
|
|
331
344
|
return renderStep({
|
|
332
345
|
step: part.step,
|
|
@@ -602,7 +615,6 @@ export function renderStep({step, isLoading, markdownRenderer, isLast}: {
|
|
|
602
615
|
markdownRenderer: MarkdownLitRenderer,
|
|
603
616
|
isLast: boolean,
|
|
604
617
|
}): Lit.LitTemplate {
|
|
605
|
-
const shouldRenderWidgets = Boolean(step.widgets?.length && Root.Runtime.hostConfig.devToolsAiAssistanceV2?.enabled);
|
|
606
618
|
const stepClasses = Lit.Directives.classMap({
|
|
607
619
|
step: true,
|
|
608
620
|
empty: !step.thought && !step.code && !step.contextDetails && !step.requestApproval,
|
|
@@ -626,11 +638,8 @@ export function renderStep({step, isLoading, markdownRenderer, isLast}: {
|
|
|
626
638
|
</summary>
|
|
627
639
|
${renderStepDetails({step, markdownRenderer, isLast})}
|
|
628
640
|
</details>
|
|
629
|
-
${
|
|
630
|
-
|
|
631
|
-
${Lit.Directives.until(renderStepWidgets(step))}
|
|
632
|
-
</div>` : Lit.nothing
|
|
633
|
-
}`;
|
|
641
|
+
${Lit.Directives.until(renderWidgets(step.widgets, {wrapperClass: 'step-widgets-wrapper'}))}
|
|
642
|
+
`;
|
|
634
643
|
// clang-format on
|
|
635
644
|
}
|
|
636
645
|
|
|
@@ -639,55 +648,76 @@ interface WidgetMakerResponse {
|
|
|
639
648
|
revealable: unknown;
|
|
640
649
|
}
|
|
641
650
|
|
|
642
|
-
const
|
|
651
|
+
const nodeCache = new Map<Protocol.DOM.BackendNodeId, SDK.DOMModel.DOMNode>();
|
|
652
|
+
|
|
653
|
+
async function resolveNode(backendNodeId: Protocol.DOM.BackendNodeId): Promise<SDK.DOMModel.DOMNode|null> {
|
|
654
|
+
const cachedNode = nodeCache.get(backendNodeId);
|
|
655
|
+
if (cachedNode) {
|
|
656
|
+
return cachedNode;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
const target = SDK.TargetManager.TargetManager.instance().primaryPageTarget();
|
|
660
|
+
if (!target) {
|
|
661
|
+
return null;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
const node = new SDK.DOMModel.DeferredDOMNode(target, backendNodeId);
|
|
665
|
+
const resolved = await node.resolvePromise();
|
|
666
|
+
if (resolved) {
|
|
667
|
+
nodeCache.set(backendNodeId, resolved);
|
|
668
|
+
}
|
|
669
|
+
return resolved;
|
|
670
|
+
}
|
|
643
671
|
|
|
644
672
|
async function makeComputedStyleWidget(widgetData: ComputedStyleAiWidget): Promise<WidgetMakerResponse|null> {
|
|
645
|
-
|
|
673
|
+
const domNodeForId = await resolveNode(widgetData.data.backendNodeId);
|
|
646
674
|
if (!domNodeForId) {
|
|
647
|
-
|
|
648
|
-
if (!target) {
|
|
649
|
-
return null;
|
|
650
|
-
}
|
|
651
|
-
const node = new SDK.DOMModel.DeferredDOMNode(
|
|
652
|
-
target,
|
|
653
|
-
widgetData.data.backendNodeId,
|
|
654
|
-
);
|
|
655
|
-
const resolved = await node.resolvePromise();
|
|
656
|
-
if (!resolved) {
|
|
657
|
-
return null;
|
|
658
|
-
}
|
|
659
|
-
domNodeForId = resolved;
|
|
660
|
-
computedStyleNodeCache.set(widgetData.data.backendNodeId, resolved);
|
|
675
|
+
return null;
|
|
661
676
|
}
|
|
662
677
|
const styles = new ComputedStyle.ComputedStyleModel.ComputedStyle(domNodeForId, widgetData.data.computedStyles);
|
|
663
678
|
|
|
664
|
-
const widgetConfig = UI.Widget.widgetConfig(Elements.ComputedStyleWidget.ComputedStyleWidget, {
|
|
665
|
-
nodeStyle: styles,
|
|
666
|
-
matchedStyles: widgetData.data.matchedCascade,
|
|
667
|
-
// This disables showing the nested traces and detailed information in the widget.
|
|
668
|
-
propertyTraces: null,
|
|
669
|
-
allowUserControl: false,
|
|
670
|
-
filterText: new RegExp(widgetData.data.properties.join('|'), 'i')
|
|
671
|
-
});
|
|
672
|
-
|
|
673
679
|
// clang-format off
|
|
674
|
-
const
|
|
680
|
+
const renderedWidget = html`<devtools-widget
|
|
681
|
+
class="computed-styles-widget" ${widget(Elements.ComputedStyleWidget.ComputedStyleWidget, {
|
|
682
|
+
nodeStyle: styles,
|
|
683
|
+
matchedStyles: widgetData.data.matchedCascade,
|
|
684
|
+
// This disables showing the nested traces and detailed information in the widget.
|
|
685
|
+
propertyTraces: null,
|
|
686
|
+
allowUserControl: false,
|
|
687
|
+
filterText: new RegExp(widgetData.data.properties.join('|'), 'i')
|
|
688
|
+
})}></devtools-widget>`;
|
|
675
689
|
// clang-format on
|
|
676
690
|
|
|
677
|
-
return {renderedWidget
|
|
691
|
+
return {renderedWidget, revealable: new Elements.ElementsPanel.NodeComputedStyles(domNodeForId)};
|
|
678
692
|
}
|
|
679
693
|
|
|
680
694
|
async function makeCoreVitalsWidget(widgetData: CoreVitalsAiWidget): Promise<WidgetMakerResponse|null> {
|
|
681
|
-
|
|
695
|
+
// clang-format off
|
|
696
|
+
const renderedWidget = html`<devtools-widget
|
|
697
|
+
class="core-vitals-widget" ${widget(TimelineComponents.CWVMetrics.CWVMetrics, {data: widgetData.data})}>
|
|
698
|
+
</devtools-widget>`;
|
|
699
|
+
// clang-format on
|
|
700
|
+
|
|
701
|
+
return {renderedWidget, revealable: new TimelineUtils.Helpers.RevealableCoreVitals(widgetData.data.insightSetKey)};
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
async function makeStylePropertiesWidget(widgetData: StylePropertiesAiWidget): Promise<WidgetMakerResponse|null> {
|
|
705
|
+
const domNodeForId = await resolveNode(widgetData.data.backendNodeId);
|
|
706
|
+
if (!domNodeForId) {
|
|
707
|
+
return null;
|
|
708
|
+
}
|
|
682
709
|
|
|
683
710
|
// clang-format off
|
|
684
|
-
const
|
|
711
|
+
const renderedWidget = html`<devtools-widget
|
|
712
|
+
class="styling-preview-widget"
|
|
713
|
+
${widget(Elements.StandaloneStylesContainer.StandaloneStylesContainer, {
|
|
714
|
+
domNode: domNodeForId,
|
|
715
|
+
filter: widgetData.data.selector ? new RegExp(widgetData.data.selector) : null,
|
|
716
|
+
})}>
|
|
717
|
+
</devtools-widget>`;
|
|
685
718
|
// clang-format on
|
|
686
719
|
|
|
687
|
-
return {
|
|
688
|
-
renderedWidget: widget,
|
|
689
|
-
revealable: new TimelineUtils.Helpers.RevealableCoreVitals(widgetData.data.insightSetKey)
|
|
690
|
-
};
|
|
720
|
+
return {renderedWidget, revealable: domNodeForId};
|
|
691
721
|
}
|
|
692
722
|
|
|
693
723
|
function renderWidgetResponse(response: WidgetMakerResponse|null): Lit.LitTemplate {
|
|
@@ -720,39 +750,74 @@ function renderWidgetResponse(response: WidgetMakerResponse|null): Lit.LitTempla
|
|
|
720
750
|
// clang-format on
|
|
721
751
|
}
|
|
722
752
|
|
|
753
|
+
async function makeDomTreeWidget(widgetData: DomTreeAiWidget): Promise<WidgetMakerResponse|null> {
|
|
754
|
+
const root = widgetData.data.root;
|
|
755
|
+
if (!(root instanceof SDK.DOMModel.DOMNodeSnapshot)) {
|
|
756
|
+
return null;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
const widgetConfig = UI.Widget.widgetConfig(Elements.ElementsTreeOutline.DOMTreeWidget, {
|
|
760
|
+
maxTreeDepth: 2,
|
|
761
|
+
enableContextMenu: false,
|
|
762
|
+
showComments: false,
|
|
763
|
+
showAIButton: false,
|
|
764
|
+
disableEdits: true,
|
|
765
|
+
expandRoot: true,
|
|
766
|
+
rootDOMNode: root,
|
|
767
|
+
visibleWidth: 400,
|
|
768
|
+
wrap: true,
|
|
769
|
+
});
|
|
770
|
+
|
|
771
|
+
// clang-format off
|
|
772
|
+
const widget = html`<devtools-widget class="dom-tree-widget" .widgetConfig=${widgetConfig}></devtools-widget>`;
|
|
773
|
+
// clang-format on
|
|
774
|
+
|
|
775
|
+
return {
|
|
776
|
+
renderedWidget: widget,
|
|
777
|
+
revealable: new SDK.DOMModel.DeferredDOMNode(root.domModel().target(), root.backendNodeId()),
|
|
778
|
+
};
|
|
779
|
+
}
|
|
780
|
+
|
|
723
781
|
/**
|
|
724
|
-
* Renders AI-defined UI widgets
|
|
725
|
-
* When a ModelChatMessage contains a WidgetPart,
|
|
726
|
-
* iterates through the
|
|
727
|
-
* the appropriate rendering logic based on
|
|
782
|
+
* Renders AI-defined UI widgets.
|
|
783
|
+
* When a ModelChatMessage contains a WidgetPart, or a Step has widgets,
|
|
784
|
+
* the ChatMessage component iterates through the \`widgets\` array.
|
|
785
|
+
* For each widget, it determines the appropriate rendering logic based on
|
|
786
|
+
* the \`widgetData.name\`.
|
|
728
787
|
*
|
|
729
|
-
* Currently,
|
|
730
|
-
*
|
|
731
|
-
* data and configuration for the
|
|
732
|
-
* and
|
|
733
|
-
*
|
|
734
|
-
* custom element, which dynamically instantiates and displays the specified
|
|
735
|
-
* UI.Widget subclass with the provided configuration.
|
|
788
|
+
* Currently, 'COMPUTED_STYLES', 'CORE_VITALS' and 'STYLE_PROPERTIES' widgets are supported.
|
|
789
|
+
* For these, the corresponding \`make...Widget\` functions are called to construct the necessary
|
|
790
|
+
* data and configuration for the UI components. The widget is then rendered using the
|
|
791
|
+
* \`<devtools-widget>\` custom element, which dynamically instantiates and displays the
|
|
792
|
+
* specified UI.Widget subclass with the provided configuration.
|
|
736
793
|
*
|
|
737
794
|
* This allows for a flexible and extensible system where new widget types
|
|
738
795
|
* can be added to the AI responses and rendered in DevTools by adding
|
|
739
|
-
* corresponding
|
|
796
|
+
* corresponding \`make...Widget\` functions and handling them here.
|
|
740
797
|
*/
|
|
741
|
-
async function
|
|
742
|
-
|
|
798
|
+
async function renderWidgets(
|
|
799
|
+
widgets: AiWidget[]|undefined, options: {wrapperClass?: string} = {}): Promise<Lit.LitTemplate> {
|
|
800
|
+
if (!Root.Runtime.hostConfig.devToolsAiAssistanceV2?.enabled || !widgets || widgets.length === 0) {
|
|
743
801
|
return Lit.nothing;
|
|
744
802
|
}
|
|
745
|
-
const ui = await Promise.all(
|
|
803
|
+
const ui = await Promise.all(widgets.map(async widgetData => {
|
|
804
|
+
let response: WidgetMakerResponse|null = null;
|
|
746
805
|
if (widgetData.name === 'COMPUTED_STYLES') {
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
if (widgetData.name === '
|
|
751
|
-
|
|
752
|
-
|
|
806
|
+
response = await makeComputedStyleWidget(widgetData);
|
|
807
|
+
} else if (widgetData.name === 'CORE_VITALS') {
|
|
808
|
+
response = await makeCoreVitalsWidget(widgetData);
|
|
809
|
+
} else if (widgetData.name === 'STYLE_PROPERTIES') {
|
|
810
|
+
response = await makeStylePropertiesWidget(widgetData);
|
|
811
|
+
} else if (widgetData.name === 'DOM_TREE') {
|
|
812
|
+
response = await makeDomTreeWidget(widgetData);
|
|
753
813
|
}
|
|
754
|
-
return
|
|
814
|
+
return renderWidgetResponse(response);
|
|
755
815
|
}));
|
|
816
|
+
|
|
817
|
+
if (options.wrapperClass) {
|
|
818
|
+
return html`<div class=${options.wrapperClass}>${ui}</div>`;
|
|
819
|
+
}
|
|
820
|
+
|
|
756
821
|
return html`${ui}`;
|
|
757
822
|
}
|
|
758
823
|
|
|
@@ -807,6 +872,9 @@ function renderError(message: ModelChatMessage): Lit.LitTemplate {
|
|
|
807
872
|
case AiAssistanceModel.AiAgent.ErrorType.MAX_STEPS:
|
|
808
873
|
errorMessage = UIStringsNotTranslate.maxStepsError;
|
|
809
874
|
break;
|
|
875
|
+
case AiAssistanceModel.AiAgent.ErrorType.CROSS_ORIGIN:
|
|
876
|
+
errorMessage = UIStringsNotTranslate.crossOriginError;
|
|
877
|
+
break;
|
|
810
878
|
case AiAssistanceModel.AiAgent.ErrorType.ABORT:
|
|
811
879
|
return html`<p class="aborted" jslog=${VisualLogging.section('aborted')}>${
|
|
812
880
|
lockedString(UIStringsNotTranslate.stoppedResponse)}</p>`;
|
|
@@ -169,7 +169,7 @@ const DEFAULT_VIEW: View = (input, output, target) => {
|
|
|
169
169
|
</div>
|
|
170
170
|
</div>
|
|
171
171
|
`}
|
|
172
|
-
<devtools-widget class=${inputWidgetClasses}
|
|
172
|
+
<devtools-widget class=${inputWidgetClasses} ${widget(ChatInput, {
|
|
173
173
|
isLoading: input.isLoading,
|
|
174
174
|
blockedByCrossOrigin: input.blockedByCrossOrigin,
|
|
175
175
|
isTextInputDisabled: input.isTextInputDisabled,
|
|
@@ -33,16 +33,21 @@ export class MarkdownRendererWithCodeBlock extends MarkdownView.MarkdownView.Mar
|
|
|
33
33
|
}}>${Platform.StringUtilities.trimEndWithMaxLength(label, 100)}</devtools-link>`;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
#renderLink(
|
|
36
|
+
#renderLink(
|
|
37
|
+
href: string,
|
|
38
|
+
fallbackText: string,
|
|
39
|
+
): Lit.LitTemplate|null {
|
|
37
40
|
if (href.startsWith('#req-')) {
|
|
38
|
-
const request =
|
|
39
|
-
|
|
41
|
+
const request = Logs.NetworkLog.NetworkLog.instance().requests().find(
|
|
42
|
+
req => req.requestId() === href.substring(5),
|
|
43
|
+
);
|
|
40
44
|
|
|
41
45
|
if (request) {
|
|
42
46
|
return this.#revealableLink(request, request.url());
|
|
43
47
|
}
|
|
44
|
-
|
|
45
|
-
}
|
|
48
|
+
return html`${fallbackText}`;
|
|
49
|
+
}
|
|
50
|
+
if (href.startsWith('#file-')) {
|
|
46
51
|
const file = AiAssistanceModel.ContextSelectionAgent.ContextSelectionAgent.getUISourceCodes().find(
|
|
47
52
|
file => AiAssistanceModel.ContextSelectionAgent.ContextSelectionAgent.uiSourceCodeId.get(file) ===
|
|
48
53
|
Number(href.substring(6)));
|
|
@@ -50,13 +55,14 @@ export class MarkdownRendererWithCodeBlock extends MarkdownView.MarkdownView.Mar
|
|
|
50
55
|
if (file) {
|
|
51
56
|
return this.#revealableLink(file, file.name());
|
|
52
57
|
}
|
|
58
|
+
return html`${fallbackText}`;
|
|
53
59
|
}
|
|
54
60
|
return null;
|
|
55
61
|
}
|
|
56
62
|
|
|
57
63
|
override templateForToken(token: Marked.Marked.MarkedToken): Lit.LitTemplate|null {
|
|
58
64
|
if (token.type === 'link') {
|
|
59
|
-
const link = this.#renderLink(token.href);
|
|
65
|
+
const link = this.#renderLink(token.href, token.text);
|
|
60
66
|
if (link) {
|
|
61
67
|
return link;
|
|
62
68
|
}
|
|
@@ -73,9 +79,12 @@ export class MarkdownRendererWithCodeBlock extends MarkdownView.MarkdownView.Mar
|
|
|
73
79
|
if (token.type === 'codespan') {
|
|
74
80
|
// LLM likes outputting the link inside a codespan block.
|
|
75
81
|
// Remove the codespan and render the link directly
|
|
76
|
-
const matches = token.text.match(/^\[
|
|
77
|
-
if (matches?.[
|
|
78
|
-
const link = this.#renderLink(
|
|
82
|
+
const matches = token.text.match(/^\[(.*)\]\((.+)\)$/);
|
|
83
|
+
if (matches?.[2]) {
|
|
84
|
+
const link = this.#renderLink(
|
|
85
|
+
matches[2],
|
|
86
|
+
matches[1],
|
|
87
|
+
);
|
|
79
88
|
if (link) {
|
|
80
89
|
return link;
|
|
81
90
|
}
|
|
@@ -354,6 +354,17 @@
|
|
|
354
354
|
width: fit-content;
|
|
355
355
|
}
|
|
356
356
|
|
|
357
|
+
.styling-preview-widget {
|
|
358
|
+
width: 100%;
|
|
359
|
+
min-height: 100px;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
.main-widgets-wrapper {
|
|
363
|
+
display: flex;
|
|
364
|
+
flex-direction: column;
|
|
365
|
+
gap: var(--sys-size-5);
|
|
366
|
+
}
|
|
367
|
+
|
|
357
368
|
.step-widgets-wrapper {
|
|
358
369
|
width: fit-content;
|
|
359
370
|
display: flex;
|