chrome-devtools-frontend 1.0.1724140 → 1.0.1726686
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/skills/review-ui-widgets/SKILL.md +7 -7
- package/.agents/skills/ui-eng-vision-local-lit-renderer/SKILL.md +12 -0
- package/.agents/skills/ui-eng-vision-widget-promoter/SKILL.md +3 -3
- package/.agents/skills/ui-widgets/SKILL.md +2 -1
- package/docs/cookbook/dependencies.md +6 -4
- package/front_end/core/i18n/i18nImpl.ts +1 -1
- package/front_end/core/root/Runtime.ts +1 -1
- package/front_end/core/sdk/ResourceTreeModel.ts +16 -0
- package/front_end/entrypoints/js_app/js_app.ts +2 -5
- package/front_end/entrypoints/node_app/node_app.ts +2 -3
- package/front_end/generated/InspectorBackendCommands.ts +1 -1
- package/front_end/generated/protocol.ts +1 -0
- package/front_end/models/ai_assistance/skills/lighthouse.md +2 -1
- package/front_end/models/ai_assistance/skills/network.md +1 -0
- package/front_end/models/ai_assistance/tools/ExecuteJavaScript.ts +26 -2
- package/front_end/models/ai_assistance/tools/GetLighthouseAudits.ts +1 -1
- package/front_end/models/ai_assistance/tools/ListNetworkRequests.ts +2 -7
- package/front_end/models/ai_assistance/tools/RunLighthouse.ts +2 -2
- package/front_end/models/comment_manager/CommentManager.ts +0 -6
- package/front_end/models/comment_manager/CommentThread.ts +23 -19
- package/front_end/models/elements/StyleChanges.ts +66 -0
- package/front_end/models/trace/EventsSerializer.ts +2 -7
- package/front_end/models/trace/ModelImpl.ts +0 -2
- package/front_end/models/trace/handlers/FlowsHandler.ts +37 -29
- package/front_end/models/trace/helpers/SyntheticEvents.ts +10 -37
- package/front_end/models/trace/insights/RenderBlocking.ts +3 -1
- package/front_end/models/trace/lantern/simulation/Simulator.ts +4 -0
- package/front_end/models/trace/lantern/types/Lantern.ts +1 -0
- package/front_end/panels/accessibility/SourceOrderView.ts +1 -1
- package/front_end/panels/application/ApplicationPanelSidebar.ts +90 -0
- package/front_end/panels/application/StorageView.ts +196 -174
- package/front_end/panels/application/SubAppsView.ts +2 -2
- package/front_end/panels/application/preloading/PreloadingView.ts +360 -336
- package/front_end/panels/application/preloading/components/PreloadingDisabledInfobar.ts +2 -2
- package/front_end/panels/application/preloading/components/PreloadingGrid.ts +6 -3
- package/front_end/panels/application/preloading/components/RuleSetGrid.ts +17 -17
- package/front_end/panels/application/preloading/components/UsedPreloadingView.ts +2 -2
- package/front_end/panels/application/preloading/preloadingView.css +12 -4
- package/front_end/panels/application/preloading/preloadingViewDropDown.css +1 -1
- package/front_end/panels/application/storageView.css +16 -21
- package/front_end/panels/browser_debugger/CategorizedBreakpointsSidebarPane.ts +2 -2
- package/front_end/panels/browser_debugger/browser_debugger-meta.ts +6 -8
- package/front_end/panels/comments/CommentsPane.ts +26 -9
- package/front_end/panels/comments/commentsPane.css +25 -6
- package/front_end/panels/common/CommentThreadWidget.ts +2 -2
- package/front_end/panels/common/CommentsOverlayWidget.ts +94 -35
- package/front_end/panels/common/commentThreadWidget.css +17 -0
- package/front_end/panels/common/commentsOverlay.css +5 -10
- package/front_end/panels/common/common-meta.ts +11 -1
- package/front_end/panels/elements/ClassesPaneWidget.ts +130 -88
- package/front_end/panels/elements/ColorSwatchPopoverIcon.ts +7 -33
- package/front_end/panels/elements/DOMTreeWidget.ts +7 -3
- package/front_end/panels/elements/ElementStatePaneWidget.ts +11 -1
- package/front_end/panels/elements/PropertyRenderer.ts +3 -2
- package/front_end/panels/elements/StyleEditorWidget.ts +60 -41
- package/front_end/panels/elements/StylePropertiesSection.ts +32 -5
- package/front_end/panels/elements/StylePropertyTreeElement.ts +227 -162
- package/front_end/panels/event_listeners/EventListenersView.ts +11 -8
- package/front_end/panels/linear_memory_inspector/components/ValueInterpreterSettings.ts +1 -1
- package/front_end/panels/network/NetworkDataGridNode.ts +3 -1
- package/front_end/panels/network/RequestConditionsDrawer.ts +1 -1
- package/front_end/panels/network/RequestPayloadView.ts +12 -5
- package/front_end/panels/profiler/HeapProfileView.ts +28 -6
- package/front_end/panels/profiler/HeapSnapshotDataGrids.ts +7 -3
- package/front_end/panels/protocol_monitor/JSONEditor.ts +0 -1
- package/front_end/panels/recorder/RecorderPanel.ts +2 -2
- package/front_end/panels/settings/SettingsScreen.ts +1 -1
- package/front_end/panels/sources/NavigatorView.ts +105 -45
- package/front_end/panels/sources/ScopeChainSidebarPane.ts +8 -5
- package/front_end/panels/sources/SourcesNavigator.ts +421 -213
- package/front_end/panels/sources/SourcesPanel.ts +6 -4
- package/front_end/panels/sources/WatchExpressionsSidebarPane.ts +10 -5
- package/front_end/panels/sources/sources-meta.ts +4 -15
- package/front_end/panels/sources/sourcesNavigator.css +5 -0
- package/front_end/panels/timeline/ModificationsManager.ts +0 -2
- package/front_end/panels/timeline/README.md +2 -0
- package/front_end/panels/timeline/TimelineCommentController.ts +132 -30
- package/front_end/panels/timeline/TimelinePanel.ts +4 -0
- package/front_end/panels/timeline/components/IgnoreListSetting.ts +1 -1
- package/front_end/panels/timeline/utils/Treemap.ts +8 -0
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/ui/comments/CommentAnchorResolver.ts +3 -0
- package/front_end/ui/comments/CommentOverlayManager.ts +2 -4
- package/front_end/ui/components/lists/List.ts +14 -1
- package/front_end/ui/components/panel_feedback/PreviewToggle.ts +1 -1
- package/front_end/ui/components/text_editor/AiCodeCompletionProvider.ts +23 -14
- package/front_end/ui/components/text_editor/AiCodeGenerationProvider.ts +3 -0
- package/front_end/ui/legacy/Toolbar.ts +0 -1
- package/front_end/ui/legacy/Treeoutline.ts +7 -2
- package/front_end/ui/legacy/UIUtils.ts +4 -1
- package/front_end/ui/legacy/components/inline_editor/Swatches.ts +19 -6
- package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +20 -11
- package/front_end/ui/legacy/components/source_frame/XMLView.ts +27 -7
- package/front_end/ui/visual_logging/KnownContextValues.ts +1 -0
- package/package.json +1 -1
|
@@ -78,10 +78,10 @@ This skill provides review guidance for Chrome DevTools frontend changes matchin
|
|
|
78
78
|
- **Look for**: Unscoped generic selectors in light-DOM `.css` files (or `:host` inside `@scope` blocks instead of `:scope`), or CSS rules combining `vertical-align`, negative `margin-top`, and pixel offsets to center icons and buttons.
|
|
79
79
|
- **Do not flag**: Shadow DOM component stylesheets where `:host` scoping is native.
|
|
80
80
|
|
|
81
|
-
### `UI_VIEW_OUTPUT_AND_CALLBACK_CONTRACTS`: Encapsulate imperative DOM actions in ViewOutput callbacks and pass user actions via semantic ViewInput callbacks instead of raw DOM references
|
|
81
|
+
### `UI_VIEW_OUTPUT_AND_CALLBACK_CONTRACTS`: Encapsulate imperative DOM and child widget actions in ViewOutput callbacks and pass user actions via semantic ViewInput callbacks instead of raw DOM or Widget references
|
|
82
82
|
- **Severity**: WARNING
|
|
83
|
-
- **Why**: Exposing raw `HTMLElement` references on `ViewOutput` or passing raw `MouseEvent`/`KeyboardEvent` objects to presenter callbacks leaks
|
|
84
|
-
- **Look for**: `ViewOutput` interfaces containing `HTMLElement` or `
|
|
83
|
+
- **Why**: Exposing raw `HTMLElement` or `UI.Widget` references on `ViewOutput` (e.g. `output.childWidget = w`) or passing raw `MouseEvent`/`KeyboardEvent` objects to presenter callbacks leaks view implementation details into presenters. Supply all configuration through setters/inputs on the child widget, or if imperative calls are strictly necessary, populate narrow functional closures on `ViewOutput` (e.g. `output.focusInput = () => ...`, `output.scrollWidgetToSomething = () => widgetRef.scrollToSomething()`), and unpack event values before calling `input.onSelect(value)`.
|
|
84
|
+
- **Look for**: `ViewOutput` interfaces containing `HTMLElement`, `Element`, or `UI.Widget` subclass properties (other than temporary intermediate CL bridges), `get*ForTest()` presenter methods backed by `ViewOutput` widget references, or `ViewInput` callbacks typed as `(event: Event) => void` instead of semantic domain values.
|
|
85
85
|
- **Do not flag**: Third-party editor or canvas host containers that require a raw mount `HTMLElement`.
|
|
86
86
|
|
|
87
87
|
### `UI_PANEL_AND_META_REGISTRATION`: Follow DevTools panel directory conventions and register settings and views in the appropriate *-meta.ts scope
|
|
@@ -102,11 +102,11 @@ This skill provides review guidance for Chrome DevTools frontend changes matchin
|
|
|
102
102
|
- **Look for**: Raw string interpolation in `querySelector('[attr="' + val + '"]')` without `CSS.escape`, `href` attribute bindings with unvalidated `javascript:` URLs, Markdown table cell serialization without escaping `|*_<>\`, or raw HTML snippet generation without HTML escaping.
|
|
103
103
|
- **Do not flag**: Standard Lit `html` text bindings (`${text}`), which escape HTML entities automatically.
|
|
104
104
|
|
|
105
|
-
### `UI_DECLARATIVE_CHILD_WIDGET_COMPOSITION`: Compose child UI.Widget instances declaratively in Lit templates using
|
|
105
|
+
### `UI_DECLARATIVE_CHILD_WIDGET_COMPOSITION`: Compose child UI.Widget instances declaratively in Lit templates using ${widget(ChildWidget, {...})} instead of imperative show() calls, single-argument factory callbacks, or bare <devtools-widget> tags
|
|
106
106
|
- **Severity**: WARNING
|
|
107
|
-
- **Why**: Imperatively instantiating child widgets and calling `child.show(container)` inside presenters or views bypasses Lit reconciliation, complicates lifecycle management, and recreates widgets unnecessarily across renders. Similarly, single-argument factory callbacks `widget(element => ...)` only run on initial creation and fail to propagate updated properties on subsequent re-renders; strongly prefer the two-argument `widget(ChildWidget, {...})` form (converting `setFoo()` methods on the child widget into `set foo()` setters if needed).
|
|
108
|
-
- **Look for**: `new ChildWidget()` followed by `.show(...)` or `.appendChild(child.element)` inside Lit view functions or migrated `performUpdate()` methods,
|
|
109
|
-
- **Do not flag**: Top-level legacy split widgets or tabbed panes that have not migrated to Lit views.
|
|
107
|
+
- **Why**: Imperatively instantiating child widgets and calling `child.show(container)` inside presenters or views bypasses Lit reconciliation, complicates lifecycle management, and recreates widgets unnecessarily across renders. Similarly, single-argument factory callbacks `widget(element => ...)` only run on initial creation and fail to propagate updated properties on subsequent re-renders; strongly prefer the two-argument `widget(ChildWidget, {...})` form (converting `setFoo()` methods on the child widget into `set foo()` setters if needed). Prefer `${widget(ChildWidget, {...})}` directly as a child expression over `<devtools-widget ${widget(ChildWidget, {...})}></devtools-widget>`; only use an explicit `<devtools-widget>` tag when setting other attributes, applying other directives (such as `widgetRef` or `ref`), or providing child nodes.
|
|
108
|
+
- **Look for**: `new ChildWidget()` followed by `.show(...)` or `.appendChild(child.element)` inside Lit view functions or migrated `performUpdate()` methods, `widget(element => ...)` factory callbacks configuring child widget properties imperatively instead of `${widget(ChildWidget, {...})}`, or `<devtools-widget ${widget(ChildWidget, {...})}></devtools-widget>` tags that have no other attributes, directives, or child nodes.
|
|
109
|
+
- **Do not flag**: Top-level legacy split widgets or tabbed panes that have not migrated to Lit views, or `<devtools-widget>` tags that set other attributes, use additional directives (e.g. `widgetRef`), or contain child nodes.
|
|
110
110
|
|
|
111
111
|
### `UI_AWAIT_UPDATE_COMPLETE_POST_RENDER`: Await this.updateComplete before executing post-render DOM measurements, focus changes, or scroll adjustments
|
|
112
112
|
- **Severity**: ERROR
|
|
@@ -126,6 +126,12 @@ existing element containers.
|
|
|
126
126
|
|
|
127
127
|
12. **Composing Child `UI.Widget`s & Pre-Existing Instances**:
|
|
128
128
|
|
|
129
|
+
* **Prefer `${widget(ChildWidgetClass, {params})}` Over `<devtools-widget>`**:
|
|
130
|
+
Prefer `${widget(ChildWidgetClass, {params})}` directly as a child
|
|
131
|
+
expression instead of `<devtools-widget ${widget(ChildWidgetClass, {params})}></devtools-widget>`.
|
|
132
|
+
Only use an explicit `<devtools-widget>` tag when you need to set other
|
|
133
|
+
HTML attributes/classes, apply additional directives (such as `widgetRef`
|
|
134
|
+
or `ref`), or provide child nodes.
|
|
129
135
|
* **Strongly Prefer Two-Argument `widget(ChildWidgetClass, {params})`**:
|
|
130
136
|
When instantiating child widgets in a Lit template, strongly prefer the
|
|
131
137
|
two-argument form `widget(ChildWidgetClass, {propA: input.a, propB: input.b})`
|
|
@@ -136,6 +142,12 @@ existing element containers.
|
|
|
136
142
|
`setFoo()` methods instead of setters, convert them into `set foo()`
|
|
137
143
|
setters on the child widget so you can use the two-argument `widget()`
|
|
138
144
|
directive.
|
|
145
|
+
* **No Widget References on `ViewOutput`**: Do not store child widget
|
|
146
|
+
references on `ViewOutput` (e.g., `output.childWidget = w`) as a final
|
|
147
|
+
result (only acceptable temporarily in intermediate CLs). Supply all
|
|
148
|
+
configuration through setters on the child widget, or if imperative
|
|
149
|
+
actions are strictly required, expose individual functions on `ViewOutput`
|
|
150
|
+
(e.g., `output.doLayout = () => w.doLayout()`).
|
|
139
151
|
* **Pre-Existing Widget Instances (`UI.Widget.WrapperWidget`)**: Use
|
|
140
152
|
`${widget(UI.Widget.WrapperWidget, {widget: input.childWidget})}` when
|
|
141
153
|
embedding widgets owned by `UI.ViewManager`
|
|
@@ -66,14 +66,14 @@ clean `UI.Widget` classes that use native update rendering delegates.
|
|
|
66
66
|
3. **Clean Up Legacy Wrappers**:
|
|
67
67
|
|
|
68
68
|
* Remove any `LegacyWrapper` bindings or custom wrappable custom elements.
|
|
69
|
-
* Replace old panel instantiations with
|
|
70
|
-
declarative entries (using `const {widget} = UI.Widget;`):
|
|
69
|
+
* Replace old panel instantiations with declarative `widget` entries (using `const {widget} = UI.Widget;`). Prefer `${widget(MyWidgetClass, {params})}` directly as a child expression over `<devtools-widget ${widget(MyWidgetClass, {params})}></devtools-widget>`; only use an explicit `<devtools-widget>` tag when setting other attributes, applying other directives (such as `widgetRef` or `ref`), or providing child nodes:
|
|
71
70
|
|
|
72
71
|
```typescript
|
|
73
|
-
html
|
|
72
|
+
html`${widget(MyWidgetClass, {params})}`
|
|
74
73
|
```
|
|
75
74
|
|
|
76
75
|
* **Strongly prefer the two-argument `widget(MyWidgetClass, {params})` form** over the single-argument factory callback `widget(element => new MyWidgetClass(element, ...))`. The single-argument factory only runs on initial creation and does not update properties on subsequent re-renders. If the child widget only exposes `setFoo(...)` methods, convert them into `set foo(...)` setters so they can be passed via the second argument of `widget()`.
|
|
76
|
+
* **No Widget References on `ViewOutput`**: Keeping child `UI.Widget` instances on `ViewOutput` (e.g., `output.childWidget = w`) is not a good practice and must not remain in the final result (it is only acceptable temporarily in intermediate CLs). Either supply all configuration through setters on the child widget, or if imperative action calls are strictly needed, expose individual functions on `ViewOutput` (such as `output.doLayout = () => w.doLayout()` or `output.scrollWidgetToSomething = () => w.scrollToSomething()`). Remove legacy `get*ForTest()` methods that were only used to grab child widgets from `ViewOutput` and update tests to query the DOM (`view.contentElement.querySelector(...)?.getWidget()`) or inspect `ViewInput`.
|
|
77
77
|
* Inspect instantiator files (e.g., `ApplicationPanelSidebar.ts`) and
|
|
78
78
|
decouple any direct accesses to `.element`.
|
|
79
79
|
|
|
@@ -59,6 +59,7 @@ const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLElement)
|
|
|
59
59
|
### Composition
|
|
60
60
|
|
|
61
61
|
* To render a child widget, the parent's View MUST use the lit-html directive `UI.Widget.widget`.
|
|
62
|
+
* **Prefer `${widget(WidgetClass, {params})}` directly as a child expression** over `<devtools-widget ${widget(WidgetClass, {params})}></devtools-widget>`. Only use an explicit `<devtools-widget>` tag when you need to set other HTML attributes/classes, apply additional directives (such as `widgetRef` or `ref`), or provide child nodes.
|
|
62
63
|
* **Strongly prefer the two-argument `widget(WidgetClass, {params})` form** over the single-argument factory callback `widget(element => new WidgetClass(element, ...))`. The two-argument form automatically updates properties and calls `requestUpdate()` on subsequent renders, whereas a factory callback only runs once on initial instantiation.
|
|
63
64
|
* If a child widget currently exposes imperative setter methods (e.g., `setStorageKey(key)` or `setStorageBucket(bucket)`) instead of public properties/setters, convert them into standard TypeScript setters (`set storageKey(key)`, `set storageBucket(bucket)`) on the child widget so it can be instantiated and updated declaratively via the two-argument `widget(WidgetClass, {params})` directive.
|
|
64
65
|
* Configuration is passed via the parameters.
|
|
@@ -110,7 +111,7 @@ render(html`
|
|
|
110
111
|
|
|
111
112
|
### Legacy Interop & Refs
|
|
112
113
|
* **Raw Elements:** Use `Directives.ref` (from `ui/lit/lit.js`) to obtain a reference to a raw `HTMLElement` if needed for imperative APIs (e.g., `splitWidget.installResizer(element)`).
|
|
113
|
-
* **Child Widgets:** Use `UI.Widget.widgetRef` to obtain the class instance of a child widget if you need to call methods on it
|
|
114
|
+
* **Child Widgets:** Use `UI.Widget.widgetRef` to obtain the class instance of a child widget inside the view function if you need to call imperative methods on it. **Do NOT store child widget instances on `ViewOutput` as a final result** (doing so is only acceptable temporarily in intermediate migration CLs). Instead, either supply all needed configuration declaratively through setters/inputs on the child widget, or if imperative calls are strictly necessary, expose narrow action functions on `ViewOutput` (e.g., `output.doLayout = () => splitWidget.doLayout()`, `output.revealPosition = pos => childWidget.revealPosition(pos)`). Do not keep `get*ForTest()` methods that return child widget instances via `ViewOutput`; tests should query rendered `<devtools-widget>` elements via `.getWidget()` or assert on `ViewInput` via `createViewFunctionStub`.
|
|
114
115
|
|
|
115
116
|
### Dependencies
|
|
116
117
|
|
|
@@ -111,10 +111,12 @@ that shared dependencies are deduplicated and thus result in a smaller archive.
|
|
|
111
111
|
`scripts/deps/npm_exclude.txt` holds rsync filter rules that drop files the
|
|
112
112
|
build and tests don't need (tests, docs, source maps, non-declaration
|
|
113
113
|
TypeScript sources, dotfiles, ...) before the archive is built. Keep rules come
|
|
114
|
-
first and the first matching rule wins.
|
|
115
|
-
package-specific
|
|
116
|
-
|
|
117
|
-
|
|
114
|
+
first and the first matching rule wins. Prefer generic patterns. A
|
|
115
|
+
package-specific rule goes into the "package-specific drops" section with a
|
|
116
|
+
comment saying why the files are unused, and must be measured and verified
|
|
117
|
+
with a full build, test and lint run, because the reference check only knows
|
|
118
|
+
about paths mentioned in GN and Python files, not about what Node resolves at
|
|
119
|
+
runtime. Check such rules again when the package in question is updated.
|
|
118
120
|
|
|
119
121
|
> **WARNING:** Updating tools such as Rollup and TypeScript will cause all build
|
|
120
122
|
> cache output to be purged, as they are part of all DevTools modules. Whenever
|
|
@@ -49,7 +49,7 @@ export function getAllSupportedDevToolsLocales(): string[] {
|
|
|
49
49
|
function getLocaleFetchUrl(locale: Intl.UnicodeBCP47LocaleIdentifier, location: string): string {
|
|
50
50
|
const remoteBase = Root.Runtime.getRemoteBase(location);
|
|
51
51
|
if (remoteBase?.version && !BUNDLED_LOCALES.has(locale)) {
|
|
52
|
-
return REMOTE_FETCH_PATTERN.replace('@HOST@', 'devtools://devtools')
|
|
52
|
+
return REMOTE_FETCH_PATTERN.replace('@HOST@', 'devtools://devtools-remote')
|
|
53
53
|
.replace('@VERSION@', remoteBase.version)
|
|
54
54
|
.replace('@LOCALE@', locale);
|
|
55
55
|
}
|
|
@@ -47,7 +47,7 @@ export function getRemoteBase(location: string = globalObject.self?.location?.to
|
|
|
47
47
|
return null;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
return {base: `devtools://devtools/remote/serve_file/${version[1]}/`, version: version[1]};
|
|
50
|
+
return {base: `devtools://devtools-remote/remote/serve_file/${version[1]}/`, version: version[1]};
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
export function getPathName(): string {
|
|
@@ -529,6 +529,22 @@ export class ResourceTreeModel extends SDKModel<EventTypes> {
|
|
|
529
529
|
return await this.agent.invoke_getAppId();
|
|
530
530
|
}
|
|
531
531
|
|
|
532
|
+
async getSubApps(): Promise<Protocol.Page.SubApp[]> {
|
|
533
|
+
const response = await this.agent.invoke_getSubApps();
|
|
534
|
+
if (response.getError()) {
|
|
535
|
+
return [];
|
|
536
|
+
}
|
|
537
|
+
return response.subApps ?? [];
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
async getSiblingSubApps(): Promise<Protocol.Page.SubApp[]> {
|
|
541
|
+
const response = await this.agent.invoke_getSiblingSubApps();
|
|
542
|
+
if (response.getError()) {
|
|
543
|
+
return [];
|
|
544
|
+
}
|
|
545
|
+
return response.subApps ?? [];
|
|
546
|
+
}
|
|
547
|
+
|
|
532
548
|
private executionContextComparator(a: ExecutionContext, b: ExecutionContext): number {
|
|
533
549
|
function framePath(frame: ResourceTreeFrame|null): ResourceTreeFrame[] {
|
|
534
550
|
let currentFrame: (ResourceTreeFrame|null) = frame;
|
|
@@ -85,12 +85,9 @@ UI.ViewManager.registerViewExtension({
|
|
|
85
85
|
commandPrompt: i18nLazyString(UIStrings.showNode),
|
|
86
86
|
order: 2,
|
|
87
87
|
persistence: UI.ViewManager.ViewPersistence.PERMANENT,
|
|
88
|
-
async loadView(
|
|
88
|
+
async loadView() {
|
|
89
89
|
const Sources = await loadSourcesModule();
|
|
90
|
-
return Sources.SourcesNavigator.NetworkNavigatorView.instance(
|
|
91
|
-
forceNew: null,
|
|
92
|
-
networkProjectManager: universe.networkProjectManager,
|
|
93
|
-
});
|
|
90
|
+
return Sources.SourcesNavigator.NetworkNavigatorView.instance();
|
|
94
91
|
},
|
|
95
92
|
});
|
|
96
93
|
|
|
@@ -81,10 +81,9 @@ UI.ViewManager.registerViewExtension({
|
|
|
81
81
|
commandPrompt: i18nLazyString(UIStrings.showNode),
|
|
82
82
|
order: 2,
|
|
83
83
|
persistence: UI.ViewManager.ViewPersistence.PERMANENT,
|
|
84
|
-
async loadView(
|
|
84
|
+
async loadView() {
|
|
85
85
|
const Sources = await loadSourcesModule();
|
|
86
|
-
return Sources.SourcesNavigator.NetworkNavigatorView.instance(
|
|
87
|
-
{forceNew: null, networkProjectManager: universe.networkProjectManager});
|
|
86
|
+
return Sources.SourcesNavigator.NetworkNavigatorView.instance();
|
|
88
87
|
},
|
|
89
88
|
});
|
|
90
89
|
|
|
@@ -838,7 +838,7 @@ inspectorBackend.registerEnum("Network.ContentSecurityPolicySource", {HTTP: "HTT
|
|
|
838
838
|
inspectorBackend.registerEnum("Network.ReportStatus", {Queued: "Queued", Pending: "Pending", MarkedForRemoval: "MarkedForRemoval", Success: "Success"});
|
|
839
839
|
inspectorBackend.registerEnum("Network.DeviceBoundSessionWithUsageUsage", {NotInScope: "NotInScope", InScopeRefreshNotYetNeeded: "InScopeRefreshNotYetNeeded", InScopeRefreshNotAllowed: "InScopeRefreshNotAllowed", ProactiveRefreshNotPossible: "ProactiveRefreshNotPossible", ProactiveRefreshAttempted: "ProactiveRefreshAttempted", Deferred: "Deferred"});
|
|
840
840
|
inspectorBackend.registerEnum("Network.DeviceBoundSessionUrlRuleRuleType", {Exclude: "Exclude", Include: "Include"});
|
|
841
|
-
inspectorBackend.registerEnum("Network.DeviceBoundSessionFetchResult", {Success: "Success", SigningKeyGenerationError: "SigningKeyGenerationError", AttestationKeyGenerationError: "AttestationKeyGenerationError", SigningError: "SigningError", TransientSigningError: "TransientSigningError", ServerRequestedTermination: "ServerRequestedTermination", InvalidSessionId: "InvalidSessionId", InvalidChallenge: "InvalidChallenge", TooManyChallenges: "TooManyChallenges", InvalidFetcherUrl: "InvalidFetcherUrl", InvalidRefreshUrl: "InvalidRefreshUrl", TransientHttpError: "TransientHttpError", ScopeOriginSameSiteMismatch: "ScopeOriginSameSiteMismatch", RefreshUrlSameSiteMismatch: "RefreshUrlSameSiteMismatch", MismatchedSessionId: "MismatchedSessionId", MissingScope: "MissingScope", NoCredentials: "NoCredentials", SubdomainRegistrationWellKnownUnavailable: "SubdomainRegistrationWellKnownUnavailable", SubdomainRegistrationUnauthorized: "SubdomainRegistrationUnauthorized", SubdomainRegistrationWellKnownMalformed: "SubdomainRegistrationWellKnownMalformed", SessionProviderWellKnownUnavailable: "SessionProviderWellKnownUnavailable", RelyingPartyWellKnownUnavailable: "RelyingPartyWellKnownUnavailable", FederatedKeyThumbprintMismatch: "FederatedKeyThumbprintMismatch", InvalidFederatedSessionUrl: "InvalidFederatedSessionUrl", InvalidFederatedKey: "InvalidFederatedKey", TooManyRelyingOriginLabels: "TooManyRelyingOriginLabels", BoundCookieSetForbidden: "BoundCookieSetForbidden", NetError: "NetError", ProxyError: "ProxyError", EmptySessionConfig: "EmptySessionConfig", InvalidCredentialsConfig: "InvalidCredentialsConfig", InvalidCredentialsType: "InvalidCredentialsType", InvalidCredentialsEmptyName: "InvalidCredentialsEmptyName", InvalidCredentialsCookie: "InvalidCredentialsCookie", PersistentHttpError: "PersistentHttpError", RegistrationAttemptedChallenge: "RegistrationAttemptedChallenge", InvalidScopeOrigin: "InvalidScopeOrigin", ScopeOriginContainsPath: "ScopeOriginContainsPath", RefreshInitiatorNotString: "RefreshInitiatorNotString", RefreshInitiatorInvalidHostPattern: "RefreshInitiatorInvalidHostPattern", InvalidScopeSpecification: "InvalidScopeSpecification", MissingScopeSpecificationType: "MissingScopeSpecificationType", EmptyScopeSpecificationDomain: "EmptyScopeSpecificationDomain", EmptyScopeSpecificationPath: "EmptyScopeSpecificationPath", InvalidScopeSpecificationType: "InvalidScopeSpecificationType", InvalidScopeIncludeSite: "InvalidScopeIncludeSite", MissingScopeIncludeSite: "MissingScopeIncludeSite", FederatedNotAuthorizedByProvider: "FederatedNotAuthorizedByProvider", FederatedNotAuthorizedByRelyingParty: "FederatedNotAuthorizedByRelyingParty", SessionProviderWellKnownMalformed: "SessionProviderWellKnownMalformed", SessionProviderWellKnownHasProviderOrigin: "SessionProviderWellKnownHasProviderOrigin", RelyingPartyWellKnownMalformed: "RelyingPartyWellKnownMalformed", RelyingPartyWellKnownHasRelyingOrigins: "RelyingPartyWellKnownHasRelyingOrigins", InvalidFederatedSessionProviderSessionMissing: "InvalidFederatedSessionProviderSessionMissing", InvalidFederatedSessionWrongProviderOrigin: "InvalidFederatedSessionWrongProviderOrigin", InvalidCredentialsCookieCreationTime: "InvalidCredentialsCookieCreationTime", InvalidCredentialsCookieName: "InvalidCredentialsCookieName", InvalidCredentialsCookieParsing: "InvalidCredentialsCookieParsing", InvalidCredentialsCookieUnpermittedAttribute: "InvalidCredentialsCookieUnpermittedAttribute", InvalidCredentialsCookieInvalidDomain: "InvalidCredentialsCookieInvalidDomain", InvalidCredentialsCookiePrefix: "InvalidCredentialsCookiePrefix", InvalidScopeRulePath: "InvalidScopeRulePath", InvalidScopeRuleHostPattern: "InvalidScopeRuleHostPattern", ScopeRuleOriginScopedHostPatternMismatch: "ScopeRuleOriginScopedHostPatternMismatch", ScopeRuleSiteScopedHostPatternMismatch: "ScopeRuleSiteScopedHostPatternMismatch", SigningQuotaExceeded: "SigningQuotaExceeded", InvalidConfigJson: "InvalidConfigJson", InvalidFederatedSessionProviderFailedToRestoreKey: "InvalidFederatedSessionProviderFailedToRestoreKey", FailedToUnwrapKey: "FailedToUnwrapKey", SessionDeletedDuringRefresh: "SessionDeletedDuringRefresh", CrossOriginRegistrationSiteNotIncluded: "CrossOriginRegistrationSiteNotIncluded", InvalidPreProvisionedKeyInitiatorMissing: "InvalidPreProvisionedKeyInitiatorMissing", PreProvisionedKeyAccessNotGranted: "PreProvisionedKeyAccessNotGranted", PreProvisionedKeyNotFound: "PreProvisionedKeyNotFound", AttestationCertificationError: "AttestationCertificationError", AttestationSigningError: "AttestationSigningError"});
|
|
841
|
+
inspectorBackend.registerEnum("Network.DeviceBoundSessionFetchResult", {Success: "Success", SigningKeyGenerationError: "SigningKeyGenerationError", AttestationKeyGenerationError: "AttestationKeyGenerationError", SigningError: "SigningError", TransientSigningError: "TransientSigningError", ServerRequestedTermination: "ServerRequestedTermination", InvalidSessionId: "InvalidSessionId", InvalidChallenge: "InvalidChallenge", TooManyChallenges: "TooManyChallenges", InvalidFetcherUrl: "InvalidFetcherUrl", InvalidRefreshUrl: "InvalidRefreshUrl", TransientHttpError: "TransientHttpError", ScopeOriginSameSiteMismatch: "ScopeOriginSameSiteMismatch", RefreshUrlSameSiteMismatch: "RefreshUrlSameSiteMismatch", MismatchedSessionId: "MismatchedSessionId", MissingScope: "MissingScope", NoCredentials: "NoCredentials", SubdomainRegistrationWellKnownUnavailable: "SubdomainRegistrationWellKnownUnavailable", SubdomainRegistrationUnauthorized: "SubdomainRegistrationUnauthorized", SubdomainRegistrationWellKnownMalformed: "SubdomainRegistrationWellKnownMalformed", SessionProviderWellKnownUnavailable: "SessionProviderWellKnownUnavailable", RelyingPartyWellKnownUnavailable: "RelyingPartyWellKnownUnavailable", FederatedKeyThumbprintMismatch: "FederatedKeyThumbprintMismatch", InvalidFederatedSessionUrl: "InvalidFederatedSessionUrl", InvalidFederatedKey: "InvalidFederatedKey", TooManyRelyingOriginLabels: "TooManyRelyingOriginLabels", BoundCookieSetForbidden: "BoundCookieSetForbidden", NetError: "NetError", ProxyError: "ProxyError", EmptySessionConfig: "EmptySessionConfig", InvalidCredentialsConfig: "InvalidCredentialsConfig", InvalidCredentialsType: "InvalidCredentialsType", InvalidCredentialsEmptyName: "InvalidCredentialsEmptyName", InvalidCredentialsCookie: "InvalidCredentialsCookie", PersistentHttpError: "PersistentHttpError", RegistrationAttemptedChallenge: "RegistrationAttemptedChallenge", InvalidScopeOrigin: "InvalidScopeOrigin", ScopeOriginContainsPath: "ScopeOriginContainsPath", RefreshInitiatorNotString: "RefreshInitiatorNotString", RefreshInitiatorInvalidHostPattern: "RefreshInitiatorInvalidHostPattern", InvalidScopeSpecification: "InvalidScopeSpecification", MissingScopeSpecificationType: "MissingScopeSpecificationType", EmptyScopeSpecificationDomain: "EmptyScopeSpecificationDomain", EmptyScopeSpecificationPath: "EmptyScopeSpecificationPath", InvalidScopeSpecificationType: "InvalidScopeSpecificationType", InvalidScopeIncludeSite: "InvalidScopeIncludeSite", MissingScopeIncludeSite: "MissingScopeIncludeSite", FederatedNotAuthorizedByProvider: "FederatedNotAuthorizedByProvider", FederatedNotAuthorizedByRelyingParty: "FederatedNotAuthorizedByRelyingParty", SessionProviderWellKnownMalformed: "SessionProviderWellKnownMalformed", SessionProviderWellKnownHasProviderOrigin: "SessionProviderWellKnownHasProviderOrigin", RelyingPartyWellKnownMalformed: "RelyingPartyWellKnownMalformed", RelyingPartyWellKnownHasRelyingOrigins: "RelyingPartyWellKnownHasRelyingOrigins", InvalidFederatedSessionProviderSessionMissing: "InvalidFederatedSessionProviderSessionMissing", InvalidFederatedSessionWrongProviderOrigin: "InvalidFederatedSessionWrongProviderOrigin", InvalidCredentialsCookieCreationTime: "InvalidCredentialsCookieCreationTime", InvalidCredentialsCookieName: "InvalidCredentialsCookieName", InvalidCredentialsCookieParsing: "InvalidCredentialsCookieParsing", InvalidCredentialsCookieUnpermittedAttribute: "InvalidCredentialsCookieUnpermittedAttribute", InvalidCredentialsCookieInvalidDomain: "InvalidCredentialsCookieInvalidDomain", InvalidCredentialsCookiePrefix: "InvalidCredentialsCookiePrefix", InvalidScopeRulePath: "InvalidScopeRulePath", InvalidScopeRuleHostPattern: "InvalidScopeRuleHostPattern", ScopeRuleOriginScopedHostPatternMismatch: "ScopeRuleOriginScopedHostPatternMismatch", ScopeRuleSiteScopedHostPatternMismatch: "ScopeRuleSiteScopedHostPatternMismatch", SigningQuotaExceeded: "SigningQuotaExceeded", InvalidConfigJson: "InvalidConfigJson", InvalidFederatedSessionProviderFailedToRestoreKey: "InvalidFederatedSessionProviderFailedToRestoreKey", FailedToUnwrapKey: "FailedToUnwrapKey", SessionDeletedDuringRefresh: "SessionDeletedDuringRefresh", CrossOriginRegistrationSiteNotIncluded: "CrossOriginRegistrationSiteNotIncluded", InvalidPreProvisionedKeyInitiatorMissing: "InvalidPreProvisionedKeyInitiatorMissing", PreProvisionedKeyAccessNotGranted: "PreProvisionedKeyAccessNotGranted", PreProvisionedKeyNotFound: "PreProvisionedKeyNotFound", AttestationCertificationError: "AttestationCertificationError", AttestationSigningError: "AttestationSigningError", FederatedRegistrationRedirected: "FederatedRegistrationRedirected"});
|
|
842
842
|
inspectorBackend.registerEnum("Network.RefreshEventDetailsRefreshResult", {Refreshed: "Refreshed", InitializedService: "InitializedService", Unreachable: "Unreachable", ServerError: "ServerError", FatalError: "FatalError", SigningQuotaExceeded: "SigningQuotaExceeded", RefreshedAsWaiter: "RefreshedAsWaiter", TransientSigningError: "TransientSigningError", InScopeRefreshNotYetNeeded: "InScopeRefreshNotYetNeeded", Canceled: "Canceled"});
|
|
843
843
|
inspectorBackend.registerEnum("Network.TerminationEventDetailsDeletionReason", {Expired: "Expired", FailedToRestoreKey: "FailedToRestoreKey", FailedToUnwrapKey: "FailedToUnwrapKey", StoragePartitionCleared: "StoragePartitionCleared", ClearBrowsingData: "ClearBrowsingData", ServerRequested: "ServerRequested", InvalidSessionParams: "InvalidSessionParams", RefreshFatalError: "RefreshFatalError", DevTools: "DevTools", Replaced: "Replaced"});
|
|
844
844
|
inspectorBackend.registerEnum("Network.ChallengeEventDetailsChallengeResult", {Success: "Success", NoSessionId: "NoSessionId", NoSessionMatch: "NoSessionMatch", CantSetBoundCookie: "CantSetBoundCookie"});
|
|
@@ -12249,6 +12249,7 @@ export namespace Network {
|
|
|
12249
12249
|
PreProvisionedKeyNotFound = 'PreProvisionedKeyNotFound',
|
|
12250
12250
|
AttestationCertificationError = 'AttestationCertificationError',
|
|
12251
12251
|
AttestationSigningError = 'AttestationSigningError',
|
|
12252
|
+
FederatedRegistrationRedirected = 'FederatedRegistrationRedirected',
|
|
12252
12253
|
}
|
|
12253
12254
|
|
|
12254
12255
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: lighthouse
|
|
3
|
-
description: Analyzing an active Lighthouse report context, running Lighthouse reports and audits (performance, accessibility, best practices, Search Engine Optimization (SEO)), accessibility audits, ARIA properties, accessible tree inspection, color contrast, and screen reader semantics. Not for general page performance measurement without a Lighthouse report; use the performance skill for that.
|
|
3
|
+
description: Analyzing an active Lighthouse report context, running Lighthouse reports and audits (performance, accessibility, best practices, Search Engine Optimization (SEO), and agentic browsing when explicitly requested), accessibility audits, ARIA properties, accessible tree inspection, color contrast, and screen reader semantics. Not for general page performance measurement without a Lighthouse report; use the performance skill for that.
|
|
4
4
|
allowed-tools:
|
|
5
5
|
- runLighthouse
|
|
6
6
|
- getLighthouseAudits
|
|
@@ -22,6 +22,7 @@ Your role is to evaluate websites using Lighthouse audits across performance, ac
|
|
|
22
22
|
- If no active report exists or a fresh audit is requested, call `runLighthouse`:
|
|
23
23
|
- If the user asks for a general report or multiple categories, use `categoryId: 'all'`.
|
|
24
24
|
- For a single category, pass that category ID (e.g. `'accessibility'`).
|
|
25
|
+
- Only pass `categoryId: 'agentic-browsing'` when the user explicitly asks for an agentic browsing audit, such as how ready the page is for AI agents to navigate and use it, or WebMCP checks. `'all'` does not include it, so never pick it for general audits, and never substitute another category (such as `'seo'`) when the user asks for it. Use `"navigation"` mode for `'agentic-browsing'` unless the user explicitly asks for another mode, because its WebMCP audits only run in `"navigation"` mode.
|
|
25
26
|
- Execution mode:
|
|
26
27
|
- Use `"navigation"` mode for full page-load audits (default for full site reviews).
|
|
27
28
|
- Use `"snapshot"` mode to re-evaluate live in-page DOM/CSS modifications without reloading.
|
|
@@ -20,3 +20,4 @@ You are an expert network request debugging assistant.
|
|
|
20
20
|
|
|
21
21
|
* **Privacy**: If the request or response payload contains sensitive personal data, authorization tokens, or API secrets, redact or generalize it in your response.
|
|
22
22
|
* **Origin Lock**: Only requests belonging to the conversation's established origin can be inspected.
|
|
23
|
+
* **Recording**: DevTools only records requests made while DevTools is open and network recording is enabled (and the log has not been cleared). If `listNetworkRequests` reports that no requests have been recorded, ask the user to ensure network recording is enabled, reload the page or repeat the action that triggers the request, and try again.
|
|
@@ -31,6 +31,24 @@ const MAX_TOTAL_CHARACTERS = 2500;
|
|
|
31
31
|
const MAX_LONG_LINES_REPORTED = 3;
|
|
32
32
|
const LONG_LINE_PREVIEW_LENGTH = 60;
|
|
33
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Matches the error observations for network requests that the isolated
|
|
36
|
+
* world's CSP (`FREESTYLER_WORLD_CSP`) blocks. When code run by this tool calls
|
|
37
|
+
* `fetch()`, Chrome rejects with exactly "Failed to fetch". A synchronous
|
|
38
|
+
* `XMLHttpRequest.send()` throws "Failed to execute 'send' on 'XMLHttpRequest':
|
|
39
|
+
* Failed to load '<url>'.".
|
|
40
|
+
*/
|
|
41
|
+
const BLOCKED_NETWORK_ERROR_PATTERN =
|
|
42
|
+
/^Error: (?:Failed to fetch$|Failed to execute 'send' on 'XMLHttpRequest': Failed to load )/;
|
|
43
|
+
const BLOCKED_NETWORK_HINT =
|
|
44
|
+
'Network access (e.g., fetch, XMLHttpRequest) is blocked for JavaScript run by this tool, so this error does not mean the page\'s own network requests are failing. Do not retry network requests with this tool.';
|
|
45
|
+
/**
|
|
46
|
+
* Only the V2 agent can load the network tools, so V1 agents do not get this
|
|
47
|
+
* part of the hint.
|
|
48
|
+
*/
|
|
49
|
+
const NETWORK_TOOLS_HINT =
|
|
50
|
+
'To inspect the page\'s network requests, load the `network` skill with `learnSkills` if it is not loaded yet, then use `listNetworkRequests` and `getNetworkRequestDetails`.';
|
|
51
|
+
|
|
34
52
|
/**
|
|
35
53
|
* Returns one message per size limit that the formatted code exceeds. Each
|
|
36
54
|
* message states the actual value, the limit, and how to fix it, so the model
|
|
@@ -178,7 +196,8 @@ const data = {
|
|
|
178
196
|
return {error: 'Error: Cannot execute JavaScript on cross-origin target.'};
|
|
179
197
|
}
|
|
180
198
|
|
|
181
|
-
|
|
199
|
+
const isV2Architecture = Root.Runtime.hostConfig.devToolsAiV2Architecture?.enabled;
|
|
200
|
+
if (isV2Architecture) {
|
|
182
201
|
const validationResult = await ExecuteJavaScriptTool.validateAndFormatCode(params.code);
|
|
183
202
|
if (validationResult.error) {
|
|
184
203
|
return {error: validationResult.error};
|
|
@@ -199,6 +218,11 @@ const data = {
|
|
|
199
218
|
},
|
|
200
219
|
context.execJs);
|
|
201
220
|
|
|
202
|
-
|
|
221
|
+
const result = await executor.executeAction(params.code, options);
|
|
222
|
+
if ('result' in result && typeof result.result === 'string' && BLOCKED_NETWORK_ERROR_PATTERN.test(result.result)) {
|
|
223
|
+
const hint = isV2Architecture ? `${BLOCKED_NETWORK_HINT} ${NETWORK_TOOLS_HINT}` : BLOCKED_NETWORK_HINT;
|
|
224
|
+
return {...result, result: `${result.result}\n${hint}`};
|
|
225
|
+
}
|
|
226
|
+
return result;
|
|
203
227
|
}
|
|
204
228
|
}
|
|
@@ -34,7 +34,7 @@ export class GetLighthouseAuditsTool implements
|
|
|
34
34
|
categoryId: {
|
|
35
35
|
type: Host.AidaClient.ParametersTypes.STRING,
|
|
36
36
|
description:
|
|
37
|
-
'The category of audits to retrieve. Use "all" to retrieve the full report and all categories, or specify a category: "accessibility", "performance", "best-practices", "seo".',
|
|
37
|
+
'The category of audits to retrieve. Use "all" to retrieve the full report and all categories, or specify a category: "accessibility", "performance", "best-practices", "seo", or "agentic-browsing" (only present when the active report includes an agentic browsing audit).',
|
|
38
38
|
nullable: false,
|
|
39
39
|
},
|
|
40
40
|
},
|
|
@@ -114,13 +114,8 @@ export class ListNetworkRequestsTool implements
|
|
|
114
114
|
};
|
|
115
115
|
}
|
|
116
116
|
return {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
name: 'NETWORK_REQUESTS_LIST',
|
|
120
|
-
data: {
|
|
121
|
-
requests: [],
|
|
122
|
-
},
|
|
123
|
-
}],
|
|
117
|
+
error:
|
|
118
|
+
'No network requests have been recorded. DevTools only records requests made while DevTools is open and network recording is enabled (and the log has not been cleared). Ask the user to ensure network recording is enabled, reload the page or repeat the action that triggers the request, and try again.',
|
|
124
119
|
};
|
|
125
120
|
}
|
|
126
121
|
|
|
@@ -45,9 +45,9 @@ export class RunLighthouseTool implements
|
|
|
45
45
|
},
|
|
46
46
|
categoryId: {
|
|
47
47
|
type: Host.AidaClient.ParametersTypes.STRING,
|
|
48
|
-
// The experimental 'agentic-browsing' category is
|
|
48
|
+
// The experimental 'agentic-browsing' category is listed separately from the standard categories and restricted to explicit user requests so the agent does not invoke it unprompted. It is also excluded when 'all' is provided (see `LighthouseController.getCategoryIDs`).
|
|
49
49
|
description:
|
|
50
|
-
'Lighthouse category. Use "all" to run all categories, or specify a category: "accessibility", "performance", "best-practices", "seo".',
|
|
50
|
+
'Lighthouse category. Use "all" to run all categories, or specify a category: "accessibility", "performance", "best-practices", "seo". Use "agentic-browsing" only when the user explicitly asks for an agentic browsing audit (how well AI agents can navigate and use the page, including WebMCP). "all" does not include "agentic-browsing". Run "agentic-browsing" in "navigation" mode, because its WebMCP audits only run in "navigation" mode.',
|
|
51
51
|
nullable: false,
|
|
52
52
|
},
|
|
53
53
|
mode: {
|
|
@@ -48,11 +48,6 @@ export class CommentManager extends Common.ObjectWrapper.ObjectWrapper<EventType
|
|
|
48
48
|
#commentMode = false;
|
|
49
49
|
#agentAttached = false;
|
|
50
50
|
|
|
51
|
-
constructor() {
|
|
52
|
-
super();
|
|
53
|
-
CommentThread.resetIndex();
|
|
54
|
-
}
|
|
55
|
-
|
|
56
51
|
#onThreadChanged(): void {
|
|
57
52
|
this.dispatchEventToListeners(Events.COMMENT_THREADS_CHANGED, this.getCommentThreads());
|
|
58
53
|
}
|
|
@@ -174,7 +169,6 @@ export class CommentManager extends Common.ObjectWrapper.ObjectWrapper<EventType
|
|
|
174
169
|
thread.removeEventListener(CommentThreadEvents.CHANGED, this.#onThreadChanged, this);
|
|
175
170
|
}
|
|
176
171
|
this.#commentThreads.clear();
|
|
177
|
-
CommentThread.resetIndex();
|
|
178
172
|
this.dispatchEventToListeners(Events.COMMENT_THREADS_CHANGED, []);
|
|
179
173
|
}
|
|
180
174
|
}
|
|
@@ -22,7 +22,10 @@ export interface DOMNodeAnchorSignature {
|
|
|
22
22
|
export interface TimelineAnchorSignature {
|
|
23
23
|
/** Identifier of the trace to scope comments to a specific recording */
|
|
24
24
|
traceId: string;
|
|
25
|
-
/**
|
|
25
|
+
/**
|
|
26
|
+
* Serializable key from Trace.EventsSerializer (e.g. 'r-123', 'p-1-2-3-4', 's-5'), or
|
|
27
|
+
* 'fc-<chartLocation>-<entryIndex>' for flame chart entries that EventsSerializer cannot key.
|
|
28
|
+
*/
|
|
26
29
|
traceEventKey: string;
|
|
27
30
|
/** Primary event title or category name */
|
|
28
31
|
entryName: string;
|
|
@@ -93,17 +96,11 @@ export interface CommentThreadOptions {
|
|
|
93
96
|
}
|
|
94
97
|
|
|
95
98
|
export class CommentThread extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
|
|
96
|
-
static #nextIndex = 1;
|
|
97
|
-
|
|
98
|
-
static resetIndex(): void {
|
|
99
|
-
CommentThread.#nextIndex = 1;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
99
|
readonly id: string = crypto.randomUUID();
|
|
103
100
|
readonly anchor: CommentAnchorSignature;
|
|
104
101
|
/** True for comments generated from the change tracker. */
|
|
105
102
|
readonly isGeneratedComment: boolean;
|
|
106
|
-
#
|
|
103
|
+
#isOrphaned = false;
|
|
107
104
|
comments: Comment[];
|
|
108
105
|
status: CommentThreadStatus = 'DRAFT';
|
|
109
106
|
transmitted: boolean = false;
|
|
@@ -115,8 +112,16 @@ export class CommentThread extends Common.ObjectWrapper.ObjectWrapper<EventTypes
|
|
|
115
112
|
this.isGeneratedComment = Boolean(options.isGeneratedComment);
|
|
116
113
|
}
|
|
117
114
|
|
|
118
|
-
get
|
|
119
|
-
return this.#
|
|
115
|
+
get isOrphaned(): boolean {
|
|
116
|
+
return this.#isOrphaned;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
setOrphaned(isOrphaned: boolean): void {
|
|
120
|
+
if (this.#isOrphaned === isOrphaned) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
this.#isOrphaned = isOrphaned;
|
|
124
|
+
this.dispatchEventToListeners(Events.CHANGED);
|
|
120
125
|
}
|
|
121
126
|
|
|
122
127
|
/**
|
|
@@ -153,9 +158,6 @@ export class CommentThread extends Common.ObjectWrapper.ObjectWrapper<EventTypes
|
|
|
153
158
|
let changed = this.#saveText(text, author);
|
|
154
159
|
if (this.status === 'DRAFT') {
|
|
155
160
|
this.#recordCommentCreated();
|
|
156
|
-
if (this.#savedIndex === undefined) {
|
|
157
|
-
this.#savedIndex = CommentThread.#nextIndex++;
|
|
158
|
-
}
|
|
159
161
|
this.status = 'ACTIVE';
|
|
160
162
|
changed = true;
|
|
161
163
|
}
|
|
@@ -183,9 +185,6 @@ export class CommentThread extends Common.ObjectWrapper.ObjectWrapper<EventTypes
|
|
|
183
185
|
this.#recordCommentCreated();
|
|
184
186
|
}
|
|
185
187
|
if (this.status === 'DRAFT' || this.status === 'ACTIVE') {
|
|
186
|
-
if (this.#savedIndex === undefined) {
|
|
187
|
-
this.#savedIndex = CommentThread.#nextIndex++;
|
|
188
|
-
}
|
|
189
188
|
this.status = 'SENT_TO_AGENT';
|
|
190
189
|
changed = true;
|
|
191
190
|
}
|
|
@@ -202,10 +201,15 @@ export class CommentThread extends Common.ObjectWrapper.ObjectWrapper<EventTypes
|
|
|
202
201
|
timestamp: Date.now(),
|
|
203
202
|
});
|
|
204
203
|
}
|
|
205
|
-
if (this.#savedIndex === undefined) {
|
|
206
|
-
this.#savedIndex = CommentThread.#nextIndex++;
|
|
207
|
-
}
|
|
208
204
|
this.status = 'RESOLVED';
|
|
209
205
|
this.dispatchEventToListeners(Events.CHANGED);
|
|
210
206
|
}
|
|
211
207
|
}
|
|
208
|
+
|
|
209
|
+
export class RevealableThread {
|
|
210
|
+
constructor(
|
|
211
|
+
readonly thread: CommentThread,
|
|
212
|
+
readonly position?: {left: number, top: number},
|
|
213
|
+
) {
|
|
214
|
+
}
|
|
215
|
+
}
|
|
@@ -95,3 +95,69 @@ export function trackStylePropertyToggle(
|
|
|
95
95
|
}
|
|
96
96
|
tracker.trackChange(describeStylePropertyToggle(toggle), buildAnchor(STYLES_PANE_VE_PATH, node));
|
|
97
97
|
}
|
|
98
|
+
|
|
99
|
+
export function trackStyleRuleAdded(
|
|
100
|
+
tracker: ChangeTracker.ChangeTracker.ChangeTracker|undefined,
|
|
101
|
+
node: SDK.DOMModel.DOMNode,
|
|
102
|
+
selector: string,
|
|
103
|
+
): void {
|
|
104
|
+
if (!tracker?.isTracking) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const trimmedSelector = Platform.StringUtilities.collapseWhitespace(selector.trim());
|
|
108
|
+
if (!trimmedSelector) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
tracker.trackChange(
|
|
112
|
+
`Added style rule "${trimValue(trimmedSelector)}"`,
|
|
113
|
+
buildAnchor(STYLES_PANE_VE_PATH, node),
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function trackRuleHeaderChange(
|
|
118
|
+
tracker: ChangeTracker.ChangeTracker.ChangeTracker|undefined,
|
|
119
|
+
node: SDK.DOMModel.DOMNode,
|
|
120
|
+
headerDescription: string,
|
|
121
|
+
oldText: string,
|
|
122
|
+
newText: string,
|
|
123
|
+
): void {
|
|
124
|
+
if (!tracker?.isTracking) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const trimmedOld = Platform.StringUtilities.collapseWhitespace(oldText.trim());
|
|
128
|
+
const trimmedNew = Platform.StringUtilities.collapseWhitespace(newText.trim());
|
|
129
|
+
if (!trimmedOld || !trimmedNew || trimmedOld === trimmedNew) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
tracker.trackChange(
|
|
133
|
+
`Changed ${headerDescription} from "${trimValue(trimmedOld)}" to "${trimValue(trimmedNew)}"`,
|
|
134
|
+
buildAnchor(STYLES_PANE_VE_PATH, node),
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export function trackStyleSelectorChange(
|
|
139
|
+
tracker: ChangeTracker.ChangeTracker.ChangeTracker|undefined,
|
|
140
|
+
node: SDK.DOMModel.DOMNode,
|
|
141
|
+
oldSelector: string,
|
|
142
|
+
newSelector: string,
|
|
143
|
+
): void {
|
|
144
|
+
trackRuleHeaderChange(tracker, node, 'style rule selector', oldSelector, newSelector);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function trackPropertyRuleNameChange(
|
|
148
|
+
tracker: ChangeTracker.ChangeTracker.ChangeTracker|undefined,
|
|
149
|
+
node: SDK.DOMModel.DOMNode,
|
|
150
|
+
oldName: string,
|
|
151
|
+
newName: string,
|
|
152
|
+
): void {
|
|
153
|
+
trackRuleHeaderChange(tracker, node, '@property rule name', oldName, newName);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export function trackKeyframeKeyChange(
|
|
157
|
+
tracker: ChangeTracker.ChangeTracker.ChangeTracker|undefined,
|
|
158
|
+
node: SDK.DOMModel.DOMNode,
|
|
159
|
+
oldKey: string,
|
|
160
|
+
newKey: string,
|
|
161
|
+
): void {
|
|
162
|
+
trackRuleHeaderChange(tracker, node, 'keyframe key', oldKey, newKey);
|
|
163
|
+
}
|
|
@@ -84,13 +84,8 @@ export class EventsSerializer {
|
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
if (EventsSerializer.isSyntheticEventKey(eventValues)) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
if (!syntheticEvent) {
|
|
90
|
-
throw new Error(`Unknown trace event. Attempted to get a synthetic event from an unknown raw event index: ${
|
|
91
|
-
eventValues.rawIndex}`);
|
|
92
|
-
}
|
|
93
|
-
return syntheticEvent;
|
|
87
|
+
return Helpers.SyntheticEvents.SyntheticEventsManager.getActiveManager().syntheticEventForRawEventIndex(
|
|
88
|
+
eventValues.rawIndex);
|
|
94
89
|
}
|
|
95
90
|
|
|
96
91
|
if (EventsSerializer.isRawEventKey(eventValues)) {
|
|
@@ -110,8 +110,6 @@ export class Model extends EventTarget {
|
|
|
110
110
|
}
|
|
111
111
|
const file = this.#storeAndCreateParsedTraceFile(
|
|
112
112
|
syntheticEventsManager, traceEvents, metadata, this.#processor.data, this.#processor.insights);
|
|
113
|
-
// Reclaim memory used by the temporary event-to-index lookup map now that trace parsing is complete.
|
|
114
|
-
syntheticEventsManager.clearRegistrationIndex();
|
|
115
113
|
// We only push the file onto this.#traces here once we know it's valid
|
|
116
114
|
// and there's been no errors in the parsing.
|
|
117
115
|
this.#traces.push(file);
|