Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chat - tweaks to chat setup #233178

Merged
merged 14 commits into from
Nov 6, 2024
Prev Previous commit
Next Next commit
wire in via welcome
  • Loading branch information
bpasero committed Nov 6, 2024
commit 6b9d7122d3330cc2e706e518e8230bb3b6e51050
1 change: 1 addition & 0 deletions src/vs/base/common/product.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ export interface IProductConfiguration {
readonly icon: string;
readonly documentationUrl: string;
readonly gettingStartedCommand: string;
readonly welcomeTitle: string;
};
}

Expand Down
44 changes: 29 additions & 15 deletions src/vs/workbench/contrib/chat/browser/actions/chatActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,12 @@ import { localize, localize2 } from '../../../../../nls.js';
import { IActionViewItemService } from '../../../../../platform/actions/browser/actionViewItemService.js';
import { DropdownWithPrimaryActionViewItem } from '../../../../../platform/actions/browser/dropdownWithPrimaryActionViewItem.js';
import { Action2, MenuId, MenuItemAction, MenuRegistry, registerAction2, SubmenuItemAction } from '../../../../../platform/actions/common/actions.js';
import { ContextKeyExpr } from '../../../../../platform/contextkey/common/contextkey.js';
import { ContextKeyExpr, IContextKeyService } from '../../../../../platform/contextkey/common/contextkey.js';
import { IsLinuxContext, IsWindowsContext } from '../../../../../platform/contextkey/common/contextkeys.js';
import { IInstantiationService, ServicesAccessor } from '../../../../../platform/instantiation/common/instantiation.js';
import { KeybindingWeight } from '../../../../../platform/keybinding/common/keybindingsRegistry.js';
import { IOpenerService } from '../../../../../platform/opener/common/opener.js';
import { IProductService } from '../../../../../platform/product/common/productService.js';
import { ProgressLocation } from '../../../../../platform/progress/common/progress.js';
import { IQuickInputButton, IQuickInputService, IQuickPickItem, IQuickPickSeparator } from '../../../../../platform/quickinput/common/quickInput.js';
import { ToggleTitleBarConfigAction } from '../../../../browser/parts/titlebar/titlebarActions.js';
import { IWorkbenchContribution } from '../../../../common/contributions.js';
Expand All @@ -51,6 +50,9 @@ import { isCancellationError } from '../../../../../base/common/errors.js';
import { ITelemetryService } from '../../../../../platform/telemetry/common/telemetry.js';
import { IChatVariablesService } from '../../common/chatVariables.js';
import { IAuthenticationService } from '../../../../services/authentication/common/authentication.js';
import { Registry } from '../../../../../platform/registry/common/platform.js';
import { IChatViewsWelcomeContributionRegistry, IChatViewsWelcomeDescriptor, ChatViewsWelcomeExtensions } from '../viewsWelcome/chatViewsWelcome.js';
import { MarkdownString } from '../../../../../base/common/htmlContent.js';

export const CHAT_CATEGORY = localize2('chat.category', 'Chat');
export const CHAT_OPEN_ACTION_ID = 'workbench.action.chat.open';
Expand Down Expand Up @@ -93,6 +95,7 @@ const defaultChat = {
icon: Codicon[product.defaultChatAgent?.icon as keyof typeof Codicon ?? 'commentDiscussion'],
documentationUrl: product.defaultChatAgent?.documentationUrl ?? '',
gettingStartedCommand: product.defaultChatAgent?.gettingStartedCommand ?? '',
welcomeTitle: product.defaultChatAgent?.welcomeTitle ?? '',
};

class OpenChatGlobalAction extends Action2 {
Expand Down Expand Up @@ -527,22 +530,32 @@ export class ChatCommandCenterRendering implements IWorkbenchContribution {
@IChatAgentService agentService: IChatAgentService,
@IInstantiationService instantiationService: IInstantiationService,
) {
// --- action to show dropdown
const that = this;
const showDropdownActionId = 'workbench.action.showDropdown';
registerAction2(class OpenDropdown extends Action2 {
const showDropdownActionId = 'chatMenu.showDropdown';
registerAction2(class OpenChatMenuDropdown extends Action2 {
constructor() {
super({
id: showDropdownActionId,
title: defaultChat.name,
f1: false,
f1: false
});
}
run() {
that._dropdown?.showDropdown();
}
});

// --- chat setup welcome
const descriptor: IChatViewsWelcomeDescriptor = {
title: defaultChat.welcomeTitle,
when: ChatContextKeys.ChatSetup.running,
icon: defaultChat.icon,
content: new MarkdownString(`$(loading~spin) Getting things ready for you...\n\n[Learn More](${defaultChat.documentationUrl})`, { isTrusted: true, supportThemeIcons: true }),
};
Registry.as<IChatViewsWelcomeContributionRegistry>(ChatViewsWelcomeExtensions.ChatViewsWelcomeRegistry).register(descriptor);

// --- dropdown menu
this._store.add(actionViewItemService.register(MenuId.CommandCenter, MenuId.ChatCommandCenter, (action, options) => {
if (!(action instanceof SubmenuItemAction)) {
return undefined;
Expand All @@ -562,15 +575,7 @@ export class ChatCommandCenterRendering implements IWorkbenchContribution {
icon: defaultChat.icon,
}, undefined, undefined, undefined, undefined);

this._dropdown = instantiationService.createInstance(
DropdownWithPrimaryActionViewItem,
primaryAction, dropdownAction, action.actions,
'',
{
...options,
skipTelemetry: true, // already handled by the workbench action bar
}
);
this._dropdown = instantiationService.createInstance(DropdownWithPrimaryActionViewItem, primaryAction, dropdownAction, action.actions, '', { ...options, skipTelemetry: true });

return this._dropdown;
}, agentService.onDidChangeAgents));
Expand Down Expand Up @@ -614,6 +619,10 @@ class InstallChatAction extends Action2 {
const extensionsWorkbenchService = accessor.get(IExtensionsWorkbenchService);
const productService = accessor.get(IProductService);
const telemetryService = accessor.get(ITelemetryService);
const contextKeyService = accessor.get(IContextKeyService);
const viewsService = accessor.get(IViewsService);

const setupRunningContextKey = ChatContextKeys.ChatSetup.running.bindTo(contextKeyService);

type InstallChatClassification = {
owner: 'bpasero';
Expand All @@ -626,14 +635,19 @@ class InstallChatAction extends Action2 {

let installResult: 'installed' | 'cancelled' | 'failed';
try {
setupRunningContextKey.set(true);
showChatView(viewsService);

await extensionsWorkbenchService.install(defaultChat.extensionId, {
enable: true,
installPreReleaseVersion: productService.quality !== 'stable'
}, ProgressLocation.Notification);
}, CHAT_VIEW_ID);

installResult = 'installed';
} catch (error) {
installResult = isCancellationError(error) ? 'cancelled' : 'failed';
} finally {
setupRunningContextKey.reset();
}

telemetryService.publicLog2<InstallChatEvent, InstallChatClassification>('commandCenter.chatInstall', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,11 @@ export class ChatExtensionPointHandler implements IWorkbenchContribution {
order: 1
},
ctorDescriptor: new SyncDescriptor(ChatViewPane, [{ location: ChatAgentLocation.Panel }]),
when: ContextKeyExpr.or(ChatContextKeys.panelParticipantRegistered, ChatContextKeys.extensionInvalid)
when: ContextKeyExpr.or(
ChatContextKeys.panelParticipantRegistered,
ChatContextKeys.extensionInvalid,
ChatContextKeys.ChatSetup.running
)
}];
Registry.as<IViewsRegistry>(ViewExtensions.ViewsRegistry).registerViews(viewDescriptor, this._viewContainer);

Expand Down
3 changes: 2 additions & 1 deletion src/vs/workbench/contrib/chat/common/chatContextKeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ export namespace ChatContextKeys {

export const ChatSetup = {
entitled: new RawContextKey<boolean>('chatSetupEntitled', false, { type: 'boolean', description: localize('chatSetupEntitled', "True when chat setup is offered for a signed-in, entitled user.") }),
signedIn: new RawContextKey<boolean>('chatSetupSignedIn', false, { type: 'boolean', description: localize('chatSetupSignedIn', "True when chat setup is offered for a signed-in user.") })
signedIn: new RawContextKey<boolean>('chatSetupSignedIn', false, { type: 'boolean', description: localize('chatSetupSignedIn', "True when chat setup is offered for a signed-in user.") }),
running: new RawContextKey<boolean>('chatSetupRunning', false, { type: 'boolean', description: localize('chatSetupRunning', "True when chat setup is running.") })
};

export const shouldShowMovedViewWelcome = new RawContextKey<boolean>('chatShouldShowMovedViewWelcome', false, { type: 'boolean', description: localize('chatShouldShowMovedViewWelcome', "True when the user should be shown the moved view welcome view.") });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2236,7 +2236,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
return false;
}

async install(arg: string | URI | IExtension, installOptions: InstallExtensionOptions = {}, progressLocation?: ProgressLocation): Promise<IExtension> {
async install(arg: string | URI | IExtension, installOptions: InstallExtensionOptions = {}, progressLocation?: ProgressLocation | string): Promise<IExtension> {
let installable: URI | IGalleryExtension | IResourceExtension | undefined;
let extension: IExtension | undefined;

Expand Down Expand Up @@ -2607,7 +2607,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
return extension;
}

private doInstall(extension: IExtension | undefined, installTask: () => Promise<ILocalExtension>, progressLocation?: ProgressLocation): Promise<IExtension> {
private doInstall(extension: IExtension | undefined, installTask: () => Promise<ILocalExtension>, progressLocation?: ProgressLocation | string): Promise<IExtension> {
const title = extension ? nls.localize('installing named extension', "Installing '{0}' extension....", extension.displayName) : nls.localize('installing extension', 'Installing extension....');
return this.withProgress({
location: progressLocation ?? ProgressLocation.Extensions,
Expand Down
6 changes: 3 additions & 3 deletions src/vs/workbench/contrib/extensions/common/extensions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,9 @@ export interface IExtensionsWorkbenchService {
getExtensions(extensionInfos: IExtensionInfo[], options: IExtensionQueryOptions, token: CancellationToken): Promise<IExtension[]>;
getResourceExtensions(locations: URI[], isWorkspaceScoped: boolean): Promise<IExtension[]>;
canInstall(extension: IExtension): Promise<boolean>;
install(id: string, installOptions?: InstallExtensionOptions, progressLocation?: ProgressLocation): Promise<IExtension>;
install(vsix: URI, installOptions?: InstallExtensionOptions, progressLocation?: ProgressLocation): Promise<IExtension>;
install(extension: IExtension, installOptions?: InstallExtensionOptions, progressLocation?: ProgressLocation): Promise<IExtension>;
install(id: string, installOptions?: InstallExtensionOptions, progressLocation?: ProgressLocation | string): Promise<IExtension>;
install(vsix: URI, installOptions?: InstallExtensionOptions, progressLocation?: ProgressLocation | string): Promise<IExtension>;
install(extension: IExtension, installOptions?: InstallExtensionOptions, progressLocation?: ProgressLocation | string): Promise<IExtension>;
installInServer(extension: IExtension, server: IExtensionManagementServer): Promise<void>;
uninstall(extension: IExtension): Promise<void>;
reinstall(extension: IExtension): Promise<IExtension>;
Expand Down
Loading