Skip to content

Commit edb5cbb

Browse files
Connor ClarkDevtools-frontend LUCI CQ
authored andcommitted
[AI] Update icons, strings, styles for Gemini rebranding
All changesa are behind `--enable-features=DevToolsGeminiRebranding`. Bug: 468206227 Change-Id: Ia00fdfb8252cd09c0bc9d8878a9be435e292a336 Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/7518036 Auto-Submit: Connor Clark <cjamcl@chromium.org> Reviewed-by: Paul Irish <paulirish@chromium.org> Commit-Queue: Connor Clark <cjamcl@chromium.org>
1 parent 9068388 commit edb5cbb

File tree

20 files changed

+179
-31
lines changed

20 files changed

+179
-31
lines changed

front_end/entrypoints/main/GlobalAiButton.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import * as Common from '../../core/common/common.js';
66
import * as i18n from '../../core/i18n/i18n.js';
77
import * as Root from '../../core/root/root.js';
8+
import * as AIAssistance from '../../models/ai_assistance/ai_assistance.js';
89
import * as UI from '../../ui/legacy/legacy.js';
910
import * as Lit from '../../ui/lit/lit.js';
1011
import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
@@ -22,6 +23,14 @@ const UIStrings = {
2223
* @description Button's tooltip text.
2324
*/
2425
openAiAssistance: 'Open AI assistance panel',
26+
/**
27+
* @description Button's string in promotion state.
28+
*/
29+
gemini: 'Gemini',
30+
/**
31+
* @description Button's tooltip text.
32+
*/
33+
openGemini: 'Open Gemini panel',
2534
} as const;
2635
const str_ = i18n.i18n.registerUIStrings('entrypoints/main/GlobalAiButton.ts', UIStrings);
2736
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
@@ -55,13 +64,19 @@ export const DEFAULT_VIEW = (input: ViewInput, output: undefined, target: HTMLEl
5564
'global-ai-button': true,
5665
expanded: inPromotionState,
5766
});
67+
68+
const strings = AIAssistance.AiUtils.isGeminiBranding() ?
69+
{title: i18nString(UIStrings.openGemini), label: i18nString(UIStrings.gemini)} :
70+
{title: i18nString(UIStrings.openAiAssistance), label: i18nString(UIStrings.aiAssistance)};
71+
const icon = AIAssistance.AiUtils.getIconName();
72+
5873
// clang-format off
5974
render(html`
6075
<style>${globalAiButtonStyles}</style>
6176
<div class="global-ai-button-container">
62-
<button class=${classes} @click=${input.onClick} title=${i18nString(UIStrings.openAiAssistance)} jslog=${VisualLogging.action().track({click: true}).context('global-ai-button')}>
63-
<devtools-icon name="smart-assistant"></devtools-icon>
64-
<span class="button-text">${` ${i18nString(UIStrings.aiAssistance)}`}</span>
77+
<button class=${classes} @click=${input.onClick} title=${strings.title} jslog=${VisualLogging.action().track({click: true}).context('global-ai-button')}>
78+
<devtools-icon name=${icon}></devtools-icon>
79+
<span class="button-text">${` ${strings.label}`}</span>
6580
</button>
6681
</div>
6782
`, target);

front_end/models/ai_assistance/AiUtils.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,11 @@ export function getDisabledReasons(aidaAvailability: Host.AidaClient.AidaAccessP
5454
reasons.push(...Common.Settings.Settings.instance().moduleSetting('ai-assistance-enabled').disabledReasons());
5555
return reasons;
5656
}
57+
58+
export function isGeminiBranding(): boolean {
59+
return !!Root.Runtime.hostConfig.devToolsGeminiRebranding?.enabled;
60+
}
61+
62+
export function getIconName(): string {
63+
return isGeminiBranding() ? 'spark' : 'smart-assistant';
64+
}

front_end/models/ai_assistance/BUILD.gn

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,11 @@ devtools_entrypoint("bundle") {
7272
":*",
7373
"../../entrypoints/main/*",
7474
"../../panels/ai_assistance/*",
75+
"../../panels/common/*",
7576
"../../panels/console/*",
77+
"../../panels/elements/*",
7678
"../../panels/settings/*",
79+
"../../panels/sources/*",
7780
"../../panels/timeline/*",
7881
"../ai_code_completion",
7982
"./data_formatters:*",

front_end/panels/ai_assistance/PatchWidget.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -556,8 +556,9 @@ export class PatchWidget extends UI.Widget.Widget {
556556
return true;
557557
}
558558

559+
const iconName = AiAssistanceModel.AiUtils.getIconName();
559560
const result = await PanelCommon.FreDialog.show({
560-
header: {iconName: 'smart-assistant', text: lockedString(UIStringsNotTranslate.freDisclaimerHeader)},
561+
header: {iconName, text: lockedString(UIStringsNotTranslate.freDisclaimerHeader)},
561562
reminderItems: [
562563
{
563564
iconName: 'psychiatry',

front_end/panels/ai_assistance/ai_assistance-meta.ts

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import * as Common from '../../core/common/common.js';
66
import * as i18n from '../../core/i18n/i18n.js';
77
import type * as Platform from '../../core/platform/platform.js';
8-
import type * as Root from '../../core/root/root.js';
8+
import * as Root from '../../core/root/root.js';
99
import * as UI from '../../ui/legacy/legacy.js';
1010

1111
import type * as AiAssistance from './ai_assistance.js';
@@ -34,6 +34,22 @@ const UIStrings = {
3434
* the current context
3535
*/
3636
debugWithAi: 'Debug with AI',
37+
/**
38+
* @description The title of the Gemini panel.
39+
*/
40+
gemini: 'Gemini',
41+
/**
42+
* @description The title of the command menu action for showing the Gemini panel.
43+
*/
44+
showGemini: 'Show Gemini',
45+
/**
46+
* @description The setting title to enable the Gemini via the settings tab.
47+
*/
48+
enableGemini: 'Enable Gemini',
49+
/**
50+
* @description Text of a context menu item to redirect to the Gemini panel with the current context
51+
*/
52+
debugWithGemini: 'Debug with Gemini',
3753
/**
3854
* @description Message shown to the user if the DevTools locale is not
3955
* supported.
@@ -53,7 +69,12 @@ const UIStrings = {
5369

5470
const str_ = i18n.i18n.registerUIStrings('panels/ai_assistance/ai_assistance-meta.ts', UIStrings);
5571
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
56-
const i18nLazyString = i18n.i18n.getLazilyComputedLocalizedString.bind(undefined, str_);
72+
73+
// Host config is initialized after this module executes, so need to lazily select the string.
74+
function i18nAiBrandedString(gemini: string, assistance: string) {
75+
// eslint-disable-next-line @devtools/l10n-i18nString-call-only-with-uistrings
76+
return () => Root.Runtime.hostConfig.devToolsGeminiRebranding?.enabled ? i18nString(gemini) : i18nString(assistance);
77+
}
5778

5879
const setting = 'ai-assistance-enabled';
5980

@@ -102,8 +123,8 @@ function isAnyFeatureAvailable(config?: Root.Runtime.HostConfig): boolean {
102123
UI.ViewManager.registerViewExtension({
103124
location: UI.ViewManager.ViewLocationValues.DRAWER_VIEW,
104125
id: 'freestyler',
105-
commandPrompt: i18nLazyString(UIStrings.showAiAssistance),
106-
title: i18nLazyString(UIStrings.aiAssistance),
126+
commandPrompt: i18nAiBrandedString(UIStrings.showGemini, UIStrings.showAiAssistance),
127+
title: i18nAiBrandedString(UIStrings.gemini, UIStrings.aiAssistance),
107128
order: 10,
108129
persistence: UI.ViewManager.ViewPersistence.CLOSEABLE,
109130
hasToolbar: false,
@@ -118,7 +139,7 @@ Common.Settings.registerSettingExtension({
118139
category: Common.Settings.SettingCategory.AI,
119140
settingName: setting,
120141
settingType: Common.Settings.SettingType.BOOLEAN,
121-
title: i18nLazyString(UIStrings.enableAiAssistance),
142+
title: i18nAiBrandedString(UIStrings.enableGemini, UIStrings.enableAiAssistance),
122143
defaultValue: false,
123144
reloadRequired: false,
124145
condition: isAnyFeatureAvailable,
@@ -146,7 +167,7 @@ UI.ActionRegistration.registerActionExtension({
146167
return [];
147168
},
148169
category: UI.ActionRegistration.ActionCategory.GLOBAL,
149-
title: i18nLazyString(UIStrings.debugWithAi),
170+
title: i18nAiBrandedString(UIStrings.debugWithGemini, UIStrings.debugWithAi),
150171
configurableBindings: false,
151172
async loadActionDelegate() {
152173
const AiAssistance = await loadAiAssistanceModule();
@@ -161,7 +182,7 @@ UI.ActionRegistration.registerActionExtension({
161182
return [];
162183
},
163184
category: UI.ActionRegistration.ActionCategory.GLOBAL,
164-
title: i18nLazyString(UIStrings.debugWithAi),
185+
title: i18nAiBrandedString(UIStrings.debugWithGemini, UIStrings.debugWithAi),
165186
configurableBindings: false,
166187
async loadActionDelegate() {
167188
const AiAssistance = await loadAiAssistanceModule();
@@ -177,7 +198,7 @@ UI.ActionRegistration.registerActionExtension({
177198
return [];
178199
},
179200
category: UI.ActionRegistration.ActionCategory.GLOBAL,
180-
title: i18nLazyString(UIStrings.debugWithAi),
201+
title: i18nAiBrandedString(UIStrings.debugWithGemini, UIStrings.debugWithAi),
181202
configurableBindings: false,
182203
async loadActionDelegate() {
183204
const AiAssistance = await loadAiAssistanceModule();
@@ -193,7 +214,7 @@ UI.ActionRegistration.registerActionExtension({
193214
return [];
194215
},
195216
category: UI.ActionRegistration.ActionCategory.GLOBAL,
196-
title: i18nLazyString(UIStrings.debugWithAi),
217+
title: i18nAiBrandedString(UIStrings.debugWithGemini, UIStrings.debugWithAi),
197218
configurableBindings: false,
198219
async loadActionDelegate() {
199220
const AiAssistance = await loadAiAssistanceModule();
@@ -209,7 +230,7 @@ UI.ActionRegistration.registerActionExtension({
209230
return [];
210231
},
211232
category: UI.ActionRegistration.ActionCategory.GLOBAL,
212-
title: i18nLazyString(UIStrings.debugWithAi),
233+
title: i18nAiBrandedString(UIStrings.debugWithGemini, UIStrings.debugWithAi),
213234
configurableBindings: false,
214235
async loadActionDelegate() {
215236
const AiAssistance = await loadAiAssistanceModule();
@@ -225,7 +246,7 @@ UI.ActionRegistration.registerActionExtension({
225246
return [];
226247
},
227248
category: UI.ActionRegistration.ActionCategory.GLOBAL,
228-
title: i18nLazyString(UIStrings.debugWithAi),
249+
title: i18nAiBrandedString(UIStrings.debugWithGemini, UIStrings.debugWithAi),
229250
configurableBindings: false,
230251
async loadActionDelegate() {
231252
const AiAssistance = await loadAiAssistanceModule();
@@ -241,7 +262,7 @@ UI.ActionRegistration.registerActionExtension({
241262
return [];
242263
},
243264
category: UI.ActionRegistration.ActionCategory.GLOBAL,
244-
title: i18nLazyString(UIStrings.debugWithAi),
265+
title: i18nAiBrandedString(UIStrings.debugWithGemini, UIStrings.debugWithAi),
245266
configurableBindings: false,
246267
async loadActionDelegate() {
247268
const AiAssistance = await loadAiAssistanceModule();
@@ -256,7 +277,7 @@ UI.ActionRegistration.registerActionExtension({
256277
return [];
257278
},
258279
category: UI.ActionRegistration.ActionCategory.GLOBAL,
259-
title: i18nLazyString(UIStrings.debugWithAi),
280+
title: i18nAiBrandedString(UIStrings.debugWithGemini, UIStrings.debugWithAi),
260281
configurableBindings: false,
261282
async loadActionDelegate() {
262283
const AiAssistance = await loadAiAssistanceModule();

front_end/panels/ai_assistance/components/ChatMessage.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,8 @@ export const DEFAULT_VIEW = (input: ChatMessageViewInput, output: ViewOutput, ta
292292
return;
293293
}
294294

295+
const icon = AiAssistanceModel.AiUtils.getIconName();
296+
295297
// clang-format off
296298
Lit.render(html`
297299
<style>${Input.textInputStyles}</style>
@@ -301,7 +303,7 @@ export const DEFAULT_VIEW = (input: ChatMessageViewInput, output: ViewOutput, ta
301303
jslog=${VisualLogging.section('answer')}
302304
>
303305
<div class="message-info">
304-
<devtools-icon name="smart-assistant"></devtools-icon>
306+
<devtools-icon name=${icon}></devtools-icon>
305307
<div class="message-name">
306308
<h2>${lockedString(UIStringsNotTranslate.ai)}</h2>
307309
</div>

front_end/panels/ai_assistance/components/ChatView.ts

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import '../../../ui/components/spinners/spinners.js';
77
import * as Host from '../../../core/host/host.js';
88
import * as i18n from '../../../core/i18n/i18n.js';
99
import type * as Platform from '../../../core/platform/platform.js';
10-
import type * as AiAssistanceModel from '../../../models/ai_assistance/ai_assistance.js';
10+
import * as AiAssistanceModel from '../../../models/ai_assistance/ai_assistance.js';
1111
import * as Buttons from '../../../ui/components/buttons/buttons.js';
1212
import type {MarkdownLitRenderer} from '../../../ui/components/markdown_view/MarkdownView.js';
1313
import * as UI from '../../../ui/legacy/legacy.js';
@@ -30,6 +30,10 @@ const UIStringsNotTranslate = {
3030
* @description Text for the empty state of the AI assistance panel.
3131
*/
3232
emptyStateText: 'How can I help you?',
33+
/**
34+
* @description Text for the empty state of the Gemini panel.
35+
*/
36+
emptyStateTextGemini: 'Where should we start?',
3337
} as const;
3438

3539
const lockedString = i18n.i18n.lockedString;
@@ -74,12 +78,18 @@ export interface Props {
7478
}
7579

7680
interface ChatWidgetInput extends Props {
81+
accountName: string;
7782
handleScroll: (ev: Event) => void;
7883
handleSuggestionClick: (title: string) => void;
7984
handleMessageContainerRef: (el: Element|undefined) => void;
8085
}
8186

8287
const DEFAULT_VIEW: View = (input, output, target) => {
88+
const chatUiClasses = classMap({
89+
'chat-ui': true,
90+
gemini: AiAssistanceModel.AiUtils.isGeminiBranding(),
91+
});
92+
8393
const inputWidgetClasses = classMap({
8494
'chat-input-widget': true,
8595
sticky: !input.isReadOnly,
@@ -88,7 +98,7 @@ const DEFAULT_VIEW: View = (input, output, target) => {
8898
// clang-format off
8999
render(html`
90100
<style>${chatViewStyles}</style>
91-
<div class="chat-ui">
101+
<div class=${chatUiClasses}>
92102
<main @scroll=${input.handleScroll} ${ref(element => { output.mainElement = element as HTMLElement; } )}>
93103
${input.messages.length > 0 ? html`
94104
<div class="messages-container" ${ref(input.handleMessageContainerRef)}>
@@ -121,7 +131,12 @@ const DEFAULT_VIEW: View = (input, output, target) => {
121131
name="smart-assistant"
122132
></devtools-icon>
123133
</div>
124-
<h1>${lockedString(UIStringsNotTranslate.emptyStateText)}</h1>
134+
${AiAssistanceModel.AiUtils.isGeminiBranding() ?
135+
html`
136+
<h1 class='greeting'>Hello, ${input.accountName}</h1>
137+
<h1>${lockedString(UIStringsNotTranslate.emptyStateTextGemini)}</h1>
138+
` : html`<h1>${lockedString(UIStringsNotTranslate.emptyStateText)}</h1>`
139+
}
125140
</div>
126141
<div class="empty-state-content">
127142
${input.emptyStateSuggestions.map(({title, jslogContext}) => {
@@ -308,6 +323,8 @@ export class ChatView extends HTMLElement {
308323
this.#view(
309324
{
310325
...this.#props,
326+
// TODO(b/468206227): This needs to be a first name.
327+
accountName: this.#props.userInfo.accountFullName ?? '',
311328
handleScroll: this.#handleScroll,
312329
handleSuggestionClick: this.#handleSuggestionClick,
313330
handleMessageContainerRef: this.#handleMessageContainerRef,

front_end/panels/ai_assistance/components/chatView.css

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,27 @@ main {
165165
}
166166
}
167167

168+
.gemini {
169+
.empty-state-container .icon {
170+
display: none;
171+
}
172+
173+
.empty-state-container .header {
174+
align-items: flex-start;
175+
}
176+
177+
.empty-state-content {
178+
align-items: flex-start
179+
}
180+
181+
.empty-state-container .greeting {
182+
color: var(--sys-color-primary);
183+
}
168184

185+
main {
186+
align-items: flex-start;
187+
}
188+
}
169189

170190
.change-summary {
171191
background-color: var(--sys-color-surface3);

front_end/panels/common/AiCodeCompletionTeaser.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import * as Common from '../../core/common/common.js';
88
import * as Host from '../../core/host/host.js';
99
import * as i18n from '../../core/i18n/i18n.js';
1010
import * as Root from '../../core/root/root.js';
11+
import * as AIAssistance from '../../models/ai_assistance/ai_assistance.js';
1112
import * as AiCodeGeneration from '../../models/ai_code_generation/ai_code_generation.js';
1213
import * as Snackbars from '../../ui/components/snackbars/snackbars.js';
1314
import * as UI from '../../ui/legacy/legacy.js';
@@ -259,8 +260,9 @@ export class AiCodeCompletionTeaser extends UI.Widget.Widget {
259260
onAction = async(event: Event): Promise<void> => {
260261
event.preventDefault();
261262

263+
const iconName = AIAssistance.AiUtils.getIconName();
262264
const result = await FreDialog.show({
263-
header: {iconName: 'smart-assistant', text: lockedString(UIStringsNotTranslate.freDisclaimerHeader)},
265+
header: {iconName, text: lockedString(UIStringsNotTranslate.freDisclaimerHeader)},
264266
reminderItems: this.#createReminderItems(),
265267
onLearnMoreClick: () => {
266268
void UI.ViewManager.ViewManager.instance().showView('chrome-ai');

front_end/panels/common/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ devtools_ui_module("common") {
5555
"../../core/root:bundle",
5656
"../../core/sdk:bundle",
5757
"../../generated:protocol",
58+
"../../models/ai_assistance:bundle",
5859
"../../models/ai_code_completion:bundle",
5960
"../../models/ai_code_generation:bundle",
6061
"../../models/annotations:bundle",

0 commit comments

Comments
 (0)