chrome-devtools-frontend 1.0.1574367 → 1.0.1575635
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/.stylelintrc.json +1 -1
- package/AUTHORS +1 -0
- package/docs/contributing/settings-experiments-features.md +5 -2
- package/front_end/core/common/Settings.ts +1 -1
- package/front_end/core/host/InspectorFrontendHostAPI.ts +7 -1
- package/front_end/core/host/InspectorFrontendHostStub.ts +10 -0
- package/front_end/core/host/UserMetrics.ts +15 -0
- package/front_end/core/root/Runtime.ts +119 -39
- package/front_end/core/sdk/CSSMatchedStyles.ts +27 -0
- package/front_end/entrypoints/main/MainImpl.ts +25 -7
- package/front_end/entrypoints/node_app/app/NodeConnectionsPanel.ts +3 -2
- package/front_end/generated/InspectorBackendCommands.ts +37 -0
- package/front_end/generated/protocol-mapping.d.ts +257 -0
- package/front_end/generated/protocol-proxy-api.d.ts +256 -0
- package/front_end/generated/protocol.ts +359 -0
- package/front_end/models/ai_assistance/AiConversation.ts +31 -10
- package/front_end/models/ai_assistance/AiHistoryStorage.ts +1 -0
- package/front_end/models/ai_assistance/agents/AiAgent.ts +29 -5
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.snapshot.txt +73 -0
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +141 -0
- package/front_end/models/ai_assistance/agents/StylingAgent.snapshot.txt +3 -3
- package/front_end/models/ai_assistance/agents/StylingAgent.ts +5 -4
- package/front_end/models/ai_assistance/ai_assistance.ts +2 -0
- package/front_end/models/issues_manager/CorsIssue.ts +0 -3
- package/front_end/models/javascript_metadata/NativeFunctions.js +5 -0
- package/front_end/models/live-metrics/LiveMetrics.ts +31 -51
- package/front_end/models/stack_trace/StackTrace.ts +41 -0
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +72 -6
- package/front_end/panels/ai_assistance/ai_assistance-meta.ts +1 -0
- package/front_end/panels/ai_assistance/components/ChatInput.ts +24 -2
- package/front_end/panels/ai_assistance/components/ChatMessage.ts +6 -4
- package/front_end/panels/ai_assistance/components/ChatView.ts +5 -6
- package/front_end/panels/ai_assistance/components/chatView.css +10 -0
- package/front_end/panels/application/StorageView.ts +3 -3
- package/front_end/panels/application/preloading/components/preloadingDisabledInfobar.css +1 -1
- package/front_end/panels/common/AiCodeGenerationUpgradeDialog.ts +32 -16
- package/front_end/panels/common/aiCodeCompletionSummaryToolbar.css +1 -1
- package/front_end/panels/console/ConsoleContextSelector.ts +4 -3
- package/front_end/panels/console/ConsoleFormat.ts +31 -2
- package/front_end/panels/console/ConsoleInsightTeaser.ts +6 -1
- package/front_end/panels/elements/ElementsTreeElement.ts +46 -2
- package/front_end/panels/elements/ElementsTreeOutline.ts +1 -1
- package/front_end/panels/elements/StylePropertyTreeElement.ts +63 -0
- package/front_end/panels/elements/StylesSidebarPane.ts +17 -2
- package/front_end/panels/elements/stylePropertiesTreeOutline.css +4 -0
- package/front_end/panels/issues/AffectedMetadataAllowedSitesView.ts +3 -3
- package/front_end/panels/layer_viewer/Layers3DView.ts +2 -1
- package/front_end/panels/lighthouse/LighthouseStartView.ts +7 -6
- package/front_end/panels/linear_memory_inspector/LinearMemoryInspectorPane.ts +3 -2
- package/front_end/panels/network/RequestConditionsDrawer.ts +2 -3
- package/front_end/panels/network/SignedExchangeInfoView.ts +3 -4
- package/front_end/panels/network/components/HeaderSectionRow.css +1 -1
- package/front_end/panels/recorder/components/RecordingView.ts +2 -2
- package/front_end/panels/recorder/components/recordingView.css +5 -0
- package/front_end/panels/security/SecurityPanelSidebar.ts +10 -9
- package/front_end/panels/settings/AISettingsTab.ts +2 -1
- package/front_end/panels/settings/KeybindsSettingsTab.ts +3 -5
- package/front_end/panels/settings/SettingsScreen.ts +14 -9
- package/front_end/panels/settings/settings-meta.ts +1 -0
- package/front_end/panels/sources/CallStackSidebarPane.ts +10 -0
- package/front_end/panels/sources/DebuggerPlugin.ts +18 -12
- package/front_end/panels/sources/ScopeChainSidebarPane.ts +4 -3
- package/front_end/panels/sources/SourcesNavigator.ts +2 -2
- package/front_end/panels/sources/SourcesPanel.ts +6 -3
- package/front_end/panels/sources/TabbedEditorContainer.ts +2 -2
- package/front_end/panels/sources/sources-meta.ts +2 -1
- package/front_end/panels/timeline/TimelinePanel.ts +2 -1
- package/front_end/panels/timeline/TimelineUIUtils.ts +2 -2
- package/front_end/panels/timeline/components/DetailsView.ts +7 -7
- package/front_end/panels/timeline/components/insights/BaseInsightComponent.ts +2 -2
- package/front_end/panels/timeline/overlays/components/EntryLabelOverlay.ts +4 -4
- package/front_end/panels/whats_new/ReleaseNoteText.ts +11 -11
- package/front_end/panels/whats_new/releaseNoteView.css +1 -1
- package/front_end/panels/whats_new/resources/WNDT.md +6 -6
- 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/cdp/TargetManager.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/TargetManager.js +30 -25
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/TargetManager.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/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/es5-iife/puppeteer-core-browser.js +30 -21
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/TargetManager.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/TargetManager.js +31 -26
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/TargetManager.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/package.json +3 -3
- package/front_end/third_party/puppeteer/package/src/cdp/TargetManager.ts +45 -44
- package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
- package/front_end/ui/components/buttons/Button.ts +2 -2
- package/front_end/ui/components/panel_feedback/PreviewToggle.ts +1 -1
- package/front_end/ui/components/panel_feedback/panelFeedback.css +1 -1
- package/front_end/ui/kit/link/Link.ts +31 -0
- package/front_end/ui/legacy/LinkContextMenuProvider.ts +3 -5
- package/front_end/ui/legacy/components/object_ui/ObjectPopoverHelper.ts +2 -2
- package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +336 -250
- package/front_end/ui/legacy/inspectorCommon.css +0 -1
- package/front_end/ui/legacy/legacy.ts +0 -4
- package/front_end/ui/visual_logging/KnownContextValues.ts +4 -0
- package/front_end/ui/visual_logging/LoggingDriver.ts +10 -6
- package/mcp/HostBindings.ts +6 -0
- package/package.json +1 -1
- package/front_end/ui/legacy/XElement.ts +0 -41
- package/front_end/ui/legacy/XLink.ts +0 -128
|
@@ -151,7 +151,7 @@ const UIStringsNotTranslate = {
|
|
|
151
151
|
*/
|
|
152
152
|
accountAvatar: 'Account avatar',
|
|
153
153
|
/**
|
|
154
|
-
* @description Title for the
|
|
154
|
+
* @description Title for the link which wraps the image input rendered in chat messages.
|
|
155
155
|
*/
|
|
156
156
|
openImageInNewTab: 'Open image in a new tab',
|
|
157
157
|
/**
|
|
@@ -250,7 +250,7 @@ export interface MessageInput {
|
|
|
250
250
|
isReadOnly: boolean;
|
|
251
251
|
isLastMessage: boolean;
|
|
252
252
|
canShowFeedbackForm: boolean;
|
|
253
|
-
userInfo: Pick<Host.InspectorFrontendHostAPI.SyncInformation, 'accountImage'|'accountFullName'>;
|
|
253
|
+
userInfo: Pick<Host.InspectorFrontendHostAPI.SyncInformation, 'accountImage'|'accountFullName'|'accountGivenName'>;
|
|
254
254
|
markdownRenderer: MarkdownLitRenderer;
|
|
255
255
|
onSuggestionClick: (suggestion: string) => void;
|
|
256
256
|
onFeedbackSubmit: (rpcId: Host.AidaClient.RpcGlobalId, rate: Host.AidaClient.Rating, feedback?: string) => void;
|
|
@@ -260,7 +260,8 @@ export interface MessageInput {
|
|
|
260
260
|
export const DEFAULT_VIEW = (input: ChatMessageViewInput, output: ViewOutput, target: HTMLElement): void => {
|
|
261
261
|
const message = input.message;
|
|
262
262
|
if (message.entity === ChatMessageEntity.USER) {
|
|
263
|
-
const
|
|
263
|
+
const givenName = AiAssistanceModel.AiUtils.isGeminiBranding() ? input.userInfo.accountGivenName : '';
|
|
264
|
+
const name = givenName || input.userInfo.accountFullName || lockedString(UIStringsNotTranslate.you);
|
|
264
265
|
const image = input.userInfo.accountImage ?
|
|
265
266
|
html`<img src="data:image/png;base64, ${input.userInfo.accountImage}" alt=${
|
|
266
267
|
UIStringsNotTranslate.accountAvatar} />` :
|
|
@@ -748,7 +749,8 @@ export class ChatMessage extends UI.Widget.Widget {
|
|
|
748
749
|
isReadOnly = false;
|
|
749
750
|
canShowFeedbackForm = false;
|
|
750
751
|
isLastMessage = false;
|
|
751
|
-
userInfo:
|
|
752
|
+
userInfo:
|
|
753
|
+
Pick<Host.InspectorFrontendHostAPI.SyncInformation, 'accountImage'|'accountFullName'|'accountGivenName'> = {};
|
|
752
754
|
markdownRenderer!: MarkdownLitRenderer;
|
|
753
755
|
onSuggestionClick: (suggestion: string) => void = () => {};
|
|
754
756
|
onFeedbackSubmit:
|
|
@@ -62,7 +62,7 @@ export interface Props {
|
|
|
62
62
|
selectedContext: AiAssistanceModel.AiAgent.ConversationContext<unknown>|null;
|
|
63
63
|
isLoading: boolean;
|
|
64
64
|
canShowFeedbackForm: boolean;
|
|
65
|
-
userInfo: Pick<Host.InspectorFrontendHostAPI.SyncInformation, 'accountImage'|'
|
|
65
|
+
userInfo: Pick<Host.InspectorFrontendHostAPI.SyncInformation, 'accountImage'|'accountGivenName'>;
|
|
66
66
|
conversationType: AiAssistanceModel.AiHistoryStorage.ConversationType;
|
|
67
67
|
isReadOnly: boolean;
|
|
68
68
|
blockedByCrossOrigin: boolean;
|
|
@@ -78,7 +78,7 @@ export interface Props {
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
interface ChatWidgetInput extends Props {
|
|
81
|
-
|
|
81
|
+
accountGivenName: string;
|
|
82
82
|
handleScroll: (ev: Event) => void;
|
|
83
83
|
handleSuggestionClick: (title: string) => void;
|
|
84
84
|
handleMessageContainerRef: (el: Element|undefined) => void;
|
|
@@ -133,8 +133,8 @@ const DEFAULT_VIEW: View = (input, output, target) => {
|
|
|
133
133
|
</div>
|
|
134
134
|
${AiAssistanceModel.AiUtils.isGeminiBranding() ?
|
|
135
135
|
html`
|
|
136
|
-
<h1 class='greeting'>Hello
|
|
137
|
-
<
|
|
136
|
+
<h1 class='greeting'>Hello${input.accountGivenName ? `, ${input.accountGivenName}` : ''}</h1>
|
|
137
|
+
<p class='cta'>${lockedString(UIStringsNotTranslate.emptyStateTextGemini)}</p>
|
|
138
138
|
` : html`<h1>${lockedString(UIStringsNotTranslate.emptyStateText)}</h1>`
|
|
139
139
|
}
|
|
140
140
|
</div>
|
|
@@ -323,8 +323,7 @@ export class ChatView extends HTMLElement {
|
|
|
323
323
|
this.#view(
|
|
324
324
|
{
|
|
325
325
|
...this.#props,
|
|
326
|
-
|
|
327
|
-
accountName: this.#props.userInfo.accountFullName ?? '',
|
|
326
|
+
accountGivenName: this.#props.userInfo.accountGivenName ?? '',
|
|
328
327
|
handleScroll: this.#handleScroll,
|
|
329
328
|
handleSuggestionClick: this.#handleSuggestionClick,
|
|
330
329
|
handleMessageContainerRef: this.#handleMessageContainerRef,
|
|
@@ -166,12 +166,17 @@ main {
|
|
|
166
166
|
}
|
|
167
167
|
|
|
168
168
|
.gemini {
|
|
169
|
+
.empty-state-container {
|
|
170
|
+
padding: var(--sys-size-8);
|
|
171
|
+
}
|
|
172
|
+
|
|
169
173
|
.empty-state-container .icon {
|
|
170
174
|
display: none;
|
|
171
175
|
}
|
|
172
176
|
|
|
173
177
|
.empty-state-container .header {
|
|
174
178
|
align-items: flex-start;
|
|
179
|
+
line-height: var(--sys-size-4);
|
|
175
180
|
}
|
|
176
181
|
|
|
177
182
|
.empty-state-content {
|
|
@@ -179,9 +184,14 @@ main {
|
|
|
179
184
|
}
|
|
180
185
|
|
|
181
186
|
.empty-state-container .greeting {
|
|
187
|
+
font-size: var(--sys-size-10);
|
|
182
188
|
color: var(--sys-color-primary);
|
|
183
189
|
}
|
|
184
190
|
|
|
191
|
+
.empty-state-container .cta {
|
|
192
|
+
font-size: var(--sys-size-10);
|
|
193
|
+
}
|
|
194
|
+
|
|
185
195
|
main {
|
|
186
196
|
align-items: flex-start;
|
|
187
197
|
}
|
|
@@ -10,7 +10,7 @@ import * as SDK from '../../core/sdk/sdk.js';
|
|
|
10
10
|
import * as Protocol from '../../generated/protocol.js';
|
|
11
11
|
import type * as Buttons from '../../ui/components/buttons/buttons.js';
|
|
12
12
|
import * as uiI18n from '../../ui/i18n/i18n.js';
|
|
13
|
-
import {Icon} from '../../ui/kit/kit.js';
|
|
13
|
+
import {Icon, Link} from '../../ui/kit/kit.js';
|
|
14
14
|
import * as PerfUI from '../../ui/legacy/components/perf_ui/perf_ui.js';
|
|
15
15
|
import * as SettingsUI from '../../ui/legacy/components/settings_ui/settings_ui.js';
|
|
16
16
|
import * as UI from '../../ui/legacy/legacy.js';
|
|
@@ -218,9 +218,9 @@ export class StorageView extends UI.Widget.VBox {
|
|
|
218
218
|
this.quotaRow = quota.appendSelectableRow();
|
|
219
219
|
this.quotaRow.classList.add('quota-usage-row');
|
|
220
220
|
const learnMoreRow = quota.appendRow();
|
|
221
|
-
const learnMore =
|
|
221
|
+
const learnMore = Link.create(
|
|
222
222
|
'https://developer.chrome.com/docs/devtools/progressive-web-apps#opaque-responses',
|
|
223
|
-
i18nString(UIStrings.learnMore), undefined,
|
|
223
|
+
i18nString(UIStrings.learnMore), undefined, 'learn-more');
|
|
224
224
|
learnMoreRow.appendChild(learnMore);
|
|
225
225
|
this.quotaUsage = null;
|
|
226
226
|
this.pieChart = new PerfUI.PieChart.PieChart();
|
|
@@ -19,33 +19,43 @@ const UIStringsNotTranslate = {
|
|
|
19
19
|
*/
|
|
20
20
|
codeCompletionJustGotBetter: 'Code completion just got better',
|
|
21
21
|
/**
|
|
22
|
-
* @description First item in the description
|
|
23
|
-
*/
|
|
24
|
-
asYouType: 'As you type, DevTools generates code suggestions to help you code faster.',
|
|
25
|
-
/**
|
|
26
|
-
* @description Second item in the description
|
|
22
|
+
* @description First item in the description.
|
|
27
23
|
*/
|
|
28
24
|
describeCodeInComment:
|
|
29
|
-
'
|
|
25
|
+
'Pressing Ctrl+I on a comment in the Console and Sources panels now generates entire code blocks based on the instructions in the comment.',
|
|
30
26
|
/**
|
|
31
|
-
* @description
|
|
27
|
+
* @description First item in the description.
|
|
32
28
|
*/
|
|
33
29
|
describeCodeInCommentForMacOs:
|
|
34
|
-
'
|
|
30
|
+
'Pressing Cmd+I on a comment in the Console and Sources panels now generates entire code blocks based on the instructions in the comment.',
|
|
31
|
+
/**
|
|
32
|
+
* @description Second item in the description.
|
|
33
|
+
*/
|
|
34
|
+
asYouType: 'You will still receive the real-time, as-you-type suggestions to help you code faster.',
|
|
35
|
+
/**
|
|
36
|
+
* @description Third item in the description.
|
|
37
|
+
*/
|
|
38
|
+
disclaimerTextPrivacy:
|
|
39
|
+
'To generate code suggestions, your console input, the history of your current console session, the currently inspected CSS, and the contents of the currently open file are shared with Google. This data may be seen by human reviewers to improve this feature.',
|
|
40
|
+
/**
|
|
41
|
+
* @description Third item in the description.
|
|
42
|
+
*/
|
|
43
|
+
disclaimerTextPrivacyNoLogging:
|
|
44
|
+
'To generate code suggestions, your console input, the history of your current console session, the currently inspected CSS, and the contents of the currently open file are shared with Google. This data will not be used to improve Google’s AI models. Your organization may change these settings at any time.',
|
|
35
45
|
/**
|
|
36
46
|
* @description Text for the manage in settings button in the upgrade notice dialog.
|
|
37
47
|
*/
|
|
38
48
|
manageInSettings: 'Manage in settings',
|
|
39
49
|
/**
|
|
40
|
-
* @description Text for the
|
|
50
|
+
* @description Text for the generate code button in the upgrade notice dialog.
|
|
41
51
|
*/
|
|
42
|
-
|
|
52
|
+
generateCode: 'Generate code',
|
|
43
53
|
} as const;
|
|
44
54
|
|
|
45
55
|
const lockedString = i18n.i18n.lockedString;
|
|
46
56
|
|
|
47
57
|
export class AiCodeGenerationUpgradeDialog {
|
|
48
|
-
static show(): void {
|
|
58
|
+
static show({noLogging}: {noLogging: boolean}): void {
|
|
49
59
|
const dialog = new UI.Dialog.Dialog();
|
|
50
60
|
dialog.setAriaLabel(lockedString(UIStringsNotTranslate.codeCompletionJustGotBetter));
|
|
51
61
|
// clang-format off
|
|
@@ -63,10 +73,6 @@ export class AiCodeGenerationUpgradeDialog {
|
|
|
63
73
|
</h2>
|
|
64
74
|
</header>
|
|
65
75
|
<main class="reminder-container">
|
|
66
|
-
<div class="reminder-item">
|
|
67
|
-
<devtools-icon class="reminder-icon" name="code"></devtools-icon>
|
|
68
|
-
<span>${lockedString(UIStringsNotTranslate.asYouType)}</span>
|
|
69
|
-
</div>
|
|
70
76
|
<div class="reminder-item">
|
|
71
77
|
<devtools-icon class="reminder-icon" name="text-analysis"></devtools-icon>
|
|
72
78
|
<span>
|
|
@@ -75,6 +81,16 @@ export class AiCodeGenerationUpgradeDialog {
|
|
|
75
81
|
lockedString(UIStringsNotTranslate.describeCodeInComment)}
|
|
76
82
|
</span>
|
|
77
83
|
</div>
|
|
84
|
+
<div class="reminder-item">
|
|
85
|
+
<devtools-icon class="reminder-icon" name="code"></devtools-icon>
|
|
86
|
+
<span>${lockedString(UIStringsNotTranslate.asYouType)}</span>
|
|
87
|
+
</div>
|
|
88
|
+
<div class="reminder-item">
|
|
89
|
+
<devtools-icon class="reminder-icon" name="google"></devtools-icon>
|
|
90
|
+
<span>${noLogging ? lockedString(UIStringsNotTranslate.disclaimerTextPrivacyNoLogging) :
|
|
91
|
+
lockedString(UIStringsNotTranslate.disclaimerTextPrivacy)}
|
|
92
|
+
</span>
|
|
93
|
+
</div>
|
|
78
94
|
</main>
|
|
79
95
|
<footer>
|
|
80
96
|
<div class="right-buttons">
|
|
@@ -93,7 +109,7 @@ export class AiCodeGenerationUpgradeDialog {
|
|
|
93
109
|
}}
|
|
94
110
|
jslogcontext="ai-code-generation-upgrade-dialog.continue"
|
|
95
111
|
.variant=${Buttons.Button.Variant.PRIMARY}>
|
|
96
|
-
${lockedString(UIStringsNotTranslate.
|
|
112
|
+
${lockedString(UIStringsNotTranslate.generateCode)}
|
|
97
113
|
</devtools-button>
|
|
98
114
|
</div>
|
|
99
115
|
</footer>
|
|
@@ -6,6 +6,7 @@ import * as Common from '../../core/common/common.js';
|
|
|
6
6
|
import * as i18n from '../../core/i18n/i18n.js';
|
|
7
7
|
import * as Platform from '../../core/platform/platform.js';
|
|
8
8
|
import * as SDK from '../../core/sdk/sdk.js';
|
|
9
|
+
import * as StackTrace from '../../models/stack_trace/stack_trace.js';
|
|
9
10
|
import * as UI from '../../ui/legacy/legacy.js';
|
|
10
11
|
import * as Lit from '../../ui/lit/lit.js';
|
|
11
12
|
|
|
@@ -63,7 +64,7 @@ export class ConsoleContextSelector implements SDK.TargetManager.SDKModelObserve
|
|
|
63
64
|
UI.Context.Context.instance().addFlavorChangeListener(
|
|
64
65
|
SDK.RuntimeModel.ExecutionContext, this.executionContextChangedExternally, this);
|
|
65
66
|
UI.Context.Context.instance().addFlavorChangeListener(
|
|
66
|
-
|
|
67
|
+
StackTrace.StackTrace.DebuggableFrameFlavor, this.callFrameSelectedInUI, this);
|
|
67
68
|
SDK.TargetManager.TargetManager.instance().observeModels(SDK.RuntimeModel.RuntimeModel, this, {scoped: true});
|
|
68
69
|
SDK.TargetManager.TargetManager.instance().addModelListener(
|
|
69
70
|
SDK.DebuggerModel.DebuggerModel, SDK.DebuggerModel.Events.CallFrameSelected, this.callFrameSelectedInModel,
|
|
@@ -263,8 +264,8 @@ export class ConsoleContextSelector implements SDK.TargetManager.SDKModelObserve
|
|
|
263
264
|
}
|
|
264
265
|
|
|
265
266
|
private callFrameSelectedInUI(): void {
|
|
266
|
-
const callFrame = UI.Context.Context.instance().flavor(
|
|
267
|
-
const callFrameContext = callFrame?.script.executionContext();
|
|
267
|
+
const callFrame = UI.Context.Context.instance().flavor(StackTrace.StackTrace.DebuggableFrameFlavor);
|
|
268
|
+
const callFrameContext = callFrame?.sdkFrame.script.executionContext();
|
|
268
269
|
if (callFrameContext) {
|
|
269
270
|
UI.Context.Context.instance().setFlavor(SDK.RuntimeModel.ExecutionContext, callFrameContext);
|
|
270
271
|
}
|
|
@@ -199,11 +199,34 @@ export const format = (fmt: string, args: SDK.RemoteObject.RemoteObject[]): {
|
|
|
199
199
|
return {tokens, args: args.slice(argIndex)};
|
|
200
200
|
};
|
|
201
201
|
|
|
202
|
+
/**
|
|
203
|
+
* This function converts a string into a partial regex string that
|
|
204
|
+
* case-insensitively matches it in CSS, even if CSS escapes are used.
|
|
205
|
+
*
|
|
206
|
+
* @param cssString the target string.
|
|
207
|
+
* @returns a partial regex matching the string in CSS.
|
|
208
|
+
*/
|
|
209
|
+
const cssEscapeRegex = (cssString: string): string => {
|
|
210
|
+
return [...cssString]
|
|
211
|
+
.map(char => {
|
|
212
|
+
const charCodes = new Set([char.toLowerCase(), char.toUpperCase()].map(c => c.charCodeAt(0).toString(16)));
|
|
213
|
+
const charCodeRegex =
|
|
214
|
+
[...charCodes].map(charCode => `\\\\0{0,${6 - charCode.length}}${charCode}[ \\n\\t]?`).join('|');
|
|
215
|
+
return `\\\\?(?:${charCodeRegex}|${char})`;
|
|
216
|
+
})
|
|
217
|
+
.join('');
|
|
218
|
+
};
|
|
219
|
+
|
|
202
220
|
export const updateStyle = (currentStyle: Map<string, {value: string, priority: string}>, styleToAdd: string): void => {
|
|
203
221
|
const ALLOWED_PROPERTY_PREFIXES = ['background', 'border', 'color', 'font', 'line', 'margin', 'padding', 'text'];
|
|
204
222
|
// We only allow data URLs with the `url()` CSS function.
|
|
205
223
|
// The capture group is not intended to grab the whole URL exactly, just enough so we can check the scheme.
|
|
206
|
-
|
|
224
|
+
// The regex also covers CSS hex-escaped variations of `url()`.
|
|
225
|
+
const URL_REGEX = new RegExp(`(?=${cssEscapeRegex('url')}\\(['"]?([^\\)]*))`, 'gi');
|
|
226
|
+
// We greedily capture all `image-set()`s to make sure that all of
|
|
227
|
+
// them properly use `url()`s to enforce the data URL check later.
|
|
228
|
+
const IMAGESET_REGEX = new RegExp(`(?=(${cssEscapeRegex('image-set')}\\(.*))`, 'gi');
|
|
229
|
+
const GOOD_IMAGESET_REGEX = /^image-set\((?:(?:(?:url|type)\("[^\\"]*"\)|[\d.]+(?:x|dpi|dpcm|dppx)),?\s*)+\)/i;
|
|
207
230
|
|
|
208
231
|
currentStyle.clear();
|
|
209
232
|
/* eslint-disable-next-line @devtools/no-imperative-dom-api --
|
|
@@ -218,9 +241,15 @@ export const updateStyle = (currentStyle: Map<string, {value: string, priority:
|
|
|
218
241
|
continue;
|
|
219
242
|
}
|
|
220
243
|
|
|
244
|
+
const value = buffer.style.getPropertyValue(property);
|
|
245
|
+
// We make sure every `image-set()` only uses `url()`s for its images.
|
|
246
|
+
// If any of them seem malformed, we skip the whole property.
|
|
247
|
+
const imageSets = [...value.matchAll(IMAGESET_REGEX)];
|
|
248
|
+
if (imageSets.some(match => !GOOD_IMAGESET_REGEX.test(match[1]))) {
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
221
251
|
// There could be multiple `url()` functions, so we check them all.
|
|
222
252
|
// If any of them is not a `data` URL, we skip the whole property.
|
|
223
|
-
const value = buffer.style.getPropertyValue(property);
|
|
224
253
|
const potentialUrls = [...value.matchAll(URL_REGEX)].map(match => match[1]);
|
|
225
254
|
if (potentialUrls.some(
|
|
226
255
|
potentialUrl => !Common.ParsedURL.schemeIs(potentialUrl as Platform.DevToolsPath.UrlString, 'data:'))) {
|
|
@@ -626,6 +626,7 @@ export class ConsoleInsightTeaser extends UI.Widget.Widget {
|
|
|
626
626
|
this.#startTime = performance.now();
|
|
627
627
|
let teaserText = '';
|
|
628
628
|
let firstChunkReceived = false;
|
|
629
|
+
let firstChunkTime = 0;
|
|
629
630
|
try {
|
|
630
631
|
for await (const chunk of this.#getOnDeviceInsight()) {
|
|
631
632
|
teaserText += chunk;
|
|
@@ -634,7 +635,9 @@ export class ConsoleInsightTeaser extends UI.Widget.Widget {
|
|
|
634
635
|
this.requestUpdate();
|
|
635
636
|
if (!firstChunkReceived) {
|
|
636
637
|
firstChunkReceived = true;
|
|
637
|
-
|
|
638
|
+
firstChunkTime = performance.now();
|
|
639
|
+
Host.userMetrics.consoleInsightTeaserFirstChunkGenerated(firstChunkTime - this.#startTime);
|
|
640
|
+
Host.userMetrics.consoleInsightTeaserFirstChunkGeneratedMedium(firstChunkTime - this.#startTime);
|
|
638
641
|
}
|
|
639
642
|
}
|
|
640
643
|
} catch (err) {
|
|
@@ -654,6 +657,8 @@ export class ConsoleInsightTeaser extends UI.Widget.Widget {
|
|
|
654
657
|
clearTimeout(this.#timeoutId);
|
|
655
658
|
const duration = performance.now() - this.#startTime;
|
|
656
659
|
Host.userMetrics.consoleInsightTeaserGenerated(duration);
|
|
660
|
+
Host.userMetrics.consoleInsightTeaserGeneratedMedium(duration);
|
|
661
|
+
Host.userMetrics.consoleInsightTeaserChunkToEndMedium(performance.now() - firstChunkTime);
|
|
657
662
|
if (teaserText.length > 300) {
|
|
658
663
|
Host.userMetrics.consoleInsightLongTeaserGenerated(duration);
|
|
659
664
|
} else {
|
|
@@ -54,7 +54,7 @@ import * as Buttons from '../../ui/components/buttons/buttons.js';
|
|
|
54
54
|
import * as CodeHighlighter from '../../ui/components/code_highlighter/code_highlighter.js';
|
|
55
55
|
import * as Highlighting from '../../ui/components/highlighting/highlighting.js';
|
|
56
56
|
import * as TextEditor from '../../ui/components/text_editor/text_editor.js';
|
|
57
|
-
import {Icon} from '../../ui/kit/kit.js';
|
|
57
|
+
import {Icon, Link} from '../../ui/kit/kit.js';
|
|
58
58
|
import * as Components from '../../ui/legacy/components/utils/utils.js';
|
|
59
59
|
import * as UI from '../../ui/legacy/legacy.js';
|
|
60
60
|
import * as Lit from '../../ui/lit/lit.js';
|
|
@@ -1092,6 +1092,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1092
1092
|
}
|
|
1093
1093
|
|
|
1094
1094
|
override onbind(): void {
|
|
1095
|
+
this.performUpdate();
|
|
1095
1096
|
if (this.treeOutline && !this.isClosingTag()) {
|
|
1096
1097
|
this.treeOutline.treeElementByNode.set(this.nodeInternal, this);
|
|
1097
1098
|
this.nodeInternal.addEventListener(SDK.DOMModel.DOMNodeEvents.TOP_LAYER_INDEX_CHANGED, this.performUpdate, this);
|
|
@@ -1115,6 +1116,49 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1115
1116
|
if (this.editing) {
|
|
1116
1117
|
this.editing.cancel();
|
|
1117
1118
|
}
|
|
1119
|
+
// Update the element to clean up adorner registrations with the
|
|
1120
|
+
// ElementsPanel.
|
|
1121
|
+
// We do not change the ElementsTreeElement state in case the
|
|
1122
|
+
// element is bound again.
|
|
1123
|
+
DEFAULT_VIEW(
|
|
1124
|
+
{
|
|
1125
|
+
containerAdornerActive: false,
|
|
1126
|
+
showAdAdorner: false,
|
|
1127
|
+
showContainerAdorner: false,
|
|
1128
|
+
containerType: this.#layout?.containerType,
|
|
1129
|
+
showFlexAdorner: false,
|
|
1130
|
+
flexAdornerActive: false,
|
|
1131
|
+
showGridAdorner: false,
|
|
1132
|
+
showGridLanesAdorner: false,
|
|
1133
|
+
showMediaAdorner: false,
|
|
1134
|
+
showPopoverAdorner: false,
|
|
1135
|
+
showTopLayerAdorner: false,
|
|
1136
|
+
gridAdornerActive: false,
|
|
1137
|
+
popoverAdornerActive: false,
|
|
1138
|
+
isSubgrid: false,
|
|
1139
|
+
showViewSourceAdorner: false,
|
|
1140
|
+
showScrollAdorner: false,
|
|
1141
|
+
showScrollSnapAdorner: false,
|
|
1142
|
+
scrollSnapAdornerActive: false,
|
|
1143
|
+
showSlotAdorner: false,
|
|
1144
|
+
showStartingStyleAdorner: false,
|
|
1145
|
+
startingStyleAdornerActive: false,
|
|
1146
|
+
nodeInfo: this.#nodeInfo,
|
|
1147
|
+
onStartingStyleAdornerClick: () => {},
|
|
1148
|
+
onSlotAdornerClick: () => {},
|
|
1149
|
+
topLayerIndex: -1,
|
|
1150
|
+
onViewSourceAdornerClick: () => {},
|
|
1151
|
+
onGutterClick: () => {},
|
|
1152
|
+
onContainerAdornerClick: () => {},
|
|
1153
|
+
onFlexAdornerClick: () => {},
|
|
1154
|
+
onGridAdornerClick: () => {},
|
|
1155
|
+
onMediaAdornerClick: () => {},
|
|
1156
|
+
onPopoverAdornerClick: () => {},
|
|
1157
|
+
onScrollSnapAdornerClick: () => {},
|
|
1158
|
+
onTopLayerAdornerClick: () => {},
|
|
1159
|
+
},
|
|
1160
|
+
this, this.listItemElement);
|
|
1161
|
+
|
|
1118
1162
|
if (this.treeOutline && this.treeOutline.treeElementByNode.get(this.nodeInternal) === this) {
|
|
1119
1163
|
this.treeOutline.treeElementByNode.delete(this.nodeInternal);
|
|
1120
1164
|
}
|
|
@@ -2414,7 +2458,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
2414
2458
|
value = Platform.StringUtilities.trimMiddle(value, 60);
|
|
2415
2459
|
}
|
|
2416
2460
|
const link = node && node.nodeName().toLowerCase() === 'a' ?
|
|
2417
|
-
|
|
2461
|
+
Link.create(rewrittenHref, value, undefined, 'image-url') :
|
|
2418
2462
|
Components.Linkifier.Linkifier.linkifyURL(rewrittenHref, {
|
|
2419
2463
|
text: value,
|
|
2420
2464
|
preventClick: true,
|
|
@@ -80,7 +80,7 @@ const str_ = i18n.i18n.registerUIStrings('panels/elements/ElementsTreeOutline.ts
|
|
|
80
80
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
81
81
|
const elementsTreeOutlineByDOMModel = new WeakMap<SDK.DOMModel.DOMModel, ElementsTreeOutline>();
|
|
82
82
|
|
|
83
|
-
const populatedTreeElements = new
|
|
83
|
+
const populatedTreeElements = new WeakSet<ElementsTreeElement>();
|
|
84
84
|
|
|
85
85
|
export type View = typeof DEFAULT_VIEW;
|
|
86
86
|
|
|
@@ -101,6 +101,14 @@ const UIStrings = {
|
|
|
101
101
|
* @description A context menu item in Styles panel to view the computed CSS property value.
|
|
102
102
|
*/
|
|
103
103
|
viewComputedValue: 'View computed value',
|
|
104
|
+
/**
|
|
105
|
+
* @description Tooltip text for a style property overridden by an animation.
|
|
106
|
+
*/
|
|
107
|
+
overriddenByAnimation: 'Overridden by animation styles.',
|
|
108
|
+
/**
|
|
109
|
+
* @description Link text in the tooltip to open the Animations panel.
|
|
110
|
+
*/
|
|
111
|
+
openAnimationsPanel: 'Open Animations panel',
|
|
104
112
|
/**
|
|
105
113
|
* @description Title of the button that opens the flexbox editor in the Styles panel.
|
|
106
114
|
*/
|
|
@@ -2465,6 +2473,7 @@ export class StylePropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
2465
2473
|
|
|
2466
2474
|
if (this.property.parsedOk) {
|
|
2467
2475
|
this.updateAuthoringHint();
|
|
2476
|
+
this.updateAnimationOverrideHint();
|
|
2468
2477
|
} else {
|
|
2469
2478
|
// Avoid having longhands under an invalid shorthand.
|
|
2470
2479
|
this.listItemElement.classList.add('not-parsed-ok');
|
|
@@ -2695,6 +2704,60 @@ export class StylePropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
2695
2704
|
}
|
|
2696
2705
|
}
|
|
2697
2706
|
|
|
2707
|
+
updateAnimationOverrideHint(): void {
|
|
2708
|
+
const existingElement = this.listItemElement.querySelector('.animation-override-hint-wrapper');
|
|
2709
|
+
if (existingElement) {
|
|
2710
|
+
existingElement?.remove();
|
|
2711
|
+
}
|
|
2712
|
+
|
|
2713
|
+
if (!this.overriddenByAnimation() || UI.ViewManager.ViewManager.instance().isViewVisible('animations')) {
|
|
2714
|
+
return;
|
|
2715
|
+
}
|
|
2716
|
+
|
|
2717
|
+
const wrapper = document.createElement('span');
|
|
2718
|
+
wrapper.classList.add('animation-override-hint-wrapper', 'hint-wrapper');
|
|
2719
|
+
const hintIcon = new Icon();
|
|
2720
|
+
hintIcon.name = 'info';
|
|
2721
|
+
hintIcon.classList.add('hint', 'small');
|
|
2722
|
+
hintIcon.tabIndex = -1;
|
|
2723
|
+
|
|
2724
|
+
wrapper.append(hintIcon);
|
|
2725
|
+
this.listItemElement.append(wrapper);
|
|
2726
|
+
|
|
2727
|
+
const tooltipId = this.getTooltipId('animation-override-hint');
|
|
2728
|
+
hintIcon.setAttribute('aria-details', tooltipId);
|
|
2729
|
+
|
|
2730
|
+
const tooltip = new Tooltips.Tooltip.Tooltip({
|
|
2731
|
+
anchor: hintIcon,
|
|
2732
|
+
variant: 'rich',
|
|
2733
|
+
padding: 'large',
|
|
2734
|
+
id: tooltipId,
|
|
2735
|
+
jslogContext: 'elements.css-animation-hint'
|
|
2736
|
+
});
|
|
2737
|
+
const message = i18nString(UIStrings.overriddenByAnimation);
|
|
2738
|
+
const content = document.createElement('div');
|
|
2739
|
+
content.classList.add('animation-override-hint');
|
|
2740
|
+
content.textContent = message;
|
|
2741
|
+
|
|
2742
|
+
const link = document.createElement('devtools-link');
|
|
2743
|
+
link.textContent = i18nString(UIStrings.openAnimationsPanel);
|
|
2744
|
+
link.jslogContext = 'open-in-animations-panel';
|
|
2745
|
+
link.addEventListener('click', event => {
|
|
2746
|
+
event.preventDefault();
|
|
2747
|
+
void UI.ViewManager.ViewManager.instance().showView('animations');
|
|
2748
|
+
});
|
|
2749
|
+
|
|
2750
|
+
content.appendChild(document.createTextNode(' '));
|
|
2751
|
+
content.appendChild(link);
|
|
2752
|
+
tooltip.appendChild(content);
|
|
2753
|
+
|
|
2754
|
+
this.listItemElement.appendChild(tooltip);
|
|
2755
|
+
}
|
|
2756
|
+
|
|
2757
|
+
private overriddenByAnimation(): boolean {
|
|
2758
|
+
return this.#matchedStyles.isPropertyOverriddenByAnimation(this.property);
|
|
2759
|
+
}
|
|
2760
|
+
|
|
2698
2761
|
private mouseUp(event: MouseEvent): void {
|
|
2699
2762
|
const activeTreeElement = parentMap.get(this.#parentPane);
|
|
2700
2763
|
parentMap.delete(this.#parentPane);
|
|
@@ -237,6 +237,12 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
|
|
|
237
237
|
}
|
|
238
238
|
return null;
|
|
239
239
|
}, () => this.node());
|
|
240
|
+
|
|
241
|
+
UI.ViewManager.ViewManager.instance().addEventListener(UI.ViewManager.Events.VIEW_VISIBILITY_CHANGED, event => {
|
|
242
|
+
if (event.data.revealedViewId === 'animations' || event.data.hiddenViewId === 'animations') {
|
|
243
|
+
this.#scheduleResetUpdateIfNotEditing();
|
|
244
|
+
}
|
|
245
|
+
});
|
|
240
246
|
}
|
|
241
247
|
|
|
242
248
|
get webCustomData(): WebCustomData|undefined {
|
|
@@ -741,6 +747,10 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
|
|
|
741
747
|
return;
|
|
742
748
|
}
|
|
743
749
|
|
|
750
|
+
if (!UI.ViewManager.ViewManager.instance().isViewVisible('animations')) {
|
|
751
|
+
return;
|
|
752
|
+
}
|
|
753
|
+
|
|
744
754
|
void this.computedStyleUpdateThrottler.schedule(async () => {
|
|
745
755
|
await this.#updateAnimatedStyles();
|
|
746
756
|
this.handledComputedStyleChangedForTest();
|
|
@@ -1078,7 +1088,14 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
|
|
|
1078
1088
|
// We disable the layer widget initially. If we see a layer in
|
|
1079
1089
|
// the matched styles we reenable the button.
|
|
1080
1090
|
LayersWidget.ButtonProvider.instance().item().setVisible(false);
|
|
1091
|
+
const animationsPanelVisible = UI.ViewManager.ViewManager.instance().isViewVisible('animations');
|
|
1081
1092
|
for (const style of matchedStyles.nodeStyles()) {
|
|
1093
|
+
const isTransitionOrAnimationStyle = style.type === SDK.CSSStyleDeclaration.Type.Transition ||
|
|
1094
|
+
style.type === SDK.CSSStyleDeclaration.Type.Animation;
|
|
1095
|
+
if (isTransitionOrAnimationStyle && !animationsPanelVisible) {
|
|
1096
|
+
continue;
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1082
1099
|
const parentNode = matchedStyles.isInherited(style) ? matchedStyles.nodeForStyle(style) : null;
|
|
1083
1100
|
if (parentNode && parentNode !== lastParentNode) {
|
|
1084
1101
|
lastParentNode = parentNode;
|
|
@@ -1090,8 +1107,6 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
|
|
|
1090
1107
|
addLayerSeparator(style);
|
|
1091
1108
|
|
|
1092
1109
|
const lastBlock = blocks[blocks.length - 1];
|
|
1093
|
-
const isTransitionOrAnimationStyle = style.type === SDK.CSSStyleDeclaration.Type.Transition ||
|
|
1094
|
-
style.type === SDK.CSSStyleDeclaration.Type.Animation;
|
|
1095
1110
|
if (lastBlock && (!isTransitionOrAnimationStyle || style.allProperties().length > 0)) {
|
|
1096
1111
|
this.idleCallbackManager.schedule(() => {
|
|
1097
1112
|
const section = new StylePropertiesSection(
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import * as i18n from '../../core/i18n/i18n.js';
|
|
7
7
|
import type * as Platform from '../../core/platform/platform.js';
|
|
8
|
-
import
|
|
8
|
+
import {Link} from '../../ui/kit/kit.js';
|
|
9
9
|
|
|
10
10
|
import {AffectedResourcesView} from './AffectedResourcesView.js';
|
|
11
11
|
|
|
@@ -46,8 +46,8 @@ export class AffectedMetadataAllowedSitesView extends AffectedResourcesView {
|
|
|
46
46
|
optOutTextElement.textContent = ' (opt-out: ' + issueData.details().optOutPercentage + '% - ';
|
|
47
47
|
textContentElement.appendChild(optOutTextElement);
|
|
48
48
|
|
|
49
|
-
const linkElement =
|
|
50
|
-
'https://developers.google.com/privacy-sandbox/blog/grace-period-opt-out', 'learn more');
|
|
49
|
+
const linkElement =
|
|
50
|
+
Link.create('https://developers.google.com/privacy-sandbox/blog/grace-period-opt-out', 'learn more');
|
|
51
51
|
textContentElement.appendChild(linkElement);
|
|
52
52
|
|
|
53
53
|
const endTextElement = document.createElement('span');
|
|
@@ -9,6 +9,7 @@ import type * as SDK from '../../core/sdk/sdk.js';
|
|
|
9
9
|
import type * as Protocol from '../../generated/protocol.js';
|
|
10
10
|
import * as Geometry from '../../models/geometry/geometry.js';
|
|
11
11
|
import * as uiI18n from '../../ui/i18n/i18n.js';
|
|
12
|
+
import {Link} from '../../ui/kit/kit.js';
|
|
12
13
|
import * as UI from '../../ui/legacy/legacy.js';
|
|
13
14
|
import * as Lit from '../../ui/lit/lit.js';
|
|
14
15
|
import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
|
|
@@ -118,7 +119,7 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
|
|
|
118
119
|
uiI18n.getFormatLocalizedString(
|
|
119
120
|
str_, UIStrings.checkSForPossibleReasons,
|
|
120
121
|
{
|
|
121
|
-
PH1:
|
|
122
|
+
PH1: Link.create('about:gpu', undefined, undefined, 'about-gpu')
|
|
122
123
|
}
|
|
123
124
|
)
|
|
124
125
|
],
|