chrome-devtools-frontend
Version:
Chrome DevTools UI
332 lines (302 loc) • 12.3 kB
text/typescript
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import * as Common from '../../core/common/common.js';
import * as i18n from '../../core/i18n/i18n.js';
import type * as Platform from '../../core/platform/platform.js';
import * as Root from '../../core/root/root.js';
import * as UI from '../../ui/legacy/legacy.js';
import type * as AiAssistance from './ai_assistance.js';
/*
* TODO(nvitkov): b/346933425
* Temporary string that should not be translated
* as they may change often during development.
*/
const UIStrings = {
/**
* @description The title of the AI assistance panel.
*/
aiAssistance: 'AI assistance',
/**
* @description The title of the command menu action for showing the AI assistance panel.
*/
showAiAssistance: 'Show AI assistance',
/**
* @description The setting title to enable the AI assistance via
* the settings tab.
*/
enableAiAssistance: 'Enable AI assistance',
/**
* @description Text of a context menu item to redirect to the AI assistance panel with
* the current context.
*/
debugWithAi: 'Debug with AI',
/**
* @description The title of the Gemini panel.
*/
gemini: 'Gemini',
/**
* @description The title of the command menu action for showing the Gemini panel.
*/
showGemini: 'Show Gemini',
/**
* @description The setting title to enable the Gemini via the settings tab.
*/
enableGemini: 'Enable Gemini',
/**
* @description Text of a context menu item to redirect to the Gemini panel with the current context.
*/
debugWithGemini: 'Debug with Gemini',
/**
* @description Message shown to the user if the DevTools locale is not
* supported.
*/
wrongLocale: 'To use this feature, set your language preference to English in DevTools settings.',
/**
* @description Message shown to the user if the user's region is not
* supported.
*/
geoRestricted: 'This feature is unavailable in your region.',
/**
* @description Message shown to the user if the enterprise policy does
* not allow this feature.
*/
policyRestricted: 'This setting is managed by your administrator.',
} as const;
const str_ = i18n.i18n.registerUIStrings('panels/ai_assistance/ai_assistance-meta.ts', UIStrings);
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
// Host config is initialized after this module executes, so need to lazily select the string.
function i18nAiBrandedString(gemini: string, assistance: string) {
// eslint-disable-next-line @devtools/l10n-i18nString-call-only-with-uistrings
return () => Root.Runtime.hostConfig.devToolsGeminiRebranding?.enabled ? i18nString(gemini) : i18nString(assistance);
}
const setting = 'ai-assistance-enabled';
function isLocaleRestricted(): boolean {
const devtoolsLocale = i18n.DevToolsLocale.DevToolsLocale.instance();
return !devtoolsLocale.locale.startsWith('en-');
}
function isGeoRestricted(config?: Root.Runtime.HostConfig): boolean {
return config?.aidaAvailability?.blockedByGeo === true;
}
function isPolicyRestricted(config?: Root.Runtime.HostConfig): boolean {
return config?.aidaAvailability?.blockedByEnterprisePolicy === true;
}
let loadedAiAssistanceModule: (typeof AiAssistance|undefined);
async function loadAiAssistanceModule(): Promise<typeof AiAssistance> {
if (!loadedAiAssistanceModule) {
loadedAiAssistanceModule = await import('./ai_assistance.js');
}
return loadedAiAssistanceModule;
}
function isStylingAgentFeatureAvailable(config?: Root.Runtime.HostConfig): boolean {
return (config?.aidaAvailability?.enabled && config?.devToolsFreestyler?.enabled) === true;
}
function isNetworkAgentFeatureAvailable(config?: Root.Runtime.HostConfig): boolean {
return (config?.aidaAvailability?.enabled && (config?.devToolsAiAssistanceNetworkAgent?.enabled)) === true;
}
function isPerformanceAgentFeatureAvailable(config?: Root.Runtime.HostConfig): boolean {
return (config?.aidaAvailability?.enabled && (config?.devToolsAiAssistancePerformanceAgent?.enabled)) === true;
}
function isFileAgentFeatureAvailable(config?: Root.Runtime.HostConfig): boolean {
return (config?.aidaAvailability?.enabled && (config?.devToolsAiAssistanceFileAgent?.enabled)) === true;
}
function isStorageAgentFeatureAvailable(config?: Root.Runtime.HostConfig): boolean {
return (config?.aidaAvailability?.enabled && (config?.devToolsAiAssistanceStorageAgent?.enabled)) === true;
}
function isAnyFeatureAvailable(config?: Root.Runtime.HostConfig): boolean {
return isStylingAgentFeatureAvailable(config) || isNetworkAgentFeatureAvailable(config) ||
isPerformanceAgentFeatureAvailable(config) || isFileAgentFeatureAvailable(config) ||
isStorageAgentFeatureAvailable(config);
}
UI.ViewManager.registerViewExtension({
location: UI.ViewManager.ViewLocationValues.DRAWER_VIEW,
id: 'freestyler',
commandPrompt: i18nAiBrandedString(UIStrings.showGemini, UIStrings.showAiAssistance),
title: i18nAiBrandedString(UIStrings.gemini, UIStrings.aiAssistance),
order: 10,
persistence: UI.ViewManager.ViewPersistence.CLOSEABLE,
hasToolbar: false,
condition: config => isAnyFeatureAvailable(config) && !isPolicyRestricted(config),
async loadView() {
const AiAssistance = await loadAiAssistanceModule();
return await AiAssistance.AiAssistancePanel.instance();
},
});
Common.Settings.registerSettingExtension({
category: Common.Settings.SettingCategory.AI,
settingName: setting,
settingType: Common.Settings.SettingType.BOOLEAN,
title: i18nAiBrandedString(UIStrings.enableGemini, UIStrings.enableAiAssistance),
defaultValue: false,
reloadRequired: false,
condition: isAnyFeatureAvailable,
disabledCondition: config => {
const reasons: Platform.UIString.LocalizedString[] = [];
if (isGeoRestricted(config)) {
reasons.push(i18nString(UIStrings.geoRestricted));
}
if (isPolicyRestricted(config)) {
reasons.push(i18nString(UIStrings.policyRestricted));
}
if (isLocaleRestricted()) {
reasons.push(i18nString(UIStrings.wrongLocale));
}
if (reasons.length > 0) {
return {disabled: true, reasons};
}
return {disabled: false};
},
});
Common.Settings.registerSettingExtension({
category: Common.Settings.SettingCategory.AI,
settingName: 'ai-assistance-v2-opt-in-change-dialog-seen',
settingType: Common.Settings.SettingType.BOOLEAN,
defaultValue: false,
});
UI.ActionRegistration.registerActionExtension({
actionId: 'freestyler.main-menu',
contextTypes(): [] {
return [];
},
category: UI.ActionRegistration.ActionCategory.GLOBAL,
title: i18nAiBrandedString(UIStrings.debugWithGemini, UIStrings.debugWithAi),
configurableBindings: false,
async loadActionDelegate() {
const AiAssistance = await loadAiAssistanceModule();
return new AiAssistance.ActionDelegate();
},
condition: config => isAnyFeatureAvailable(config) && !isPolicyRestricted(config) && !isGeoRestricted(config),
});
UI.ActionRegistration.registerActionExtension({
actionId: 'freestyler.elements-floating-button',
contextTypes(): [] {
return [];
},
category: UI.ActionRegistration.ActionCategory.GLOBAL,
title: i18nAiBrandedString(UIStrings.debugWithGemini, UIStrings.debugWithAi),
configurableBindings: false,
async loadActionDelegate() {
const AiAssistance = await loadAiAssistanceModule();
return new AiAssistance.ActionDelegate();
},
condition: config =>
isStylingAgentFeatureAvailable(config) && !isPolicyRestricted(config) && !isGeoRestricted(config),
});
UI.ActionRegistration.registerActionExtension({
actionId: 'freestyler.element-panel-context',
contextTypes(): [] {
return [];
},
category: UI.ActionRegistration.ActionCategory.GLOBAL,
title: i18nAiBrandedString(UIStrings.debugWithGemini, UIStrings.debugWithAi),
configurableBindings: false,
async loadActionDelegate() {
const AiAssistance = await loadAiAssistanceModule();
return new AiAssistance.ActionDelegate();
},
condition: config =>
isStylingAgentFeatureAvailable(config) && !isPolicyRestricted(config) && !isGeoRestricted(config),
});
UI.ActionRegistration.registerActionExtension({
actionId: 'drjones.network-floating-button',
contextTypes(): [] {
return [];
},
category: UI.ActionRegistration.ActionCategory.GLOBAL,
title: i18nAiBrandedString(UIStrings.debugWithGemini, UIStrings.debugWithAi),
configurableBindings: false,
async loadActionDelegate() {
const AiAssistance = await loadAiAssistanceModule();
return new AiAssistance.ActionDelegate();
},
condition: config =>
isNetworkAgentFeatureAvailable(config) && !isPolicyRestricted(config) && !isGeoRestricted(config),
});
UI.ActionRegistration.registerActionExtension({
actionId: 'drjones.network-panel-context',
contextTypes(): [] {
return [];
},
category: UI.ActionRegistration.ActionCategory.GLOBAL,
title: i18nAiBrandedString(UIStrings.debugWithGemini, UIStrings.debugWithAi),
configurableBindings: false,
async loadActionDelegate() {
const AiAssistance = await loadAiAssistanceModule();
return new AiAssistance.ActionDelegate();
},
condition: config =>
isNetworkAgentFeatureAvailable(config) && !isPolicyRestricted(config) && !isGeoRestricted(config),
});
UI.ActionRegistration.registerActionExtension({
actionId: 'drjones.performance-panel-context',
contextTypes(): [] {
return [];
},
category: UI.ActionRegistration.ActionCategory.GLOBAL,
title: i18nAiBrandedString(UIStrings.debugWithGemini, UIStrings.debugWithAi),
configurableBindings: false,
async loadActionDelegate() {
const AiAssistance = await loadAiAssistanceModule();
return new AiAssistance.ActionDelegate();
},
condition: config =>
isPerformanceAgentFeatureAvailable(config) && !isPolicyRestricted(config) && !isGeoRestricted(config),
});
UI.ActionRegistration.registerActionExtension({
actionId: 'drjones.sources-floating-button',
contextTypes(): [] {
return [];
},
category: UI.ActionRegistration.ActionCategory.GLOBAL,
title: i18nAiBrandedString(UIStrings.debugWithGemini, UIStrings.debugWithAi),
configurableBindings: false,
async loadActionDelegate() {
const AiAssistance = await loadAiAssistanceModule();
return new AiAssistance.ActionDelegate();
},
condition: config => isFileAgentFeatureAvailable(config) && !isPolicyRestricted(config) && !isGeoRestricted(config),
});
UI.ActionRegistration.registerActionExtension({
actionId: 'drjones.sources-panel-context',
contextTypes() {
return [];
},
category: UI.ActionRegistration.ActionCategory.GLOBAL,
title: i18nAiBrandedString(UIStrings.debugWithGemini, UIStrings.debugWithAi),
configurableBindings: false,
async loadActionDelegate() {
const AiAssistance = await loadAiAssistanceModule();
return new AiAssistance.ActionDelegate();
},
condition: config => isFileAgentFeatureAvailable(config) && !isPolicyRestricted(config) && !isGeoRestricted(config),
});
UI.ActionRegistration.registerActionExtension({
actionId: 'ai-assistance.storage-floating-button',
contextTypes(): [] {
return [];
},
category: UI.ActionRegistration.ActionCategory.GLOBAL,
title: i18nAiBrandedString(UIStrings.debugWithGemini, UIStrings.debugWithAi),
configurableBindings: false,
async loadActionDelegate() {
const AiAssistance = await loadAiAssistanceModule();
return new AiAssistance.ActionDelegate();
},
condition: config =>
isStorageAgentFeatureAvailable(config) && !isPolicyRestricted(config) && !isGeoRestricted(config),
});
UI.ActionRegistration.registerActionExtension({
actionId: 'ai-assistance.application-panel-context',
contextTypes(): [] {
return [];
},
category: UI.ActionRegistration.ActionCategory.GLOBAL,
title: i18nAiBrandedString(UIStrings.debugWithGemini, UIStrings.debugWithAi),
configurableBindings: false,
async loadActionDelegate() {
const AiAssistance = await loadAiAssistanceModule();
return new AiAssistance.ActionDelegate();
},
condition: config =>
isStorageAgentFeatureAvailable(config) && !isPolicyRestricted(config) && !isGeoRestricted(config),
});