chrome-devtools-frontend 1.0.1534251 → 1.0.1534717
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/contributing/infrastructure.md +32 -0
- package/front_end/core/host/InspectorFrontendHost.ts +1 -5
- package/front_end/core/host/InspectorFrontendHostAPI.ts +1 -0
- package/front_end/core/host/UserMetrics.ts +24 -0
- package/front_end/core/protocol_client/InspectorBackend.ts +0 -89
- package/front_end/core/root/Runtime.ts +1 -0
- package/front_end/core/sdk/RehydratingConnection.ts +1 -1
- package/front_end/devtools_compatibility.js +206 -16
- package/front_end/models/ai_assistance/BuiltInAi.ts +141 -39
- package/front_end/panels/common/BadgeNotification.ts +1 -3
- package/front_end/panels/console/ConsoleInsightTeaser.ts +2 -0
- package/front_end/panels/network/components/ResponseHeaderSection.ts +1 -2
- package/front_end/ui/components/dialogs/Dialog.ts +7 -17
- package/front_end/ui/components/text_editor/TextEditor.ts +2 -3
- package/front_end/ui/components/text_editor/config.ts +1 -3
- package/front_end/ui/legacy/UIUtils.ts +5 -0
- package/front_end/ui/legacy/components/inline_editor/CSSAngle.ts +1 -1
- package/front_end/ui/legacy/components/perf_ui/BrickBreaker.ts +2 -2
- package/front_end/ui/legacy/components/perf_ui/Font.ts +1 -14
- package/inspector_overlay/testing/InspectorOverlayHelpers.ts +2 -10
- package/package.json +1 -1
- package/front_end/services/window_bounds/WindowBoundsService.ts +0 -27
- package/front_end/services/window_bounds/window_bounds.ts +0 -9
|
@@ -68,6 +68,27 @@ https://chromium.googlesource.com/chromium/tools/build/+/refs/heads/main/recipes
|
|
|
68
68
|
and upload a CL for
|
|
69
69
|
[`chromium/tools/build`](https://chromium.googlesource.com/chromium/tools/build/+/refs/heads/main).
|
|
70
70
|
|
|
71
|
+
It's good practice to also manually test your recipes. You can test your recipe
|
|
72
|
+
changes against a build that was performed with the same recipes. To do so
|
|
73
|
+
follow these steps:
|
|
74
|
+
- authenticate with `led auth-login`
|
|
75
|
+
- select a particular build that ran with your target recipe ([example](https://ci.chromium.org/ui/p/devtools-frontend/builders/try/dtf_linux_dbg/14161))
|
|
76
|
+
- got to Infra tab and collect the Buildbucket id (8700153319150087425 for the example above)
|
|
77
|
+
- run `led get-build --real-build 8700153319150087425 | led edit-recipe-bundle | led edit-system -p 25 | led launch` while in your local recipe checkout
|
|
78
|
+
- collect the output link to your test build and verify that you got the expected result
|
|
79
|
+
|
|
80
|
+
## Pin older version of DevTools recipes to a branch
|
|
81
|
+
|
|
82
|
+
Updating a recipe that depends on DevTools repo recent changes can break the
|
|
83
|
+
build in beta/stable/extended branches. If those changes cannot be back-merged
|
|
84
|
+
into the branches you can pin the older version of the recipe to the branches in
|
|
85
|
+
infra/config.
|
|
86
|
+
|
|
87
|
+
To do so update the `legacy_recipe` config in `definitions.star` with the number
|
|
88
|
+
of the last branch you need the old version of the recipe to run on and with the
|
|
89
|
+
revision hash of that version. Branches with number higher than the one you
|
|
90
|
+
configured will run ToT recipe version. [Example](https://crrev.com/c/7003685)
|
|
91
|
+
|
|
71
92
|
## Updating test commands in the infrastructure
|
|
72
93
|
|
|
73
94
|
The DevTools recipes are defined in
|
|
@@ -228,6 +249,17 @@ Below is a detailed description of what happens in such a build:
|
|
|
228
249
|
- fail the builder if tests failed in the deflaking phase
|
|
229
250
|
- otherwise report build as passing
|
|
230
251
|
|
|
252
|
+
## Skip flake detection
|
|
253
|
+
|
|
254
|
+
Test that are already flaky can end up being updated in CLs that do not deal
|
|
255
|
+
with the original flakiness nor can be blamed for introducing or increasing the
|
|
256
|
+
flakiness of the test. However CQ builder will fail in Flake Detection steps
|
|
257
|
+
because they picked up the test as it was being touched.
|
|
258
|
+
|
|
259
|
+
You can skip Flake Detection for your tests by adding the `Skip-Flake-Detection`
|
|
260
|
+
CL footer (see example [CL](https://crrev.com/c/6994031)). Make sure you use the
|
|
261
|
+
full path to your test.
|
|
262
|
+
|
|
231
263
|
### Common build failures
|
|
232
264
|
|
|
233
265
|
The first place where a build usually fails is on `bot_update` and this usually
|
|
@@ -600,13 +600,9 @@ class InspectorFrontendAPIImpl {
|
|
|
600
600
|
resourceLoaderStreamWrite(id, chunk);
|
|
601
601
|
}
|
|
602
602
|
}
|
|
603
|
-
/**
|
|
604
|
-
* Used in `front_end/devtools_compatibility.js` to verify that calls from there
|
|
605
|
-
* are valid.
|
|
606
|
-
*/
|
|
607
|
-
export type InspectorFrontendAPIImplMethods = keyof InspectorFrontendAPIImpl;
|
|
608
603
|
|
|
609
604
|
(function(): void {
|
|
605
|
+
|
|
610
606
|
function initializeInspectorFrontendHost(): void {
|
|
611
607
|
if (!InspectorFrontendHostInstance) {
|
|
612
608
|
// Instantiate stub for web-hosted mode if necessary.
|
|
@@ -550,5 +550,6 @@ export const enum EnumeratedHistogram {
|
|
|
550
550
|
LighthouseCategoryUsed = 'DevTools.LighthouseCategoryUsed',
|
|
551
551
|
SwatchActivated = 'DevTools.SwatchActivated',
|
|
552
552
|
AnimationPlaybackRateChanged = 'DevTools.AnimationPlaybackRateChanged',
|
|
553
|
+
BuiltInAiAvailability = 'DevTools.BuiltInAiAvailability',
|
|
553
554
|
// LINT.ThenChange(/front_end/devtools_compatibility.js:EnumeratedHistogram)
|
|
554
555
|
}
|
|
@@ -307,6 +307,16 @@ export class UserMetrics {
|
|
|
307
307
|
InspectorFrontendHostInstance.recordCountHistogram(
|
|
308
308
|
'DevTools.PerformanceAI.MainThreadActivityResponseSize', bytes, 0, 100_000, 100);
|
|
309
309
|
}
|
|
310
|
+
|
|
311
|
+
builtInAiAvailability(availability: BuiltInAiAvailability): void {
|
|
312
|
+
InspectorFrontendHostInstance.recordEnumeratedHistogram(
|
|
313
|
+
EnumeratedHistogram.BuiltInAiAvailability, availability, BuiltInAiAvailability.MAX_VALUE);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
consoleInsightTeaserGenerated(timeInMilliseconds: number): void {
|
|
317
|
+
InspectorFrontendHostInstance.recordPerformanceHistogram(
|
|
318
|
+
'DevTools.Insights.TeaserGenerationTime', timeInMilliseconds);
|
|
319
|
+
}
|
|
310
320
|
}
|
|
311
321
|
|
|
312
322
|
/**
|
|
@@ -1229,3 +1239,17 @@ export const enum TimelineNavigationSetting {
|
|
|
1229
1239
|
SWITCHED_TO_MODERN = 3,
|
|
1230
1240
|
MAX_VALUE = 4,
|
|
1231
1241
|
}
|
|
1242
|
+
|
|
1243
|
+
export const enum BuiltInAiAvailability {
|
|
1244
|
+
UNAVAILABLE_HAS_GPU = 0,
|
|
1245
|
+
DOWNLOADABLE_HAS_GPU = 1,
|
|
1246
|
+
DOWNLOADING_HAS_GPU = 2,
|
|
1247
|
+
AVAILABLE_HAS_GPU = 3,
|
|
1248
|
+
DISABLED_HAS_GPU = 4,
|
|
1249
|
+
UNAVAILABLE_NO_GPU = 5,
|
|
1250
|
+
DOWNLOADABLE_NO_GPU = 6,
|
|
1251
|
+
DOWNLOADING_NO_GPU = 7,
|
|
1252
|
+
AVAILABLE_NO_GPU = 8,
|
|
1253
|
+
DISABLED_NO_GPU = 9,
|
|
1254
|
+
MAX_VALUE = 10,
|
|
1255
|
+
}
|
|
@@ -855,13 +855,11 @@ export class TargetBase {
|
|
|
855
855
|
* of the invoke_enable, etc. methods that the front-end uses.
|
|
856
856
|
*/
|
|
857
857
|
class AgentPrototype {
|
|
858
|
-
replyArgs: Record<string, string[]>;
|
|
859
858
|
description = '';
|
|
860
859
|
metadata: Record<string, {parameters: CommandParameter[], description: string, replyArgs: string[]}>;
|
|
861
860
|
readonly domain: string;
|
|
862
861
|
target!: TargetBase;
|
|
863
862
|
constructor(domain: string) {
|
|
864
|
-
this.replyArgs = {};
|
|
865
863
|
this.domain = domain;
|
|
866
864
|
this.metadata = {};
|
|
867
865
|
}
|
|
@@ -869,11 +867,6 @@ class AgentPrototype {
|
|
|
869
867
|
registerCommand(
|
|
870
868
|
methodName: UnqualifiedName, parameters: CommandParameter[], replyArgs: string[], description: string): void {
|
|
871
869
|
const domainAndMethod = qualifyName(this.domain, methodName);
|
|
872
|
-
function sendMessagePromise(this: AgentPrototype, ...args: unknown[]): Promise<unknown> {
|
|
873
|
-
return AgentPrototype.prototype.sendMessageToBackendPromise.call(this, domainAndMethod, parameters, args);
|
|
874
|
-
}
|
|
875
|
-
// @ts-expect-error Method code generation
|
|
876
|
-
this[methodName] = sendMessagePromise;
|
|
877
870
|
this.metadata[domainAndMethod] = {parameters, description, replyArgs};
|
|
878
871
|
|
|
879
872
|
function invoke(this: AgentPrototype, request: Object|undefined = {}): Promise<Protocol.ProtocolResponseWithError> {
|
|
@@ -882,88 +875,6 @@ class AgentPrototype {
|
|
|
882
875
|
|
|
883
876
|
// @ts-expect-error Method code generation
|
|
884
877
|
this['invoke_' + methodName] = invoke;
|
|
885
|
-
this.replyArgs[domainAndMethod] = replyArgs;
|
|
886
|
-
}
|
|
887
|
-
|
|
888
|
-
private prepareParameters(
|
|
889
|
-
method: string, parameters: CommandParameter[], args: unknown[], errorCallback: (arg0: string) => void): Object
|
|
890
|
-
|null {
|
|
891
|
-
const params: Record<string, unknown> = {};
|
|
892
|
-
let hasParams = false;
|
|
893
|
-
|
|
894
|
-
for (const param of parameters) {
|
|
895
|
-
const paramName = param.name;
|
|
896
|
-
const typeName = param.type;
|
|
897
|
-
const optionalFlag = param.optional;
|
|
898
|
-
|
|
899
|
-
if (!args.length && !optionalFlag) {
|
|
900
|
-
errorCallback(
|
|
901
|
-
`Protocol Error: Invalid number of arguments for method '${method}' call. ` +
|
|
902
|
-
`It must have the following arguments ${JSON.stringify(parameters)}'.`);
|
|
903
|
-
return null;
|
|
904
|
-
}
|
|
905
|
-
|
|
906
|
-
const value = args.shift();
|
|
907
|
-
if (optionalFlag && typeof value === 'undefined') {
|
|
908
|
-
continue;
|
|
909
|
-
}
|
|
910
|
-
const expectedJSType = typeName === 'array' ? 'object' : typeName;
|
|
911
|
-
if (typeof value !== expectedJSType) {
|
|
912
|
-
errorCallback(
|
|
913
|
-
`Protocol Error: Invalid type of argument '${paramName}' for method '${method}' call. ` +
|
|
914
|
-
`It must be '${typeName}' but it is '${typeof value}'.`);
|
|
915
|
-
return null;
|
|
916
|
-
}
|
|
917
|
-
|
|
918
|
-
params[paramName] = value;
|
|
919
|
-
hasParams = true;
|
|
920
|
-
}
|
|
921
|
-
|
|
922
|
-
if (args.length) {
|
|
923
|
-
errorCallback(`Protocol Error: Extra ${args.length} arguments in a call to method '${method}'.`);
|
|
924
|
-
return null;
|
|
925
|
-
}
|
|
926
|
-
|
|
927
|
-
return hasParams ? params : null;
|
|
928
|
-
}
|
|
929
|
-
|
|
930
|
-
private sendMessageToBackendPromise(method: QualifiedName, parameters: CommandParameter[], args: unknown[]):
|
|
931
|
-
Promise<unknown> {
|
|
932
|
-
let errorMessage;
|
|
933
|
-
function onError(message: string): void {
|
|
934
|
-
console.error(message);
|
|
935
|
-
errorMessage = message;
|
|
936
|
-
}
|
|
937
|
-
const params = this.prepareParameters(method, parameters, args, onError);
|
|
938
|
-
if (errorMessage) {
|
|
939
|
-
return Promise.resolve(null);
|
|
940
|
-
}
|
|
941
|
-
|
|
942
|
-
return new Promise(resolve => {
|
|
943
|
-
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
|
|
944
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
945
|
-
const callback: Callback = (error: MessageError|null, result: any|null): void => {
|
|
946
|
-
if (error) {
|
|
947
|
-
if (!test.suppressRequestErrors && error.code !== DevToolsStubErrorCode && error.code !== GenericErrorCode &&
|
|
948
|
-
error.code !== ConnectionClosedErrorCode) {
|
|
949
|
-
console.error('Request ' + method + ' failed. ' + JSON.stringify(error));
|
|
950
|
-
}
|
|
951
|
-
|
|
952
|
-
resolve(null);
|
|
953
|
-
return;
|
|
954
|
-
}
|
|
955
|
-
|
|
956
|
-
const args = this.replyArgs[method];
|
|
957
|
-
resolve(result && args.length ? result[args[0]] : undefined);
|
|
958
|
-
};
|
|
959
|
-
|
|
960
|
-
const router = this.target.router();
|
|
961
|
-
if (!router) {
|
|
962
|
-
SessionRouter.dispatchConnectionError(callback, method);
|
|
963
|
-
} else {
|
|
964
|
-
router.sendMessage(this.target.sessionId, this.domain, method, params, callback);
|
|
965
|
-
}
|
|
966
|
-
});
|
|
967
878
|
}
|
|
968
879
|
|
|
969
880
|
private invoke(method: QualifiedName, request: Object|null): Promise<Protocol.ProtocolResponseWithError> {
|
|
@@ -109,7 +109,7 @@ export class RehydratingConnection implements ProtocolClient.ConnectionTransport
|
|
|
109
109
|
if (this.#rehydratingWindow.opener) {
|
|
110
110
|
this.#rehydratingWindow.opener.postMessage({type: 'REHYDRATING_WINDOW_READY'});
|
|
111
111
|
} else if (this.#rehydratingWindow !== window.top) {
|
|
112
|
-
this.#rehydratingWindow.parent.postMessage({type: 'REHYDRATING_IFRAME_READY'});
|
|
112
|
+
this.#rehydratingWindow.parent.postMessage({type: 'REHYDRATING_IFRAME_READY'}, '*');
|
|
113
113
|
} else {
|
|
114
114
|
this.#onConnectionLost(i18nString(UIStrings.noHostWindow));
|
|
115
115
|
}
|
|
@@ -7,10 +7,6 @@
|
|
|
7
7
|
// https://crsrc.org/c/third_party/blink/renderer/controller/dev_tools_frontend_impl.cc;l=107
|
|
8
8
|
(window => {
|
|
9
9
|
/**
|
|
10
|
-
* A function that tries to check the remotely connected instance
|
|
11
|
-
* major version. You should check against this to provide
|
|
12
|
-
* forward and backwards compatibility.
|
|
13
|
-
*
|
|
14
10
|
* @returns {number|null}
|
|
15
11
|
*/
|
|
16
12
|
function getRemoteMajorVersion() {
|
|
@@ -24,6 +20,8 @@
|
|
|
24
20
|
return null;
|
|
25
21
|
}
|
|
26
22
|
}
|
|
23
|
+
// eslint-disable-next-line no-unused-vars
|
|
24
|
+
const majorVersion = getRemoteMajorVersion();
|
|
27
25
|
|
|
28
26
|
// DevToolsAPI ----------------------------------------------------------------
|
|
29
27
|
/**
|
|
@@ -55,9 +53,19 @@
|
|
|
55
53
|
_addExtensionCallback = null;
|
|
56
54
|
|
|
57
55
|
/**
|
|
58
|
-
* @type {
|
|
56
|
+
* @type {Promise<string>}
|
|
59
57
|
*/
|
|
60
|
-
|
|
58
|
+
_initialTargetIdPromise;
|
|
59
|
+
/**
|
|
60
|
+
* @type {(param:string) => void}
|
|
61
|
+
*/
|
|
62
|
+
_setInitialTargetId;
|
|
63
|
+
|
|
64
|
+
constructor() {
|
|
65
|
+
this._initialTargetIdPromise = new Promise(resolve => {
|
|
66
|
+
this._setInitialTargetId = resolve;
|
|
67
|
+
});
|
|
68
|
+
}
|
|
61
69
|
|
|
62
70
|
/**
|
|
63
71
|
* @param id
|
|
@@ -89,9 +97,7 @@
|
|
|
89
97
|
}
|
|
90
98
|
|
|
91
99
|
/**
|
|
92
|
-
* @
|
|
93
|
-
* @typedef {import('./core/host/InspectorFrontendHost.js').InspectorFrontendAPIImplMethods} Methods
|
|
94
|
-
* @param method {`${Events|Methods}`}
|
|
100
|
+
* @param method
|
|
95
101
|
* @param args
|
|
96
102
|
*/
|
|
97
103
|
_dispatchOnInspectorFrontendAPI(method, args) {
|
|
@@ -161,7 +167,7 @@
|
|
|
161
167
|
}
|
|
162
168
|
|
|
163
169
|
/**
|
|
164
|
-
* @param count
|
|
170
|
+
* @param count
|
|
165
171
|
*/
|
|
166
172
|
deviceCountUpdated(count) {
|
|
167
173
|
this._dispatchOnInspectorFrontendAPI('deviceCountUpdated', [count]);
|
|
@@ -341,7 +347,7 @@
|
|
|
341
347
|
* @param targetId {string}
|
|
342
348
|
*/
|
|
343
349
|
setInitialTargetId(targetId) {
|
|
344
|
-
this.
|
|
350
|
+
this._setInitialTargetId(targetId);
|
|
345
351
|
}
|
|
346
352
|
|
|
347
353
|
/**
|
|
@@ -437,7 +443,8 @@
|
|
|
437
443
|
TimelineNavigationSettingState: 'DevTools.TimelineNavigationSettingState',
|
|
438
444
|
SyncSetting: 'DevTools.SyncSetting',
|
|
439
445
|
SwatchActivated: 'DevTools.SwatchActivated',
|
|
440
|
-
AnimationPlaybackRateChanged: 'DevTools.AnimationPlaybackRateChanged'
|
|
446
|
+
AnimationPlaybackRateChanged: 'DevTools.AnimationPlaybackRateChanged',
|
|
447
|
+
BuiltInAiAvailability: 'DevTools.BuiltInAiAvailability'
|
|
441
448
|
// LINT.ThenChange(/front_end/core/host/InspectorFrontendHostAPI.ts:EnumeratedHistogram)
|
|
442
449
|
};
|
|
443
450
|
|
|
@@ -452,6 +459,34 @@
|
|
|
452
459
|
*/
|
|
453
460
|
events;
|
|
454
461
|
|
|
462
|
+
/**
|
|
463
|
+
* @returns
|
|
464
|
+
*/
|
|
465
|
+
getSelectionBackgroundColor() {
|
|
466
|
+
return '#6e86ff';
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* @returns
|
|
471
|
+
*/
|
|
472
|
+
getSelectionForegroundColor() {
|
|
473
|
+
return '#ffffff';
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* @returns
|
|
478
|
+
*/
|
|
479
|
+
getInactiveSelectionBackgroundColor() {
|
|
480
|
+
return '#c9c8c8';
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* @returns
|
|
485
|
+
*/
|
|
486
|
+
getInactiveSelectionForegroundColor() {
|
|
487
|
+
return '#323232';
|
|
488
|
+
}
|
|
489
|
+
|
|
455
490
|
/**
|
|
456
491
|
* @returns
|
|
457
492
|
*/
|
|
@@ -986,12 +1021,21 @@
|
|
|
986
1021
|
}
|
|
987
1022
|
|
|
988
1023
|
// Backward-compatible methods below this line --------------------------------------------
|
|
1024
|
+
/**
|
|
1025
|
+
* Support for legacy front-ends (<M65).
|
|
1026
|
+
* @returns
|
|
1027
|
+
*/
|
|
1028
|
+
isUnderTest() {
|
|
1029
|
+
return false;
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
// Backward-compatible methods end before line --------------------------------------------
|
|
989
1033
|
|
|
990
1034
|
/**
|
|
991
1035
|
* @returns
|
|
992
1036
|
*/
|
|
993
1037
|
initialTargetId() {
|
|
994
|
-
return DevToolsAPI.
|
|
1038
|
+
return DevToolsAPI._initialTargetIdPromise;
|
|
995
1039
|
}
|
|
996
1040
|
|
|
997
1041
|
/**
|
|
@@ -1110,9 +1154,155 @@
|
|
|
1110
1154
|
}
|
|
1111
1155
|
|
|
1112
1156
|
function installBackwardsCompatibility() {
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1157
|
+
const majorVersion = getRemoteMajorVersion();
|
|
1158
|
+
if (!majorVersion) {
|
|
1159
|
+
return;
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
/** @type {!Array<string>} */
|
|
1163
|
+
const styleRules = [];
|
|
1164
|
+
// Shadow DOM V0 polyfill
|
|
1165
|
+
if (majorVersion <= 73 && !Element.prototype.createShadowRoot) {
|
|
1166
|
+
Element.prototype.createShadowRoot = function() {
|
|
1167
|
+
try {
|
|
1168
|
+
return this.attachShadow({mode: 'open'});
|
|
1169
|
+
} catch {
|
|
1170
|
+
// some elements we use to add shadow roots can no
|
|
1171
|
+
// longer have shadow roots.
|
|
1172
|
+
const fakeShadowHost = document.createElement('span');
|
|
1173
|
+
this.appendChild(fakeShadowHost);
|
|
1174
|
+
fakeShadowHost.className = 'fake-shadow-host';
|
|
1175
|
+
return fakeShadowHost.createShadowRoot();
|
|
1176
|
+
}
|
|
1177
|
+
};
|
|
1178
|
+
|
|
1179
|
+
const origAdd = DOMTokenList.prototype.add;
|
|
1180
|
+
DOMTokenList.prototype.add = function(...tokens) {
|
|
1181
|
+
if (tokens[0].startsWith('insertion-point') || tokens[0].startsWith('tabbed-pane-header')) {
|
|
1182
|
+
this._myElement.slot = '.' + tokens[0];
|
|
1183
|
+
}
|
|
1184
|
+
return origAdd.apply(this, tokens);
|
|
1185
|
+
};
|
|
1186
|
+
|
|
1187
|
+
const origCreateElement = Document.prototype.createElement;
|
|
1188
|
+
Document.prototype.createElement = function(tagName, ...rest) {
|
|
1189
|
+
if (tagName === 'content') {
|
|
1190
|
+
tagName = 'slot';
|
|
1191
|
+
}
|
|
1192
|
+
const element = origCreateElement.call(this, tagName, ...rest);
|
|
1193
|
+
element.classList._myElement = element;
|
|
1194
|
+
return element;
|
|
1195
|
+
};
|
|
1196
|
+
|
|
1197
|
+
Object.defineProperty(HTMLSlotElement.prototype, 'select', {
|
|
1198
|
+
set(selector) {
|
|
1199
|
+
this.name = selector;
|
|
1200
|
+
}
|
|
1201
|
+
});
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
// Custom Elements V0 polyfill
|
|
1205
|
+
if (majorVersion <= 73 && !Document.prototype.hasOwnProperty('registerElement')) {
|
|
1206
|
+
const fakeRegistry = new Map();
|
|
1207
|
+
Document.prototype.registerElement = function(typeExtension, options) {
|
|
1208
|
+
const {prototype, extends: localName} = options;
|
|
1209
|
+
const document = this;
|
|
1210
|
+
const callback = function() {
|
|
1211
|
+
const element = document.createElement(localName || typeExtension);
|
|
1212
|
+
const skip = new Set(['constructor', '__proto__']);
|
|
1213
|
+
for (const key of Object.keys(Object.getOwnPropertyDescriptors(prototype.__proto__ || {}))) {
|
|
1214
|
+
if (skip.has(key)) {
|
|
1215
|
+
continue;
|
|
1216
|
+
}
|
|
1217
|
+
element[key] = prototype[key];
|
|
1218
|
+
}
|
|
1219
|
+
element.setAttribute('is', typeExtension);
|
|
1220
|
+
if (element['createdCallback']) {
|
|
1221
|
+
element['createdCallback']();
|
|
1222
|
+
}
|
|
1223
|
+
return element;
|
|
1224
|
+
};
|
|
1225
|
+
fakeRegistry.set(typeExtension, callback);
|
|
1226
|
+
return callback;
|
|
1227
|
+
};
|
|
1228
|
+
|
|
1229
|
+
const origCreateElement = Document.prototype.createElement;
|
|
1230
|
+
Document.prototype.createElement = function(tagName, fakeCustomElementType) {
|
|
1231
|
+
const fakeConstructor = fakeRegistry.get(fakeCustomElementType);
|
|
1232
|
+
if (fakeConstructor) {
|
|
1233
|
+
return fakeConstructor();
|
|
1234
|
+
}
|
|
1235
|
+
return origCreateElement.call(this, tagName, fakeCustomElementType);
|
|
1236
|
+
};
|
|
1237
|
+
|
|
1238
|
+
// DevTools front-ends mistakenly assume that
|
|
1239
|
+
// classList.toggle('a', undefined) works as
|
|
1240
|
+
// classList.toggle('a', false) rather than as
|
|
1241
|
+
// classList.toggle('a');
|
|
1242
|
+
const originalDOMTokenListToggle = DOMTokenList.prototype.toggle;
|
|
1243
|
+
DOMTokenList.prototype.toggle = function(token, force) {
|
|
1244
|
+
if (arguments.length === 1) {
|
|
1245
|
+
force = !this.contains(token);
|
|
1246
|
+
}
|
|
1247
|
+
return originalDOMTokenListToggle.call(this, token, Boolean(force));
|
|
1248
|
+
};
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
if (majorVersion <= 66) {
|
|
1252
|
+
/** @type {(!function(number, number):Element|undefined)} */
|
|
1253
|
+
ShadowRoot.prototype.__originalShadowRootElementFromPoint;
|
|
1254
|
+
|
|
1255
|
+
if (!ShadowRoot.prototype.__originalShadowRootElementFromPoint) {
|
|
1256
|
+
ShadowRoot.prototype.__originalShadowRootElementFromPoint = ShadowRoot.prototype.elementFromPoint;
|
|
1257
|
+
/**
|
|
1258
|
+
* @param x
|
|
1259
|
+
* @param y
|
|
1260
|
+
* @returns
|
|
1261
|
+
*/
|
|
1262
|
+
ShadowRoot.prototype.elementFromPoint = function(x, y) {
|
|
1263
|
+
const originalResult = ShadowRoot.prototype.__originalShadowRootElementFromPoint.apply(this, arguments);
|
|
1264
|
+
if (this.host && originalResult === this.host) {
|
|
1265
|
+
return null;
|
|
1266
|
+
}
|
|
1267
|
+
return originalResult;
|
|
1268
|
+
};
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
if (majorVersion <= 71) {
|
|
1273
|
+
styleRules.push(
|
|
1274
|
+
'.coverage-toolbar-container, .animation-timeline-toolbar-container, .computed-properties { flex-basis: auto; }');
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1277
|
+
installExtraStyleRules(styleRules);
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
/**
|
|
1281
|
+
* @param styleRules
|
|
1282
|
+
*/
|
|
1283
|
+
function installExtraStyleRules(styleRules) {
|
|
1284
|
+
if (!styleRules.length) {
|
|
1285
|
+
return;
|
|
1286
|
+
}
|
|
1287
|
+
const styleText = styleRules.join('\n');
|
|
1288
|
+
document.head.appendChild(createStyleElement(styleText));
|
|
1289
|
+
|
|
1290
|
+
const origCreateShadowRoot = HTMLElement.prototype.createShadowRoot;
|
|
1291
|
+
HTMLElement.prototype.createShadowRoot = function(...args) {
|
|
1292
|
+
const shadowRoot = origCreateShadowRoot.call(this, ...args);
|
|
1293
|
+
shadowRoot.appendChild(createStyleElement(styleText));
|
|
1294
|
+
return shadowRoot;
|
|
1295
|
+
};
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
/**
|
|
1299
|
+
* @param styleText
|
|
1300
|
+
* @returns
|
|
1301
|
+
*/
|
|
1302
|
+
function createStyleElement(styleText) {
|
|
1303
|
+
const style = document.createElement('style');
|
|
1304
|
+
style.textContent = styleText;
|
|
1305
|
+
return style;
|
|
1116
1306
|
}
|
|
1117
1307
|
|
|
1118
1308
|
installBackwardsCompatibility();
|
|
@@ -2,10 +2,13 @@
|
|
|
2
2
|
// Use of this source code is governed by a BSD-style license that can be
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
|
|
5
|
+
import * as Host from '../../core/host/host.js';
|
|
5
6
|
import * as Root from '../../core/root/root.js';
|
|
6
7
|
|
|
7
8
|
let builtInAiInstance: BuiltInAi|undefined;
|
|
8
|
-
let availability
|
|
9
|
+
let availability: LanguageModelAvailability|undefined;
|
|
10
|
+
let hasGpu: boolean|undefined;
|
|
11
|
+
let isFirstRun = true;
|
|
9
12
|
|
|
10
13
|
export interface LanguageModel {
|
|
11
14
|
promptStreaming: (arg0: string, opts?: {
|
|
@@ -15,20 +18,62 @@ export interface LanguageModel {
|
|
|
15
18
|
destroy: () => void;
|
|
16
19
|
}
|
|
17
20
|
|
|
21
|
+
export const enum LanguageModelAvailability {
|
|
22
|
+
UNAVAILABLE = 'unavailable',
|
|
23
|
+
DOWNLOADABLE = 'downloadable',
|
|
24
|
+
DOWNLOADING = 'downloading',
|
|
25
|
+
AVAILABLE = 'available',
|
|
26
|
+
DISABLED = 'disabled',
|
|
27
|
+
}
|
|
28
|
+
|
|
18
29
|
export class BuiltInAi {
|
|
19
30
|
#consoleInsightsSession: LanguageModel;
|
|
20
31
|
|
|
21
|
-
static async
|
|
32
|
+
static async getLanguageModelAvailability(): Promise<LanguageModelAvailability> {
|
|
22
33
|
if (!Root.Runtime.hostConfig.devToolsAiPromptApi?.enabled) {
|
|
23
|
-
return
|
|
34
|
+
return LanguageModelAvailability.DISABLED;
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
// @ts-expect-error
|
|
38
|
+
availability = await window.LanguageModel.availability({expectedOutputs: [{type: 'text', languages: ['en']}]}) as
|
|
39
|
+
LanguageModelAvailability;
|
|
40
|
+
return availability;
|
|
41
|
+
} catch {
|
|
42
|
+
return LanguageModelAvailability.UNAVAILABLE;
|
|
24
43
|
}
|
|
25
|
-
// @ts-expect-error
|
|
26
|
-
availability = await window.LanguageModel.availability({expectedOutputs: [{type: 'text', languages: ['en']}]});
|
|
27
|
-
return availability === 'available';
|
|
28
44
|
}
|
|
29
45
|
|
|
30
46
|
static cachedIsAvailable(): boolean {
|
|
31
|
-
return availability ===
|
|
47
|
+
return availability === LanguageModelAvailability.AVAILABLE;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
static isGpuAvailable(): boolean {
|
|
51
|
+
const hasGpuHelper = (): boolean => {
|
|
52
|
+
const canvas = document.createElement('canvas');
|
|
53
|
+
try {
|
|
54
|
+
const webgl = canvas.getContext('webgl');
|
|
55
|
+
if (!webgl) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
const debugInfo = webgl.getExtension('WEBGL_debug_renderer_info');
|
|
59
|
+
if (!debugInfo) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
const renderer = webgl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL);
|
|
63
|
+
if (renderer.includes('SwiftShader')) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
} catch {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
return true;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
if (hasGpu !== undefined) {
|
|
73
|
+
return hasGpu;
|
|
74
|
+
}
|
|
75
|
+
hasGpu = hasGpuHelper();
|
|
76
|
+
return hasGpu;
|
|
32
77
|
}
|
|
33
78
|
|
|
34
79
|
private constructor(consoleInsightsSession: LanguageModel) {
|
|
@@ -37,40 +82,97 @@ export class BuiltInAi {
|
|
|
37
82
|
|
|
38
83
|
static async instance(): Promise<BuiltInAi|undefined> {
|
|
39
84
|
if (builtInAiInstance === undefined) {
|
|
40
|
-
if (
|
|
41
|
-
|
|
85
|
+
if (isFirstRun) {
|
|
86
|
+
const languageModelAvailability = await BuiltInAi.getLanguageModelAvailability();
|
|
87
|
+
const hasGpu = BuiltInAi.isGpuAvailable();
|
|
88
|
+
if (hasGpu) {
|
|
89
|
+
switch (languageModelAvailability) {
|
|
90
|
+
case LanguageModelAvailability.UNAVAILABLE:
|
|
91
|
+
Host.userMetrics.builtInAiAvailability(Host.UserMetrics.BuiltInAiAvailability.UNAVAILABLE_HAS_GPU);
|
|
92
|
+
break;
|
|
93
|
+
case LanguageModelAvailability.DOWNLOADABLE:
|
|
94
|
+
Host.userMetrics.builtInAiAvailability(Host.UserMetrics.BuiltInAiAvailability.DOWNLOADABLE_HAS_GPU);
|
|
95
|
+
break;
|
|
96
|
+
case LanguageModelAvailability.DOWNLOADING:
|
|
97
|
+
Host.userMetrics.builtInAiAvailability(Host.UserMetrics.BuiltInAiAvailability.DOWNLOADING_HAS_GPU);
|
|
98
|
+
break;
|
|
99
|
+
case LanguageModelAvailability.AVAILABLE:
|
|
100
|
+
Host.userMetrics.builtInAiAvailability(Host.UserMetrics.BuiltInAiAvailability.AVAILABLE_HAS_GPU);
|
|
101
|
+
break;
|
|
102
|
+
case LanguageModelAvailability.DISABLED:
|
|
103
|
+
Host.userMetrics.builtInAiAvailability(Host.UserMetrics.BuiltInAiAvailability.DISABLED_HAS_GPU);
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
} else {
|
|
107
|
+
switch (languageModelAvailability) {
|
|
108
|
+
case LanguageModelAvailability.UNAVAILABLE:
|
|
109
|
+
Host.userMetrics.builtInAiAvailability(Host.UserMetrics.BuiltInAiAvailability.UNAVAILABLE_NO_GPU);
|
|
110
|
+
break;
|
|
111
|
+
case LanguageModelAvailability.DOWNLOADABLE:
|
|
112
|
+
Host.userMetrics.builtInAiAvailability(Host.UserMetrics.BuiltInAiAvailability.DOWNLOADABLE_NO_GPU);
|
|
113
|
+
break;
|
|
114
|
+
case LanguageModelAvailability.DOWNLOADING:
|
|
115
|
+
Host.userMetrics.builtInAiAvailability(Host.UserMetrics.BuiltInAiAvailability.DOWNLOADING_NO_GPU);
|
|
116
|
+
break;
|
|
117
|
+
case LanguageModelAvailability.AVAILABLE:
|
|
118
|
+
Host.userMetrics.builtInAiAvailability(Host.UserMetrics.BuiltInAiAvailability.AVAILABLE_NO_GPU);
|
|
119
|
+
break;
|
|
120
|
+
case LanguageModelAvailability.DISABLED:
|
|
121
|
+
Host.userMetrics.builtInAiAvailability(Host.UserMetrics.BuiltInAiAvailability.DISABLED_NO_GPU);
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
isFirstRun = false;
|
|
126
|
+
if (!Root.Runtime.hostConfig.devToolsAiPromptApi?.allowWithoutGpu && !hasGpu) {
|
|
127
|
+
return undefined;
|
|
128
|
+
}
|
|
129
|
+
if (languageModelAvailability !== LanguageModelAvailability.AVAILABLE) {
|
|
130
|
+
return undefined;
|
|
131
|
+
}
|
|
132
|
+
} else {
|
|
133
|
+
if (!Root.Runtime.hostConfig.devToolsAiPromptApi?.allowWithoutGpu && !BuiltInAi.isGpuAvailable()) {
|
|
134
|
+
return undefined;
|
|
135
|
+
}
|
|
136
|
+
if ((await BuiltInAi.getLanguageModelAvailability()) !== LanguageModelAvailability.AVAILABLE) {
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
42
139
|
}
|
|
43
|
-
// @ts-expect-error
|
|
44
|
-
const consoleInsightsSession = await window.LanguageModel.create({
|
|
45
|
-
initialPrompts: [{
|
|
46
|
-
role: 'system',
|
|
47
|
-
content: `
|
|
48
|
-
You are an expert web developer. Your goal is to help a human web developer who
|
|
49
|
-
is using Chrome DevTools to debug a web site or web app. The Chrome DevTools
|
|
50
|
-
console is showing a message which is either an error or a warning. Please help
|
|
51
|
-
the user understand the problematic console message.
|
|
52
140
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
141
|
+
try {
|
|
142
|
+
// @ts-expect-error
|
|
143
|
+
const consoleInsightsSession = await window.LanguageModel.create({
|
|
144
|
+
initialPrompts: [{
|
|
145
|
+
role: 'system',
|
|
146
|
+
content: `
|
|
147
|
+
You are an expert web developer. Your goal is to help a human web developer who
|
|
148
|
+
is using Chrome DevTools to debug a web site or web app. The Chrome DevTools
|
|
149
|
+
console is showing a message which is either an error or a warning. Please help
|
|
150
|
+
the user understand the problematic console message.
|
|
151
|
+
|
|
152
|
+
Your instructions are as follows:
|
|
153
|
+
- Explain the reason why the error or warning is showing up.
|
|
154
|
+
- The explanation has a maximum length of 200 characters. Anything beyond this
|
|
155
|
+
length will be cut off. Make sure that your explanation is at most 200 characters long.
|
|
156
|
+
- Your explanation should not end in the middle of a sentence.
|
|
157
|
+
- Your explanation should consist of a single paragraph only. Do not include any
|
|
158
|
+
headings or code blocks. Only write a single paragraph of text.
|
|
159
|
+
- Your response should be concise and to the point. Avoid lengthy explanations
|
|
160
|
+
or unnecessary details.
|
|
161
|
+
`
|
|
162
|
+
}],
|
|
163
|
+
expectedInputs: [{
|
|
164
|
+
type: 'text',
|
|
165
|
+
languages: ['en'],
|
|
166
|
+
}],
|
|
167
|
+
expectedOutputs: [{
|
|
168
|
+
type: 'text',
|
|
169
|
+
languages: ['en'],
|
|
170
|
+
}],
|
|
171
|
+
}) as LanguageModel;
|
|
172
|
+
builtInAiInstance = new BuiltInAi(consoleInsightsSession);
|
|
173
|
+
} catch {
|
|
174
|
+
return undefined;
|
|
175
|
+
}
|
|
74
176
|
}
|
|
75
177
|
return builtInAiInstance;
|
|
76
178
|
}
|
|
@@ -6,7 +6,6 @@ import * as Common from '../../core/common/common.js';
|
|
|
6
6
|
import * as Host from '../../core/host/host.js';
|
|
7
7
|
import * as i18n from '../../core/i18n/i18n.js';
|
|
8
8
|
import * as Badges from '../../models/badges/badges.js';
|
|
9
|
-
import * as WindowBoundsService from '../../services/window_bounds/window_bounds.js';
|
|
10
9
|
import * as Buttons from '../../ui/components/buttons/buttons.js';
|
|
11
10
|
import * as UI from '../../ui/legacy/legacy.js';
|
|
12
11
|
import * as Lit from '../../ui/lit/lit.js';
|
|
@@ -166,8 +165,7 @@ export class BadgeNotification extends UI.Widget.Widget {
|
|
|
166
165
|
|
|
167
166
|
#positionNotification(): void {
|
|
168
167
|
const boundingRect = this.contentElement.getBoundingClientRect();
|
|
169
|
-
const container =
|
|
170
|
-
WindowBoundsService.WindowBoundsService.WindowBoundsServiceImpl.instance().getDevToolsBoundingElement();
|
|
168
|
+
const container = UI.UIUtils.getDevToolsBoundingElement();
|
|
171
169
|
this.contentElement.positionAt(
|
|
172
170
|
LEFT_OFFSET, container.clientHeight - boundingRect.height - BOTTOM_OFFSET, container);
|
|
173
171
|
}
|
|
@@ -346,6 +346,7 @@ export class ConsoleInsightTeaser extends UI.Widget.Widget {
|
|
|
346
346
|
this.#headerText = this.#consoleViewMessage.toMessageTextString().substring(0, 70);
|
|
347
347
|
this.#isGenerating = true;
|
|
348
348
|
this.#timeoutId = setTimeout(this.#setSlow.bind(this), SLOW_GENERATION_CUTOFF_MILLISECONDS);
|
|
349
|
+
const startTime = performance.now();
|
|
349
350
|
let teaserText = '';
|
|
350
351
|
try {
|
|
351
352
|
for await (const chunk of this.#getOnDeviceInsight()) {
|
|
@@ -366,6 +367,7 @@ export class ConsoleInsightTeaser extends UI.Widget.Widget {
|
|
|
366
367
|
}
|
|
367
368
|
|
|
368
369
|
clearTimeout(this.#timeoutId);
|
|
370
|
+
Host.userMetrics.consoleInsightTeaserGenerated(performance.now() - startTime);
|
|
369
371
|
this.#isGenerating = false;
|
|
370
372
|
this.#mainText = teaserText;
|
|
371
373
|
this.requestUpdate();
|
|
@@ -29,7 +29,6 @@ import {
|
|
|
29
29
|
type HeaderEditedEvent,
|
|
30
30
|
type HeaderEditorDescriptor,
|
|
31
31
|
type HeaderRemovedEvent,
|
|
32
|
-
type HeaderSectionRow,
|
|
33
32
|
type HeaderSectionRowData,
|
|
34
33
|
isValidHeaderName,
|
|
35
34
|
} from './HeaderSectionRow.js';
|
|
@@ -515,7 +514,7 @@ export class ResponseHeaderSection extends ResponseHeaderSectionBase {
|
|
|
515
514
|
this.#updateOverrides(this.#headerEditors[index].name, this.#headerEditors[index].value || '', index);
|
|
516
515
|
this.#render();
|
|
517
516
|
|
|
518
|
-
const rows = this.shadow.querySelectorAll
|
|
517
|
+
const rows = this.shadow.querySelectorAll('devtools-header-section-row');
|
|
519
518
|
const [lastRow] = Array.from(rows).slice(-1);
|
|
520
519
|
lastRow?.focus();
|
|
521
520
|
Host.userMetrics.actionTaken(Host.UserMetrics.Action.HeaderOverrideHeaderAdded);
|
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
|
|
6
6
|
import * as i18n from '../../../core/i18n/i18n.js';
|
|
7
7
|
import * as Platform from '../../../core/platform/platform.js';
|
|
8
|
-
import * as WindowBoundsService from '../../../services/window_bounds/window_bounds.js';
|
|
9
8
|
import * as ComponentHelpers from '../../../ui/components/helpers/helpers.js';
|
|
10
9
|
import * as RenderCoordinator from '../../../ui/components/render_coordinator/render_coordinator.js';
|
|
11
10
|
import * as Lit from '../../../ui/lit/lit.js';
|
|
12
11
|
import * as VisualLogging from '../../../ui/visual_logging/visual_logging.js';
|
|
12
|
+
import * as UI from '../../legacy/legacy.js';
|
|
13
13
|
import * as Buttons from '../buttons/buttons.js';
|
|
14
14
|
|
|
15
15
|
import dialogStyles from './dialog.css.js';
|
|
@@ -77,10 +77,6 @@ interface DialogData {
|
|
|
77
77
|
*/
|
|
78
78
|
dialogShownCallback: (() => unknown)|null;
|
|
79
79
|
|
|
80
|
-
/**
|
|
81
|
-
* Optional. Service that provides the window dimensions used for positioning the Dialog.
|
|
82
|
-
*/
|
|
83
|
-
windowBoundsService: WindowBoundsService.WindowBoundsService.WindowBoundsService;
|
|
84
80
|
/**
|
|
85
81
|
* Whether the dialog is closed when the 'Escape' key is pressed. When true, the event is
|
|
86
82
|
* propagation is stopped.
|
|
@@ -132,7 +128,6 @@ export class Dialog extends HTMLElement {
|
|
|
132
128
|
horizontalAlignment: DialogHorizontalAlignment.CENTER,
|
|
133
129
|
getConnectorCustomXPosition: null,
|
|
134
130
|
dialogShownCallback: null,
|
|
135
|
-
windowBoundsService: WindowBoundsService.WindowBoundsService.WindowBoundsServiceImpl.instance(),
|
|
136
131
|
closeOnESC: true,
|
|
137
132
|
closeOnScroll: true,
|
|
138
133
|
closeButton: false,
|
|
@@ -161,7 +156,7 @@ export class Dialog extends HTMLElement {
|
|
|
161
156
|
this.#forceDialogCloseInDevToolsBound();
|
|
162
157
|
});
|
|
163
158
|
readonly #dialogResizeObserver = new ResizeObserver(this.#updateDialogBounds.bind(this));
|
|
164
|
-
#devToolsBoundingElement =
|
|
159
|
+
#devToolsBoundingElement = UI.UIUtils.getDevToolsBoundingElement();
|
|
165
160
|
|
|
166
161
|
// We bind here because we have to listen to keydowns on the entire window,
|
|
167
162
|
// not on the Dialog element itself. This is because if the user has the
|
|
@@ -204,16 +199,6 @@ export class Dialog extends HTMLElement {
|
|
|
204
199
|
this.#onStateChange();
|
|
205
200
|
}
|
|
206
201
|
|
|
207
|
-
get windowBoundsService(): WindowBoundsService.WindowBoundsService.WindowBoundsService {
|
|
208
|
-
return this.#props.windowBoundsService;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
set windowBoundsService(windowBoundsService: WindowBoundsService.WindowBoundsService.WindowBoundsService) {
|
|
212
|
-
this.#props.windowBoundsService = windowBoundsService;
|
|
213
|
-
this.#devToolsBoundingElement = this.windowBoundsService.getDevToolsBoundingElement();
|
|
214
|
-
this.#onStateChange();
|
|
215
|
-
}
|
|
216
|
-
|
|
217
202
|
get bestVerticalPosition(): DialogVerticalPosition|null {
|
|
218
203
|
return this.#bestVerticalPosition;
|
|
219
204
|
}
|
|
@@ -733,6 +718,11 @@ export class Dialog extends HTMLElement {
|
|
|
733
718
|
VisualLogging.setMappedParent(this.#getDialog(), this.parentElementOrShadowHost() as HTMLElement);
|
|
734
719
|
// clang-format on
|
|
735
720
|
}
|
|
721
|
+
|
|
722
|
+
setBoundingElementForTesting(element: HTMLElement): void {
|
|
723
|
+
this.#devToolsBoundingElement = element;
|
|
724
|
+
this.#onStateChange();
|
|
725
|
+
}
|
|
736
726
|
}
|
|
737
727
|
|
|
738
728
|
customElements.define('devtools-dialog', Dialog);
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
|
|
5
5
|
import * as Common from '../../../core/common/common.js';
|
|
6
|
-
import * as WindowBoundsService from '../../../services/window_bounds/window_bounds.js';
|
|
7
6
|
import * as CodeMirror from '../../../third_party/codemirror.next/codemirror.next.js';
|
|
7
|
+
import * as UI from '../../legacy/legacy.js';
|
|
8
8
|
import * as ThemeSupport from '../../legacy/theme_support/theme_support.js';
|
|
9
9
|
import * as CodeHighlighter from '../code_highlighter/code_highlighter.js';
|
|
10
10
|
|
|
@@ -166,8 +166,7 @@ export class TextEditor extends HTMLElement {
|
|
|
166
166
|
}
|
|
167
167
|
|
|
168
168
|
#startObservingResize(): void {
|
|
169
|
-
const devtoolsElement =
|
|
170
|
-
WindowBoundsService.WindowBoundsService.WindowBoundsServiceImpl.instance().getDevToolsBoundingElement();
|
|
169
|
+
const devtoolsElement = UI.UIUtils.getDevToolsBoundingElement();
|
|
171
170
|
if (devtoolsElement) {
|
|
172
171
|
this.#devtoolsResizeObserver.observe(devtoolsElement);
|
|
173
172
|
}
|
|
@@ -7,7 +7,6 @@ import * as Common from '../../../core/common/common.js';
|
|
|
7
7
|
import type * as Host from '../../../core/host/host.js';
|
|
8
8
|
import * as i18n from '../../../core/i18n/i18n.js';
|
|
9
9
|
import * as TextUtils from '../../../models/text_utils/text_utils.js';
|
|
10
|
-
import * as WindowBoundsService from '../../../services/window_bounds/window_bounds.js';
|
|
11
10
|
import * as CM from '../../../third_party/codemirror.next/codemirror.next.js';
|
|
12
11
|
import * as UI from '../../legacy/legacy.js';
|
|
13
12
|
import * as VisualLogging from '../../visual_logging/visual_logging.js';
|
|
@@ -343,8 +342,7 @@ let sideBarElement: HTMLElement|null = null;
|
|
|
343
342
|
|
|
344
343
|
function getTooltipSpace(): DOMRect {
|
|
345
344
|
if (!sideBarElement) {
|
|
346
|
-
sideBarElement =
|
|
347
|
-
WindowBoundsService.WindowBoundsService.WindowBoundsServiceImpl.instance().getDevToolsBoundingElement();
|
|
345
|
+
sideBarElement = UI.UIUtils.getDevToolsBoundingElement();
|
|
348
346
|
}
|
|
349
347
|
return sideBarElement.getBoundingClientRect();
|
|
350
348
|
}
|
|
@@ -56,6 +56,7 @@ import confirmDialogStyles from './confirmDialog.css.js';
|
|
|
56
56
|
import {Dialog} from './Dialog.js';
|
|
57
57
|
import {GlassPane, PointerEventsBehavior, SizeBehavior} from './GlassPane.js';
|
|
58
58
|
import inspectorCommonStyles from './inspectorCommon.css.js';
|
|
59
|
+
import {InspectorView} from './InspectorView.js';
|
|
59
60
|
import {KeyboardShortcut, Keys} from './KeyboardShortcut.js';
|
|
60
61
|
import smallBubbleStyles from './smallBubble.css.js';
|
|
61
62
|
import {Tooltip} from './Tooltip.js';
|
|
@@ -2348,3 +2349,7 @@ export function copyTextToClipboard(text: string, alert?: string): void {
|
|
|
2348
2349
|
ARIAUtils.LiveAnnouncer.alert(alert);
|
|
2349
2350
|
}
|
|
2350
2351
|
}
|
|
2352
|
+
|
|
2353
|
+
export function getDevToolsBoundingElement(): HTMLElement {
|
|
2354
|
+
return InspectorView.maybeGetInspectorViewInstance()?.element || document.body;
|
|
2355
|
+
}
|
|
@@ -99,7 +99,7 @@ export class CSSAngle extends HTMLElement {
|
|
|
99
99
|
this.angleElement = this.querySelector<HTMLElement>('.css-angle');
|
|
100
100
|
}
|
|
101
101
|
if (!this.swatchElement) {
|
|
102
|
-
this.swatchElement = this.querySelector
|
|
102
|
+
this.swatchElement = this.querySelector('devtools-css-angle-swatch');
|
|
103
103
|
}
|
|
104
104
|
if (!this.angleElement || !this.swatchElement) {
|
|
105
105
|
return;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
/* eslint-disable @devtools/no-imperative-dom-api */
|
|
5
5
|
|
|
6
6
|
import * as i18n from '../../../../core/i18n/i18n.js';
|
|
7
|
-
import * as
|
|
7
|
+
import * as UI from '../../legacy.js';
|
|
8
8
|
import * as ThemeSupport from '../../theme_support/theme_support.js';
|
|
9
9
|
|
|
10
10
|
import type {FlameChart} from './FlameChart.js';
|
|
@@ -124,7 +124,7 @@ export class BrickBreaker extends HTMLElement {
|
|
|
124
124
|
#keyPressHandlerBound = this.#keyPressHandler.bind(this);
|
|
125
125
|
#closeGameBound = this.#closeGame.bind(this);
|
|
126
126
|
#mouseMoveHandlerBound = this.#mouseMoveHandler.bind(this);
|
|
127
|
-
#boundingElement =
|
|
127
|
+
#boundingElement = UI.UIUtils.getDevToolsBoundingElement();
|
|
128
128
|
// Value by which we moved the game up relative to the viewport
|
|
129
129
|
#gameViewportOffset = 0;
|
|
130
130
|
#running = false;
|
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
import * as Host from '../../../../core/host/host.js';
|
|
5
5
|
|
|
6
|
-
let fontFamily: string|null = null;
|
|
7
|
-
|
|
8
6
|
/**
|
|
9
7
|
* Because we run our UI in a couple of contexts (actual app & test
|
|
10
8
|
* environments) and on multiple platforms, the font is not consistent, so this
|
|
@@ -19,18 +17,7 @@ let fontFamily: string|null = null;
|
|
|
19
17
|
* to ensure that the screenshot tests are consistent.
|
|
20
18
|
**/
|
|
21
19
|
export function getFontFamilyForCanvas(): string {
|
|
22
|
-
|
|
23
|
-
return fontFamily;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const bodyStyles = getComputedStyle(document.body);
|
|
27
|
-
if (bodyStyles.fontFamily) {
|
|
28
|
-
fontFamily = bodyStyles.fontFamily;
|
|
29
|
-
} else {
|
|
30
|
-
fontFamily = Host.Platform.fontFamily();
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return fontFamily;
|
|
20
|
+
return Host.Platform.fontFamily();
|
|
34
21
|
}
|
|
35
22
|
|
|
36
23
|
export const DEFAULT_FONT_SIZE = '11px';
|
|
@@ -217,11 +217,7 @@ export function drawGridLineNamesAndAssertLabels(
|
|
|
217
217
|
|
|
218
218
|
for (const expected of expectedLabels) {
|
|
219
219
|
const foundLabel = foundLabels.find(({textContent}) => textContent === expected.textContent);
|
|
220
|
-
|
|
221
|
-
if (!foundLabel) {
|
|
222
|
-
assert.fail(`Expected line name label with text content ${expected.textContent} not found`);
|
|
223
|
-
return;
|
|
224
|
-
}
|
|
220
|
+
assert.exists(foundLabel, `Expected line name label with text content ${expected.textContent} not found`);
|
|
225
221
|
|
|
226
222
|
if (expected.type === 'column' && typeof expected.x !== 'undefined') {
|
|
227
223
|
assert.closeTo(
|
|
@@ -256,11 +252,7 @@ export function drawGridAreaNamesAndAssertLabels(
|
|
|
256
252
|
});
|
|
257
253
|
for (const expected of expectedLabels) {
|
|
258
254
|
const foundLabel = foundLabels.find(({textContent}) => textContent === expected.textContent);
|
|
259
|
-
|
|
260
|
-
if (!foundLabel) {
|
|
261
|
-
assert.fail(`Expected area label with text content ${expected.textContent} not found`);
|
|
262
|
-
return;
|
|
263
|
-
}
|
|
255
|
+
assert.exists(foundLabel, `Expected area label with text content ${expected.textContent} not found`);
|
|
264
256
|
|
|
265
257
|
if (typeof expected.left !== 'undefined') {
|
|
266
258
|
assert.strictEqual(
|
package/package.json
CHANGED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
// Copyright 2021 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 Legacy from '../../ui/legacy/legacy.js';
|
|
6
|
-
|
|
7
|
-
export interface WindowBoundsService {
|
|
8
|
-
getDevToolsBoundingElement(): HTMLElement;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
let windowBoundsServiceImplInstance: WindowBoundsServiceImpl;
|
|
12
|
-
export class WindowBoundsServiceImpl implements WindowBoundsService {
|
|
13
|
-
static instance(opts: {
|
|
14
|
-
forceNew: boolean|null,
|
|
15
|
-
} = {forceNew: null}): WindowBoundsServiceImpl {
|
|
16
|
-
const {forceNew} = opts;
|
|
17
|
-
if (!windowBoundsServiceImplInstance || forceNew) {
|
|
18
|
-
windowBoundsServiceImplInstance = new WindowBoundsServiceImpl();
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
return windowBoundsServiceImplInstance;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
getDevToolsBoundingElement(): HTMLElement {
|
|
25
|
-
return Legacy.InspectorView.InspectorView.maybeGetInspectorViewInstance()?.element || document.body;
|
|
26
|
-
}
|
|
27
|
-
}
|