chrome-devtools-frontend 1.0.1581449 → 1.0.1581708
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/agents/prompts/merging-devtools-module.md +144 -0
- package/agents/prompts/ui-widgets.md +351 -0
- package/agents/prompts/verification.md +2 -1
- package/docs/contributing/README.md +5 -6
- package/docs/contributing/changes.md +1 -2
- package/docs/styleguide/ux/README.md +1 -1
- package/front_end/core/sdk/OverlayModel.ts +4 -2
- package/front_end/core/sdk/StorageKeyManager.ts +6 -1
- package/front_end/core/sdk/Target.ts +4 -2
- package/front_end/entrypoints/greendev_floaty/FloatyEntrypoint.ts +22 -16
- package/front_end/entrypoints/greendev_floaty/floaty.css +41 -1
- package/front_end/entrypoints/greendev_floaty/floaty.html +8 -1
- package/front_end/entrypoints/greendev_floaty/greendev_floaty.ts +4 -4
- package/front_end/entrypoints/node_app/app/NodeMain.ts +19 -1
- package/front_end/entrypoints/node_app/node_app.ts +34 -0
- package/front_end/models/ai_assistance/AiConversation.ts +10 -0
- package/front_end/models/ai_assistance/agents/AiAgent.ts +2 -0
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.snapshot.txt +22 -0
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +71 -1
- package/front_end/models/computed_style/ComputedStyleModel.ts +26 -0
- package/front_end/models/issues_manager/CookieIssue.ts +0 -28
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +87 -6
- package/front_end/panels/ai_assistance/components/ChatInput.ts +1 -1
- package/front_end/panels/application/ApplicationPanelSidebar.ts +13 -11
- package/front_end/panels/application/DOMStorageModel.ts +1 -1
- package/front_end/panels/application/ResourcesPanel.ts +10 -5
- package/front_end/panels/common/AiCodeCompletionTeaser.ts +13 -3
- package/front_end/panels/common/aiCodeCompletionTeaser.css +6 -0
- package/front_end/panels/console_counters/WarningErrorCounter.ts +16 -10
- package/front_end/panels/elements/ComputedStyleWidget.ts +55 -37
- package/front_end/panels/elements/PlatformFontsWidget.ts +23 -10
- package/front_end/panels/greendev/GreenDevPanel.css +42 -1
- package/front_end/panels/greendev/GreenDevPanel.ts +30 -1
- package/front_end/panels/network/RequestInitiatorView.ts +8 -11
- package/front_end/panels/network/RequestTimingView.ts +1 -1
- package/front_end/panels/settings/KeybindsSettingsTab.ts +4 -3
- package/front_end/panels/sources/OutlineQuickOpen.ts +19 -0
- package/front_end/panels/timeline/TimelinePanel.ts +25 -0
- package/front_end/third_party/lighthouse/README.chromium +2 -2
- package/front_end/third_party/lighthouse/lighthouse-dt-bundle.js +145 -144
- package/front_end/third_party/lighthouse/report/bundle.js +12 -5
- package/front_end/third_party/lighthouse/report-assets/report-generator.mjs +2 -2
- package/front_end/ui/legacy/ListControl.ts +28 -1
- package/front_end/ui/legacy/Treeoutline.ts +1 -1
- package/front_end/ui/legacy/UIUtils.ts +17 -7
- package/front_end/ui/legacy/components/utils/JSPresentationUtils.ts +4 -2
- package/front_end/ui/visual_logging/KnownContextValues.ts +2 -0
- package/inspector_overlay/main.ts +18 -3
- package/inspector_overlay/tool_green_dev_anchors.css +54 -0
- package/inspector_overlay/tool_green_dev_anchors.ts +164 -0
- package/inspector_overlay/tool_persistent.ts +14 -0
- package/package.json +1 -1
- package/docs/contributing/design.md +0 -166
- package/docs/design_guidelines.md +0 -1
|
@@ -282,6 +282,26 @@ export class ListControl<T> {
|
|
|
282
282
|
return false;
|
|
283
283
|
}
|
|
284
284
|
|
|
285
|
+
selectFirstItem(center?: boolean): boolean {
|
|
286
|
+
const index = this.findFirstSelectable(0, +1, false);
|
|
287
|
+
if (index !== -1) {
|
|
288
|
+
this.scrollIntoView(index, center);
|
|
289
|
+
this.select(index);
|
|
290
|
+
return true;
|
|
291
|
+
}
|
|
292
|
+
return false;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
selectLastItem(center?: boolean): boolean {
|
|
296
|
+
const index = this.findFirstSelectable(this.model.length - 1, -1, false);
|
|
297
|
+
if (index !== -1) {
|
|
298
|
+
this.scrollIntoView(index, center);
|
|
299
|
+
this.select(index);
|
|
300
|
+
return true;
|
|
301
|
+
}
|
|
302
|
+
return false;
|
|
303
|
+
}
|
|
304
|
+
|
|
285
305
|
private scrollIntoView(index: number, center?: boolean): void {
|
|
286
306
|
if (this.mode === ListMode.NonViewport) {
|
|
287
307
|
this.elementAtIndex(index).scrollIntoViewIfNeeded(Boolean(center));
|
|
@@ -328,6 +348,12 @@ export class ListControl<T> {
|
|
|
328
348
|
case 'PageDown':
|
|
329
349
|
selected = this.selectItemNextPage(false);
|
|
330
350
|
break;
|
|
351
|
+
case 'Home':
|
|
352
|
+
selected = this.selectFirstItem();
|
|
353
|
+
break;
|
|
354
|
+
case 'End':
|
|
355
|
+
selected = this.selectLastItem();
|
|
356
|
+
break;
|
|
331
357
|
}
|
|
332
358
|
if (selected) {
|
|
333
359
|
event.consume(true);
|
|
@@ -364,7 +390,8 @@ export class ListControl<T> {
|
|
|
364
390
|
element = this.delegate.createElementForItem(item);
|
|
365
391
|
if (!element.hasAttribute('jslog')) {
|
|
366
392
|
element.setAttribute(
|
|
367
|
-
'jslog',
|
|
393
|
+
'jslog',
|
|
394
|
+
`${VisualLogging.item().track({click: true, keydown: 'ArrowUp|ArrowDown|PageUp|PageDown|Home|End'})}`);
|
|
368
395
|
}
|
|
369
396
|
this.itemToElement.set(item, element);
|
|
370
397
|
this.updateElementARIA(element, index);
|
|
@@ -1566,7 +1566,7 @@ class TreeViewTreeElement extends TreeElement {
|
|
|
1566
1566
|
this.listItemElement.classList.add(className);
|
|
1567
1567
|
this.#clonedClasses.add(className);
|
|
1568
1568
|
}
|
|
1569
|
-
InterceptBindingDirective.
|
|
1569
|
+
InterceptBindingDirective.setEventListeners(this.configElement, this.listItemElement);
|
|
1570
1570
|
|
|
1571
1571
|
for (const child of this.configElement.childNodes) {
|
|
1572
1572
|
if (child instanceof HTMLUListElement && child.role === 'group') {
|
|
@@ -1970,6 +1970,7 @@ export function bindToAction(actionName: string): ReturnType<typeof Directives.r
|
|
|
1970
1970
|
type BindingEventListener = (arg: any) => any;
|
|
1971
1971
|
export class InterceptBindingDirective extends Lit.Directive.Directive {
|
|
1972
1972
|
static readonly #interceptedBindings = new WeakMap<Element, Map<string, BindingEventListener>>();
|
|
1973
|
+
static readonly #attachedBindings = new WeakMap<Element, Map<string, BindingEventListener>>();
|
|
1973
1974
|
|
|
1974
1975
|
override update(part: Lit.Directive.Part, [listener]: [BindingEventListener]): unknown {
|
|
1975
1976
|
if (part.type !== Lit.Directive.PartType.EVENT) {
|
|
@@ -1990,13 +1991,22 @@ export class InterceptBindingDirective extends Lit.Directive.Directive {
|
|
|
1990
1991
|
return undefined;
|
|
1991
1992
|
}
|
|
1992
1993
|
|
|
1993
|
-
static
|
|
1994
|
-
const
|
|
1995
|
-
if (
|
|
1996
|
-
|
|
1994
|
+
static setEventListeners(templateElement: Element, renderedElement: Element): void {
|
|
1995
|
+
const attachedListeners = InterceptBindingDirective.#attachedBindings.get(renderedElement);
|
|
1996
|
+
if (attachedListeners) {
|
|
1997
|
+
for (const [name, listener] of attachedListeners) {
|
|
1998
|
+
renderedElement.removeEventListener(name, listener);
|
|
1999
|
+
}
|
|
1997
2000
|
}
|
|
1998
|
-
|
|
1999
|
-
|
|
2001
|
+
|
|
2002
|
+
const newListeners = InterceptBindingDirective.#interceptedBindings.get(templateElement);
|
|
2003
|
+
if (newListeners?.size) {
|
|
2004
|
+
for (const [name, listener] of newListeners) {
|
|
2005
|
+
renderedElement.addEventListener(name, listener);
|
|
2006
|
+
}
|
|
2007
|
+
InterceptBindingDirective.#attachedBindings.set(renderedElement, new Map(newListeners));
|
|
2008
|
+
} else {
|
|
2009
|
+
InterceptBindingDirective.#attachedBindings.delete(renderedElement);
|
|
2000
2010
|
}
|
|
2001
2011
|
}
|
|
2002
2012
|
}
|
|
@@ -2029,7 +2039,7 @@ export class HTMLElementWithLightDOMTemplate extends HTMLElement {
|
|
|
2029
2039
|
clone.appendChild(HTMLElementWithLightDOMTemplate.cloneNode(child));
|
|
2030
2040
|
}
|
|
2031
2041
|
if (node instanceof Element && clone instanceof Element) {
|
|
2032
|
-
InterceptBindingDirective.
|
|
2042
|
+
InterceptBindingDirective.setEventListeners(node, clone);
|
|
2033
2043
|
}
|
|
2034
2044
|
return clone;
|
|
2035
2045
|
}
|
|
@@ -353,8 +353,6 @@ export class StackTracePreviewContent extends UI.Widget.Widget {
|
|
|
353
353
|
this.#table = this.contentElement.createChild('table', 'stack-preview-container');
|
|
354
354
|
this.#table.classList.toggle('width-constrained', this.#options.widthConstrained ?? false);
|
|
355
355
|
|
|
356
|
-
this.#stackTrace?.addEventListener(StackTrace.StackTrace.Events.UPDATED, this.performUpdate.bind(this));
|
|
357
|
-
|
|
358
356
|
this.performUpdate();
|
|
359
357
|
}
|
|
360
358
|
|
|
@@ -407,7 +405,11 @@ export class StackTracePreviewContent extends UI.Widget.Widget {
|
|
|
407
405
|
}
|
|
408
406
|
|
|
409
407
|
set stackTrace(stackTrace: StackTrace.StackTrace.StackTrace) {
|
|
408
|
+
if (this.#stackTrace) {
|
|
409
|
+
this.#stackTrace.removeEventListener(StackTrace.StackTrace.Events.UPDATED, this.requestUpdate, this);
|
|
410
|
+
}
|
|
410
411
|
this.#stackTrace = stackTrace;
|
|
412
|
+
this.#stackTrace.addEventListener(StackTrace.StackTrace.Events.UPDATED, this.requestUpdate, this);
|
|
411
413
|
this.requestUpdate();
|
|
412
414
|
}
|
|
413
415
|
|
|
@@ -923,12 +923,14 @@ export const knownContextValues = new Set([
|
|
|
923
923
|
'content-type',
|
|
924
924
|
'content-visibility',
|
|
925
925
|
'context',
|
|
926
|
+
'context-added',
|
|
926
927
|
'context-change-drjones-file',
|
|
927
928
|
'context-change-drjones-network-request',
|
|
928
929
|
'context-change-drjones-performance',
|
|
929
930
|
'context-change-freestyler',
|
|
930
931
|
'context-change-none',
|
|
931
932
|
'context-change-performance-insight',
|
|
933
|
+
'context-removed',
|
|
932
934
|
'context3',
|
|
933
935
|
'contextmenu',
|
|
934
936
|
'continue',
|
|
@@ -7,6 +7,13 @@ import commonStyle from './common.css';
|
|
|
7
7
|
import {adoptStyleSheet} from './common.js';
|
|
8
8
|
import {gridStyle} from './highlight_grid_common.js';
|
|
9
9
|
// @ts-expect-error Importing CSS is handled in Rollup.
|
|
10
|
+
import greenDevAnchorsStyle from './tool_green_dev_anchors.css';
|
|
11
|
+
import {
|
|
12
|
+
type GreenDevAnchorsDispatchMessage,
|
|
13
|
+
GreenDevAnchorsOverlay,
|
|
14
|
+
type GreenDevAnchorsToolMessage
|
|
15
|
+
} from './tool_green_dev_anchors.js';
|
|
16
|
+
// @ts-expect-error Importing CSS is handled in Rollup.
|
|
10
17
|
import highlightGridStyle from './tool_grid.css';
|
|
11
18
|
// @ts-expect-error Importing CSS is handled in Rollup.
|
|
12
19
|
import highlightStyle from './tool_highlight.css';
|
|
@@ -29,7 +36,9 @@ import {WindowControlsOverlay} from './tool_window_controls.js';
|
|
|
29
36
|
declare global {
|
|
30
37
|
interface Window {
|
|
31
38
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
32
|
-
InspectorOverlayHost: {
|
|
39
|
+
InspectorOverlayHost: {
|
|
40
|
+
send(data: PausedToolMessage|PersistentToolMessage|ScreenshotToolMessage|GreenDevAnchorsToolMessage|string): void,
|
|
41
|
+
};
|
|
33
42
|
}
|
|
34
43
|
}
|
|
35
44
|
|
|
@@ -39,14 +48,18 @@ const gridStyleSheet = new CSSStyleSheet();
|
|
|
39
48
|
gridStyleSheet.replaceSync(gridStyle);
|
|
40
49
|
|
|
41
50
|
const highlightOverlay = new HighlightOverlay(window, [highlightStyle, gridStyleSheet]);
|
|
42
|
-
const persistentOverlay = new PersistentOverlay(window, [highlightGridStyle, gridStyleSheet]);
|
|
51
|
+
const persistentOverlay = new PersistentOverlay(window, [highlightGridStyle, greenDevAnchorsStyle, gridStyleSheet]);
|
|
43
52
|
const pausedOverlay = new PausedOverlay(window, pausedStyle);
|
|
44
53
|
const screenshotOverlay = new ScreenshotOverlay(window, screenshotStyle);
|
|
54
|
+
const greenDevAnchorsOverlay = new GreenDevAnchorsOverlay(window, greenDevAnchorsStyle);
|
|
45
55
|
const sourceOrderOverlay = new SourceOrderOverlay(window, sourceOrderStyle);
|
|
46
56
|
const viewportSizeOverlay = new ViewportSizeOverlay(window);
|
|
47
57
|
const windowControlsOverlay = new WindowControlsOverlay(window, [wcoStyle]);
|
|
48
58
|
|
|
59
|
+
persistentOverlay.setGreenDevAnchorsOverlay(greenDevAnchorsOverlay);
|
|
60
|
+
|
|
49
61
|
interface Overlays {
|
|
62
|
+
greenDevFloaty: GreenDevAnchorsOverlay;
|
|
50
63
|
highlight: HighlightOverlay;
|
|
51
64
|
persistent: PersistentOverlay;
|
|
52
65
|
paused: PausedOverlay;
|
|
@@ -60,6 +73,7 @@ type PlatformName = string;
|
|
|
60
73
|
|
|
61
74
|
// Key in this object is the name the backend refers to a particular overlay by.
|
|
62
75
|
const overlays: Overlays = {
|
|
76
|
+
greenDevFloaty: greenDevAnchorsOverlay,
|
|
63
77
|
highlight: highlightOverlay,
|
|
64
78
|
persistent: persistentOverlay,
|
|
65
79
|
paused: pausedOverlay,
|
|
@@ -76,6 +90,7 @@ interface MessageLookup {
|
|
|
76
90
|
setOverlay: keyof Overlays;
|
|
77
91
|
setPlatform: PlatformName;
|
|
78
92
|
drawingFinished: '';
|
|
93
|
+
update: GreenDevAnchorsDispatchMessage;
|
|
79
94
|
}
|
|
80
95
|
|
|
81
96
|
const dispatch = <K extends keyof MessageLookup>(message: [a: K, b: MessageLookup[K]]) => {
|
|
@@ -93,7 +108,7 @@ const dispatch = <K extends keyof MessageLookup>(message: [a: K, b: MessageLooku
|
|
|
93
108
|
currentOverlay.install();
|
|
94
109
|
}
|
|
95
110
|
} else if (functionName === 'setPlatform') {
|
|
96
|
-
platformName = message[1];
|
|
111
|
+
platformName = message[1] as PlatformName;
|
|
97
112
|
} else if (functionName === 'drawingFinished') {
|
|
98
113
|
// TODO The logic needs to be added here once the backend starts sending this event.
|
|
99
114
|
} else {
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026 The Chromium Authors
|
|
3
|
+
* Use of this source code is governed by a BSD-style license that can be
|
|
4
|
+
* found in the LICENSE file.
|
|
5
|
+
*/
|
|
6
|
+
/* eslint-disable color-named, plugin/use_theme_colors */
|
|
7
|
+
|
|
8
|
+
:root {
|
|
9
|
+
--gemini-logo: url("data:image/svg+xml,%0A%3Csvg%20fill%3D%22none%22%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2065%2065%22%3E%3Cmask%20id%3D%22maskme%22%20style%3D%22mask-type%3Aalpha%22%20maskUnits%3D%22userSpaceOnUse%22%20x%3D%220%22%20y%3D%220%22%20width%3D%2265%22%20height%3D%2265%22%3E%3Cpath%20d%3D%22M32.447%200c.68%200%201.273.465%201.439%201.125a38.904%2038.904%200%20001.999%205.905c2.152%205%205.105%209.376%208.854%2013.125%203.751%203.75%208.126%206.703%2013.125%208.855a38.98%2038.98%200%20005.906%201.999c.66.166%201.124.758%201.124%201.438%200%20.68-.464%201.273-1.125%201.439a38.902%2038.902%200%2000-5.905%201.999c-5%202.152-9.375%205.105-13.125%208.854-3.749%203.751-6.702%208.126-8.854%2013.125a38.973%2038.973%200%2000-2%205.906%201.485%201.485%200%2001-1.438%201.124c-.68%200-1.272-.464-1.438-1.125a38.913%2038.913%200%2000-2-5.905c-2.151-5-5.103-9.375-8.854-13.125-3.75-3.749-8.125-6.702-13.125-8.854a38.973%2038.973%200%2000-5.905-2A1.485%201.485%200%20010%2032.448c0-.68.465-1.272%201.125-1.438a38.903%2038.903%200%20005.905-2c5-2.151%209.376-5.104%2013.125-8.854%203.75-3.749%206.703-8.125%208.855-13.125a38.972%2038.972%200%20001.999-5.905A1.485%201.485%200%200132.447%200z%22%20fill%3D%22%23000%22/%3E%3Cpath%20d%3D%22M32.447%200c.68%200%201.273.465%201.439%201.125a38.904%2038.904%200%20001.999%205.905c2.152%205%205.105%209.376%208.854%2013.125%203.751%203.75%208.126%206.703%2013.125%208.855a38.98%2038.98%200%20005.906%201.999c.66.166%201.124.758%201.124%201.438%200%20.68-.464%201.273-1.125%201.439a38.902%2038.902%200%2000-5.905%201.999c-5%202.152-9.375%205.105-13.125%208.854-3.749%203.751-6.702%208.126-8.854%2013.125a38.973%2038.973%200%2000-2%205.906%201.485%201.485%200%2001-1.438%201.124c-.68%200-1.272-.464-1.438-1.125a38.913%2038.913%200%2000-2-5.905c-2.151-5-5.103-9.375-8.854-13.125-3.75-3.749-8.125-6.702-13.125-8.854a38.973%2038.973%200%2000-5.905-2A1.485%201.485%200%20010%2032.448c0-.68.465-1.272%201.125-1.438a38.903%2038.903%200%20005.905-2c5-2.151%209.376-5.104%2013.125-8.854%203.75-3.749%206.703-8.125%208.855-13.125a38.972%2038.972%200%20001.999-5.905A1.485%201.485%200%200132.447%200z%22%20fill%3D%22%23000%22/%3E%3C/mask%3E%3Cg%20mask%3D%22url(%23maskme)%22%3E%3Cpath%20fill%3D%22%234285F4%22%20d%3D%22M0%200h38.235L65%2027.66%2065%2065H0z%22/%3E%3Cpath%20fill%3D%22%23EA4335%22%20d%3D%22M26.765%200H65v38.235z%22/%3E%3Cpath%20fill%3D%22%2334A853%22%20d%3D%22M0%2026.765H38.235V65H0z%22/%3E%3Cpath%20fill%3D%22%23FBBC04%22%20d%3D%22M27.66%2065L65%2038.235V65z%22/%3E%3C/g%3E%3C/svg%3E");
|
|
10
|
+
--open-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23666' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6' /%3E%3Cpolyline points='15 3 21 3 21 9' /%3E%3Cline x1='10' y1='14' x2='21' y2='3' /%3E%3C/svg%3E");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
#green-dev-anchors-container {
|
|
14
|
+
position: absolute;
|
|
15
|
+
top: 0;
|
|
16
|
+
left: 0;
|
|
17
|
+
width: 100%;
|
|
18
|
+
height: 100%;
|
|
19
|
+
z-index: 1000;
|
|
20
|
+
pointer-events: none;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.green-dev-anchor-minimal {
|
|
24
|
+
position: absolute;
|
|
25
|
+
width: 70px;
|
|
26
|
+
height: 40px;
|
|
27
|
+
background-color: #fff;
|
|
28
|
+
border-radius: 12px;
|
|
29
|
+
box-shadow: 0 4px 8px rgb(0 0 0 / 20%);
|
|
30
|
+
pointer-events: auto;
|
|
31
|
+
z-index: 1001;
|
|
32
|
+
display: flex;
|
|
33
|
+
align-items: center;
|
|
34
|
+
justify-content: center;
|
|
35
|
+
padding: 0 5px;
|
|
36
|
+
cursor: pointer;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.green-dev-anchor-icon-gemini {
|
|
40
|
+
width: 24px;
|
|
41
|
+
height: 24px;
|
|
42
|
+
background-image: var(--gemini-logo);
|
|
43
|
+
background-size: cover;
|
|
44
|
+
background-repeat: no-repeat;
|
|
45
|
+
margin-right: 5px;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.green-dev-anchor-icon-open {
|
|
49
|
+
width: 20px;
|
|
50
|
+
height: 20px;
|
|
51
|
+
background-image: var(--open-icon);
|
|
52
|
+
background-size: cover;
|
|
53
|
+
background-repeat: no-repeat;
|
|
54
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
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 {Overlay} from './common.js';
|
|
6
|
+
|
|
7
|
+
export interface GreenDevAnchorsHighlight {
|
|
8
|
+
nodeId: number;
|
|
9
|
+
x: number;
|
|
10
|
+
y: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type GreenDevAnchorsToolMessage = {
|
|
14
|
+
highlightType: 'greenDevFloaty',
|
|
15
|
+
command: 'setInputValue',
|
|
16
|
+
nodeId: number,
|
|
17
|
+
value: string,
|
|
18
|
+
}|{
|
|
19
|
+
highlightType: 'greenDevFloaty',
|
|
20
|
+
command: 'debugMessage',
|
|
21
|
+
message: string,
|
|
22
|
+
}|{
|
|
23
|
+
highlightType: 'greenDevFloaty',
|
|
24
|
+
command: 'openDevTools',
|
|
25
|
+
nodeId: number,
|
|
26
|
+
}|{
|
|
27
|
+
highlightType: 'greenDevFloaty',
|
|
28
|
+
command: 'restoreFloaty',
|
|
29
|
+
nodeId: number,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
function consoleLog(message: string) {
|
|
33
|
+
window.InspectorOverlayHost.send({highlightType: 'greenDevFloaty', command: 'debugMessage', message});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface GreenDevAnchorsDispatchMessage {
|
|
37
|
+
nodeId: number;
|
|
38
|
+
value: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export class GreenDevAnchorsOverlay extends Overlay {
|
|
42
|
+
#anchorsContainer!: HTMLElement;
|
|
43
|
+
#anchorsByNodeId = new Map<number, HTMLElement>();
|
|
44
|
+
|
|
45
|
+
override install() {
|
|
46
|
+
consoleLog('GreenDevAnchorsOverlay.install() called');
|
|
47
|
+
|
|
48
|
+
this.document.body.classList.add('fill');
|
|
49
|
+
|
|
50
|
+
const canvas = this.document.createElement('canvas');
|
|
51
|
+
canvas.id = 'canvas';
|
|
52
|
+
canvas.classList.add('fill');
|
|
53
|
+
canvas.style.pointerEvents = 'none';
|
|
54
|
+
this.document.body.append(canvas);
|
|
55
|
+
|
|
56
|
+
const anchorsContainer = this.document.createElement('div');
|
|
57
|
+
anchorsContainer.id = 'green-dev-anchors-container';
|
|
58
|
+
this.document.body.append(anchorsContainer);
|
|
59
|
+
this.#anchorsContainer = anchorsContainer;
|
|
60
|
+
|
|
61
|
+
this.setCanvas(canvas);
|
|
62
|
+
super.install();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
override uninstall() {
|
|
66
|
+
consoleLog('GreenDevAnchorsOverlay.uninstall() called');
|
|
67
|
+
|
|
68
|
+
this.document.body.classList.remove('fill');
|
|
69
|
+
if (this.#anchorsContainer && this.#anchorsContainer.parentElement) {
|
|
70
|
+
this.#anchorsContainer.parentElement.removeChild(this.#anchorsContainer);
|
|
71
|
+
}
|
|
72
|
+
// Clear the map as the elements are removed from DOM.
|
|
73
|
+
this.#anchorsByNodeId.clear();
|
|
74
|
+
super.uninstall();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
drawGreenDevAnchors(highlights: GreenDevAnchorsHighlight[]) {
|
|
78
|
+
if (this.#anchorsContainer && !this.#anchorsContainer.isConnected) {
|
|
79
|
+
// The container was removed from the DOM (likely by PersistentOverlay.uninstall cleaning up),
|
|
80
|
+
// but this overlay still thinks it's installed. We need to re-install to restore the DOM.
|
|
81
|
+
try {
|
|
82
|
+
this.uninstall();
|
|
83
|
+
} catch (e) {
|
|
84
|
+
console.error('Error during uninstall in drawGreenDevAnchors:', e);
|
|
85
|
+
}
|
|
86
|
+
this.install();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const newAnchorsByNodeId = new Map<number, HTMLElement>();
|
|
90
|
+
|
|
91
|
+
for (const highlight of highlights) {
|
|
92
|
+
const {x, y, nodeId} = highlight;
|
|
93
|
+
let anchor = this.#anchorsByNodeId.get(nodeId);
|
|
94
|
+
|
|
95
|
+
if (anchor) {
|
|
96
|
+
anchor.style.left = `${x}px`;
|
|
97
|
+
anchor.style.top = `${y}px`;
|
|
98
|
+
// Remove from the old map so only anchors that need to be deleted remain.
|
|
99
|
+
this.#anchorsByNodeId.delete(nodeId);
|
|
100
|
+
} else {
|
|
101
|
+
const newAnchor = this.drawGreenDevAnchor(highlight);
|
|
102
|
+
if (!newAnchor) {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
anchor = newAnchor;
|
|
106
|
+
anchor.style.left = `${x}px`;
|
|
107
|
+
anchor.style.top = `${y}px`;
|
|
108
|
+
this.#anchorsContainer.append(anchor);
|
|
109
|
+
}
|
|
110
|
+
newAnchorsByNodeId.set(nodeId, anchor);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Remove any anchors that were not present in the new highlights list.
|
|
114
|
+
for (const anchor of this.#anchorsByNodeId.values()) {
|
|
115
|
+
anchor.remove();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
this.#anchorsByNodeId = newAnchorsByNodeId;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
private drawGreenDevAnchor(highlight: GreenDevAnchorsHighlight): HTMLElement {
|
|
122
|
+
const {nodeId} = highlight;
|
|
123
|
+
const anchor = this.document.createElement('div');
|
|
124
|
+
anchor.classList.add('green-dev-anchor-minimal');
|
|
125
|
+
|
|
126
|
+
const geminiIcon = this.document.createElement('div');
|
|
127
|
+
geminiIcon.classList.add('green-dev-anchor-icon-gemini');
|
|
128
|
+
anchor.append(geminiIcon);
|
|
129
|
+
|
|
130
|
+
const openIcon = this.document.createElement('div');
|
|
131
|
+
openIcon.classList.add('green-dev-anchor-icon-open');
|
|
132
|
+
anchor.append(openIcon);
|
|
133
|
+
|
|
134
|
+
const onEvent = (event: MouseEvent) => {
|
|
135
|
+
event.stopPropagation();
|
|
136
|
+
event.preventDefault();
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
openIcon.addEventListener('mousedown', onEvent);
|
|
140
|
+
openIcon.addEventListener('mouseup', onEvent);
|
|
141
|
+
openIcon.addEventListener('mousemove', onEvent);
|
|
142
|
+
openIcon.addEventListener('mouseenter', onEvent);
|
|
143
|
+
openIcon.addEventListener('mouseleave', onEvent);
|
|
144
|
+
openIcon.addEventListener('click', (event: MouseEvent) => {
|
|
145
|
+
onEvent(event);
|
|
146
|
+
window.InspectorOverlayHost.send({highlightType: 'greenDevFloaty', command: 'openDevTools', nodeId});
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
anchor.addEventListener('mousedown', onEvent);
|
|
150
|
+
anchor.addEventListener('mouseup', onEvent);
|
|
151
|
+
anchor.addEventListener('mousemove', onEvent);
|
|
152
|
+
anchor.addEventListener('mouseenter', onEvent);
|
|
153
|
+
anchor.addEventListener('mouseleave', onEvent);
|
|
154
|
+
anchor.addEventListener('click', (event: MouseEvent) => {
|
|
155
|
+
if (event.target !== anchor && !anchor.contains(event.target as Node)) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
onEvent(event);
|
|
159
|
+
window.InspectorOverlayHost.send({highlightType: 'greenDevFloaty', command: 'restoreFloaty', nodeId});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
return anchor;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
@@ -9,6 +9,7 @@ import {drawLayoutFlexContainerHighlight, type FlexContainerHighlight} from './h
|
|
|
9
9
|
import {drawLayoutGridHighlight, type GridHighlight} from './highlight_grid_common.js';
|
|
10
10
|
import {drawIsolatedElementHighlight, type IsolatedElementHighlight} from './highlight_isolated_element.js';
|
|
11
11
|
import {drawScrollSnapHighlight, type ScrollSnapHighlight} from './highlight_scroll_snap.js';
|
|
12
|
+
import type {GreenDevAnchorsHighlight, GreenDevAnchorsOverlay} from './tool_green_dev_anchors.js';
|
|
12
13
|
|
|
13
14
|
export interface PersistentToolMessage {
|
|
14
15
|
highlightType: string;
|
|
@@ -65,11 +66,17 @@ export class PersistentOverlay extends Overlay {
|
|
|
65
66
|
initialHeight: number,
|
|
66
67
|
}>();
|
|
67
68
|
private dragHandler?: DragResizeHandler;
|
|
69
|
+
private greenDevAnchorsOverlay?: GreenDevAnchorsOverlay;
|
|
70
|
+
|
|
71
|
+
setGreenDevAnchorsOverlay(greenDevAnchorsOverlay: GreenDevAnchorsOverlay) {
|
|
72
|
+
this.greenDevAnchorsOverlay = greenDevAnchorsOverlay;
|
|
73
|
+
}
|
|
68
74
|
|
|
69
75
|
override reset(data: ResetData) {
|
|
70
76
|
super.reset(data);
|
|
71
77
|
this.gridLabelState.gridLayerCounter = 0;
|
|
72
78
|
this.gridLabels.innerHTML = '';
|
|
79
|
+
this.greenDevAnchorsOverlay?.reset(data);
|
|
73
80
|
}
|
|
74
81
|
|
|
75
82
|
renderGridMarkup() {
|
|
@@ -129,6 +136,13 @@ export class PersistentOverlay extends Overlay {
|
|
|
129
136
|
this.context.restore();
|
|
130
137
|
}
|
|
131
138
|
|
|
139
|
+
drawGreenDevFloatyAnchors(highlights: GreenDevAnchorsHighlight[]) {
|
|
140
|
+
if (this.greenDevAnchorsOverlay && !this.greenDevAnchorsOverlay.installed) {
|
|
141
|
+
this.greenDevAnchorsOverlay.install();
|
|
142
|
+
}
|
|
143
|
+
this.greenDevAnchorsOverlay?.drawGreenDevAnchors(highlights);
|
|
144
|
+
}
|
|
145
|
+
|
|
132
146
|
drawIsolatedElementHighlight(highlight: IsolatedElementHighlight) {
|
|
133
147
|
if (!this.dragHandler) {
|
|
134
148
|
this.dragHandler = new DragResizeHandler(this.document, makeDraggableDelegate(this));
|
package/package.json
CHANGED
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
# Design Documents
|
|
2
|
-
|
|
3
|
-
**TL;DR**: This document outlines the development process for Chromium DevTools,
|
|
4
|
-
in particular the established culture and processes around design artifacts.
|
|
5
|
-
|
|
6
|
-
[TOC]
|
|
7
|
-
|
|
8
|
-
## Writing a design document
|
|
9
|
-
|
|
10
|
-
Any non-trivial technical effort that will significantly impact Chromium DevTools
|
|
11
|
-
should have a design doc ([template](https://goo.gle/devtools-design-doc-template)),
|
|
12
|
-
sometimes also referred to as _bluedoc_. Specifically, we require design docs
|
|
13
|
-
(DDs) in the following cases:
|
|
14
|
-
|
|
15
|
-
1. When writing code that will have a large impact on DevTools as a whole, e.g.
|
|
16
|
-
when you are changing behavior of a critical component like the Console or
|
|
17
|
-
Sources panel.
|
|
18
|
-
1. When beginning a large technical undertaking that should be documented for
|
|
19
|
-
historical reasons (>1 person-month of work can be used as a general
|
|
20
|
-
guideline).
|
|
21
|
-
|
|
22
|
-
*** promo
|
|
23
|
-
**Tip (Googlers):**
|
|
24
|
-
For smaller scale changes or when you are not sure yet whether any of the
|
|
25
|
-
criteria above will apply, but you still want to have it written up and
|
|
26
|
-
discussed, you can start with a Design Proposal
|
|
27
|
-
([template](http://go/chrome-devtools-greendoc-template)).
|
|
28
|
-
These should always be Google internal.
|
|
29
|
-
***
|
|
30
|
-
|
|
31
|
-
Public design docs have to live in the
|
|
32
|
-
[Design Documents](https://drive.google.com/drive/folders/1JbUthATfybvMQR3yAHC4J0P7n6oftYNq)
|
|
33
|
-
folder of the shared public
|
|
34
|
-
[Chromium DevTools](http://go/chrome-devtools/team-resources#chromium-devtools-shared-drive) team drive,
|
|
35
|
-
which automatically makes them commentable for
|
|
36
|
-
[contributors@chromium.org](mailto:contributors@chromium.org) and
|
|
37
|
-
[devtools-dev@chromium.org](mailto:devtools-dev@chromium.org). And they need to
|
|
38
|
-
be send to
|
|
39
|
-
[devtools-dev+design@chromium.org](mailto:devtools-dev+design@chromium.org).
|
|
40
|
-
|
|
41
|
-
Google internal design docs have to live in the
|
|
42
|
-
[Design Documents (internal)](http://go/chrome-devtools:design-internal-drive)
|
|
43
|
-
folder of the shared internal
|
|
44
|
-
[Chrome DevTools](http://go/chrome-devtools/team-resources#chrome-devtools-shared-drive) team drive, and
|
|
45
|
-
should be sent to
|
|
46
|
-
[chrome-devtools@google.com](mailto:chrome-devtools@google.com).
|
|
47
|
-
|
|
48
|
-
*** note
|
|
49
|
-
**IMPORTANT (Googlers):** Every design document (whether public or internal) must be editable
|
|
50
|
-
by [chrome-devtools-staff@google.com](mailto:chrome-devtools-staff@google.com) and
|
|
51
|
-
must have a `go/chrome-devtools:<project-name>-design` go/ link pointing to it
|
|
52
|
-
(even for publicly visible documents).
|
|
53
|
-
***
|
|
54
|
-
|
|
55
|
-
Follow the steps in the
|
|
56
|
-
[Chrome DevTools Design Review Guidelines](#Review-Guidelines)
|
|
57
|
-
to proceed with your design document and get it reviewed and approved.
|
|
58
|
-
|
|
59
|
-
## Review Guidelines
|
|
60
|
-
|
|
61
|
-
When contributing to Chrome DevTools, please follow the process explained in this document. This is to reach a clear agreement on proposals, while involving all relevant stakeholders and decision makers.
|
|
62
|
-
|
|
63
|
-
This process puts the IC in charge, but also requires Chrome DevTools' leaders to help the IC navigate the decision process. It includes an escalation path in case of disagreement. The overhead of this process should be proportionate to the scope of the proposal.
|
|
64
|
-
|
|
65
|
-
**Important:**
|
|
66
|
-
|
|
67
|
-
1. Assume good intentions.
|
|
68
|
-
1. Be kind and civilized.
|
|
69
|
-
1. Be pragmatic.
|
|
70
|
-
|
|
71
|
-

|
|
72
|
-
|
|
73
|
-
### Roles
|
|
74
|
-
|
|
75
|
-
#### Individual Contributor (IC)
|
|
76
|
-
|
|
77
|
-
_LGTM_: N/A
|
|
78
|
-
|
|
79
|
-
This person is the creator of the feature and the creator of the design documentation.
|
|
80
|
-
|
|
81
|
-
#### Technical Lead (TL)
|
|
82
|
-
|
|
83
|
-
_LGTM_: Required. May delegate.
|
|
84
|
-
|
|
85
|
-
The Chrome DevTools TL is Danil Somsikov (dsv@chromium.org). The TL ensures architectural consistency and good coverage by the right set of LGTM providers, and is required to sign off on the design. They may however explicitly delegate to other LGTM providers.
|
|
86
|
-
|
|
87
|
-
In the absence of the TL, an EnReOw can act in their stead.
|
|
88
|
-
|
|
89
|
-
#### LGTM provider
|
|
90
|
-
|
|
91
|
-
_LGTM_: Required. May delegate.
|
|
92
|
-
|
|
93
|
-
This is a person that is required to give LGTM. These are usually ICs with significant knowledge about the areas in question.
|
|
94
|
-
|
|
95
|
-
#### Reviewer
|
|
96
|
-
|
|
97
|
-
_LGTM_: Not required.
|
|
98
|
-
|
|
99
|
-
This is somebody who reviews and comments on the proposal. Their input should be considered, although their LGTM is not required.
|
|
100
|
-
|
|
101
|
-
#### The Eng Review Owners (EnReOw)
|
|
102
|
-
|
|
103
|
-
_LGTM_: Not required. However, LGTM or non-LGTM is binding.
|
|
104
|
-
|
|
105
|
-
Stuck proposals can be escalated to the [ENG_REVIEW_OWNERS](https://cs.chromium.org/chromium/src/third_party/devtools-frontend/src/config/owner/ENG_REVIEW_OWNERS). Potential use cases of such an escalation:
|
|
106
|
-
|
|
107
|
-
- An LGTM provider is non-responsive.
|
|
108
|
-
- No consensus on the design can be reached.
|
|
109
|
-
|
|
110
|
-
The EnReOw can overrule non-LGTMs or LGTMs.
|
|
111
|
-
|
|
112
|
-
### Detailed workflow
|
|
113
|
-
|
|
114
|
-
1. IC shares the document with LGTM providers and reviewers according to the roles listed above.
|
|
115
|
-
1. LGTM providers may add more LGTM providers to remove themselves as LGTM providers.
|
|
116
|
-
1. LGTM providers and reviewers review the design document and add feedback.
|
|
117
|
-
1. IC incorporates feedback and iterates on their design document.
|
|
118
|
-
1. Optional: the design doc is shared publicly with devtools-dev+design@chromium.org (make sure to give comment access to contributors@chromium.org, but untick the "Notify" checkbox).
|
|
119
|
-
1. IC collects LGTMs by addressing feedback. Iterate if necessary.
|
|
120
|
-
1. Once all required LGTMs have been collected, proceed with implementation.
|
|
121
|
-
1. On disagreement that cannot be resolved or unreasonable delays, escalate to EnReOw.
|
|
122
|
-
1. Implement and iterate on CLs with code owners. We expect the implementation to take place on the public repository's main branch. Note that a series of small incremental changes has a higher chance of receiving timely reviews and actionable feedback.
|
|
123
|
-
|
|
124
|
-
## FAQ
|
|
125
|
-
|
|
126
|
-
### Is it worth creating a design document?
|
|
127
|
-
|
|
128
|
-
It is always useful to have a design document. Its length can vary depending on the scope of the proposed change.
|
|
129
|
-
|
|
130
|
-
### When should the design process be kicked off?
|
|
131
|
-
|
|
132
|
-
As soon as possible so that a wide range of opinions can be taken into consideration. If you share your idea or prototype at a later stage, you risk having to redo the work because you missed a constraint.
|
|
133
|
-
|
|
134
|
-
### How to decide who to add to the list of LGTM providers?
|
|
135
|
-
|
|
136
|
-
Some pointers when people should be added to the list of LGTM providers:
|
|
137
|
-
|
|
138
|
-
- OWNERs of the source files/directories you anticipate to touch
|
|
139
|
-
- Main component expert of the components you anticipate to touch
|
|
140
|
-
- Downstream consumers of your changes e.g. when you change an API
|
|
141
|
-
|
|
142
|
-
### Where can I find a template for design documents?
|
|
143
|
-
|
|
144
|
-
[goo.gle/devtools-design-doc-template](https://goo.gle/devtools-design-doc-template)
|
|
145
|
-
|
|
146
|
-
### What if I made big changes to the design document?
|
|
147
|
-
|
|
148
|
-
Make sure you still have the LGTMs e.g. by pinging the LGTM providers.
|
|
149
|
-
|
|
150
|
-
### LGTM providers do not comment on my design document, what should I do?
|
|
151
|
-
|
|
152
|
-
In this case you can follow this path of escalation:
|
|
153
|
-
|
|
154
|
-
1. Ping them directly via mail, chat or comment/assignment in the doc and specifically ask them explicitly to add an LGTM or non-LGTM.
|
|
155
|
-
1. Get your TL involved and ask them for help.
|
|
156
|
-
1. Escalate to EnReOw.
|
|
157
|
-
|
|
158
|
-
### Somebody added me as an LGTM provider to a doc, what should I do?
|
|
159
|
-
|
|
160
|
-
Review the design document. If you think there are other people who should take a look, add them as LGTM providers or as reviewers. If you don't think you are the right person, remove yourself as LGTM provider.
|
|
161
|
-
|
|
162
|
-
If you agree with the design, add an LGTM to the table. If you have blocking concerns, add "Not LGTM, because <reason>" to the table. Be prepared to re-review the design after another iteration.
|
|
163
|
-
|
|
164
|
-
### How does this work together with the Blink Intents process?
|
|
165
|
-
|
|
166
|
-
The Chromium DevTools Design Review Guidelines complement [Chromium’s feature launch process](https://www.chromium.org/blink/launching-features). If you are launching a new Web platform feature, please follow the Chromium launch process. It likely makes sense to have all the LGTMs gathered at the point in time you would send an Intent to Implement.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
This document has moved [here](./contributing/design.md#Review-Guidelines).
|