chrome-devtools-frontend 1.0.1539972 → 1.0.1541552
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/eslint.config.mjs +167 -151
- package/front_end/Tests.js +5 -1
- package/front_end/core/common/Revealer.ts +5 -0
- package/front_end/core/common/Settings.ts +106 -95
- package/front_end/core/host/InspectorFrontendHost.ts +10 -10
- package/front_end/core/sdk/NetworkManager.ts +16 -11
- package/front_end/core/sdk/sdk-meta.ts +0 -35
- package/front_end/entrypoints/main/MainImpl.ts +15 -7
- package/front_end/entrypoints/shell/shell.ts +1 -0
- package/front_end/entrypoints/trace_app/trace_app.ts +1 -0
- package/front_end/foundation/README.md +10 -0
- package/front_end/foundation/Universe.ts +29 -0
- package/front_end/foundation/foundation.ts +7 -0
- package/front_end/generated/InspectorBackendCommands.ts +6 -3
- package/front_end/generated/SupportedCSSProperties.js +13 -0
- package/front_end/generated/protocol.ts +58 -2
- package/front_end/models/ai_assistance/BuiltInAi.ts +2 -1
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +44 -34
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +121 -56
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.ts +104 -62
- package/front_end/models/ai_assistance/performance/AIQueries.ts +56 -2
- package/front_end/{panels/issues → models/issues_manager}/IssueAggregator.ts +83 -65
- package/front_end/models/issues_manager/issues_manager.ts +2 -0
- package/front_end/models/trace/Processor.ts +5 -4
- package/front_end/models/trace/insights/types.ts +1 -1
- package/front_end/models/trace/types/TraceEvents.ts +1 -1
- package/front_end/models/workspace/IgnoreListManager.ts +41 -47
- package/front_end/models/workspace/workspace-meta.ts +40 -0
- package/front_end/panels/ai_assistance/components/MarkdownRendererWithCodeBlock.ts +1 -1
- package/front_end/panels/ai_assistance/components/PerformanceAgentMarkdownRenderer.ts +1 -1
- package/front_end/panels/animation/AnimationTimeline.ts +4 -4
- package/front_end/panels/animation/AnimationUI.ts +28 -34
- package/front_end/panels/elements/ElementsTreeElement.ts +37 -9
- package/front_end/panels/elements/LayoutPane.ts +2 -2
- package/front_end/panels/elements/components/AdornerManager.ts +9 -9
- package/front_end/panels/elements/layoutPane.css +5 -9
- package/front_end/panels/event_listeners/EventListenersView.ts +1 -1
- package/front_end/panels/explain/components/ConsoleInsight.ts +498 -449
- package/front_end/panels/issues/AffectedResourcesView.ts +3 -4
- package/front_end/panels/issues/CorsIssueDetailsView.ts +1 -2
- package/front_end/panels/issues/IssueView.ts +1 -1
- package/front_end/panels/issues/IssuesPane.ts +12 -15
- package/front_end/panels/issues/issues.ts +0 -2
- package/front_end/panels/network/NetworkDataGridNode.ts +2 -1
- package/front_end/panels/network/RequestConditionsDrawer.ts +149 -46
- package/front_end/panels/network/RequestTimingView.ts +13 -8
- package/front_end/panels/network/network-meta.ts +11 -0
- package/front_end/panels/settings/emulation/components/userAgentClientHintsForm.css +1 -1
- package/front_end/panels/sources/DebuggerPlugin.ts +1 -1
- package/front_end/panels/sources/WatchExpressionsSidebarPane.ts +1 -1
- package/front_end/panels/sources/breakpointsView.css +1 -1
- package/front_end/panels/sources/sourcesPanel.css +2 -2
- package/front_end/panels/timeline/TimelineFlameChartView.ts +3 -3
- package/front_end/panels/timeline/TimelinePanel.ts +3 -3
- package/front_end/panels/timeline/components/LayoutShiftDetails.ts +16 -10
- package/front_end/panels/timeline/components/SidebarSingleInsightSet.ts +2 -0
- package/front_end/panels/timeline/overlays/components/EntryLabelOverlay.ts +4 -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/cdp/NetworkManager.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/NetworkManager.js +3 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/NetworkManager.js.map +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/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.js +4 -4
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/NetworkManager.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/NetworkManager.js +3 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/NetworkManager.js.map +1 -1
- 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/package.json +1 -1
- package/front_end/third_party/puppeteer/package/src/cdp/NetworkManager.ts +3 -1
- 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/ui/components/markdown_view/MarkdownView.ts +6 -6
- package/front_end/ui/components/snackbars/Snackbars.docs.ts +46 -0
- package/front_end/ui/{components/docs/context_menu/basic.ts → legacy/ContextMenu.docs.ts} +58 -25
- package/front_end/ui/legacy/UIUtils.ts +2 -1
- package/front_end/ui/legacy/components/inline_editor/BezierEditor.ts +1 -1
- package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +148 -125
- package/front_end/ui/legacy/components/perf_ui/TimelineOverviewPane.ts +3 -3
- package/front_end/ui/legacy/components/perf_ui/pieChart.css +1 -1
- package/front_end/ui/legacy/components/utils/Linkifier.ts +1 -1
- package/front_end/ui/legacy/inspectorCommon.css +3 -2
- package/front_end/ui/visual_logging/KnownContextValues.ts +1 -0
- package/mcp/mcp.ts +16 -0
- package/package.json +2 -1
- package/front_end/ui/components/docs/context_menu/basic.html +0 -45
- package/front_end/ui/components/docs/linkifier/simple-url.html +0 -25
- package/front_end/ui/components/docs/linkifier/simple-url.ts +0 -25
- package/front_end/ui/components/docs/panel_feedback/basic.html +0 -25
- package/front_end/ui/components/docs/panel_feedback/basic.ts +0 -21
- package/front_end/ui/components/docs/panel_feedback/button.html +0 -25
- package/front_end/ui/components/docs/panel_feedback/button.ts +0 -19
- package/front_end/ui/components/docs/panel_introduction_steps/basic.html +0 -25
- package/front_end/ui/components/docs/panel_introduction_steps/basic.ts +0 -28
- package/front_end/ui/components/docs/perf_piechart/basic-with-legend.html +0 -20
- package/front_end/ui/components/docs/perf_piechart/basic-with-legend.ts +0 -20
- package/front_end/ui/components/docs/perf_piechart/basic-without-legend.html +0 -20
- package/front_end/ui/components/docs/perf_piechart/basic-without-legend.ts +0 -18
- package/front_end/ui/components/docs/snackbars/basic.html +0 -17
- package/front_end/ui/components/docs/snackbars/basic.ts +0 -50
|
@@ -187,6 +187,28 @@ const REPORT_URL = 'https://support.google.com/legal/troubleshooter/1114905?hl=e
|
|
|
187
187
|
Platform.DevToolsPath.UrlString;
|
|
188
188
|
const SIGN_IN_URL = 'https://accounts.google.com' as Platform.DevToolsPath.UrlString;
|
|
189
189
|
|
|
190
|
+
interface ViewInput {
|
|
191
|
+
state: StateData;
|
|
192
|
+
disableAnimations: boolean;
|
|
193
|
+
renderer: MarkdownView.MarkdownView.MarkdownInsightRenderer;
|
|
194
|
+
selectedRating?: boolean;
|
|
195
|
+
noLogging: boolean;
|
|
196
|
+
onClose: () => void;
|
|
197
|
+
onSearch: () => void;
|
|
198
|
+
onRating: (event: Event) => void;
|
|
199
|
+
onReport: () => void;
|
|
200
|
+
onGoToSignIn: () => void;
|
|
201
|
+
onConsentReminderConfirmed: () => Promise<void>;
|
|
202
|
+
onToggleReferenceDetails: () => void;
|
|
203
|
+
onDisclaimerSettingsLink: () => void;
|
|
204
|
+
onReminderSettingsLink: () => void;
|
|
205
|
+
onEnableInsightsInSettingsLink: () => void;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
interface ViewOutput {
|
|
209
|
+
referenceDetailsRef: Lit.Directives.Ref<HTMLDetailsElement>;
|
|
210
|
+
}
|
|
211
|
+
|
|
190
212
|
const enum State {
|
|
191
213
|
INSIGHT = 'insight',
|
|
192
214
|
LOADING = 'loading',
|
|
@@ -209,6 +231,7 @@ type StateData = {
|
|
|
209
231
|
isPageReloadRecommended: boolean,
|
|
210
232
|
completed: boolean,
|
|
211
233
|
directCitationUrls: string[],
|
|
234
|
+
relatedUrls: string[],
|
|
212
235
|
timedOut?: boolean,
|
|
213
236
|
}&Host.AidaClient.DoConversationResponse|{
|
|
214
237
|
type: State.ERROR,
|
|
@@ -247,10 +270,420 @@ const markedExtension = {
|
|
|
247
270
|
renderer: () => '',
|
|
248
271
|
};
|
|
249
272
|
|
|
273
|
+
function isSearchRagResponse(metadata: Host.AidaClient.ResponseMetadata): boolean {
|
|
274
|
+
return Boolean(metadata.factualityMetadata?.facts.length);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function renderSearchButton(input: ViewInput): Lit.TemplateResult {
|
|
278
|
+
// clang-format off
|
|
279
|
+
return html`<devtools-button
|
|
280
|
+
@click=${input.onSearch}
|
|
281
|
+
class="search-button"
|
|
282
|
+
.variant=${Buttons.Button.Variant.OUTLINED}
|
|
283
|
+
.jslogContext=${'search'}
|
|
284
|
+
>
|
|
285
|
+
${i18nString(UIStrings.search)}
|
|
286
|
+
</devtools-button>`;
|
|
287
|
+
// clang-format on
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function renderLearnMoreAboutInsights(): Lit.TemplateResult {
|
|
291
|
+
// clang-format off
|
|
292
|
+
return html`<x-link href=${LEARN_MORE_URL} class="link" jslog=${VisualLogging.link('learn-more').track({click: true})}>
|
|
293
|
+
${i18nString(UIStrings.learnMore)}
|
|
294
|
+
</x-link>`;
|
|
295
|
+
// clang-format on
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function maybeRenderSources(state: StateData): Lit.LitTemplate {
|
|
299
|
+
if (state.type !== State.INSIGHT || !state.directCitationUrls.length) {
|
|
300
|
+
return Lit.nothing;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// clang-format off
|
|
304
|
+
return html`
|
|
305
|
+
<ol class="sources-list">
|
|
306
|
+
${state.directCitationUrls.map((url, index) => html`
|
|
307
|
+
<li>
|
|
308
|
+
<x-link
|
|
309
|
+
href=${url}
|
|
310
|
+
class="link"
|
|
311
|
+
data-index=${index + 1}
|
|
312
|
+
jslog=${VisualLogging.link('references.console-insights').track({click: true})}
|
|
313
|
+
>
|
|
314
|
+
${url}
|
|
315
|
+
</x-link>
|
|
316
|
+
</li>
|
|
317
|
+
`)}
|
|
318
|
+
</ol>
|
|
319
|
+
`;
|
|
320
|
+
// clang-format on
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function maybeRenderRelatedContent(state: StateData): Lit.LitTemplate {
|
|
324
|
+
if (state.type !== State.INSIGHT || state.relatedUrls.length === 0) {
|
|
325
|
+
return Lit.nothing;
|
|
326
|
+
}
|
|
327
|
+
// clang-format off
|
|
328
|
+
return html`
|
|
329
|
+
${state.directCitationUrls.length ? html`<h3>${i18nString(UIStrings.relatedContent)}</h3>` : Lit.nothing}
|
|
330
|
+
<ul class="references-list">
|
|
331
|
+
${state.relatedUrls.map(relatedUrl => html`
|
|
332
|
+
<li>
|
|
333
|
+
<x-link
|
|
334
|
+
href=${relatedUrl}
|
|
335
|
+
class="link"
|
|
336
|
+
jslog=${VisualLogging.link('references.console-insights').track({click: true})}
|
|
337
|
+
>
|
|
338
|
+
${relatedUrl}
|
|
339
|
+
</x-link>
|
|
340
|
+
</li>
|
|
341
|
+
`)}
|
|
342
|
+
</ul>
|
|
343
|
+
`;
|
|
344
|
+
// clang-format on
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function renderMain(input: ViewInput, output: ViewOutput): Lit.TemplateResult {
|
|
348
|
+
const jslog = `${VisualLogging.section(input.state.type).track({resize: true})}`;
|
|
349
|
+
|
|
350
|
+
// clang-format off
|
|
351
|
+
switch (input.state.type) {
|
|
352
|
+
case State.LOADING:
|
|
353
|
+
return html`<main jslog=${jslog}>
|
|
354
|
+
<div role="presentation" aria-label="Loading" class="loader" style="clip-path: url('#clipPath');">
|
|
355
|
+
<svg width="100%" height="64">
|
|
356
|
+
<clipPath id="clipPath">
|
|
357
|
+
<rect x="0" y="0" width="100%" height="16" rx="8"></rect>
|
|
358
|
+
<rect x="0" y="24" width="100%" height="16" rx="8"></rect>
|
|
359
|
+
<rect x="0" y="48" width="100%" height="16" rx="8"></rect>
|
|
360
|
+
</clipPath>
|
|
361
|
+
</svg>
|
|
362
|
+
</div>
|
|
363
|
+
</main>`;
|
|
364
|
+
case State.INSIGHT:
|
|
365
|
+
return html`
|
|
366
|
+
<main jslog=${jslog}>
|
|
367
|
+
${
|
|
368
|
+
input.state.validMarkdown ? html`<devtools-markdown-view
|
|
369
|
+
.data=${{tokens: input.state.tokens, renderer: input.renderer, animationEnabled: !input.disableAnimations} as MarkdownView.MarkdownView.MarkdownViewData}>
|
|
370
|
+
</devtools-markdown-view>`: input.state.explanation
|
|
371
|
+
}
|
|
372
|
+
${input.state.timedOut ? html`<p class="error-message">${i18nString(UIStrings.timedOut)}</p>` : Lit.nothing}
|
|
373
|
+
${isSearchRagResponse(input.state.metadata) ? html`
|
|
374
|
+
<details class="references" ${Lit.Directives.ref(output.referenceDetailsRef)} @toggle=${input.onToggleReferenceDetails} jslog=${VisualLogging.expand('references').track({click: true})}>
|
|
375
|
+
<summary>${i18nString(UIStrings.references)}</summary>
|
|
376
|
+
${maybeRenderSources(input.state)}
|
|
377
|
+
${maybeRenderRelatedContent(input.state)}
|
|
378
|
+
</details>
|
|
379
|
+
` : Lit.nothing}
|
|
380
|
+
<details jslog=${VisualLogging.expand('sources').track({click: true})}>
|
|
381
|
+
<summary>${i18nString(UIStrings.inputData)}</summary>
|
|
382
|
+
<devtools-console-insight-sources-list .sources=${input.state.sources} .isPageReloadRecommended=${input.state.isPageReloadRecommended}>
|
|
383
|
+
</devtools-console-insight-sources-list>
|
|
384
|
+
</details>
|
|
385
|
+
<div class="buttons">
|
|
386
|
+
${renderSearchButton(input)}
|
|
387
|
+
</div>
|
|
388
|
+
</main>`;
|
|
389
|
+
case State.ERROR:
|
|
390
|
+
return html`
|
|
391
|
+
<main jslog=${jslog}>
|
|
392
|
+
<div class="error">${i18nString(UIStrings.errorBody)}</div>
|
|
393
|
+
</main>`;
|
|
394
|
+
case State.CONSENT_REMINDER:
|
|
395
|
+
return html`
|
|
396
|
+
<main class="reminder-container" jslog=${jslog}>
|
|
397
|
+
<h3>Things to consider</h3>
|
|
398
|
+
<div class="reminder-items">
|
|
399
|
+
<div>
|
|
400
|
+
<devtools-icon name="google" class="medium">
|
|
401
|
+
</devtools-icon>
|
|
402
|
+
</div>
|
|
403
|
+
<div>The console message, associated stack trace, related source code, and the associated network headers are sent to Google to generate explanations. ${input.noLogging
|
|
404
|
+
? 'The content you submit and that is generated by this feature will not be used to improve Google’s AI models.'
|
|
405
|
+
: 'This data may be seen by human reviewers to improve this feature. Avoid sharing sensitive or personal information.'}
|
|
406
|
+
</div>
|
|
407
|
+
<div>
|
|
408
|
+
<devtools-icon name="policy" class="medium">
|
|
409
|
+
</devtools-icon>
|
|
410
|
+
</div>
|
|
411
|
+
<div>Use of this feature is subject to the <x-link
|
|
412
|
+
href=${TERMS_OF_SERVICE_URL}
|
|
413
|
+
class="link"
|
|
414
|
+
jslog=${VisualLogging.link('terms-of-service.console-insights').track({click: true})}>
|
|
415
|
+
Google Terms of Service
|
|
416
|
+
</x-link> and <x-link
|
|
417
|
+
href=${PRIVACY_POLICY_URL}
|
|
418
|
+
class="link"
|
|
419
|
+
jslog=${VisualLogging.link('privacy-policy.console-insights').track({click: true})}>
|
|
420
|
+
Google Privacy Policy
|
|
421
|
+
</x-link>
|
|
422
|
+
</div>
|
|
423
|
+
<div>
|
|
424
|
+
<devtools-icon name="warning" class="medium">
|
|
425
|
+
</devtools-icon>
|
|
426
|
+
</div>
|
|
427
|
+
<div>
|
|
428
|
+
<x-link
|
|
429
|
+
href=${CODE_SNIPPET_WARNING_URL}
|
|
430
|
+
class="link"
|
|
431
|
+
jslog=${VisualLogging.link('code-snippets-explainer.console-insights').track({click: true})}
|
|
432
|
+
>Use generated code snippets with caution</x-link>
|
|
433
|
+
</div>
|
|
434
|
+
</div>
|
|
435
|
+
</main>
|
|
436
|
+
`;
|
|
437
|
+
case State.SETTING_IS_NOT_TRUE: {
|
|
438
|
+
const settingsLink = html`<button
|
|
439
|
+
class="link" role="link"
|
|
440
|
+
jslog=${VisualLogging.action('open-ai-settings').track({click: true})}
|
|
441
|
+
@click=${input.onEnableInsightsInSettingsLink}
|
|
442
|
+
>${i18nString(UIStrings.settingsLink)}</button>`;
|
|
443
|
+
|
|
444
|
+
return html`<main class="opt-in-teaser" jslog=${jslog}>
|
|
445
|
+
<div class="badge">
|
|
446
|
+
<devtools-icon name="lightbulb-spark" class="medium">
|
|
447
|
+
</devtools-icon>
|
|
448
|
+
</div>
|
|
449
|
+
<div>
|
|
450
|
+
${i18nTemplate(UIStrings.turnOnInSettings, {PH1: settingsLink})} ${
|
|
451
|
+
renderLearnMoreAboutInsights()}
|
|
452
|
+
</div>
|
|
453
|
+
</main>`;
|
|
454
|
+
}
|
|
455
|
+
case State.NOT_LOGGED_IN:
|
|
456
|
+
case State.SYNC_IS_PAUSED:
|
|
457
|
+
return html`
|
|
458
|
+
<main jslog=${jslog}>
|
|
459
|
+
<div class="error">${Root.Runtime.hostConfig.isOffTheRecord ? i18nString(UIStrings.notAvailableInIncognitoMode) : i18nString(UIStrings.notLoggedIn)}</div>
|
|
460
|
+
</main>`;
|
|
461
|
+
case State.OFFLINE:
|
|
462
|
+
return html`
|
|
463
|
+
<main jslog=${jslog}>
|
|
464
|
+
<div class="error">${i18nString(UIStrings.offline)}</div>
|
|
465
|
+
</main>`;
|
|
466
|
+
}
|
|
467
|
+
// clang-format on
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
function renderDisclaimer(input: ViewInput): Lit.LitTemplate {
|
|
471
|
+
// clang-format off
|
|
472
|
+
return html`<span>
|
|
473
|
+
AI tools may generate inaccurate info that doesn't represent Google's views. ${input.noLogging
|
|
474
|
+
? 'The content you submit and that is generated by this feature will not be used to improve Google’s AI models.'
|
|
475
|
+
: 'Data sent to Google may be seen by human reviewers to improve this feature.'
|
|
476
|
+
} <button class="link" role="link" @click=${input.onDisclaimerSettingsLink}
|
|
477
|
+
jslog=${VisualLogging.action('open-ai-settings').track({click: true})}>
|
|
478
|
+
Open settings
|
|
479
|
+
</button> or <x-link href=${LEARN_MORE_URL}
|
|
480
|
+
class="link" jslog=${VisualLogging.link('learn-more').track({click: true})}>
|
|
481
|
+
learn more
|
|
482
|
+
</x-link>
|
|
483
|
+
</span>`;
|
|
484
|
+
// clang-format on
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
function renderFooter(input: ViewInput): Lit.LitTemplate {
|
|
488
|
+
const disclaimer = renderDisclaimer(input);
|
|
489
|
+
// clang-format off
|
|
490
|
+
switch (input.state.type) {
|
|
491
|
+
case State.LOADING:
|
|
492
|
+
case State.SETTING_IS_NOT_TRUE:
|
|
493
|
+
return Lit.nothing;
|
|
494
|
+
case State.ERROR:
|
|
495
|
+
case State.OFFLINE:
|
|
496
|
+
return html`<footer jslog=${VisualLogging.section('footer')}>
|
|
497
|
+
<div class="disclaimer">
|
|
498
|
+
${disclaimer}
|
|
499
|
+
</div>
|
|
500
|
+
</footer>`;
|
|
501
|
+
case State.NOT_LOGGED_IN:
|
|
502
|
+
case State.SYNC_IS_PAUSED:
|
|
503
|
+
if (Root.Runtime.hostConfig.isOffTheRecord) {
|
|
504
|
+
return Lit.nothing;
|
|
505
|
+
}
|
|
506
|
+
return html`<footer jslog=${VisualLogging.section('footer')}>
|
|
507
|
+
<div class="filler"></div>
|
|
508
|
+
<div>
|
|
509
|
+
<devtools-button
|
|
510
|
+
@click=${input.onGoToSignIn}
|
|
511
|
+
.data=${
|
|
512
|
+
{
|
|
513
|
+
variant: Buttons.Button.Variant.PRIMARY,
|
|
514
|
+
jslogContext: 'update-settings',
|
|
515
|
+
} as Buttons.Button.ButtonData
|
|
516
|
+
}
|
|
517
|
+
>
|
|
518
|
+
${UIStrings.signIn}
|
|
519
|
+
</devtools-button>
|
|
520
|
+
</div>
|
|
521
|
+
</footer>`;
|
|
522
|
+
case State.CONSENT_REMINDER:
|
|
523
|
+
return html`<footer jslog=${VisualLogging.section('footer')}>
|
|
524
|
+
<div class="filler"></div>
|
|
525
|
+
<div class="buttons">
|
|
526
|
+
<devtools-button
|
|
527
|
+
@click=${input.onReminderSettingsLink}
|
|
528
|
+
.data=${
|
|
529
|
+
{
|
|
530
|
+
variant: Buttons.Button.Variant.TONAL,
|
|
531
|
+
jslogContext: 'settings',
|
|
532
|
+
title: 'Settings',
|
|
533
|
+
} as Buttons.Button.ButtonData
|
|
534
|
+
}
|
|
535
|
+
>
|
|
536
|
+
Settings
|
|
537
|
+
</devtools-button>
|
|
538
|
+
<devtools-button
|
|
539
|
+
class='continue-button'
|
|
540
|
+
@click=${input.onConsentReminderConfirmed}
|
|
541
|
+
.data=${
|
|
542
|
+
{
|
|
543
|
+
variant: Buttons.Button.Variant.PRIMARY,
|
|
544
|
+
jslogContext: 'continue',
|
|
545
|
+
title: 'continue',
|
|
546
|
+
} as Buttons.Button.ButtonData
|
|
547
|
+
}
|
|
548
|
+
>
|
|
549
|
+
Continue
|
|
550
|
+
</devtools-button>
|
|
551
|
+
</div>
|
|
552
|
+
</footer>`;
|
|
553
|
+
case State.INSIGHT:
|
|
554
|
+
return html`<footer jslog=${VisualLogging.section('footer')}>
|
|
555
|
+
<div class="disclaimer">
|
|
556
|
+
${disclaimer}
|
|
557
|
+
</div>
|
|
558
|
+
<div class="filler"></div>
|
|
559
|
+
<div class="rating">
|
|
560
|
+
<devtools-button
|
|
561
|
+
data-rating="true"
|
|
562
|
+
.data=${
|
|
563
|
+
{
|
|
564
|
+
variant: Buttons.Button.Variant.ICON_TOGGLE,
|
|
565
|
+
size: Buttons.Button.Size.SMALL,
|
|
566
|
+
iconName: 'thumb-up',
|
|
567
|
+
toggledIconName: 'thumb-up',
|
|
568
|
+
toggleOnClick: false,
|
|
569
|
+
toggleType: Buttons.Button.ToggleType.PRIMARY,
|
|
570
|
+
disabled: input.selectedRating !== undefined,
|
|
571
|
+
toggled: input.selectedRating === true,
|
|
572
|
+
title: i18nString(UIStrings.goodResponse),
|
|
573
|
+
jslogContext: 'thumbs-up',
|
|
574
|
+
} as Buttons.Button.ButtonData
|
|
575
|
+
}
|
|
576
|
+
@click=${input.onRating}
|
|
577
|
+
></devtools-button>
|
|
578
|
+
<devtools-button
|
|
579
|
+
data-rating="false"
|
|
580
|
+
.data=${
|
|
581
|
+
{
|
|
582
|
+
variant: Buttons.Button.Variant.ICON_TOGGLE,
|
|
583
|
+
size: Buttons.Button.Size.SMALL,
|
|
584
|
+
iconName: 'thumb-down',
|
|
585
|
+
toggledIconName: 'thumb-down',
|
|
586
|
+
toggleOnClick: false,
|
|
587
|
+
toggleType: Buttons.Button.ToggleType.PRIMARY,
|
|
588
|
+
disabled: input.selectedRating !== undefined,
|
|
589
|
+
toggled: input.selectedRating === false,
|
|
590
|
+
title: i18nString(UIStrings.badResponse),
|
|
591
|
+
jslogContext: 'thumbs-down',
|
|
592
|
+
} as Buttons.Button.ButtonData
|
|
593
|
+
}
|
|
594
|
+
@click=${input.onRating}
|
|
595
|
+
></devtools-button>
|
|
596
|
+
<devtools-button
|
|
597
|
+
.data=${
|
|
598
|
+
{
|
|
599
|
+
variant: Buttons.Button.Variant.ICON,
|
|
600
|
+
size: Buttons.Button.Size.SMALL,
|
|
601
|
+
iconName: 'report',
|
|
602
|
+
title: i18nString(UIStrings.report),
|
|
603
|
+
jslogContext: 'report',
|
|
604
|
+
} as Buttons.Button.ButtonData
|
|
605
|
+
}
|
|
606
|
+
@click=${input.onReport}
|
|
607
|
+
></devtools-button>
|
|
608
|
+
</div>
|
|
609
|
+
|
|
610
|
+
</footer>`;
|
|
611
|
+
}
|
|
612
|
+
// clang-format on
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
function getHeader(state: StateData): string {
|
|
616
|
+
switch (state.type) {
|
|
617
|
+
case State.NOT_LOGGED_IN:
|
|
618
|
+
case State.SYNC_IS_PAUSED:
|
|
619
|
+
return i18nString(UIStrings.signInToUse);
|
|
620
|
+
case State.OFFLINE:
|
|
621
|
+
return i18nString(UIStrings.offlineHeader);
|
|
622
|
+
case State.LOADING:
|
|
623
|
+
return i18nString(UIStrings.generating);
|
|
624
|
+
case State.INSIGHT:
|
|
625
|
+
return i18nString(UIStrings.insight);
|
|
626
|
+
case State.ERROR:
|
|
627
|
+
return i18nString(UIStrings.error);
|
|
628
|
+
case State.CONSENT_REMINDER:
|
|
629
|
+
return 'Understand console messages with AI';
|
|
630
|
+
case State.SETTING_IS_NOT_TRUE:
|
|
631
|
+
return ''; // not reached
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
function renderSpinner(state: StateData): Lit.LitTemplate {
|
|
636
|
+
// clang-format off
|
|
637
|
+
if (state.type === State.INSIGHT && !state.completed) {
|
|
638
|
+
return html`<devtools-spinner></devtools-spinner>`;
|
|
639
|
+
}
|
|
640
|
+
return Lit.nothing;
|
|
641
|
+
// clang-format on
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
function renderHeader(input: ViewInput): Lit.LitTemplate {
|
|
645
|
+
if (input.state.type === State.SETTING_IS_NOT_TRUE) {
|
|
646
|
+
return Lit.nothing;
|
|
647
|
+
}
|
|
648
|
+
const hasIcon = input.state.type === State.CONSENT_REMINDER;
|
|
649
|
+
// clang-format off
|
|
650
|
+
return html`
|
|
651
|
+
<header>
|
|
652
|
+
${hasIcon ? html`
|
|
653
|
+
<div class="header-icon-container">
|
|
654
|
+
<devtools-icon name="lightbulb-spark" class="large">
|
|
655
|
+
</devtools-icon>
|
|
656
|
+
</div>`
|
|
657
|
+
: Lit.nothing}
|
|
658
|
+
<div class="filler">
|
|
659
|
+
<h2 tabindex="-1">
|
|
660
|
+
${getHeader(input.state)}
|
|
661
|
+
</h2>
|
|
662
|
+
${renderSpinner(input.state)}
|
|
663
|
+
</div>
|
|
664
|
+
<div class="close-button">
|
|
665
|
+
<devtools-button
|
|
666
|
+
.data=${
|
|
667
|
+
{
|
|
668
|
+
variant: Buttons.Button.Variant.ICON,
|
|
669
|
+
size: Buttons.Button.Size.SMALL,
|
|
670
|
+
iconName: 'cross',
|
|
671
|
+
title: i18nString(UIStrings.closeInsight),
|
|
672
|
+
} as Buttons.Button.ButtonData
|
|
673
|
+
}
|
|
674
|
+
jslog=${VisualLogging.close().track({click: true})}
|
|
675
|
+
@click=${input.onClose}
|
|
676
|
+
></devtools-button>
|
|
677
|
+
</div>
|
|
678
|
+
</header>
|
|
679
|
+
`;
|
|
680
|
+
// clang-format on
|
|
681
|
+
}
|
|
682
|
+
|
|
250
683
|
export class ConsoleInsight extends HTMLElement {
|
|
251
684
|
static async create(promptBuilder: PublicPromptBuilder, aidaClient: PublicAidaClient): Promise<ConsoleInsight> {
|
|
252
|
-
const
|
|
253
|
-
return new ConsoleInsight(promptBuilder, aidaClient,
|
|
685
|
+
const aidaPreconditions = await Host.AidaClient.AidaClient.checkAccessPreconditions();
|
|
686
|
+
return new ConsoleInsight(promptBuilder, aidaClient, aidaPreconditions);
|
|
254
687
|
}
|
|
255
688
|
|
|
256
689
|
readonly #shadow = this.attachShadow({mode: 'open'});
|
|
@@ -270,17 +703,17 @@ export class ConsoleInsight extends HTMLElement {
|
|
|
270
703
|
#selectedRating?: boolean;
|
|
271
704
|
|
|
272
705
|
#consoleInsightsEnabledSetting: Common.Settings.Setting<boolean>|undefined;
|
|
273
|
-
#
|
|
706
|
+
#aidaPreconditions: Host.AidaClient.AidaAccessPreconditions;
|
|
274
707
|
#boundOnAidaAvailabilityChange: () => Promise<void>;
|
|
275
708
|
#marked: Marked.Marked.Marked;
|
|
276
709
|
|
|
277
710
|
constructor(
|
|
278
711
|
promptBuilder: PublicPromptBuilder, aidaClient: PublicAidaClient,
|
|
279
|
-
|
|
712
|
+
aidaPreconditions: Host.AidaClient.AidaAccessPreconditions) {
|
|
280
713
|
super();
|
|
281
714
|
this.#promptBuilder = promptBuilder;
|
|
282
715
|
this.#aidaClient = aidaClient;
|
|
283
|
-
this.#
|
|
716
|
+
this.#aidaPreconditions = aidaPreconditions;
|
|
284
717
|
this.#consoleInsightsEnabledSetting = this.#getConsoleInsightsEnabledSetting();
|
|
285
718
|
this.#renderer = new MarkdownView.MarkdownView.MarkdownInsightRenderer(this.#citationClickHandler.bind(this));
|
|
286
719
|
this.#marked = new Marked.Marked.Marked({extensions: [markedExtension]});
|
|
@@ -330,7 +763,7 @@ export class ConsoleInsight extends HTMLElement {
|
|
|
330
763
|
}
|
|
331
764
|
|
|
332
765
|
#getStateFromAidaAvailability(): StateData {
|
|
333
|
-
switch (this.#
|
|
766
|
+
switch (this.#aidaPreconditions) {
|
|
334
767
|
case Host.AidaClient.AidaAccessPreconditions.AVAILABLE: {
|
|
335
768
|
// Allows skipping the consent reminder if the user enabled the feature via settings in the current session
|
|
336
769
|
const skipReminder =
|
|
@@ -400,8 +833,8 @@ export class ConsoleInsight extends HTMLElement {
|
|
|
400
833
|
|
|
401
834
|
async #onAidaAvailabilityChange(): Promise<void> {
|
|
402
835
|
const currentAidaAvailability = await Host.AidaClient.AidaClient.checkAccessPreconditions();
|
|
403
|
-
if (currentAidaAvailability !== this.#
|
|
404
|
-
this.#
|
|
836
|
+
if (currentAidaAvailability !== this.#aidaPreconditions) {
|
|
837
|
+
this.#aidaPreconditions = currentAidaAvailability;
|
|
405
838
|
this.#state = this.#getStateFromAidaAvailability();
|
|
406
839
|
void this.#generateInsightIfNeeded();
|
|
407
840
|
}
|
|
@@ -528,7 +961,7 @@ export class ConsoleInsight extends HTMLElement {
|
|
|
528
961
|
#insertCitations(explanation: string, metadata: Host.AidaClient.ResponseMetadata):
|
|
529
962
|
{explanationWithCitations: string, directCitationUrls: string[]} {
|
|
530
963
|
const directCitationUrls: string[] = [];
|
|
531
|
-
if (!
|
|
964
|
+
if (!isSearchRagResponse(metadata) || !metadata.attributionMetadata) {
|
|
532
965
|
return {explanationWithCitations: explanation, directCitationUrls};
|
|
533
966
|
}
|
|
534
967
|
|
|
@@ -576,10 +1009,33 @@ export class ConsoleInsight extends HTMLElement {
|
|
|
576
1009
|
}
|
|
577
1010
|
}
|
|
578
1011
|
|
|
1012
|
+
#deriveRelatedUrls(directCitationUrls: string[], metadata: Host.AidaClient.ResponseMetadata): string[] {
|
|
1013
|
+
if (!metadata.factualityMetadata?.facts.length) {
|
|
1014
|
+
return [];
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
const relatedUrls =
|
|
1018
|
+
metadata.factualityMetadata.facts.filter(fact => fact.sourceUri && !directCitationUrls.includes(fact.sourceUri))
|
|
1019
|
+
.map(fact => fact.sourceUri as string) ||
|
|
1020
|
+
[];
|
|
1021
|
+
const trainingDataUrls =
|
|
1022
|
+
metadata.attributionMetadata?.citations
|
|
1023
|
+
.filter(
|
|
1024
|
+
citation => citation.sourceType === Host.AidaClient.CitationSourceType.TRAINING_DATA &&
|
|
1025
|
+
(citation.uri || citation.repository))
|
|
1026
|
+
.map(citation => citation.uri || `https://www.github.com/${citation.repository}`) ||
|
|
1027
|
+
[];
|
|
1028
|
+
const dedupedTrainingDataUrls =
|
|
1029
|
+
[...new Set(trainingDataUrls.filter(url => !relatedUrls.includes(url) && !directCitationUrls.includes(url)))];
|
|
1030
|
+
relatedUrls.push(...dedupedTrainingDataUrls);
|
|
1031
|
+
return relatedUrls;
|
|
1032
|
+
}
|
|
1033
|
+
|
|
579
1034
|
async #generateInsight(): Promise<void> {
|
|
580
1035
|
try {
|
|
581
1036
|
for await (const {sources, isPageReloadRecommended, explanation, metadata, completed} of this.#getInsight()) {
|
|
582
1037
|
const {explanationWithCitations, directCitationUrls} = this.#insertCitations(explanation, metadata);
|
|
1038
|
+
const relatedUrls = this.#deriveRelatedUrls(directCitationUrls, metadata);
|
|
583
1039
|
const tokens = this.#validateMarkdown(explanationWithCitations);
|
|
584
1040
|
const valid = tokens !== false;
|
|
585
1041
|
if (valid) {
|
|
@@ -595,6 +1051,7 @@ export class ConsoleInsight extends HTMLElement {
|
|
|
595
1051
|
isPageReloadRecommended,
|
|
596
1052
|
completed,
|
|
597
1053
|
directCitationUrls,
|
|
1054
|
+
relatedUrls,
|
|
598
1055
|
});
|
|
599
1056
|
}
|
|
600
1057
|
Host.userMetrics.actionTaken(Host.UserMetrics.Action.InsightGenerated);
|
|
@@ -669,465 +1126,57 @@ export class ConsoleInsight extends HTMLElement {
|
|
|
669
1126
|
}, {once: true});
|
|
670
1127
|
}
|
|
671
1128
|
|
|
672
|
-
#renderSearchButton(): Lit.TemplateResult {
|
|
673
|
-
// clang-format off
|
|
674
|
-
return html`<devtools-button
|
|
675
|
-
@click=${this.#onSearch}
|
|
676
|
-
class="search-button"
|
|
677
|
-
.data=${
|
|
678
|
-
{
|
|
679
|
-
variant: Buttons.Button.Variant.OUTLINED,
|
|
680
|
-
jslogContext: 'search',
|
|
681
|
-
} as Buttons.Button.ButtonData
|
|
682
|
-
}
|
|
683
|
-
>
|
|
684
|
-
${i18nString(UIStrings.search)}
|
|
685
|
-
</devtools-button>`;
|
|
686
|
-
// clang-format on
|
|
687
|
-
}
|
|
688
|
-
|
|
689
|
-
#renderLearnMoreAboutInsights(): Lit.TemplateResult {
|
|
690
|
-
// clang-format off
|
|
691
|
-
return html`<x-link href=${LEARN_MORE_URL} class="link" jslog=${VisualLogging.link('learn-more').track({click: true})}>
|
|
692
|
-
${i18nString(UIStrings.learnMore)}
|
|
693
|
-
</x-link>`;
|
|
694
|
-
// clang-format on
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
#maybeRenderSources(): Lit.LitTemplate {
|
|
698
|
-
if (this.#state.type !== State.INSIGHT || !this.#state.directCitationUrls.length) {
|
|
699
|
-
return Lit.nothing;
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
// clang-format off
|
|
703
|
-
return html`
|
|
704
|
-
<ol class="sources-list">
|
|
705
|
-
${this.#state.directCitationUrls.map((url, index) => html`
|
|
706
|
-
<li>
|
|
707
|
-
<x-link
|
|
708
|
-
href=${url}
|
|
709
|
-
class="link"
|
|
710
|
-
data-index=${index + 1}
|
|
711
|
-
jslog=${VisualLogging.link('references.console-insights').track({click: true})}
|
|
712
|
-
>
|
|
713
|
-
${url}
|
|
714
|
-
</x-link>
|
|
715
|
-
</li>
|
|
716
|
-
`)}
|
|
717
|
-
</ol>
|
|
718
|
-
`;
|
|
719
|
-
// clang-format on
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
#maybeRenderRelatedContent(): Lit.LitTemplate {
|
|
723
|
-
if (this.#state.type !== State.INSIGHT || !this.#state.metadata.factualityMetadata?.facts.length) {
|
|
724
|
-
return Lit.nothing;
|
|
725
|
-
}
|
|
726
|
-
const directCitationUrls = this.#state.directCitationUrls;
|
|
727
|
-
const relatedUrls = this.#state.metadata.factualityMetadata.facts
|
|
728
|
-
.filter(fact => fact.sourceUri && !directCitationUrls.includes(fact.sourceUri))
|
|
729
|
-
.map(fact => fact.sourceUri as string);
|
|
730
|
-
const trainingDataUrls =
|
|
731
|
-
this.#state.metadata.attributionMetadata?.citations
|
|
732
|
-
.filter(
|
|
733
|
-
citation => citation.sourceType === Host.AidaClient.CitationSourceType.TRAINING_DATA &&
|
|
734
|
-
(citation.uri || citation.repository))
|
|
735
|
-
.map(citation => citation.uri || `https://www.github.com/${citation.repository}`) ||
|
|
736
|
-
[];
|
|
737
|
-
const dedupedTrainingDataUrls =
|
|
738
|
-
[...new Set(trainingDataUrls.filter(url => !relatedUrls.includes(url) && !directCitationUrls.includes(url)))];
|
|
739
|
-
relatedUrls.push(...dedupedTrainingDataUrls);
|
|
740
|
-
|
|
741
|
-
if (relatedUrls.length === 0) {
|
|
742
|
-
return Lit.nothing;
|
|
743
|
-
}
|
|
744
|
-
// clang-format off
|
|
745
|
-
return html`
|
|
746
|
-
${this.#state.directCitationUrls.length ? html`<h3>${i18nString(UIStrings.relatedContent)}</h3>` : Lit.nothing}
|
|
747
|
-
<ul class="references-list">
|
|
748
|
-
${relatedUrls.map(relatedUrl => html`
|
|
749
|
-
<li>
|
|
750
|
-
<x-link
|
|
751
|
-
href=${relatedUrl}
|
|
752
|
-
class="link"
|
|
753
|
-
jslog=${VisualLogging.link('references.console-insights').track({click: true})}
|
|
754
|
-
>
|
|
755
|
-
${relatedUrl}
|
|
756
|
-
</x-link>
|
|
757
|
-
</li>
|
|
758
|
-
`)}
|
|
759
|
-
</ul>
|
|
760
|
-
`;
|
|
761
|
-
// clang-format on
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
#isSearchRagResponse(metadata: Host.AidaClient.ResponseMetadata): boolean {
|
|
765
|
-
return Boolean(metadata.factualityMetadata?.facts.length);
|
|
766
|
-
}
|
|
767
|
-
|
|
768
1129
|
#onToggleReferenceDetails(): void {
|
|
769
1130
|
if (this.#referenceDetailsRef.value) {
|
|
770
1131
|
this.#areReferenceDetailsOpen = this.#referenceDetailsRef.value.open;
|
|
771
1132
|
}
|
|
772
1133
|
}
|
|
773
1134
|
|
|
774
|
-
#
|
|
775
|
-
|
|
776
|
-
const noLogging = Root.Runtime.hostConfig.aidaAvailability?.enterprisePolicyValue ===
|
|
777
|
-
Root.Runtime.GenAiEnterprisePolicyValue.ALLOW_WITHOUT_LOGGING;
|
|
778
|
-
|
|
779
|
-
// clang-format off
|
|
780
|
-
switch (this.#state.type) {
|
|
781
|
-
case State.LOADING:
|
|
782
|
-
return html`<main jslog=${jslog}>
|
|
783
|
-
<div role="presentation" aria-label="Loading" class="loader" style="clip-path: url('#clipPath');">
|
|
784
|
-
<svg width="100%" height="64">
|
|
785
|
-
<clipPath id="clipPath">
|
|
786
|
-
<rect x="0" y="0" width="100%" height="16" rx="8"></rect>
|
|
787
|
-
<rect x="0" y="24" width="100%" height="16" rx="8"></rect>
|
|
788
|
-
<rect x="0" y="48" width="100%" height="16" rx="8"></rect>
|
|
789
|
-
</clipPath>
|
|
790
|
-
</svg>
|
|
791
|
-
</div>
|
|
792
|
-
</main>`;
|
|
793
|
-
case State.INSIGHT:
|
|
794
|
-
return html`
|
|
795
|
-
<main jslog=${jslog}>
|
|
796
|
-
${
|
|
797
|
-
this.#state.validMarkdown ? html`<devtools-markdown-view
|
|
798
|
-
.data=${{tokens: this.#state.tokens, renderer: this.#renderer, animationEnabled: !this.disableAnimations} as MarkdownView.MarkdownView.MarkdownViewData}>
|
|
799
|
-
</devtools-markdown-view>`: this.#state.explanation
|
|
800
|
-
}
|
|
801
|
-
${this.#state.timedOut ? html`<p class="error-message">${i18nString(UIStrings.timedOut)}</p>` : Lit.nothing}
|
|
802
|
-
${this.#isSearchRagResponse(this.#state.metadata) ? html`
|
|
803
|
-
<details class="references" ${Lit.Directives.ref(this.#referenceDetailsRef)} @toggle=${this.#onToggleReferenceDetails} jslog=${VisualLogging.expand('references').track({click: true})}>
|
|
804
|
-
<summary>${i18nString(UIStrings.references)}</summary>
|
|
805
|
-
${this.#maybeRenderSources()}
|
|
806
|
-
${this.#maybeRenderRelatedContent()}
|
|
807
|
-
</details>
|
|
808
|
-
` : Lit.nothing}
|
|
809
|
-
<details jslog=${VisualLogging.expand('sources').track({click: true})}>
|
|
810
|
-
<summary>${i18nString(UIStrings.inputData)}</summary>
|
|
811
|
-
<devtools-console-insight-sources-list .sources=${this.#state.sources} .isPageReloadRecommended=${this.#state.isPageReloadRecommended}>
|
|
812
|
-
</devtools-console-insight-sources-list>
|
|
813
|
-
</details>
|
|
814
|
-
<div class="buttons">
|
|
815
|
-
${this.#renderSearchButton()}
|
|
816
|
-
</div>
|
|
817
|
-
</main>`;
|
|
818
|
-
case State.ERROR:
|
|
819
|
-
return html`
|
|
820
|
-
<main jslog=${jslog}>
|
|
821
|
-
<div class="error">${i18nString(UIStrings.errorBody)}</div>
|
|
822
|
-
</main>`;
|
|
823
|
-
case State.CONSENT_REMINDER:
|
|
824
|
-
return html`
|
|
825
|
-
<main class="reminder-container" jslog=${jslog}>
|
|
826
|
-
<h3>Things to consider</h3>
|
|
827
|
-
<div class="reminder-items">
|
|
828
|
-
<div>
|
|
829
|
-
<devtools-icon name="google" class="medium">
|
|
830
|
-
</devtools-icon>
|
|
831
|
-
</div>
|
|
832
|
-
<div>The console message, associated stack trace, related source code, and the associated network headers are sent to Google to generate explanations. ${noLogging
|
|
833
|
-
? 'The content you submit and that is generated by this feature will not be used to improve Google’s AI models.'
|
|
834
|
-
: 'This data may be seen by human reviewers to improve this feature. Avoid sharing sensitive or personal information.'}
|
|
835
|
-
</div>
|
|
836
|
-
<div>
|
|
837
|
-
<devtools-icon name="policy" class="medium">
|
|
838
|
-
</devtools-icon>
|
|
839
|
-
</div>
|
|
840
|
-
<div>Use of this feature is subject to the <x-link
|
|
841
|
-
href=${TERMS_OF_SERVICE_URL}
|
|
842
|
-
class="link"
|
|
843
|
-
jslog=${VisualLogging.link('terms-of-service.console-insights').track({click: true})}>
|
|
844
|
-
Google Terms of Service
|
|
845
|
-
</x-link> and <x-link
|
|
846
|
-
href=${PRIVACY_POLICY_URL}
|
|
847
|
-
class="link"
|
|
848
|
-
jslog=${VisualLogging.link('privacy-policy.console-insights').track({click: true})}>
|
|
849
|
-
Google Privacy Policy
|
|
850
|
-
</x-link>
|
|
851
|
-
</div>
|
|
852
|
-
<div>
|
|
853
|
-
<devtools-icon name="warning" class="medium">
|
|
854
|
-
</devtools-icon>
|
|
855
|
-
</div>
|
|
856
|
-
<div>
|
|
857
|
-
<x-link
|
|
858
|
-
href=${CODE_SNIPPET_WARNING_URL}
|
|
859
|
-
class="link"
|
|
860
|
-
jslog=${VisualLogging.link('code-snippets-explainer.console-insights').track({click: true})}
|
|
861
|
-
>Use generated code snippets with caution</x-link>
|
|
862
|
-
</div>
|
|
863
|
-
</div>
|
|
864
|
-
</main>
|
|
865
|
-
`;
|
|
866
|
-
case State.SETTING_IS_NOT_TRUE: {
|
|
867
|
-
const settingsLink = html`<button
|
|
868
|
-
class="link" role="link"
|
|
869
|
-
jslog=${VisualLogging.action('open-ai-settings').track({click: true})}
|
|
870
|
-
@click=${() => {
|
|
871
|
-
Host.userMetrics.actionTaken(Host.UserMetrics.Action.InsightsOptInTeaserSettingsLinkClicked);
|
|
872
|
-
void UI.ViewManager.ViewManager.instance().showView('chrome-ai');
|
|
873
|
-
}}
|
|
874
|
-
>${i18nString(UIStrings.settingsLink)}</button>`;
|
|
875
|
-
|
|
876
|
-
return html`<main class="opt-in-teaser" jslog=${jslog}>
|
|
877
|
-
<div class="badge">
|
|
878
|
-
<devtools-icon name="lightbulb-spark" class="medium">
|
|
879
|
-
</devtools-icon>
|
|
880
|
-
</div>
|
|
881
|
-
<div>
|
|
882
|
-
${i18nTemplate(UIStrings.turnOnInSettings, {PH1: settingsLink})} ${
|
|
883
|
-
this.#renderLearnMoreAboutInsights()}
|
|
884
|
-
</div>
|
|
885
|
-
</main>`;
|
|
886
|
-
}
|
|
887
|
-
case State.NOT_LOGGED_IN:
|
|
888
|
-
case State.SYNC_IS_PAUSED:
|
|
889
|
-
return html`
|
|
890
|
-
<main jslog=${jslog}>
|
|
891
|
-
<div class="error">${Root.Runtime.hostConfig.isOffTheRecord ? i18nString(UIStrings.notAvailableInIncognitoMode) : i18nString(UIStrings.notLoggedIn)}</div>
|
|
892
|
-
</main>`;
|
|
893
|
-
case State.OFFLINE:
|
|
894
|
-
return html`
|
|
895
|
-
<main jslog=${jslog}>
|
|
896
|
-
<div class="error">${i18nString(UIStrings.offline)}</div>
|
|
897
|
-
</main>`;
|
|
898
|
-
}
|
|
899
|
-
// clang-format on
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
#renderDisclaimer(): Lit.LitTemplate {
|
|
903
|
-
const noLogging = Root.Runtime.hostConfig.aidaAvailability?.enterprisePolicyValue ===
|
|
904
|
-
Root.Runtime.GenAiEnterprisePolicyValue.ALLOW_WITHOUT_LOGGING;
|
|
905
|
-
|
|
906
|
-
// clang-format off
|
|
907
|
-
return html`<span>
|
|
908
|
-
AI tools may generate inaccurate info that doesn't represent Google's views. ${noLogging
|
|
909
|
-
? 'The content you submit and that is generated by this feature will not be used to improve Google’s AI models.'
|
|
910
|
-
: 'Data sent to Google may be seen by human reviewers to improve this feature.'
|
|
911
|
-
} <button class="link" role="link" @click=${() => UI.ViewManager.ViewManager.instance().showView('chrome-ai')}
|
|
912
|
-
jslog=${VisualLogging.action('open-ai-settings').track({click: true})}>
|
|
913
|
-
Open settings
|
|
914
|
-
</button> or <x-link href=${LEARN_MORE_URL}
|
|
915
|
-
class="link" jslog=${VisualLogging.link('learn-more').track({click: true})}>
|
|
916
|
-
learn more
|
|
917
|
-
</x-link>
|
|
918
|
-
</span>`;
|
|
919
|
-
// clang-format on
|
|
920
|
-
}
|
|
921
|
-
|
|
922
|
-
#renderFooter(): Lit.LitTemplate {
|
|
923
|
-
const disclaimer = this.#renderDisclaimer();
|
|
924
|
-
// clang-format off
|
|
925
|
-
switch (this.#state.type) {
|
|
926
|
-
case State.LOADING:
|
|
927
|
-
case State.SETTING_IS_NOT_TRUE:
|
|
928
|
-
return Lit.nothing;
|
|
929
|
-
case State.ERROR:
|
|
930
|
-
case State.OFFLINE:
|
|
931
|
-
return html`<footer jslog=${VisualLogging.section('footer')}>
|
|
932
|
-
<div class="disclaimer">
|
|
933
|
-
${disclaimer}
|
|
934
|
-
</div>
|
|
935
|
-
</footer>`;
|
|
936
|
-
case State.NOT_LOGGED_IN:
|
|
937
|
-
case State.SYNC_IS_PAUSED:
|
|
938
|
-
if (Root.Runtime.hostConfig.isOffTheRecord) {
|
|
939
|
-
return Lit.nothing;
|
|
940
|
-
}
|
|
941
|
-
return html`<footer jslog=${VisualLogging.section('footer')}>
|
|
942
|
-
<div class="filler"></div>
|
|
943
|
-
<div>
|
|
944
|
-
<devtools-button
|
|
945
|
-
@click=${this.#onGoToSignIn}
|
|
946
|
-
.data=${
|
|
947
|
-
{
|
|
948
|
-
variant: Buttons.Button.Variant.PRIMARY,
|
|
949
|
-
jslogContext: 'update-settings',
|
|
950
|
-
} as Buttons.Button.ButtonData
|
|
951
|
-
}
|
|
952
|
-
>
|
|
953
|
-
${UIStrings.signIn}
|
|
954
|
-
</devtools-button>
|
|
955
|
-
</div>
|
|
956
|
-
</footer>`;
|
|
957
|
-
case State.CONSENT_REMINDER:
|
|
958
|
-
return html`<footer jslog=${VisualLogging.section('footer')}>
|
|
959
|
-
<div class="filler"></div>
|
|
960
|
-
<div class="buttons">
|
|
961
|
-
<devtools-button
|
|
962
|
-
@click=${() => {
|
|
963
|
-
Host.userMetrics.actionTaken(Host.UserMetrics.Action.InsightsReminderTeaserSettingsLinkClicked);
|
|
964
|
-
void UI.ViewManager.ViewManager.instance().showView('chrome-ai');
|
|
965
|
-
}}
|
|
966
|
-
.data=${
|
|
967
|
-
{
|
|
968
|
-
variant: Buttons.Button.Variant.TONAL,
|
|
969
|
-
jslogContext: 'settings',
|
|
970
|
-
title: 'Settings',
|
|
971
|
-
} as Buttons.Button.ButtonData
|
|
972
|
-
}
|
|
973
|
-
>
|
|
974
|
-
Settings
|
|
975
|
-
</devtools-button>
|
|
976
|
-
<devtools-button
|
|
977
|
-
class='continue-button'
|
|
978
|
-
@click=${this.#onConsentReminderConfirmed}
|
|
979
|
-
.data=${
|
|
980
|
-
{
|
|
981
|
-
variant: Buttons.Button.Variant.PRIMARY,
|
|
982
|
-
jslogContext: 'continue',
|
|
983
|
-
title: 'continue',
|
|
984
|
-
} as Buttons.Button.ButtonData
|
|
985
|
-
}
|
|
986
|
-
>
|
|
987
|
-
Continue
|
|
988
|
-
</devtools-button>
|
|
989
|
-
</div>
|
|
990
|
-
</footer>`;
|
|
991
|
-
case State.INSIGHT:
|
|
992
|
-
return html`<footer jslog=${VisualLogging.section('footer')}>
|
|
993
|
-
<div class="disclaimer">
|
|
994
|
-
${disclaimer}
|
|
995
|
-
</div>
|
|
996
|
-
<div class="filler"></div>
|
|
997
|
-
<div class="rating">
|
|
998
|
-
<devtools-button
|
|
999
|
-
data-rating="true"
|
|
1000
|
-
.data=${
|
|
1001
|
-
{
|
|
1002
|
-
variant: Buttons.Button.Variant.ICON_TOGGLE,
|
|
1003
|
-
size: Buttons.Button.Size.SMALL,
|
|
1004
|
-
iconName: 'thumb-up',
|
|
1005
|
-
toggledIconName: 'thumb-up',
|
|
1006
|
-
toggleOnClick: false,
|
|
1007
|
-
toggleType: Buttons.Button.ToggleType.PRIMARY,
|
|
1008
|
-
disabled: this.#selectedRating !== undefined,
|
|
1009
|
-
toggled: this.#selectedRating === true,
|
|
1010
|
-
title: i18nString(UIStrings.goodResponse),
|
|
1011
|
-
jslogContext: 'thumbs-up',
|
|
1012
|
-
} as Buttons.Button.ButtonData
|
|
1013
|
-
}
|
|
1014
|
-
@click=${this.#onRating}
|
|
1015
|
-
></devtools-button>
|
|
1016
|
-
<devtools-button
|
|
1017
|
-
data-rating="false"
|
|
1018
|
-
.data=${
|
|
1019
|
-
{
|
|
1020
|
-
variant: Buttons.Button.Variant.ICON_TOGGLE,
|
|
1021
|
-
size: Buttons.Button.Size.SMALL,
|
|
1022
|
-
iconName: 'thumb-down',
|
|
1023
|
-
toggledIconName: 'thumb-down',
|
|
1024
|
-
toggleOnClick: false,
|
|
1025
|
-
toggleType: Buttons.Button.ToggleType.PRIMARY,
|
|
1026
|
-
disabled: this.#selectedRating !== undefined,
|
|
1027
|
-
toggled: this.#selectedRating === false,
|
|
1028
|
-
title: i18nString(UIStrings.badResponse),
|
|
1029
|
-
jslogContext: 'thumbs-down',
|
|
1030
|
-
} as Buttons.Button.ButtonData
|
|
1031
|
-
}
|
|
1032
|
-
@click=${this.#onRating}
|
|
1033
|
-
></devtools-button>
|
|
1034
|
-
<devtools-button
|
|
1035
|
-
.data=${
|
|
1036
|
-
{
|
|
1037
|
-
variant: Buttons.Button.Variant.ICON,
|
|
1038
|
-
size: Buttons.Button.Size.SMALL,
|
|
1039
|
-
iconName: 'report',
|
|
1040
|
-
title: i18nString(UIStrings.report),
|
|
1041
|
-
jslogContext: 'report',
|
|
1042
|
-
} as Buttons.Button.ButtonData
|
|
1043
|
-
}
|
|
1044
|
-
@click=${this.#onReport}
|
|
1045
|
-
></devtools-button>
|
|
1046
|
-
</div>
|
|
1047
|
-
|
|
1048
|
-
</footer>`;
|
|
1049
|
-
}
|
|
1050
|
-
// clang-format on
|
|
1051
|
-
}
|
|
1052
|
-
|
|
1053
|
-
#getHeader(): string {
|
|
1054
|
-
switch (this.#state.type) {
|
|
1055
|
-
case State.NOT_LOGGED_IN:
|
|
1056
|
-
case State.SYNC_IS_PAUSED:
|
|
1057
|
-
return i18nString(UIStrings.signInToUse);
|
|
1058
|
-
case State.OFFLINE:
|
|
1059
|
-
return i18nString(UIStrings.offlineHeader);
|
|
1060
|
-
case State.LOADING:
|
|
1061
|
-
return i18nString(UIStrings.generating);
|
|
1062
|
-
case State.INSIGHT:
|
|
1063
|
-
return i18nString(UIStrings.insight);
|
|
1064
|
-
case State.ERROR:
|
|
1065
|
-
return i18nString(UIStrings.error);
|
|
1066
|
-
case State.CONSENT_REMINDER:
|
|
1067
|
-
return 'Understand console messages with AI';
|
|
1068
|
-
case State.SETTING_IS_NOT_TRUE:
|
|
1069
|
-
return ''; // not reached
|
|
1070
|
-
}
|
|
1135
|
+
#onDisclaimerSettingsLink(): void {
|
|
1136
|
+
void UI.ViewManager.ViewManager.instance().showView('chrome-ai');
|
|
1071
1137
|
}
|
|
1072
1138
|
|
|
1073
|
-
#
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
return html`<devtools-spinner></devtools-spinner>`;
|
|
1077
|
-
}
|
|
1078
|
-
return Lit.nothing;
|
|
1079
|
-
// clang-format on
|
|
1139
|
+
#onReminderSettingsLink(): void {
|
|
1140
|
+
Host.userMetrics.actionTaken(Host.UserMetrics.Action.InsightsReminderTeaserSettingsLinkClicked);
|
|
1141
|
+
void UI.ViewManager.ViewManager.instance().showView('chrome-ai');
|
|
1080
1142
|
}
|
|
1081
1143
|
|
|
1082
|
-
#
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
}
|
|
1086
|
-
const hasIcon = this.#state.type === State.CONSENT_REMINDER;
|
|
1087
|
-
// clang-format off
|
|
1088
|
-
return html`
|
|
1089
|
-
<header>
|
|
1090
|
-
${hasIcon ? html`
|
|
1091
|
-
<div class="header-icon-container">
|
|
1092
|
-
<devtools-icon name="lightbulb-spark" class="large">
|
|
1093
|
-
</devtools-icon>
|
|
1094
|
-
</div>`
|
|
1095
|
-
: Lit.nothing}
|
|
1096
|
-
<div class="filler">
|
|
1097
|
-
<h2 tabindex="-1">
|
|
1098
|
-
${this.#getHeader()}
|
|
1099
|
-
</h2>
|
|
1100
|
-
${this.#renderSpinner()}
|
|
1101
|
-
</div>
|
|
1102
|
-
<div class="close-button">
|
|
1103
|
-
<devtools-button
|
|
1104
|
-
.data=${
|
|
1105
|
-
{
|
|
1106
|
-
variant: Buttons.Button.Variant.ICON,
|
|
1107
|
-
size: Buttons.Button.Size.SMALL,
|
|
1108
|
-
iconName: 'cross',
|
|
1109
|
-
title: i18nString(UIStrings.closeInsight),
|
|
1110
|
-
} as Buttons.Button.ButtonData
|
|
1111
|
-
}
|
|
1112
|
-
jslog=${VisualLogging.close().track({click: true})}
|
|
1113
|
-
@click=${this.#onClose}
|
|
1114
|
-
></devtools-button>
|
|
1115
|
-
</div>
|
|
1116
|
-
</header>
|
|
1117
|
-
`;
|
|
1118
|
-
// clang-format on
|
|
1144
|
+
#onEnableInsightsInSettingsLink(): void {
|
|
1145
|
+
Host.userMetrics.actionTaken(Host.UserMetrics.Action.InsightsOptInTeaserSettingsLinkClicked);
|
|
1146
|
+
void UI.ViewManager.ViewManager.instance().showView('chrome-ai');
|
|
1119
1147
|
}
|
|
1120
1148
|
|
|
1121
1149
|
#render(): void {
|
|
1150
|
+
const input: ViewInput = {
|
|
1151
|
+
state: this.#state,
|
|
1152
|
+
disableAnimations: this.disableAnimations,
|
|
1153
|
+
renderer: this.#renderer,
|
|
1154
|
+
selectedRating: this.#selectedRating,
|
|
1155
|
+
noLogging: Root.Runtime.hostConfig.aidaAvailability?.enterprisePolicyValue ===
|
|
1156
|
+
Root.Runtime.GenAiEnterprisePolicyValue.ALLOW_WITHOUT_LOGGING,
|
|
1157
|
+
onClose: this.#onClose.bind(this),
|
|
1158
|
+
onSearch: this.#onSearch.bind(this),
|
|
1159
|
+
onRating: this.#onRating.bind(this),
|
|
1160
|
+
onReport: this.#onReport.bind(this),
|
|
1161
|
+
onGoToSignIn: this.#onGoToSignIn.bind(this),
|
|
1162
|
+
onConsentReminderConfirmed: this.#onConsentReminderConfirmed.bind(this),
|
|
1163
|
+
onToggleReferenceDetails: this.#onToggleReferenceDetails.bind(this),
|
|
1164
|
+
onDisclaimerSettingsLink: this.#onDisclaimerSettingsLink.bind(this),
|
|
1165
|
+
onReminderSettingsLink: this.#onReminderSettingsLink.bind(this),
|
|
1166
|
+
onEnableInsightsInSettingsLink: this.#onEnableInsightsInSettingsLink.bind(this),
|
|
1167
|
+
};
|
|
1168
|
+
const output: ViewOutput = {
|
|
1169
|
+
referenceDetailsRef: this.#referenceDetailsRef,
|
|
1170
|
+
};
|
|
1122
1171
|
// clang-format off
|
|
1123
1172
|
render(html`
|
|
1124
1173
|
<style>${styles}</style>
|
|
1125
1174
|
<style>${Input.checkboxStyles}</style>
|
|
1126
1175
|
<div class="wrapper" jslog=${VisualLogging.pane('console-insights').track({resize: true})}>
|
|
1127
1176
|
<div class="animation-wrapper">
|
|
1128
|
-
${
|
|
1129
|
-
${
|
|
1130
|
-
${
|
|
1177
|
+
${renderHeader(input)}
|
|
1178
|
+
${renderMain(input, output)}
|
|
1179
|
+
${renderFooter(input)}
|
|
1131
1180
|
</div>
|
|
1132
1181
|
</div>
|
|
1133
1182
|
`, this.#shadow, {
|