Skip to content

Commit 9a19cd4

Browse files
Samiya CaurDevtools-frontend LUCI CQ
authored andcommitted
Add AI code completion disclaimer to existing sources toolbar
Bug: 438199108 Change-Id: I08b6e2f1454ba8feb6d4f0d0dd21f42107a7fd4c Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/6841276 Reviewed-by: Ergün Erdoğmuş <[email protected]> Commit-Queue: Samiya Caur <[email protected]>
1 parent db5435d commit 9a19cd4

File tree

8 files changed

+60
-33
lines changed

8 files changed

+60
-33
lines changed

front_end/panels/common/AiCodeCompletionDisclaimer.test.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,10 @@ import * as UI from '../../ui/legacy/legacy.js';
1111
import * as Common from './common.js';
1212

1313
describeWithEnvironment('AiCodeCompletionDisclaimer', () => {
14-
async function createDisclaimer(panelName = 'console') {
14+
async function createDisclaimer() {
1515
const view = createViewFunctionStub(Common.AiCodeCompletionDisclaimer);
1616
const widget = new Common.AiCodeCompletionDisclaimer(undefined, view);
1717
widget.disclaimerTooltipId = 'disclaimer-tooltip';
18-
widget.panelName = panelName;
1918
widget.markAsRoot();
2019
renderElementIntoDOM(widget);
2120
await view.nextInput;

front_end/panels/common/AiCodeCompletionDisclaimer.ts

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ const lockedString = i18n.i18n.lockedString;
4646

4747
export interface ViewInput {
4848
disclaimerTooltipId?: string;
49-
panelName?: string;
5049
noLogging: boolean;
5150
onManageInSettingsTooltipClick: () => void;
5251
}
@@ -58,12 +57,13 @@ export interface ViewOutput {
5857

5958
export type View = (input: ViewInput, output: ViewOutput, target: HTMLElement) => void;
6059

61-
export const DEFAULT_SUMMARY_TOOLBAR_VIEW: View = (input, output, target) => {
62-
if (!input.disclaimerTooltipId || !input.panelName) {
63-
render(nothing, target);
64-
return;
65-
}
66-
// clang-format off
60+
export const DEFAULT_SUMMARY_TOOLBAR_VIEW: View =
61+
(input, output, target) => {
62+
if (!input.disclaimerTooltipId) {
63+
render(nothing, target);
64+
return;
65+
}
66+
// clang-format off
6767
render(
6868
html`
6969
<style>${styles}</style>
@@ -92,7 +92,7 @@ export const DEFAULT_SUMMARY_TOOLBAR_VIEW: View = (input, output, target) => {
9292
<devtools-tooltip
9393
id=${input.disclaimerTooltipId}
9494
variant=${'rich'}
95-
jslogContext=${input.panelName + '.ai-code-completion-disclaimer'}
95+
jslogContext=${'ai-code-completion-disclaimer'}
9696
${Directives.ref(el => {
9797
if (el instanceof HTMLElement) {
9898
output.hideTooltip = () => {
@@ -113,8 +113,8 @@ export const DEFAULT_SUMMARY_TOOLBAR_VIEW: View = (input, output, target) => {
113113
>${lockedString(UIStringsNotTranslate.manageInSettings)}</span></div></devtools-tooltip>
114114
</div class="ai-code-completion-disclaimer">
115115
`, target);
116-
// clang-format on
117-
};
116+
// clang-format on
117+
};
118118

119119
const MINIMUM_LOADING_STATE_TIMEOUT = 1000;
120120

@@ -123,14 +123,14 @@ export class AiCodeCompletionDisclaimer extends UI.Widget.Widget {
123123
#viewOutput: ViewOutput = {};
124124

125125
#disclaimerTooltipId?: string;
126-
#panelName?: string;
127126
#noLogging: boolean; // Whether the enterprise setting is `ALLOW_WITHOUT_LOGGING` or not.
128127
#loading = false;
129128
#loadingStartTime = 0;
130129
#spinnerLoadingTimeout: number|undefined;
131130

132131
constructor(element?: HTMLElement, view: View = DEFAULT_SUMMARY_TOOLBAR_VIEW) {
133132
super(element);
133+
this.markAsExternallyManaged();
134134
this.#noLogging = Root.Runtime.hostConfig.aidaAvailability?.enterprisePolicyValue ===
135135
Root.Runtime.GenAiEnterprisePolicyValue.ALLOW_WITHOUT_LOGGING;
136136
this.#view = view;
@@ -141,11 +141,6 @@ export class AiCodeCompletionDisclaimer extends UI.Widget.Widget {
141141
this.requestUpdate();
142142
}
143143

144-
set panelName(panelName: string) {
145-
this.#panelName = panelName;
146-
this.requestUpdate();
147-
}
148-
149144
set loading(loading: boolean) {
150145
if (!loading && !this.#loading) {
151146
return;
@@ -182,7 +177,6 @@ export class AiCodeCompletionDisclaimer extends UI.Widget.Widget {
182177
this.#view(
183178
{
184179
disclaimerTooltipId: this.#disclaimerTooltipId,
185-
panelName: this.#panelName,
186180
noLogging: this.#noLogging,
187181
onManageInSettingsTooltipClick: this.#onManageInSettingsTooltipClick.bind(this),
188182
},

front_end/panels/common/AiCodeCompletionSummaryToolbar.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ import {createViewFunctionStub} from '../../testing/ViewFunctionHelpers.js';
99
import * as Common from './common.js';
1010

1111
describeWithEnvironment('AiCodeCompletionSummaryToolbar', () => {
12-
async function createToolbar(panelName = 'console') {
12+
async function createToolbar() {
1313
const view = createViewFunctionStub(Common.AiCodeCompletionSummaryToolbar);
1414
const widget = new Common.AiCodeCompletionSummaryToolbar(
15-
{citationsTooltipId: 'citations-tooltip', panelName, disclaimerTooltipId: 'disclaimer-tooltip'}, view);
15+
{citationsTooltipId: 'citations-tooltip', disclaimerTooltipId: 'disclaimer-tooltip'}, view);
1616
widget.markAsRoot();
1717
renderElementIntoDOM(widget);
1818
await view.nextInput;

front_end/panels/common/AiCodeCompletionSummaryToolbar.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,11 @@ const lockedString = i18n.i18n.lockedString;
2828

2929
export interface AiCodeCompletionSummaryToolbarProps {
3030
citationsTooltipId: string;
31-
panelName: string;
3231
disclaimerTooltipId?: string;
3332
}
3433

3534
export interface ViewInput {
3635
disclaimerTooltipId?: string;
37-
panelName: string;
3836
citations?: string[];
3937
citationsTooltipId: string;
4038
loading: boolean;
@@ -54,7 +52,6 @@ export const DEFAULT_SUMMARY_TOOLBAR_VIEW: View = (input, _output, target) => {
5452
html`<devtools-widget
5553
.widgetConfig=${UI.Widget.widgetConfig(AiCodeCompletionDisclaimer, {
5654
disclaimerTooltipId: input.disclaimerTooltipId,
57-
panelName: input.panelName,
5855
loading: input.loading,
5956
})} class="disclaimer-widget"></devtools-widget>` : nothing;
6057

@@ -69,12 +66,12 @@ export const DEFAULT_SUMMARY_TOOLBAR_VIEW: View = (input, _output, target) => {
6966
<devtools-tooltip
7067
id=${input.citationsTooltipId}
7168
variant=${'rich'}
72-
jslogContext=${input.panelName + '.ai-code-completion-citations'}
69+
jslogContext=${'ai-code-completion-citations'}
7370
><div class="citations-tooltip-container">
7471
${Directives.repeat(input.citations, citation => html`<x-link
7572
tabIndex="0"
7673
href=${citation}
77-
jslog=${VisualLogging.link(input.panelName + '.ai-code-completion-citations.citation-link').track({
74+
jslog=${VisualLogging.link('ai-code-completion-citations.citation-link').track({
7875
click: true
7976
})}>${citation}</x-link>`)}</div></devtools-tooltip>
8077
</div>` : nothing;
@@ -95,15 +92,13 @@ export class AiCodeCompletionSummaryToolbar extends UI.Widget.Widget {
9592

9693
#disclaimerTooltipId?: string;
9794
#citationsTooltipId: string;
98-
#panelName: string;
9995
#citations: string[] = [];
10096
#loading = false;
10197

10298
constructor(props: AiCodeCompletionSummaryToolbarProps, view?: View) {
10399
super();
104100
this.#disclaimerTooltipId = props.disclaimerTooltipId;
105101
this.#citationsTooltipId = props.citationsTooltipId;
106-
this.#panelName = props.panelName;
107102
this.#view = view ?? DEFAULT_SUMMARY_TOOLBAR_VIEW;
108103
this.requestUpdate();
109104
}
@@ -133,7 +128,6 @@ export class AiCodeCompletionSummaryToolbar extends UI.Widget.Widget {
133128
disclaimerTooltipId: this.#disclaimerTooltipId,
134129
citations: this.#citations,
135130
citationsTooltipId: this.#citationsTooltipId,
136-
panelName: this.#panelName,
137131
loading: this.#loading,
138132
},
139133
undefined, this.contentElement);

front_end/panels/common/aiCodeCompletionDisclaimer.css

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
*/
66

77
@scope to (devtools-widget > *) {
8+
display: flex;
9+
810
.ai-code-completion-disclaimer {
911
gap: 5px;
1012
display: flex;

front_end/panels/console/ConsoleView.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -624,7 +624,7 @@ export class ConsoleView extends UI.Widget.VBox implements
624624

625625
createAiCodeCompletionSummaryToolbar(): void {
626626
this.aiCodeCompletionSummaryToolbar = new AiCodeCompletionSummaryToolbar(
627-
{citationsTooltipId: CITATIONS_TOOLTIP_ID, panelName: 'console', disclaimerTooltipId: DISCLAIMER_TOOLTIP_ID});
627+
{citationsTooltipId: CITATIONS_TOOLTIP_ID, disclaimerTooltipId: DISCLAIMER_TOOLTIP_ID});
628628
this.aiCodeCompletionSummaryToolbarContainer = this.element.createChild('div');
629629
this.aiCodeCompletionSummaryToolbar.show(this.aiCodeCompletionSummaryToolbarContainer, undefined, true);
630630
}

front_end/panels/sources/AiCodeCompletionPlugin.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright 2025 The Chromium Authors. All rights reserved.
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
4+
45
import * as Common from '../../core/common/common.js';
56
import * as Host from '../../core/host/host.js';
67
import * as Root from '../../core/root/root.js';
@@ -15,6 +16,7 @@ import * as PanelCommon from '../common/common.js';
1516
import {Plugin} from './Plugin.js';
1617

1718
const AI_CODE_COMPLETION_CHARACTER_LIMIT = 20_000;
19+
const DISCLAIMER_TOOLTIP_ID = 'sources-ai-code-completion-disclaimer-tooltip';
1820

1921
export class AiCodeCompletionPlugin extends Plugin {
2022
#aidaClient?: Host.AidaClient.AidaClient;
@@ -26,6 +28,9 @@ export class AiCodeCompletionPlugin extends Plugin {
2628
#teaser?: PanelCommon.AiCodeCompletionTeaser;
2729
#teaserDisplayTimeout?: number;
2830
#editor?: TextEditor.TextEditor.TextEditor;
31+
#aiCodeCompletionDisclaimer?: PanelCommon.AiCodeCompletionDisclaimer;
32+
#aiCodeCompletionDisclaimerContainer = document.createElement('div');
33+
#aiCodeCompletionDisclaimerToolbarItem = new UI.Toolbar.ToolbarItem(this.#aiCodeCompletionDisclaimerContainer);
2934

3035
#boundEditorKeyDown: (event: Event) => Promise<void>;
3136
#boundOnAiCodeCompletionSettingChanged: () => void;
@@ -51,6 +56,10 @@ export class AiCodeCompletionPlugin extends Plugin {
5156
this.#teaser = undefined;
5257
this.#aiCodeCompletionSetting.removeChangeListener(this.#boundOnAiCodeCompletionSettingChanged);
5358
this.#editor?.removeEventListener('keydown', this.#boundEditorKeyDown);
59+
this.#aiCodeCompletion?.removeEventListener(
60+
AiCodeCompletion.AiCodeCompletion.Events.REQUEST_TRIGGERED, this.#onAiRequestTriggered, this);
61+
this.#aiCodeCompletion?.removeEventListener(
62+
AiCodeCompletion.AiCodeCompletion.Events.RESPONSE_RECEIVED, this.#onAiResponseReceived, this);
5463
this.#aiCodeCompletion?.remove();
5564
super.dispose();
5665
}
@@ -72,6 +81,10 @@ export class AiCodeCompletionPlugin extends Plugin {
7281
];
7382
}
7483

84+
override rightToolbarItems(): UI.Toolbar.ToolbarItem[] {
85+
return [this.#aiCodeCompletionDisclaimerToolbarItem];
86+
}
87+
7588
#editorUpdate(update: CodeMirror.ViewUpdate): void {
7689
if (this.#teaser) {
7790
if (update.docChanged) {
@@ -181,17 +194,42 @@ export class AiCodeCompletionPlugin extends Plugin {
181194
}
182195
this.#aiCodeCompletion =
183196
new AiCodeCompletion.AiCodeCompletion.AiCodeCompletion({aidaClient: this.#aidaClient}, this.#editor);
197+
this.#aiCodeCompletion.addEventListener(
198+
AiCodeCompletion.AiCodeCompletion.Events.REQUEST_TRIGGERED, this.#onAiRequestTriggered, this);
199+
this.#aiCodeCompletion.addEventListener(
200+
AiCodeCompletion.AiCodeCompletion.Events.RESPONSE_RECEIVED, this.#onAiResponseReceived, this);
201+
}
202+
203+
#createAiCodeCompletionDisclaimer(): void {
204+
this.#aiCodeCompletionDisclaimer = new PanelCommon.AiCodeCompletionDisclaimer();
205+
this.#aiCodeCompletionDisclaimer.disclaimerTooltipId = DISCLAIMER_TOOLTIP_ID;
206+
this.#aiCodeCompletionDisclaimer.show(this.#aiCodeCompletionDisclaimerContainer, undefined, true);
184207
}
185208

186209
#onAiCodeCompletionSettingChanged(): void {
187210
if (this.#aiCodeCompletionSetting.get()) {
188211
this.#setAiCodeCompletion();
212+
this.#createAiCodeCompletionDisclaimer();
189213
} else if (this.#aiCodeCompletion) {
190214
this.#aiCodeCompletion.remove();
191215
this.#aiCodeCompletion = undefined;
216+
this.#aiCodeCompletionDisclaimerContainer.removeChildren();
217+
this.#aiCodeCompletionDisclaimer = undefined;
192218
}
193219
}
194220

221+
#onAiRequestTriggered = (): void => {
222+
if (this.#aiCodeCompletionDisclaimer) {
223+
this.#aiCodeCompletionDisclaimer.loading = true;
224+
}
225+
};
226+
227+
#onAiResponseReceived = (): void => {
228+
if (this.#aiCodeCompletionDisclaimer) {
229+
this.#aiCodeCompletionDisclaimer.loading = false;
230+
}
231+
};
232+
195233
#detachAiCodeCompletionTeaser(): void {
196234
this.#editor?.dispatch({
197235
effects: this.#teaserCompartment.reconfigure([]),

front_end/ui/visual_logging/KnownContextValues.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,9 @@ export const knownContextValues = new Set([
344344
'ai-assistance-history-images',
345345
'ai-assistance-patching-fre-completed',
346346
'ai-assistance-patching-selected-project-id',
347+
'ai-code-completion-citations',
348+
'ai-code-completion-citations.citation-link',
349+
'ai-code-completion-disclaimer',
347350
'ai-code-completion-enabled',
348351
'ai-code-completion-teaser-dismissed',
349352
'ai-code-completion-teaser.dismiss',
@@ -855,9 +858,6 @@ export const knownContextValues = new Set([
855858
'console-user-activation-eval',
856859
'console-user-activation-eval-false',
857860
'console-view',
858-
'console.ai-code-completion-citations',
859-
'console.ai-code-completion-citations.citation-link',
860-
'console.ai-code-completion-disclaimer',
861861
'console.clear',
862862
'console.clear.history',
863863
'console.create-pin',

0 commit comments

Comments
 (0)