chrome-devtools-frontend 1.0.1565595 → 1.0.1567721
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/contributing/performance.md +24 -0
- package/front_end/Images/src/lock-person.svg +1 -0
- package/front_end/core/common/Base64.ts +21 -2
- package/front_end/core/common/ResourceType.ts +7 -0
- package/front_end/core/host/InspectorFrontendHostStub.ts +3 -0
- package/front_end/core/host/UserMetrics.ts +20 -0
- package/front_end/core/root/Runtime.ts +5 -0
- package/front_end/core/sdk/DOMModel.ts +32 -2
- package/front_end/core/sdk/NetworkManager.ts +16 -3
- package/front_end/core/sdk/ResourceTreeModel.ts +11 -6
- package/front_end/entrypoints/main/MainImpl.ts +1 -7
- package/front_end/generated/Deprecation.ts +0 -8
- package/front_end/generated/InspectorBackendCommands.ts +10 -1
- package/front_end/generated/SupportedCSSProperties.js +48 -62
- package/front_end/generated/protocol-mapping.d.ts +4 -0
- package/front_end/generated/protocol-proxy-api.d.ts +5 -0
- package/front_end/generated/protocol.ts +203 -0
- package/front_end/models/ai_assistance/agents/AiAgent.ts +2 -1
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +98 -105
- package/front_end/models/emulation/DeviceModeModel.ts +1 -1
- package/front_end/models/formatter/FormatterWorkerPool.ts +8 -6
- package/front_end/models/javascript_metadata/NativeFunctions.js +4 -9
- package/front_end/models/persistence/PersistenceImpl.ts +8 -0
- package/front_end/models/text_utils/TextUtils.snapshot.txt +83 -0
- package/front_end/panels/ai_assistance/ai_assistance-meta.ts +0 -1
- package/front_end/panels/ai_assistance/components/ArtifactsViewer.ts +28 -4
- package/front_end/panels/ai_assistance/components/ChatView.ts +52 -169
- package/front_end/panels/ai_assistance/components/CollapsibleAssistanceContentWidget.ts +27 -8
- package/front_end/panels/ai_assistance/components/PerformanceAgentMarkdownRenderer.ts +19 -4
- package/front_end/panels/application/ApplicationPanelSidebar.ts +29 -0
- package/front_end/panels/application/ApplicationPanelTreeElement.ts +12 -0
- package/front_end/panels/application/DeviceBoundSessionsModel.ts +169 -0
- package/front_end/panels/application/DeviceBoundSessionsTreeElement.ts +219 -0
- package/front_end/panels/application/DeviceBoundSessionsView.ts +1096 -0
- package/front_end/panels/application/ResourcesPanel.ts +19 -0
- package/front_end/panels/application/application.ts +6 -0
- package/front_end/panels/application/deviceBoundSessionsView.css +27 -0
- package/front_end/panels/common/AiCodeGenerationUpgradeDialog.ts +115 -0
- package/front_end/panels/common/aiCodeGenerationUpgradeDialog.css +79 -0
- package/front_end/panels/common/common.ts +1 -0
- package/front_end/panels/console/ConsoleInsightTeaser.ts +41 -8
- package/front_end/panels/console/ConsoleViewMessage.ts +20 -13
- package/front_end/panels/elements/ElementsTreeOutline.ts +13 -0
- package/front_end/panels/elements/MetricsSidebarPane.ts +3 -1
- package/front_end/panels/issues/AffectedSourcesView.ts +0 -1
- package/front_end/panels/issues/IssuesPane.ts +0 -4
- package/front_end/panels/network/RequestTimingView.ts +5 -20
- package/front_end/panels/network/networkTimingTable.css +5 -5
- package/front_end/panels/recorder/components/StepEditor.ts +15 -8
- package/front_end/panels/security/SecurityPanelSidebar.ts +0 -1
- package/front_end/panels/settings/AISettingsTab.ts +31 -2
- package/front_end/panels/sources/InplaceFormatterEditorAction.ts +8 -6
- package/front_end/panels/sources/UISourceCodeFrame.ts +9 -3
- package/front_end/panels/timeline/TimelinePanel.ts +12 -4
- package/front_end/panels/timeline/components/insights/DuplicatedJavaScript.ts +1 -1
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/third_party/puppeteer/README.chromium +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Browser.d.ts +9 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Browser.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Browser.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.d.ts +8 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.js +8 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Browser.d.ts +2 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Browser.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Browser.js +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Browser.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/BrowserContext.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/BrowserContext.js +3 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/BrowserContext.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Frame.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Frame.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Frame.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/BrowsingContext.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/BrowsingContext.js +3 -3
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/BrowsingContext.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/UserContext.d.ts +1 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/UserContext.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/UserContext.js +1 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/UserContext.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.js +1 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.js +33 -31
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/WebWorker.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/WebWorker.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/WebWorker.js +1 -4
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/WebWorker.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/ConsoleMessage.d.ts +7 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/ConsoleMessage.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/ConsoleMessage.js +11 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/ConsoleMessage.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/Cookie.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/injected/injected.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Mutex.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.d.ts +13 -4
- package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +62 -42
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Browser.d.ts +9 -2
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Browser.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Browser.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.d.ts +8 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.js +8 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Browser.d.ts +2 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Browser.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Browser.js +2 -2
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Browser.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/BrowserContext.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/BrowserContext.js +3 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/BrowserContext.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Frame.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Frame.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Frame.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/BrowsingContext.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/BrowsingContext.js +3 -3
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/BrowsingContext.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/UserContext.d.ts +1 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/UserContext.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/UserContext.js +1 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/UserContext.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.js +1 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.js +33 -31
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/WebWorker.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/WebWorker.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/WebWorker.js +1 -4
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/WebWorker.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/ConsoleMessage.d.ts +7 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/ConsoleMessage.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/ConsoleMessage.js +11 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/ConsoleMessage.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/Cookie.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js +2 -2
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/types.d.ts +13 -4
- package/front_end/third_party/puppeteer/package/package.json +3 -3
- package/front_end/third_party/puppeteer/package/src/api/Browser.ts +11 -3
- package/front_end/third_party/puppeteer/package/src/api/Page.ts +9 -0
- package/front_end/third_party/puppeteer/package/src/bidi/Browser.ts +3 -3
- package/front_end/third_party/puppeteer/package/src/bidi/BrowserContext.ts +3 -1
- package/front_end/third_party/puppeteer/package/src/bidi/Frame.ts +1 -0
- package/front_end/third_party/puppeteer/package/src/bidi/core/BrowsingContext.ts +3 -5
- package/front_end/third_party/puppeteer/package/src/bidi/core/UserContext.ts +2 -0
- package/front_end/third_party/puppeteer/package/src/cdp/Browser.ts +1 -0
- package/front_end/third_party/puppeteer/package/src/cdp/Page.ts +43 -45
- package/front_end/third_party/puppeteer/package/src/cdp/WebWorker.ts +3 -11
- package/front_end/third_party/puppeteer/package/src/common/ConsoleMessage.ts +12 -0
- package/front_end/third_party/puppeteer/package/src/common/Cookie.ts +2 -2
- package/front_end/third_party/puppeteer/package/src/revisions.ts +2 -2
- package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
- package/front_end/third_party/source-map-scopes-codec/README.chromium +2 -5
- package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/builder.d.ts +1 -1
- package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/builder.d.ts.map +1 -1
- package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/safe_builder.d.ts +1 -1
- package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/safe_builder.d.ts.map +1 -1
- package/front_end/third_party/source-map-scopes-codec/package/_dist/src/decode/decode.d.ts +1 -1
- package/front_end/third_party/source-map-scopes-codec/package/_dist/src/decode/decode.d.ts.map +1 -1
- package/front_end/third_party/source-map-scopes-codec/package/_dist/src/encode/encode.d.ts +1 -1
- package/front_end/third_party/source-map-scopes-codec/package/_dist/src/encode/encode.d.ts.map +1 -1
- package/front_end/third_party/source-map-scopes-codec/package/_dist/src/mod.d.ts +1 -1
- package/front_end/third_party/source-map-scopes-codec/package/_dist/src/mod.d.ts.map +1 -1
- package/front_end/third_party/source-map-scopes-codec/package/_dist/src/scopes.d.ts +130 -0
- package/front_end/third_party/source-map-scopes-codec/package/_dist/src/scopes.d.ts.map +1 -0
- package/front_end/third_party/source-map-scopes-codec/package/deno.json +1 -1
- package/front_end/third_party/source-map-scopes-codec/package/package.json +1 -1
- package/front_end/third_party/source-map-scopes-codec/package/src/builder/builder.ts +1 -1
- package/front_end/third_party/source-map-scopes-codec/package/src/builder/safe_builder.ts +1 -1
- package/front_end/third_party/source-map-scopes-codec/package/src/codec.js +4 -0
- package/front_end/third_party/source-map-scopes-codec/package/src/codec.js.map +1 -1
- package/front_end/third_party/source-map-scopes-codec/package/src/codec.ts +4 -0
- package/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.js +30 -13
- package/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.js.map +1 -1
- package/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.ts +35 -17
- package/front_end/third_party/source-map-scopes-codec/package/src/encode/encode.ts +1 -1
- package/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.js +1 -1
- package/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.js.map +1 -1
- package/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.ts +2 -2
- package/front_end/third_party/source-map-scopes-codec/package/src/mod.ts +1 -1
- package/front_end/third_party/source-map-scopes-codec/package/src/scopes.js +7 -0
- package/front_end/third_party/source-map-scopes-codec/package/src/scopes.js.map +1 -0
- package/front_end/third_party/source-map-scopes-codec/package/src/util.ts +1 -1
- package/front_end/ui/legacy/components/color_picker/FormatPickerContextMenu.ts +8 -1
- package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +4 -0
- package/front_end/ui/visual_logging/KnownContextValues.ts +13 -0
- package/mcp/mcp.ts +1 -0
- package/package.json +1 -2
- package/front_end/third_party/source-map-scopes-codec/package/src/scopes-tsconfig.json +0 -8
- /package/front_end/third_party/source-map-scopes-codec/package/src/{scopes.d.ts → scopes.ts} +0 -0
|
@@ -208,7 +208,6 @@ export class ChatView extends HTMLElement {
|
|
|
208
208
|
};
|
|
209
209
|
|
|
210
210
|
#render(): void {
|
|
211
|
-
|
|
212
211
|
const inputWidgetClasses = Lit.Directives.classMap({
|
|
213
212
|
'chat-input-widget': true,
|
|
214
213
|
sticky: !this.#props.isReadOnly,
|
|
@@ -219,22 +218,58 @@ export class ChatView extends HTMLElement {
|
|
|
219
218
|
<style>${chatViewStyles}</style>
|
|
220
219
|
<div class="chat-ui">
|
|
221
220
|
<main @scroll=${this.#handleScroll} ${ref(this.#mainElementRef)}>
|
|
222
|
-
${
|
|
223
|
-
messages
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
221
|
+
${this.#props.messages.length > 0 ? html`
|
|
222
|
+
<div class="messages-container" ${ref(this.#handleMessageContainerRef)}>
|
|
223
|
+
${repeat(this.#props.messages, message =>
|
|
224
|
+
html`<devtools-widget .widgetConfig=${UI.Widget.widgetConfig(ChatMessage, {
|
|
225
|
+
message,
|
|
226
|
+
isLoading: this.#props.isLoading,
|
|
227
|
+
isReadOnly: this.#props.isReadOnly,
|
|
228
|
+
canShowFeedbackForm: this.#props.canShowFeedbackForm,
|
|
229
|
+
userInfo: this.#props.userInfo,
|
|
230
|
+
markdownRenderer: this.#props.markdownRenderer,
|
|
231
|
+
isLastMessage: this.#props.messages.at(-1) === message,
|
|
232
|
+
onSuggestionClick: this.#handleSuggestionClick,
|
|
233
|
+
onFeedbackSubmit: this.#props.onFeedbackSubmit,
|
|
234
|
+
onCopyResponseClick: this.#props.onCopyResponseClick,
|
|
235
|
+
})}></devtools-widget>`
|
|
236
|
+
)}
|
|
237
|
+
${this.#props.isLoading ? Lit.nothing : html`<devtools-widget
|
|
238
|
+
.widgetConfig=${UI.Widget.widgetConfig(PatchWidget, {
|
|
239
|
+
changeSummary: this.#props.changeSummary ?? '',
|
|
240
|
+
changeManager: this.#props.changeManager,
|
|
241
|
+
})}
|
|
242
|
+
></devtools-widget>`}
|
|
243
|
+
</div>
|
|
244
|
+
` : html`
|
|
245
|
+
<div class="empty-state-container">
|
|
246
|
+
<div class="header">
|
|
247
|
+
<div class="icon">
|
|
248
|
+
<devtools-icon
|
|
249
|
+
name="smart-assistant"
|
|
250
|
+
></devtools-icon>
|
|
251
|
+
</div>
|
|
252
|
+
<h1>${lockedString(UIStringsNotTranslate.emptyStateText)}</h1>
|
|
253
|
+
</div>
|
|
254
|
+
<div class="empty-state-content">
|
|
255
|
+
${this.#props.emptyStateSuggestions.map(({title, jslogContext}) => {
|
|
256
|
+
return html`<devtools-button
|
|
257
|
+
class="suggestion"
|
|
258
|
+
@click=${() => this.#handleSuggestionClick(title)}
|
|
259
|
+
.data=${
|
|
260
|
+
{
|
|
261
|
+
variant: Buttons.Button.Variant.OUTLINED,
|
|
262
|
+
size: Buttons.Button.Size.REGULAR,
|
|
263
|
+
title,
|
|
264
|
+
jslogContext: jslogContext ?? 'suggestion',
|
|
265
|
+
disabled: this.#props.isTextInputDisabled,
|
|
266
|
+
} as Buttons.Button.ButtonData
|
|
267
|
+
}
|
|
268
|
+
>${title}</devtools-button>`;
|
|
269
|
+
})}
|
|
270
|
+
</div>
|
|
271
|
+
</div>
|
|
272
|
+
`}
|
|
238
273
|
<devtools-widget class=${inputWidgetClasses} .widgetConfig=${UI.Widget.widgetConfig(ChatInput, {
|
|
239
274
|
isLoading: this.#props.isLoading,
|
|
240
275
|
blockedByCrossOrigin: this.#props.blockedByCrossOrigin,
|
|
@@ -266,158 +301,6 @@ export class ChatView extends HTMLElement {
|
|
|
266
301
|
}
|
|
267
302
|
}
|
|
268
303
|
|
|
269
|
-
function renderMainContents({
|
|
270
|
-
messages,
|
|
271
|
-
isLoading,
|
|
272
|
-
isReadOnly,
|
|
273
|
-
canShowFeedbackForm,
|
|
274
|
-
isTextInputDisabled,
|
|
275
|
-
suggestions,
|
|
276
|
-
userInfo,
|
|
277
|
-
markdownRenderer,
|
|
278
|
-
changeSummary,
|
|
279
|
-
changeManager,
|
|
280
|
-
onSuggestionClick,
|
|
281
|
-
onFeedbackSubmit,
|
|
282
|
-
onCopyResponseClick,
|
|
283
|
-
onMessageContainerRef,
|
|
284
|
-
}: {
|
|
285
|
-
messages: Message[],
|
|
286
|
-
isLoading: boolean,
|
|
287
|
-
isReadOnly: boolean,
|
|
288
|
-
canShowFeedbackForm: boolean,
|
|
289
|
-
isTextInputDisabled: boolean,
|
|
290
|
-
suggestions: AiAssistanceModel.AiAgent.ConversationSuggestion[],
|
|
291
|
-
userInfo: Pick<Host.InspectorFrontendHostAPI.SyncInformation, 'accountImage'|'accountFullName'>,
|
|
292
|
-
markdownRenderer: MarkdownLitRenderer,
|
|
293
|
-
changeManager: AiAssistanceModel.ChangeManager.ChangeManager,
|
|
294
|
-
onSuggestionClick: (suggestion: string) => void,
|
|
295
|
-
onFeedbackSubmit: (rpcId: Host.AidaClient.RpcGlobalId, rate: Host.AidaClient.Rating, feedback?: string) => void,
|
|
296
|
-
onCopyResponseClick: (message: ModelChatMessage) => void,
|
|
297
|
-
onMessageContainerRef: (el: Element|undefined) => void,
|
|
298
|
-
changeSummary?: string,
|
|
299
|
-
}): Lit.LitTemplate {
|
|
300
|
-
if (messages.length > 0) {
|
|
301
|
-
return renderMessages({
|
|
302
|
-
messages,
|
|
303
|
-
isLoading,
|
|
304
|
-
isReadOnly,
|
|
305
|
-
canShowFeedbackForm,
|
|
306
|
-
userInfo,
|
|
307
|
-
markdownRenderer,
|
|
308
|
-
changeSummary,
|
|
309
|
-
changeManager,
|
|
310
|
-
onSuggestionClick,
|
|
311
|
-
onFeedbackSubmit,
|
|
312
|
-
onMessageContainerRef,
|
|
313
|
-
onCopyResponseClick
|
|
314
|
-
});
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
return renderEmptyState({isTextInputDisabled, suggestions, onSuggestionClick});
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
function renderMessages({
|
|
321
|
-
messages,
|
|
322
|
-
isLoading,
|
|
323
|
-
isReadOnly,
|
|
324
|
-
canShowFeedbackForm,
|
|
325
|
-
userInfo,
|
|
326
|
-
markdownRenderer,
|
|
327
|
-
changeSummary,
|
|
328
|
-
changeManager,
|
|
329
|
-
onSuggestionClick,
|
|
330
|
-
onFeedbackSubmit,
|
|
331
|
-
onCopyResponseClick,
|
|
332
|
-
onMessageContainerRef,
|
|
333
|
-
}: {
|
|
334
|
-
messages: Message[],
|
|
335
|
-
isLoading: boolean,
|
|
336
|
-
isReadOnly: boolean,
|
|
337
|
-
canShowFeedbackForm: boolean,
|
|
338
|
-
userInfo: Pick<Host.InspectorFrontendHostAPI.SyncInformation, 'accountImage'|'accountFullName'>,
|
|
339
|
-
markdownRenderer: MarkdownLitRenderer,
|
|
340
|
-
onSuggestionClick: (suggestion: string) => void,
|
|
341
|
-
onFeedbackSubmit: (rpcId: Host.AidaClient.RpcGlobalId, rate: Host.AidaClient.Rating, feedback?: string) => void,
|
|
342
|
-
onCopyResponseClick: (message: ModelChatMessage) => void,
|
|
343
|
-
onMessageContainerRef: (el: Element|undefined) => void,
|
|
344
|
-
changeSummary?: string,
|
|
345
|
-
changeManager?: AiAssistanceModel.ChangeManager.ChangeManager,
|
|
346
|
-
}): Lit.TemplateResult {
|
|
347
|
-
function renderPatchWidget(): Lit.LitTemplate {
|
|
348
|
-
if (isLoading) {
|
|
349
|
-
return Lit.nothing;
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
// clang-format off
|
|
353
|
-
return html`<devtools-widget
|
|
354
|
-
.widgetConfig=${UI.Widget.widgetConfig(PatchWidget, {
|
|
355
|
-
changeSummary: changeSummary ?? '',
|
|
356
|
-
changeManager,
|
|
357
|
-
})}
|
|
358
|
-
></devtools-widget>`;
|
|
359
|
-
// clang-format on
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
// clang-format off
|
|
363
|
-
return html`
|
|
364
|
-
<div class="messages-container" ${ref(onMessageContainerRef)}>
|
|
365
|
-
${repeat(messages, message =>
|
|
366
|
-
html`<devtools-widget .widgetConfig=${UI.Widget.widgetConfig(ChatMessage, {
|
|
367
|
-
message,
|
|
368
|
-
isLoading,
|
|
369
|
-
isReadOnly,
|
|
370
|
-
canShowFeedbackForm,
|
|
371
|
-
userInfo,
|
|
372
|
-
markdownRenderer,
|
|
373
|
-
isLastMessage: messages.at(-1) === message,
|
|
374
|
-
onSuggestionClick,
|
|
375
|
-
onFeedbackSubmit,
|
|
376
|
-
onCopyResponseClick,
|
|
377
|
-
})}></devtools-widget>`
|
|
378
|
-
)}
|
|
379
|
-
${renderPatchWidget()}
|
|
380
|
-
</div>
|
|
381
|
-
`;
|
|
382
|
-
// clang-format on
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
function renderEmptyState({isTextInputDisabled, suggestions, onSuggestionClick}: {
|
|
386
|
-
isTextInputDisabled: boolean,
|
|
387
|
-
suggestions: AiAssistanceModel.AiAgent.ConversationSuggestion[],
|
|
388
|
-
onSuggestionClick: (suggestion: string) => void,
|
|
389
|
-
}): Lit.TemplateResult {
|
|
390
|
-
// clang-format off
|
|
391
|
-
return html`<div class="empty-state-container">
|
|
392
|
-
<div class="header">
|
|
393
|
-
<div class="icon">
|
|
394
|
-
<devtools-icon
|
|
395
|
-
name="smart-assistant"
|
|
396
|
-
></devtools-icon>
|
|
397
|
-
</div>
|
|
398
|
-
<h1>${lockedString(UIStringsNotTranslate.emptyStateText)}</h1>
|
|
399
|
-
</div>
|
|
400
|
-
<div class="empty-state-content">
|
|
401
|
-
${suggestions.map(({title, jslogContext}) => {
|
|
402
|
-
return html`<devtools-button
|
|
403
|
-
class="suggestion"
|
|
404
|
-
@click=${() => onSuggestionClick(title)}
|
|
405
|
-
.data=${
|
|
406
|
-
{
|
|
407
|
-
variant: Buttons.Button.Variant.OUTLINED,
|
|
408
|
-
size: Buttons.Button.Size.REGULAR,
|
|
409
|
-
title,
|
|
410
|
-
jslogContext: jslogContext ?? 'suggestion',
|
|
411
|
-
disabled: isTextInputDisabled,
|
|
412
|
-
} as Buttons.Button.ButtonData
|
|
413
|
-
}
|
|
414
|
-
>${title}</devtools-button>`;
|
|
415
|
-
})}
|
|
416
|
-
</div>
|
|
417
|
-
</div>`;
|
|
418
|
-
// clang-format on
|
|
419
|
-
}
|
|
420
|
-
|
|
421
304
|
declare global {
|
|
422
305
|
interface HTMLElementTagNameMap {
|
|
423
306
|
'devtools-ai-chat-view': ChatView;
|
|
@@ -12,15 +12,18 @@ const {render, html} = Lit;
|
|
|
12
12
|
|
|
13
13
|
export interface CollapsibleAssistanceContentWidgetData {
|
|
14
14
|
headerText: string;
|
|
15
|
+
onReveal?: () => void;
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
export class CollapsibleAssistanceContentWidget extends HTMLElement {
|
|
18
19
|
readonly #shadow = this.attachShadow({mode: 'open'});
|
|
19
20
|
#isCollapsed = false;
|
|
20
21
|
#headerText = 'Details';
|
|
22
|
+
#onReveal?: () => void;
|
|
21
23
|
|
|
22
24
|
set data(data: CollapsibleAssistanceContentWidgetData) {
|
|
23
25
|
this.#headerText = data.headerText;
|
|
26
|
+
this.#onReveal = data.onReveal;
|
|
24
27
|
this.#render();
|
|
25
28
|
}
|
|
26
29
|
|
|
@@ -43,14 +46,30 @@ export class CollapsibleAssistanceContentWidget extends HTMLElement {
|
|
|
43
46
|
this.#toggleCollapse();
|
|
44
47
|
}}>
|
|
45
48
|
${this.#headerText}
|
|
46
|
-
<
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
<div>
|
|
50
|
+
<devtools-button .data=${{
|
|
51
|
+
variant: Buttons.Button.Variant.ICON,
|
|
52
|
+
iconName: 'select-element',
|
|
53
|
+
color: 'var(--sys-color-on-surface)',
|
|
54
|
+
width: '14px',
|
|
55
|
+
height: '14px',
|
|
56
|
+
title: 'reveal',
|
|
57
|
+
} as Buttons.Button.ButtonData}
|
|
58
|
+
@click=${(event: Event) => {
|
|
59
|
+
event.stopPropagation();
|
|
60
|
+
this.#onReveal?.();
|
|
61
|
+
}}
|
|
62
|
+
></devtools-button>
|
|
63
|
+
<devtools-button .data=${{
|
|
64
|
+
variant: Buttons.Button.Variant.ICON,
|
|
65
|
+
iconName: this.#isCollapsed ? 'triangle-right' : 'triangle-down',
|
|
66
|
+
color: 'var(--sys-color-on-surface)',
|
|
67
|
+
width: '14px',
|
|
68
|
+
height: '14px',
|
|
69
|
+
title: 'expand',
|
|
70
|
+
} as Buttons.Button.ButtonData}
|
|
71
|
+
></devtools-button>
|
|
72
|
+
</div>
|
|
54
73
|
</summary>
|
|
55
74
|
<div class="content">
|
|
56
75
|
<slot></slot>
|
|
@@ -2,10 +2,10 @@
|
|
|
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 './CollapsibleAssistanceContentWidget.js';
|
|
6
5
|
import '../../../models/trace/insights/insights.js';
|
|
7
6
|
import '../../../panels/timeline/components/components.js';
|
|
8
7
|
import './PerformanceAgentFlameChart.js';
|
|
8
|
+
import './CollapsibleAssistanceContentWidget.js';
|
|
9
9
|
|
|
10
10
|
import * as Common from '../../../core/common/common.js';
|
|
11
11
|
import * as SDK from '../../../core/sdk/sdk.js';
|
|
@@ -19,9 +19,11 @@ import type * as Marked from '../../../third_party/marked/marked.js';
|
|
|
19
19
|
import * as UI from '../../../ui/legacy/legacy.js';
|
|
20
20
|
import * as Lit from '../../../ui/lit/lit.js';
|
|
21
21
|
import * as PanelsCommon from '../../common/common.js';
|
|
22
|
+
import * as NetworkForward from '../../network/forward/forward.js';
|
|
22
23
|
import * as Network from '../../network/network.js';
|
|
23
24
|
import * as TimelineComponents from '../../timeline/components/components.js';
|
|
24
25
|
import * as Insights from '../../timeline/components/insights/insights.js';
|
|
26
|
+
import * as Timeline from '../../timeline/timeline.js';
|
|
25
27
|
|
|
26
28
|
import {MarkdownRendererWithCodeBlock} from './MarkdownRendererWithCodeBlock.js';
|
|
27
29
|
import type * as PerformanceAgentFlameChart from './PerformanceAgentFlameChart.js';
|
|
@@ -86,7 +88,11 @@ export class PerformanceAgentMarkdownRenderer extends MarkdownRendererWithCodeBl
|
|
|
86
88
|
}
|
|
87
89
|
|
|
88
90
|
return html`<devtools-collapsible-assistance-content-widget .data=${{
|
|
89
|
-
headerText: `Insight - ${componentName}
|
|
91
|
+
headerText: `Insight - ${componentName}`, onReveal: () => {
|
|
92
|
+
void UI.InspectorView.InspectorView.instance().showPanel('timeline').then(() => {
|
|
93
|
+
Timeline.TimelinePanel.TimelinePanel.instance().revealInsight(insightM);
|
|
94
|
+
});
|
|
95
|
+
},
|
|
90
96
|
}
|
|
91
97
|
}>
|
|
92
98
|
${this.#insightRenderer.renderInsightToWidgetElement(this.parsedTrace, insightSet, insightM, componentName, {
|
|
@@ -115,7 +121,13 @@ export class PerformanceAgentMarkdownRenderer extends MarkdownRendererWithCodeBl
|
|
|
115
121
|
return html`<devtools-collapsible-assistance-content-widget
|
|
116
122
|
.data=${{
|
|
117
123
|
headerText: `Network Request: ${
|
|
118
|
-
networkRequest.url().length > 80 ? networkRequest.url().slice(0, 80) + '...' : networkRequest.url()}
|
|
124
|
+
networkRequest.url().length > 80 ? networkRequest.url().slice(0, 80) + '...' : networkRequest.url()}`,
|
|
125
|
+
onReveal: () => {
|
|
126
|
+
void UI.InspectorView.InspectorView.instance().showPanel('network').then(() => {
|
|
127
|
+
void Common.Revealer.reveal(NetworkForward.UIRequestLocation.UIRequestLocation.tab(
|
|
128
|
+
networkRequest, NetworkForward.UIRequestLocation.UIRequestTabs.TIMING));
|
|
129
|
+
});
|
|
130
|
+
},
|
|
119
131
|
}
|
|
120
132
|
}>
|
|
121
133
|
<devtools-widget class="actions" .widgetConfig=${
|
|
@@ -142,7 +154,10 @@ export class PerformanceAgentMarkdownRenderer extends MarkdownRendererWithCodeBl
|
|
|
142
154
|
|
|
143
155
|
return html`<devtools-collapsible-assistance-content-widget
|
|
144
156
|
.data=${{
|
|
145
|
-
headerText: 'Network Request'
|
|
157
|
+
headerText: 'Network Request', onReveal: () => {
|
|
158
|
+
// eslint-disable-next-line no-console
|
|
159
|
+
console.log('Reveal network request', value);
|
|
160
|
+
},
|
|
146
161
|
}
|
|
147
162
|
}>
|
|
148
163
|
${networkTooltip}
|
|
@@ -37,6 +37,7 @@ import * as Common from '../../core/common/common.js';
|
|
|
37
37
|
import * as Host from '../../core/host/host.js';
|
|
38
38
|
import * as i18n from '../../core/i18n/i18n.js';
|
|
39
39
|
import * as Platform from '../../core/platform/platform.js';
|
|
40
|
+
import * as Root from '../../core/root/root.js';
|
|
40
41
|
import * as SDK from '../../core/sdk/sdk.js';
|
|
41
42
|
import * as Protocol from '../../generated/protocol.js';
|
|
42
43
|
import * as IssuesManager from '../../models/issues_manager/issues_manager.js';
|
|
@@ -51,6 +52,8 @@ import {BackForwardCacheTreeElement} from './BackForwardCacheTreeElement.js';
|
|
|
51
52
|
import {BackgroundServiceModel} from './BackgroundServiceModel.js';
|
|
52
53
|
import {BackgroundServiceView} from './BackgroundServiceView.js';
|
|
53
54
|
import {BounceTrackingMitigationsTreeElement} from './BounceTrackingMitigationsTreeElement.js';
|
|
55
|
+
import {DeviceBoundSessionsModel} from './DeviceBoundSessionsModel.js';
|
|
56
|
+
import {RootTreeElement as DeviceBoundSessionsRootTreeElement} from './DeviceBoundSessionsTreeElement.js';
|
|
54
57
|
import {type DOMStorage, DOMStorageModel, Events as DOMStorageModelEvents} from './DOMStorageModel.js';
|
|
55
58
|
import {
|
|
56
59
|
Events as ExtensionStorageModelEvents,
|
|
@@ -343,6 +346,8 @@ export class ApplicationPanelSidebar extends UI.Widget.VBox implements SDK.Targe
|
|
|
343
346
|
periodicBackgroundSyncTreeElement: BackgroundServiceTreeElement;
|
|
344
347
|
pushMessagingTreeElement: BackgroundServiceTreeElement;
|
|
345
348
|
reportingApiTreeElement: ReportingApiTreeElement;
|
|
349
|
+
deviceBoundSessionsRootTreeElement: DeviceBoundSessionsRootTreeElement|undefined;
|
|
350
|
+
deviceBoundSessionsModel: DeviceBoundSessionsModel|undefined;
|
|
346
351
|
preloadingSummaryTreeElement: PreloadingSummaryTreeElement|undefined;
|
|
347
352
|
private readonly resourcesSection: ResourcesSection;
|
|
348
353
|
private domStorageTreeElements: Map<DOMStorage, DOMStorageTreeElement>;
|
|
@@ -481,6 +486,13 @@ export class ApplicationPanelSidebar extends UI.Widget.VBox implements SDK.Targe
|
|
|
481
486
|
this.reportingApiTreeElement = new ReportingApiTreeElement(panel);
|
|
482
487
|
backgroundServiceTreeElement.appendChild(this.reportingApiTreeElement);
|
|
483
488
|
|
|
489
|
+
if (Root.Runtime.hostConfig.deviceBoundSessionsDebugging?.enabled) {
|
|
490
|
+
this.deviceBoundSessionsModel = new DeviceBoundSessionsModel();
|
|
491
|
+
this.deviceBoundSessionsRootTreeElement =
|
|
492
|
+
new DeviceBoundSessionsRootTreeElement(panel, this.deviceBoundSessionsModel);
|
|
493
|
+
backgroundServiceTreeElement.appendChild(this.deviceBoundSessionsRootTreeElement);
|
|
494
|
+
}
|
|
495
|
+
|
|
484
496
|
const resourcesSectionTitle = i18nString(UIStrings.frames);
|
|
485
497
|
const resourcesTreeElement = this.addSidebarSection(resourcesSectionTitle, 'frames');
|
|
486
498
|
this.resourcesSection = new ResourcesSection(panel, resourcesTreeElement);
|
|
@@ -760,6 +772,8 @@ export class ApplicationPanelSidebar extends UI.Widget.VBox implements SDK.Targe
|
|
|
760
772
|
this.domains = {};
|
|
761
773
|
this.cookieListTreeElement.removeChildren();
|
|
762
774
|
this.interestGroupTreeElement.clearEvents();
|
|
775
|
+
this.deviceBoundSessionsModel?.clearVisibleSites();
|
|
776
|
+
this.deviceBoundSessionsModel?.clearEvents();
|
|
763
777
|
}
|
|
764
778
|
|
|
765
779
|
private frameNavigated(event: Common.EventTarget.EventTargetEvent<SDK.ResourceTreeModel.ResourceTreeFrame>): void {
|
|
@@ -791,6 +805,21 @@ export class ApplicationPanelSidebar extends UI.Widget.VBox implements SDK.Targe
|
|
|
791
805
|
this.domains[domain] = true;
|
|
792
806
|
const cookieDomainTreeElement = new CookieTreeElement(this.panel, frame, parsedURL);
|
|
793
807
|
this.cookieListTreeElement.appendChild(cookieDomainTreeElement);
|
|
808
|
+
|
|
809
|
+
// Update device bound session visibility for new cookie domain.
|
|
810
|
+
if (this.deviceBoundSessionsModel) {
|
|
811
|
+
const target = frame.resourceTreeModel().target();
|
|
812
|
+
const networkAgent = target.networkAgent();
|
|
813
|
+
void networkAgent.invoke_fetchSchemefulSite({origin: domain}).then(response => {
|
|
814
|
+
if (response.getError() || !this.deviceBoundSessionsModel) {
|
|
815
|
+
return;
|
|
816
|
+
}
|
|
817
|
+
// Confirm the domain is still present first.
|
|
818
|
+
if (this.domains[domain]) {
|
|
819
|
+
this.deviceBoundSessionsModel.addVisibleSite(response.schemefulSite);
|
|
820
|
+
}
|
|
821
|
+
});
|
|
822
|
+
}
|
|
794
823
|
}
|
|
795
824
|
}
|
|
796
825
|
|
|
@@ -10,6 +10,7 @@ import type {ResourcesPanel} from './ResourcesPanel.js';
|
|
|
10
10
|
|
|
11
11
|
export class ApplicationPanelTreeElement extends UI.TreeOutline.TreeElement {
|
|
12
12
|
protected readonly resourcesPanel: ResourcesPanel;
|
|
13
|
+
private customItemURL?: Platform.DevToolsPath.UrlString;
|
|
13
14
|
|
|
14
15
|
constructor(resourcesPanel: ResourcesPanel, title: string, expandable: boolean, jslogContext: string) {
|
|
15
16
|
super(title, expandable, jslogContext);
|
|
@@ -24,9 +25,16 @@ export class ApplicationPanelTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
get itemURL(): Platform.DevToolsPath.UrlString {
|
|
28
|
+
if (this.customItemURL) {
|
|
29
|
+
return this.customItemURL;
|
|
30
|
+
}
|
|
27
31
|
throw new Error('Unimplemented Method');
|
|
28
32
|
}
|
|
29
33
|
|
|
34
|
+
set itemURL(value: Platform.DevToolsPath.UrlString) {
|
|
35
|
+
this.customItemURL = value;
|
|
36
|
+
}
|
|
37
|
+
|
|
30
38
|
override onselect(selectedByUser: boolean|undefined): boolean {
|
|
31
39
|
if (!selectedByUser) {
|
|
32
40
|
return false;
|
|
@@ -76,6 +84,10 @@ export class ExpandableApplicationPanelTreeElement extends ApplicationPanelTreeE
|
|
|
76
84
|
return 'category://' + this.categoryName as Platform.DevToolsPath.UrlString;
|
|
77
85
|
}
|
|
78
86
|
|
|
87
|
+
override set itemURL(value: Platform.DevToolsPath.UrlString) {
|
|
88
|
+
super.itemURL = value;
|
|
89
|
+
}
|
|
90
|
+
|
|
79
91
|
setLink(link: Platform.DevToolsPath.UrlString): void {
|
|
80
92
|
this.categoryLink = link;
|
|
81
93
|
}
|
|
@@ -0,0 +1,169 @@
|
|
|
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 * as Common from '../../core/common/common.js';
|
|
6
|
+
import * as SDK from '../../core/sdk/sdk.js';
|
|
7
|
+
import type * as Protocol from '../../generated/protocol.js';
|
|
8
|
+
|
|
9
|
+
interface EventWithTimestamp {
|
|
10
|
+
event: Protocol.Network.DeviceBoundSessionEventOccurredEvent;
|
|
11
|
+
timestamp: Date;
|
|
12
|
+
}
|
|
13
|
+
export interface SessionAndEvents {
|
|
14
|
+
session?: Protocol.Network.DeviceBoundSession;
|
|
15
|
+
eventsById: Map<string, EventWithTimestamp>;
|
|
16
|
+
}
|
|
17
|
+
type SessionIdToSessionMap = Map<string|undefined, SessionAndEvents>;
|
|
18
|
+
|
|
19
|
+
export class DeviceBoundSessionsModel extends Common.ObjectWrapper.ObjectWrapper<DeviceBoundSessionModelEventTypes>
|
|
20
|
+
implements SDK.TargetManager.SDKModelObserver<SDK.NetworkManager.NetworkManager> {
|
|
21
|
+
#siteSessions = new Map<string, SessionIdToSessionMap>();
|
|
22
|
+
#visibleSites = new Set<string>();
|
|
23
|
+
|
|
24
|
+
constructor() {
|
|
25
|
+
super();
|
|
26
|
+
SDK.TargetManager.TargetManager.instance().observeModels(SDK.NetworkManager.NetworkManager, this, {scoped: true});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
modelAdded(networkManager: SDK.NetworkManager.NetworkManager): void {
|
|
30
|
+
networkManager.addEventListener(SDK.NetworkManager.Events.DeviceBoundSessionsAdded, this.#onSessionsSet, this);
|
|
31
|
+
networkManager.addEventListener(
|
|
32
|
+
SDK.NetworkManager.Events.DeviceBoundSessionEventOccurred, this.#onEventOccurred, this);
|
|
33
|
+
void networkManager.enableDeviceBoundSessions();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
modelRemoved(networkManager: SDK.NetworkManager.NetworkManager): void {
|
|
37
|
+
networkManager.removeEventListener(SDK.NetworkManager.Events.DeviceBoundSessionsAdded, this.#onSessionsSet, this);
|
|
38
|
+
networkManager.removeEventListener(
|
|
39
|
+
SDK.NetworkManager.Events.DeviceBoundSessionEventOccurred, this.#onEventOccurred, this);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
addVisibleSite(site: string): void {
|
|
43
|
+
if (this.#visibleSites.has(site)) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
this.#visibleSites.add(site);
|
|
47
|
+
this.dispatchEventToListeners(DeviceBoundSessionModelEvents.ADD_VISIBLE_SITE, {site});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
clearVisibleSites(): void {
|
|
51
|
+
if (this.getPreserveLogSetting().get()) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
this.#visibleSites.clear();
|
|
55
|
+
this.dispatchEventToListeners(DeviceBoundSessionModelEvents.CLEAR_VISIBLE_SITES);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
clearEvents(): void {
|
|
59
|
+
if (this.getPreserveLogSetting().get()) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const emptySessions = new Map<string, Array<string|undefined>>();
|
|
63
|
+
const emptySites = new Set<string>();
|
|
64
|
+
for (const [site, sessionIdToSessionMap] of [...this.#siteSessions]) {
|
|
65
|
+
let emptySessionsSiteEntry = emptySessions.get(site);
|
|
66
|
+
for (const [sessionId, sessionAndEvents] of sessionIdToSessionMap) {
|
|
67
|
+
sessionAndEvents.eventsById.clear();
|
|
68
|
+
if (sessionAndEvents.session) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
// Remove empty sessions.
|
|
72
|
+
sessionIdToSessionMap.delete(sessionId);
|
|
73
|
+
if (!emptySessionsSiteEntry) {
|
|
74
|
+
emptySessionsSiteEntry = [];
|
|
75
|
+
emptySessions.set(site, emptySessionsSiteEntry);
|
|
76
|
+
}
|
|
77
|
+
emptySessionsSiteEntry.push(sessionId);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Remove empty sites.
|
|
81
|
+
if (sessionIdToSessionMap.size === 0) {
|
|
82
|
+
this.#siteSessions.delete(site);
|
|
83
|
+
emptySites.add(site);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
this.dispatchEventToListeners(DeviceBoundSessionModelEvents.CLEAR_EVENTS, {emptySessions, emptySites});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
isSiteVisible(site: string): boolean {
|
|
91
|
+
return this.#visibleSites.has(site);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
getSession(site: string, sessionId?: string): SessionAndEvents|undefined {
|
|
95
|
+
return this.#siteSessions.get(site)?.get(sessionId);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
getPreserveLogSetting(): Common.Settings.Setting<boolean> {
|
|
99
|
+
return Common.Settings.Settings.instance().createSetting('device-bound-sessions-preserve-log', false);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
#onSessionsSet({data: sessions}: {data: Protocol.Network.DeviceBoundSession[]}): void {
|
|
103
|
+
for (const session of sessions) {
|
|
104
|
+
const sessionAndEvents = this.#ensureSiteAndSessionInitialized(session.key.site, session.key.id);
|
|
105
|
+
sessionAndEvents.session = session;
|
|
106
|
+
}
|
|
107
|
+
this.dispatchEventToListeners(DeviceBoundSessionModelEvents.INITIALIZE_SESSIONS, {sessions});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
#ensureSiteAndSessionInitialized(site: string, sessionId?: string): SessionAndEvents {
|
|
111
|
+
let sessionIdToSessionMap = this.#siteSessions.get(site);
|
|
112
|
+
if (!sessionIdToSessionMap) {
|
|
113
|
+
sessionIdToSessionMap = new Map();
|
|
114
|
+
this.#siteSessions.set(site, sessionIdToSessionMap);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
let sessionAndEvent = sessionIdToSessionMap.get(sessionId);
|
|
118
|
+
if (!sessionAndEvent) {
|
|
119
|
+
sessionAndEvent = {session: undefined, eventsById: new Map<string, EventWithTimestamp>()};
|
|
120
|
+
sessionIdToSessionMap.set(sessionId, sessionAndEvent);
|
|
121
|
+
}
|
|
122
|
+
return sessionAndEvent;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
#onEventOccurred({data: event}: {data: Protocol.Network.DeviceBoundSessionEventOccurredEvent}): void {
|
|
126
|
+
const sessionAndEvent = this.#ensureSiteAndSessionInitialized(event.site, event.sessionId);
|
|
127
|
+
|
|
128
|
+
// If this eventId has already been tracked, quit early.
|
|
129
|
+
if (sessionAndEvent.eventsById.has(event.eventId)) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Add the new event.
|
|
134
|
+
const eventWithTimestamp = {event, timestamp: new Date()};
|
|
135
|
+
sessionAndEvent.eventsById.set(event.eventId, eventWithTimestamp);
|
|
136
|
+
|
|
137
|
+
// Add the new session if there is one.
|
|
138
|
+
const newSession = event.creationEventDetails?.newSession || event.refreshEventDetails?.newSession;
|
|
139
|
+
if (newSession) {
|
|
140
|
+
sessionAndEvent.session = newSession;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Add the new challenge onto the session if there is one.
|
|
144
|
+
if (event.succeeded && sessionAndEvent.session && event.challengeEventDetails) {
|
|
145
|
+
sessionAndEvent.session.cachedChallenge = event.challengeEventDetails.challenge;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
this.dispatchEventToListeners(
|
|
149
|
+
DeviceBoundSessionModelEvents.EVENT_OCCURRED,
|
|
150
|
+
{site: eventWithTimestamp.event.site, sessionId: eventWithTimestamp.event.sessionId});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export const enum DeviceBoundSessionModelEvents {
|
|
155
|
+
INITIALIZE_SESSIONS = 'INITIALIZE_SESSIONS',
|
|
156
|
+
ADD_VISIBLE_SITE = 'ADD_VISIBLE_SITE',
|
|
157
|
+
CLEAR_VISIBLE_SITES = 'CLEAR_VISIBLE_SITES',
|
|
158
|
+
EVENT_OCCURRED = 'EVENT_OCCURRED',
|
|
159
|
+
CLEAR_EVENTS = 'CLEAR_EVENTS',
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export interface DeviceBoundSessionModelEventTypes {
|
|
163
|
+
[DeviceBoundSessionModelEvents.INITIALIZE_SESSIONS]: {sessions: Protocol.Network.DeviceBoundSession[]};
|
|
164
|
+
[DeviceBoundSessionModelEvents.ADD_VISIBLE_SITE]: {site: string};
|
|
165
|
+
[DeviceBoundSessionModelEvents.CLEAR_VISIBLE_SITES]: void;
|
|
166
|
+
[DeviceBoundSessionModelEvents.EVENT_OCCURRED]: {site: string, sessionId?: string};
|
|
167
|
+
[DeviceBoundSessionModelEvents.CLEAR_EVENTS]:
|
|
168
|
+
{emptySessions: Map<string, Array<string|undefined>>, emptySites: Set<string>};
|
|
169
|
+
}
|