chrome-devtools-frontend 1.0.1697998 → 1.0.1698733

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.
Files changed (102) hide show
  1. package/.agents/skills/version-control/SKILL.md +21 -9
  2. package/front_end/core/platform/HostRuntime.ts +12 -0
  3. package/front_end/core/platform/api/HostRuntime.ts +13 -0
  4. package/front_end/core/platform/browser/HostRuntime.ts +34 -0
  5. package/front_end/core/platform/node/HostRuntime.ts +40 -0
  6. package/front_end/core/sdk/AnimationModel.ts +12 -98
  7. package/front_end/core/sdk/CSSModel.ts +4 -2
  8. package/front_end/core/sdk/CSSPropertyParser.ts +4 -4
  9. package/front_end/core/sdk/CSSPropertyParserMatchers.ts +4 -44
  10. package/front_end/core/sdk/Connections.ts +6 -1
  11. package/front_end/core/sdk/ConsoleModel.ts +1 -12
  12. package/front_end/core/sdk/DOMModel.ts +3 -51
  13. package/front_end/core/sdk/DebuggerModel.ts +9 -8
  14. package/front_end/core/sdk/NetworkRequest.ts +1 -1
  15. package/front_end/core/sdk/PageFunctions.ts +187 -0
  16. package/front_end/core/sdk/Resource.ts +1 -1
  17. package/front_end/core/sdk/RuntimeModel.ts +1 -20
  18. package/front_end/core/sdk/Script.ts +21 -0
  19. package/front_end/core/sdk/SourceMap.ts +15 -2
  20. package/front_end/core/sdk/SourceMapCache.ts +13 -10
  21. package/front_end/core/sdk/SourceMapManager.ts +11 -9
  22. package/front_end/core/sdk/SourceMapScopeChainEntry.ts +59 -17
  23. package/front_end/core/sdk/SourceMapScopesInfo.ts +8 -2
  24. package/front_end/entrypoints/heap_snapshot_worker/ContextAnalyzer.ts +635 -0
  25. package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshot.ts +26 -12
  26. package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshotLoader.ts +16 -2
  27. package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshotWorkerDispatcher.ts +4 -4
  28. package/front_end/entrypoints/heap_snapshot_worker/heap_snapshot_worker.ts +2 -0
  29. package/front_end/entrypoints/shell/shell.ts +1 -1
  30. package/front_end/models/ai_assistance/DOMHelpers.ts +95 -0
  31. package/front_end/models/ai_assistance/EvaluateAction.ts +5 -42
  32. package/front_end/models/ai_assistance/ExtensionScope.ts +2 -31
  33. package/front_end/models/ai_assistance/agents/AiAgent.ts +2 -1
  34. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +3 -4
  35. package/front_end/models/ai_assistance/ai_assistance.ts +2 -0
  36. package/front_end/models/ai_assistance/contexts/DOMNodeContext.ts +10 -7
  37. package/front_end/models/ai_assistance/contexts/FileContext.ts +2 -10
  38. package/front_end/models/ai_assistance/tools/GetSourceContent.ts +3 -2
  39. package/front_end/models/ai_assistance/tools/ListSources.ts +21 -14
  40. package/front_end/models/bindings/CompilerScriptMapping.ts +3 -10
  41. package/front_end/models/bindings/DebuggerLanguagePlugins.ts +48 -17
  42. package/front_end/models/bindings/ResourceScriptMapping.ts +2 -2
  43. package/front_end/models/bindings/StylesSourceMapping.ts +1 -1
  44. package/front_end/models/comment_manager/CD4ABridge.ts +55 -12
  45. package/front_end/models/comment_manager/CommentManager.ts +46 -91
  46. package/front_end/models/comment_manager/CommentThread.ts +145 -0
  47. package/front_end/models/comment_manager/comment_manager.ts +2 -0
  48. package/front_end/models/emulation/DeviceModeModel.ts +53 -0
  49. package/front_end/models/extensions/ExtensionAPI.ts +8 -6
  50. package/front_end/models/extensions/ExtensionEndpoint.ts +11 -8
  51. package/front_end/models/extensions/HostUrlPattern.ts +4 -3
  52. package/front_end/models/extensions/LanguageExtensionEndpoint.ts +3 -2
  53. package/front_end/models/extensions/RecorderExtensionEndpoint.ts +2 -1
  54. package/front_end/models/formatter/FormatterWorkerPool.ts +4 -6
  55. package/front_end/models/heap_snapshot/HeapSnapshotModel.ts +55 -0
  56. package/front_end/models/heap_snapshot/HeapSnapshotProxy.ts +18 -14
  57. package/front_end/models/issues_manager/IssuesManager.ts +5 -0
  58. package/front_end/models/issues_manager/WebInstallIssue.ts +63 -0
  59. package/front_end/models/issues_manager/descriptions/webInstallManifestMissingId.md +3 -0
  60. package/front_end/models/issues_manager/descriptions/webInstallManifestMissingNameOrShortName.md +3 -0
  61. package/front_end/models/issues_manager/descriptions/webInstallManifestParsingOrNetworkError.md +3 -0
  62. package/front_end/models/issues_manager/descriptions/webInstallNoManifest.md +3 -0
  63. package/front_end/models/issues_manager/descriptions/webInstallStartUrlInvalid.md +3 -0
  64. package/front_end/models/issues_manager/issues_manager.ts +2 -0
  65. package/front_end/models/workspace/UISourceCode.ts +20 -0
  66. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +4 -6
  67. package/front_end/panels/ai_assistance/components/AIv2MarkdownRenderer.ts +4 -10
  68. package/front_end/{ui/comments → panels/common}/CommentThreadWidget.ts +4 -4
  69. package/front_end/{ui/comments → panels/common}/CommentsOverlayWidget.ts +39 -62
  70. package/front_end/{ui/comments → panels/common}/CommentsStatusBarPill.ts +5 -5
  71. package/front_end/panels/common/ExtensionServer.ts +2 -1
  72. package/front_end/{ui/comments → panels/common}/commentsOverlay.css +2 -1
  73. package/front_end/{ui/comments/comments-meta.ts → panels/common/common-meta.ts} +11 -11
  74. package/front_end/panels/common/common.ts +3 -0
  75. package/front_end/panels/elements/AdoptedStyleSheetTreeElement.ts +3 -3
  76. package/front_end/panels/elements/ElementsPanel.ts +5 -1
  77. package/front_end/panels/elements/ElementsTreeElement.ts +4 -1
  78. package/front_end/panels/elements/ElementsTreeOutline.ts +58 -51
  79. package/front_end/panels/elements/PropertiesWidget.ts +11 -10
  80. package/front_end/panels/elements/PropertyRenderer.ts +29 -25
  81. package/front_end/panels/elements/StylePropertyTreeElement.ts +6 -6
  82. package/front_end/panels/elements/elementsTreeOutline.css +7 -1
  83. package/front_end/panels/emulation/DeviceModeToolbar.ts +2 -3
  84. package/front_end/panels/event_listeners/EventListenersView.ts +33 -44
  85. package/front_end/panels/linear_memory_inspector/LinearMemoryInspectorController.ts +6 -7
  86. package/front_end/panels/linear_memory_inspector/components/linearMemoryInspector.css +5 -1
  87. package/front_end/panels/linear_memory_inspector/linear_memory_inspector-meta.ts +1 -1
  88. package/front_end/panels/recorder/stepView.css +1 -0
  89. package/front_end/panels/security/SecurityPanel.ts +5 -5
  90. package/front_end/panels/security/SecurityPanelSidebar.ts +2 -11
  91. package/front_end/panels/sources/DebuggerPlugin.ts +1 -1
  92. package/front_end/panels/sources/WatchExpressionsSidebarPane.ts +11 -16
  93. package/front_end/panels/sources/sources-meta.ts +1 -1
  94. package/front_end/panels/timeline/overlays/OverlaysImpl.ts +0 -3
  95. package/front_end/third_party/chromium/README.chromium +1 -1
  96. package/front_end/ui/comments/CommentOverlayManager.ts +28 -110
  97. package/front_end/ui/comments/comments.ts +0 -6
  98. package/front_end/ui/legacy/Treeoutline.ts +4 -0
  99. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +14 -7
  100. package/front_end/ui/visual_logging/KnownContextValues.ts +1 -0
  101. package/package.json +1 -1
  102. /package/front_end/{ui/comments → panels/common}/commentThreadWidget.css +0 -0
@@ -0,0 +1,63 @@
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 type * as SDK from '../../core/sdk/sdk.js';
6
+ import * as Protocol from '../../generated/protocol.js';
7
+
8
+ import {Issue, IssueCategory, IssueKind} from './Issue.js';
9
+ import type {MarkdownIssueDescription} from './MarkdownIssueDescription.js';
10
+
11
+ export class WebInstallIssue extends Issue<Protocol.Audits.WebInstallIssueDetails> {
12
+ constructor(issueDetails: Protocol.Audits.WebInstallIssueDetails, issuesModel: SDK.IssuesModel.IssuesModel|null) {
13
+ super(`${Protocol.Audits.InspectorIssueCode.WebInstallIssue}::${issueDetails.reason}`, issueDetails, issuesModel);
14
+ }
15
+
16
+ override requests(): Protocol.Audits.AffectedRequest[] {
17
+ const {manifestUrl, reason} = this.details();
18
+ if (reason === Protocol.Audits.WebInstallIssueReason.NoManifest || !manifestUrl) {
19
+ return [];
20
+ }
21
+ return [{url: manifestUrl}];
22
+ }
23
+
24
+ getCategory(): IssueCategory {
25
+ return IssueCategory.OTHER;
26
+ }
27
+
28
+ getDescription(): MarkdownIssueDescription|null {
29
+ switch (this.details().reason) {
30
+ case Protocol.Audits.WebInstallIssueReason.ManifestParsingOrNetworkError:
31
+ return {file: 'webInstallManifestParsingOrNetworkError.md', links: []};
32
+ case Protocol.Audits.WebInstallIssueReason.StartUrlInvalid:
33
+ return {file: 'webInstallStartUrlInvalid.md', links: []};
34
+ case Protocol.Audits.WebInstallIssueReason.ManifestMissingNameOrShortName:
35
+ return {file: 'webInstallManifestMissingNameOrShortName.md', links: []};
36
+ case Protocol.Audits.WebInstallIssueReason.ManifestMissingId:
37
+ return {file: 'webInstallManifestMissingId.md', links: []};
38
+ case Protocol.Audits.WebInstallIssueReason.NoManifest:
39
+ return {file: 'webInstallNoManifest.md', links: []};
40
+ default:
41
+ console.warn('Unknown WebInstallIssueReason:', this.details().reason);
42
+ return null;
43
+ }
44
+ }
45
+
46
+ getKind(): IssueKind {
47
+ return IssueKind.PAGE_ERROR;
48
+ }
49
+
50
+ primaryKey(): string {
51
+ return JSON.stringify(this.details());
52
+ }
53
+
54
+ static fromInspectorIssue(issuesModel: SDK.IssuesModel.IssuesModel|null,
55
+ inspectorIssue: Protocol.Audits.InspectorIssue): WebInstallIssue[] {
56
+ const details = inspectorIssue.details.webInstallIssueDetails;
57
+ if (!details) {
58
+ console.warn('Web install issue without details received.');
59
+ return [];
60
+ }
61
+ return [new WebInstallIssue(details, issuesModel)];
62
+ }
63
+ }
@@ -0,0 +1,3 @@
1
+ # Manifest does not contain an `id` field
2
+
3
+ Add an `id` to the manifest. Alternatively, for installs using an explicit manifest URL, provide the computed manifest ID as `manifestId` alongside the manifest URL.
@@ -0,0 +1,3 @@
1
+ # Manifest does not contain a 'name' or 'short_name' field
2
+
3
+ Add a `name` or `short_name` field to the manifest.
@@ -0,0 +1,3 @@
1
+ # Manifest could not be fetched, is empty, or could not be parsed
2
+
3
+ Check that the web app manifest can be fetched and that it contains valid, non-empty JSON.
@@ -0,0 +1,3 @@
1
+ # No manifest detected
2
+
3
+ Provide a web app manifest for this page.
@@ -0,0 +1,3 @@
1
+ # Manifest 'start_url' is not valid
2
+
3
+ Provide a valid `start_url` in the manifest.
@@ -36,6 +36,7 @@ import * as SourceFrameIssuesManager from './SourceFrameIssuesManager.js';
36
36
  import * as SRIMessageSignatureIssue from './SRIMessageSignatureIssue.js';
37
37
  import * as StylesheetLoadingIssue from './StylesheetLoadingIssue.js';
38
38
  import * as UnencodedDigestIssue from './UnencodedDigestIssue.js';
39
+ import * as WebInstallIssue from './WebInstallIssue.js';
39
40
 
40
41
  export {
41
42
  ClientHintIssue,
@@ -72,4 +73,5 @@ export {
72
73
  SRIMessageSignatureIssue,
73
74
  StylesheetLoadingIssue,
74
75
  UnencodedDigestIssue,
76
+ WebInstallIssue,
75
77
  };
@@ -7,6 +7,7 @@
7
7
  import * as Common from '../../core/common/common.js';
8
8
  import * as i18n from '../../core/i18n/i18n.js';
9
9
  import * as Platform from '../../core/platform/platform.js';
10
+ import * as SDK from '../../core/sdk/sdk.js';
10
11
  import * as TextUtils from '../../core/text_utils/text_utils.js';
11
12
 
12
13
  import {IgnoreListManager} from './IgnoreListManager.js';
@@ -29,6 +30,7 @@ export class UISourceCode extends Common.ObjectWrapper.ObjectWrapper<EventTypes>
29
30
  TextUtils.ContentProvider.ContentProvider {
30
31
  readonly #origin: Platform.DevToolsPath.UrlString;
31
32
  readonly #parentURL: Platform.DevToolsPath.UrlString;
33
+ #securityOrigin?: SDK.SecurityOrigin.SecurityOrigin;
32
34
  #project: Project;
33
35
  #url: Platform.DevToolsPath.UrlString;
34
36
  #name: string;
@@ -110,6 +112,23 @@ export class UISourceCode extends Common.ObjectWrapper.ObjectWrapper<EventTypes>
110
112
  return this.#origin;
111
113
  }
112
114
 
115
+ /**
116
+ * Returns the security origin for this source code.
117
+ * Prefers the project security origin if available. If the project does not
118
+ * define a security origin, derives it from the source code's URL and caches
119
+ * the result until the source code is renamed.
120
+ */
121
+ securityOrigin(): SDK.SecurityOrigin.SecurityOrigin {
122
+ const projectOrigin = this.#project.securityOrigin?.();
123
+ if (projectOrigin) {
124
+ return projectOrigin;
125
+ }
126
+ if (!this.#securityOrigin) {
127
+ this.#securityOrigin = SDK.SecurityOrigin.SecurityOrigin.create(this.#url);
128
+ }
129
+ return this.#securityOrigin;
130
+ }
131
+
113
132
  fullDisplayName(): string {
114
133
  return this.#project.fullDisplayName(this);
115
134
  }
@@ -150,6 +169,7 @@ export class UISourceCode extends Common.ObjectWrapper.ObjectWrapper<EventTypes>
150
169
  #updateName(
151
170
  name: Platform.DevToolsPath.RawPathString, url: Platform.DevToolsPath.UrlString,
152
171
  contentType?: Common.ResourceType.ResourceType): void {
172
+ this.#securityOrigin = undefined;
153
173
  const oldURL = this.#url;
154
174
  this.#name = name;
155
175
  if (url) {
@@ -282,12 +282,10 @@ async function getEmptyStateSuggestions(conversation?: AiAssistanceModel.AiConve
282
282
  }
283
283
  }
284
284
 
285
- function createV2MarkdownRenderer(conversation?: AiAssistanceModel.AiConversation.AiConversation):
286
- AIv2MarkdownRenderer {
287
- const options: AIv2MarkdownRendererOptions = {};
288
- if (conversation) {
289
- options.getEstablishedOrigin = () => conversation.origin;
290
- }
285
+ function createV2MarkdownRenderer(conversation: AiAssistanceModel.AiConversation.AiConversation): AIv2MarkdownRenderer {
286
+ const options: AIv2MarkdownRendererOptions = {
287
+ getOriginLock: () => conversation.getOriginLock(),
288
+ };
291
289
  const primaryTarget = SDK.TargetManager.TargetManager.instance().primaryPageTarget();
292
290
  const domModel = primaryTarget?.model(SDK.DOMModel.DOMModel);
293
291
  const resourceTreeModel = primaryTarget?.model(SDK.ResourceTreeModel.ResourceTreeModel);
@@ -21,13 +21,10 @@ export interface AIv2MarkdownRendererOptions {
21
21
  mainFrameId?: string;
22
22
  mainDocumentURL?: Platform.DevToolsPath.UrlString;
23
23
  /**
24
- * Retrieves the established origin locked for the active conversation.
24
+ * Retrieves the origin lock for the active conversation.
25
25
  * Required to authorize #file-<id> links and prevent cross-origin file leakage.
26
- *
27
- * TODO(crbug.com/559522248): Defer renderer instantiation until a conversation
28
- * starts so this origin can be passed as a mandatory, non-getter property.
29
26
  */
30
- getEstablishedOrigin?: () => SDK.SecurityOrigin.SecurityOrigin | undefined;
27
+ getOriginLock: () => AiAssistanceModel.Tool.OriginLockState;
31
28
  lookupTraceEvent?: (key: string) => Trace.Types.Events.Event | null;
32
29
  }
33
30
 
@@ -45,7 +42,7 @@ type ParsedLink = {
45
42
  * the only markdown renderer used by AI assistance.
46
43
  */
47
44
  export class AIv2MarkdownRenderer extends MarkdownView.MarkdownView.MarkdownInsightRenderer {
48
- constructor(private readonly options: AIv2MarkdownRendererOptions = {}) {
45
+ constructor(private readonly options: AIv2MarkdownRendererOptions) {
49
46
  super();
50
47
  }
51
48
 
@@ -119,10 +116,7 @@ export class AIv2MarkdownRenderer extends MarkdownView.MarkdownView.MarkdownInsi
119
116
  }
120
117
  if (href.startsWith('#file-')) {
121
118
  const fileId = Number(href.substring(6));
122
- const origin = this.options.getEstablishedOrigin?.();
123
- const file = (origin && Number.isInteger(fileId) && fileId > 0) ?
124
- AiAssistanceModel.ListSources.ListSourcesTool.getSourceById(fileId, origin) :
125
- undefined;
119
+ const file = AiAssistanceModel.ListSources.ListSourcesTool.getSourceById(fileId, this.options.getOriginLock());
126
120
 
127
121
  if (file) {
128
122
  return this.#revealableLink(file, file.name());
@@ -2,14 +2,14 @@
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 '../components/tooltips/tooltips.js';
5
+ import '../../ui/components/tooltips/tooltips.js';
6
6
 
7
7
  import * as i18n from '../../core/i18n/i18n.js';
8
8
  import type * as CommentManager from '../../models/comment_manager/comment_manager.js';
9
+ import * as Input from '../../ui/components/input/input.js';
10
+ import * as MarkdownView from '../../ui/components/markdown_view/markdown_view.js';
9
11
  import * as UI from '../../ui/legacy/legacy.js';
10
12
  import * as Lit from '../../ui/lit/lit.js';
11
- import * as Input from '../components/input/input.js';
12
- import * as MarkdownView from '../components/markdown_view/markdown_view.js';
13
13
 
14
14
  import commentThreadWidgetStyles from './commentThreadWidget.css.js';
15
15
 
@@ -52,7 +52,7 @@ const UIStringsNotTranslate = {
52
52
  'Comment strings, DOM hierarchy snippets, tracked CSS and DOM changes, Visual Element (VE) paths and signatures, and tracked presenter changes are sent to the connected third-party agent to assist with debugging and code updates.',
53
53
  } as const;
54
54
 
55
- const str_ = i18n.i18n.registerUIStrings('ui/comments/CommentThreadWidget.ts', UIStrings);
55
+ const str_ = i18n.i18n.registerUIStrings('panels/common/CommentThreadWidget.ts', UIStrings);
56
56
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
57
57
  const lockedString = i18n.i18n.lockedString;
58
58
 
@@ -5,18 +5,10 @@
5
5
  import type * as Common from '../../core/common/common.js';
6
6
  import * as Root from '../../core/root/root.js';
7
7
  import * as CommentManager from '../../models/comment_manager/comment_manager.js';
8
+ import * as Comments from '../../ui/comments/comments.js';
8
9
  import * as UI from '../../ui/legacy/legacy.js';
9
10
  import * as Lit from '../../ui/lit/lit.js';
10
11
 
11
- import {
12
- CommentOverlayManager,
13
- Events as CommentOverlayManagerEvents,
14
- type HighlightRectData,
15
- type HoverHighlightData,
16
- type PendingHighlightRectData,
17
- type PendingPinPositionData,
18
- type PinPositionData,
19
- } from './CommentOverlayManager.js';
20
12
  import commentsOverlayStyles from './commentsOverlay.css.js';
21
13
  import {CommentThreadWidget} from './CommentThreadWidget.js';
22
14
 
@@ -27,18 +19,14 @@ const {
27
19
  Directives: {repeat, styleMap},
28
20
  } = Lit;
29
21
 
30
- export type ViewHighlightRectData = HighlightRectData|PendingHighlightRectData;
31
-
32
22
  export interface ViewInput {
33
- pins: PinPositionData[];
34
- pendingPin: PendingPinPositionData|null;
35
- highlights: ViewHighlightRectData[];
36
- hoverHighlight: HoverHighlightData|null;
23
+ pins: Comments.CommentOverlayManager.PinPositionData[];
24
+ highlights: Comments.CommentOverlayManager.HighlightRectData[];
25
+ hoverHighlight: Comments.CommentOverlayManager.HoverHighlightData|null;
37
26
  commentMode: boolean;
38
27
  onPinClick: (threadId: string) => void;
39
28
  activeThread: CommentManager.CommentManager.CommentThread|null;
40
- activePin: PinPositionData|PendingPinPositionData|null;
41
- activeTargetKey: unknown;
29
+ activePin: Comments.CommentOverlayManager.PinPositionData|null;
42
30
  onAddComment: (text: string) => void;
43
31
  }
44
32
 
@@ -72,7 +60,6 @@ const DEFAULT_VIEW: View = (input: ViewInput, _output: undefined, target: HTMLEl
72
60
  ${input.highlights.map(h => h.visible ? html`
73
61
  <div
74
62
  class="comment-anchor-highlight"
75
- data-comment-id=${('id' in h && h.id) || nothing}
76
63
  style=${styleMap({
77
64
  top: `${h.top}px`,
78
65
  left: `${h.left}px`,
@@ -81,20 +68,9 @@ const DEFAULT_VIEW: View = (input: ViewInput, _output: undefined, target: HTMLEl
81
68
  })}>
82
69
  </div>
83
70
  ` : nothing)}
84
- ${input.pendingPin && input.pendingPin.visible ? html`
85
- <div
86
- class="comment-pin"
87
- style=${styleMap({
88
- top: `${input.pendingPin.top}px`,
89
- left: `${input.pendingPin.left}px`,
90
- })}>
91
- <div class="comment-cursor">${input.pendingPin.index}</div>
92
- </div>
93
- ` : nothing}
94
71
  ${input.pins.map(p => p.visible ? html`
95
72
  <div
96
73
  class="comment-pin"
97
- data-comment-id=${p.id}
98
74
  style=${styleMap({
99
75
  top: `${p.top}px`,
100
76
  left: `${p.left}px`,
@@ -103,9 +79,9 @@ const DEFAULT_VIEW: View = (input: ViewInput, _output: undefined, target: HTMLEl
103
79
  <div class="comment-cursor">${p.index}</div>
104
80
  </div>
105
81
  ` : nothing)}
106
- ${input.activePin ? repeat(
107
- [{pin: input.activePin, key: input.activeTargetKey}],
108
- item => item.key,
82
+ ${input.activePin && input.activeThread ? repeat(
83
+ [{pin: input.activePin, thread: input.activeThread}],
84
+ item => item.thread.id,
109
85
  item => html`
110
86
  <div
111
87
  class="comment-popup-widget"
@@ -120,7 +96,7 @@ const DEFAULT_VIEW: View = (input: ViewInput, _output: undefined, target: HTMLEl
120
96
  )}px`,
121
97
  })}>
122
98
  ${UI.Widget.widget(CommentThreadWidget, {
123
- comments: input.activeThread ? [...input.activeThread.comments] : [],
99
+ comments: [...item.thread.comments],
124
100
  onAddComment: input.onAddComment,
125
101
  })}
126
102
  </div>
@@ -137,7 +113,7 @@ export class CommentsOverlayWidget extends UI.Widget.Widget {
137
113
 
138
114
  readonly #view: View;
139
115
  readonly #commentManager: CommentManager.CommentManager.CommentManager;
140
- #commentOverlayManager: CommentOverlayManager;
116
+ #commentOverlayManager: Comments.CommentOverlayManager.CommentOverlayManager;
141
117
  #activeThreadId: string|null = null;
142
118
 
143
119
  constructor(
@@ -148,12 +124,12 @@ export class CommentsOverlayWidget extends UI.Widget.Widget {
148
124
  super(element, {useShadowDom: false});
149
125
  this.#view = view;
150
126
  this.#commentManager = commentManager;
151
- this.#commentOverlayManager = new CommentOverlayManager(
127
+ this.#commentOverlayManager = new Comments.CommentOverlayManager.CommentOverlayManager(
152
128
  this.#commentManager,
153
129
  );
154
130
  }
155
131
 
156
- setOverlayManagerForTest(overlayManager: CommentOverlayManager): void {
132
+ setOverlayManagerForTest(overlayManager: Comments.CommentOverlayManager.CommentOverlayManager): void {
157
133
  this.#commentOverlayManager = overlayManager;
158
134
  }
159
135
 
@@ -161,12 +137,12 @@ export class CommentsOverlayWidget extends UI.Widget.Widget {
161
137
  super.wasShown();
162
138
  this.#commentOverlayManager.start();
163
139
  this.#commentOverlayManager.addEventListener(
164
- CommentOverlayManagerEvents.POSITIONS_UPDATED,
140
+ Comments.CommentOverlayManager.Events.POSITIONS_UPDATED,
165
141
  this.#onStateChanged,
166
142
  this,
167
143
  );
168
144
  this.#commentOverlayManager.addEventListener(
169
- CommentOverlayManagerEvents.HOVER_HIGHLIGHT_CHANGED,
145
+ Comments.CommentOverlayManager.Events.HOVER_HIGHLIGHT_CHANGED,
170
146
  this.#onStateChanged,
171
147
  this,
172
148
  );
@@ -188,12 +164,12 @@ export class CommentsOverlayWidget extends UI.Widget.Widget {
188
164
  override willHide(): void {
189
165
  this.#commentOverlayManager.stop();
190
166
  this.#commentOverlayManager.removeEventListener(
191
- CommentOverlayManagerEvents.POSITIONS_UPDATED,
167
+ Comments.CommentOverlayManager.Events.POSITIONS_UPDATED,
192
168
  this.#onStateChanged,
193
169
  this,
194
170
  );
195
171
  this.#commentOverlayManager.removeEventListener(
196
- CommentOverlayManagerEvents.HOVER_HIGHLIGHT_CHANGED,
172
+ Comments.CommentOverlayManager.Events.HOVER_HIGHLIGHT_CHANGED,
197
173
  this.#onStateChanged,
198
174
  this,
199
175
  );
@@ -217,6 +193,9 @@ export class CommentsOverlayWidget extends UI.Widget.Widget {
217
193
  CommentManager.CommentManager.EventTypes[CommentManager.CommentManager.Events.COMMENT_MODE_CHANGED]>,
218
194
  ): void {
219
195
  const isModeActive = event.data;
196
+ if (!isModeActive) {
197
+ this.#activeThreadId = null;
198
+ }
220
199
  const action = UI.ActionRegistry.ActionRegistry.instance().getAction(
221
200
  'comments.toggle-comment-mode',
222
201
  );
@@ -225,17 +204,24 @@ export class CommentsOverlayWidget extends UI.Widget.Widget {
225
204
  }
226
205
 
227
206
  #onStateChanged(): void {
228
- if (this.#commentOverlayManager.getPendingDraft()) {
207
+ const draftThread = this.#commentManager.getCommentThreads().find(t => t.status === 'DRAFT');
208
+ if (draftThread) {
209
+ this.#activeThreadId = draftThread.id;
210
+ } else if (this.#activeThreadId && !this.#commentManager.getCommentThread(this.#activeThreadId)) {
229
211
  this.#activeThreadId = null;
230
212
  }
231
213
  this.requestUpdate();
232
214
  }
233
215
 
234
216
  #handlePinClick = (threadId: string): void => {
235
- this.#commentOverlayManager.clearPendingAnchor();
217
+ const thread = this.#commentManager.getCommentThread(threadId);
236
218
  if (this.#activeThreadId === threadId) {
219
+ if (thread?.status === 'DRAFT') {
220
+ this.#commentOverlayManager.clearDraftThreads();
221
+ }
237
222
  this.#activeThreadId = null;
238
223
  } else {
224
+ this.#commentOverlayManager.clearDraftThreads();
239
225
  this.#activeThreadId = threadId;
240
226
  }
241
227
  this.requestUpdate();
@@ -243,41 +229,25 @@ export class CommentsOverlayWidget extends UI.Widget.Widget {
243
229
 
244
230
  override performUpdate(): void {
245
231
  const pins = this.#commentOverlayManager.getPinPositions();
246
- const draft = this.#commentOverlayManager.getPendingDraft();
247
- const pendingPin = draft?.pin ?? null;
248
- const highlights: ViewHighlightRectData[] = [
249
- ...this.#commentOverlayManager.getHighlightRects(),
250
- ];
251
-
252
- if (draft?.highlight) {
253
- highlights.push(draft.highlight);
254
- }
232
+ const highlights = this.#commentOverlayManager.getHighlightRects();
255
233
 
256
- let activePin: PinPositionData|PendingPinPositionData|null = null;
234
+ let activePin: Comments.CommentOverlayManager.PinPositionData|null = null;
257
235
  let activeThread: CommentManager.CommentManager.CommentThread|null = null;
258
- if (pendingPin) {
259
- activePin = pendingPin;
260
- } else if (this.#activeThreadId) {
236
+ if (this.#activeThreadId) {
261
237
  activePin = pins.find(p => p.id === this.#activeThreadId) ?? null;
262
238
  activeThread = this.#commentManager.getCommentThread(this.#activeThreadId) ?? null;
263
239
  }
264
240
 
265
241
  const viewInput: ViewInput = {
266
242
  pins,
267
- pendingPin,
268
243
  highlights,
269
244
  hoverHighlight: this.#commentOverlayManager.getHoverHighlight(),
270
245
  commentMode: this.#commentManager.isCommentMode(),
271
246
  onPinClick: this.#handlePinClick,
272
247
  activeThread,
273
248
  activePin,
274
- activeTargetKey: draft ?? activeThread,
275
249
  onAddComment: (text: string) => {
276
- const pendingDraft = this.#commentOverlayManager.getPendingDraft();
277
-
278
- if (pendingDraft) {
279
- this.#commentOverlayManager.createComment(pendingDraft.element, text, {pendingDraft});
280
- }
250
+ activeThread?.save(text);
281
251
  },
282
252
  };
283
253
  this.#view(viewInput, undefined, this.contentElement);
@@ -313,4 +283,11 @@ export class ActionDelegate implements UI.ActionRegistration.ActionDelegate {
313
283
  }
314
284
  return false;
315
285
  }
286
+
287
+ static resetForTest(): void {
288
+ if (widgetInstance) {
289
+ widgetInstance.detach();
290
+ widgetInstance = null;
291
+ }
292
+ }
316
293
  }
@@ -4,9 +4,9 @@
4
4
 
5
5
  import * as i18n from '../../core/i18n/i18n.js';
6
6
  import * as CommentManager from '../../models/comment_manager/comment_manager.js';
7
- import * as UI from '../legacy/legacy.js';
8
- import * as Lit from '../lit/lit.js';
9
- import * as VisualLogging from '../visual_logging/visual_logging.js';
7
+ import * as UI from '../../ui/legacy/legacy.js';
8
+ import * as Lit from '../../ui/lit/lit.js';
9
+ import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
10
10
 
11
11
  const UIStrings = {
12
12
  /**
@@ -15,7 +15,7 @@ const UIStrings = {
15
15
  */
16
16
  commentsCount: 'Comments ({PH1})',
17
17
  } as const;
18
- const str_ = i18n.i18n.registerUIStrings('ui/comments/CommentsStatusBarPill.ts', UIStrings);
18
+ const str_ = i18n.i18n.registerUIStrings('panels/common/CommentsStatusBarPill.ts', UIStrings);
19
19
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
20
20
 
21
21
  const {html, render} = Lit;
@@ -86,7 +86,7 @@ export class CommentsStatusBarPill extends UI.Widget.Widget {
86
86
 
87
87
  override performUpdate(): void {
88
88
  const viewInput: ViewInput = {
89
- threads: this.#commentManager.getCommentThreads(),
89
+ threads: this.#commentManager.getCommentThreads().filter(thread => thread.status !== 'DRAFT'),
90
90
  onPillClick: this.#handlePillClick,
91
91
  };
92
92
  this.#view(viewInput, undefined, this.contentElement);
@@ -1287,7 +1287,8 @@ export class ExtensionServer extends Common.ObjectWrapper.ObjectWrapper<EventTyp
1287
1287
  if (scriptFiles.length > 0) {
1288
1288
  for (const script of scriptFiles) {
1289
1289
  const resourceFile = debuggerBindingsInstance.scriptFile(resource.uiSourceCode, script.debuggerModel);
1290
- resourceFile?.addSourceMapURL(message.sourceMapURL as Platform.DevToolsPath.UrlString);
1290
+ resourceFile?.addSourceMapURL(message.sourceMapURL as Platform.DevToolsPath.UrlString,
1291
+ SDK.SourceMap.SourceMapProvenance.EXTENSION);
1291
1292
  }
1292
1293
  }
1293
1294
 
@@ -10,7 +10,8 @@
10
10
  position: fixed;
11
11
  inset: 0;
12
12
  pointer-events: none;
13
- /* Needs to be above regular panel widgets (e.g. flame chart at z-index 2000) but below floating glass panes (which start at z-index 3000). */
13
+ /* Needs to be above regular panel widgets (e.g. flame chart at z-index 2000)
14
+ but below floating glass panes (which start at z-index 3000). */
14
15
  z-index: 2500;
15
16
  overflow: hidden;
16
17
  width: 100vw;
@@ -6,7 +6,7 @@ import * as i18n from '../../core/i18n/i18n.js';
6
6
  import type * as Root from '../../core/root/root.js';
7
7
  import * as UI from '../../ui/legacy/legacy.js';
8
8
 
9
- import type * as Comments from './comments.js';
9
+ import type * as Common from './common.js';
10
10
 
11
11
  const UIStrings = {
12
12
  /**
@@ -22,16 +22,16 @@ const UIStrings = {
22
22
  */
23
23
  comments: 'Comments',
24
24
  } as const;
25
- const str_ = i18n.i18n.registerUIStrings('ui/comments/comments-meta.ts', UIStrings);
25
+ const str_ = i18n.i18n.registerUIStrings('panels/common/common-meta.ts', UIStrings);
26
26
  const i18nLazyString = i18n.i18n.getLazilyComputedLocalizedString.bind(undefined, str_);
27
27
 
28
- let loadedCommentsModule: (typeof Comments|undefined);
28
+ let loadedCommonModule: (typeof Common|undefined);
29
29
 
30
- async function loadCommentsModule(): Promise<typeof Comments> {
31
- if (!loadedCommentsModule) {
32
- loadedCommentsModule = await import('./comments.js');
30
+ async function loadCommonModule(): Promise<typeof Common> {
31
+ if (!loadedCommonModule) {
32
+ loadedCommonModule = await import('./common.js');
33
33
  }
34
- return loadedCommentsModule;
34
+ return loadedCommonModule;
35
35
  }
36
36
 
37
37
  function isCommentsEnabled(config?: Root.Runtime.HostConfig): boolean {
@@ -46,8 +46,8 @@ UI.ViewManager.registerViewExtension({
46
46
  commandPrompt: i18nLazyString(UIStrings.showComments),
47
47
  title: i18nLazyString(UIStrings.comments),
48
48
  async loadView(universe) {
49
- const Comments = await loadCommentsModule();
50
- return new Comments.CommentsStatusBarPill.CommentsStatusBarPill(undefined, [universe.commentManager]);
49
+ const Common = await loadCommonModule();
50
+ return new Common.CommentsStatusBarPill.CommentsStatusBarPill(undefined, [universe.commentManager]);
51
51
  },
52
52
  });
53
53
 
@@ -59,8 +59,8 @@ UI.ActionRegistration.registerActionExtension({
59
59
  toggleable: true,
60
60
  condition: isCommentsEnabled,
61
61
  async loadActionDelegate() {
62
- const Comments = await loadCommentsModule();
63
- return new Comments.CommentsOverlayWidget.ActionDelegate();
62
+ const Common = await loadCommonModule();
63
+ return new Common.CommentsOverlayWidget.ActionDelegate();
64
64
  },
65
65
  });
66
66
 
@@ -13,3 +13,6 @@ export * as ExtensionView from './ExtensionView.js';
13
13
  export * as PersistenceUtils from './PersistenceUtils.js';
14
14
  export * as DOMLinkifier from './DOMLinkifier.js';
15
15
  export * as ExtensionIframe from './ExtensionView.js';
16
+ export * as CommentThreadWidget from './CommentThreadWidget.js';
17
+ export * as CommentsOverlayWidget from './CommentsOverlayWidget.js';
18
+ export * as CommentsStatusBarPill from './CommentsStatusBarPill.js';
@@ -20,7 +20,7 @@ const {Directives: {ref}, html, render} = Lit;
20
20
 
21
21
  export class AdoptedStyleSheetSetTreeElement extends UI.TreeOutline.TreeElement {
22
22
  constructor(readonly adoptedStyleSheets: SDK.DOMModel.AdoptedStyleSheet[]) {
23
- super('');
23
+ super('', undefined, 'adopted-style-sheets');
24
24
  const documentElement = this.listItemElement.createChild('span');
25
25
  UI.UIUtils.createTextChild(documentElement, '#adopted-style-sheets');
26
26
  for (const adoptedStyleSheet of adoptedStyleSheets) {
@@ -33,7 +33,7 @@ export class AdoptedStyleSheetTreeElement extends UI.TreeOutline.TreeElement {
33
33
  private eventListener: Common.EventTarget.EventDescriptor|null = null;
34
34
 
35
35
  constructor(readonly adoptedStyleSheet: SDK.DOMModel.AdoptedStyleSheet) {
36
- super('');
36
+ super('', undefined, 'adopted-style-sheet');
37
37
  const header = adoptedStyleSheet.cssModel.styleSheetHeaderForId(adoptedStyleSheet.id);
38
38
  if (header) {
39
39
  AdoptedStyleSheetTreeElement.createContents(header, this);
@@ -79,7 +79,7 @@ export class AdoptedStyleSheetContentsTreeElement extends UI.TreeOutline.TreeEle
79
79
  private readonly widgetWrapper: HTMLElement;
80
80
 
81
81
  constructor(styleSheetHeader: SDK.CSSStyleSheetHeader.CSSStyleSheetHeader) {
82
- super('');
82
+ super('', undefined, 'adopted-style-sheet-contents');
83
83
  this.widgetWrapper = document.createElement('div');
84
84
  this.widgetWrapper.style.display = 'contents';
85
85
  this.title = this.widgetWrapper;
@@ -228,6 +228,10 @@ export class ElementsPanel extends UI.Panel.Panel implements UI.SearchableView.S
228
228
  return this.#domTreeWidget.getTreeOutlineForTesting();
229
229
  }
230
230
 
231
+ getDOMTreeWidgetForTesting(): DOMTreeWidget {
232
+ return this.#domTreeWidget;
233
+ }
234
+
231
235
  constructor(
232
236
  targetManager?: SDK.TargetManager.TargetManager,
233
237
  settings?: Common.Settings.Settings,
@@ -1300,7 +1304,7 @@ export class ElementsPanel extends UI.Panel.Panel implements UI.SearchableView.S
1300
1304
  }
1301
1305
 
1302
1306
  toggleHideElement(node: SDK.DOMModel.DOMNode): void {
1303
- this.#domTreeWidget.toggleHideElement(node);
1307
+ void this.#domTreeWidget.toggleHideElement(node);
1304
1308
  }
1305
1309
 
1306
1310
  toggleEditAsHTML(node: SDK.DOMModel.DOMNode): void {