put new profiles UI behind flag (#214586)

This commit is contained in:
Sandeep Somavarapu 2024-06-07 14:03:34 +02:00 committed by GitHub
parent af5696c630
commit 9548a679f5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 206 additions and 16 deletions

View file

@ -31,10 +31,17 @@ import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IHostService } from 'vs/workbench/services/host/browser/host';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IUserDataProfilesEditor } from 'vs/workbench/contrib/userDataProfile/common/userDataProfile';
import { ConfigurationScope, Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuration';
import { IProductService } from 'vs/platform/product/common/productService';
type IProfileTemplateQuickPickItem = IQuickPickItem & IProfileTemplateInfo;
export const OpenProfileMenu = new MenuId('OpenProfile');
const CONFIG_ENABLE_NEW_PROFILES_UI = 'workbench.experimental.enableNewProfilesUI';
const CONTEXT_ENABLE_NEW_PROFILES_UI = ContextKeyExpr.equals('config.workbench.experimental.enableNewProfilesUI', true);
export class UserDataProfilesWorkbenchContribution extends Disposable implements IWorkbenchContribution {
@ -54,6 +61,10 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
@IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService,
@IWorkspaceTagsService private readonly workspaceTagsService: IWorkspaceTagsService,
@IContextKeyService contextKeyService: IContextKeyService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IEditorGroupsService private readonly editorGroupsService: IEditorGroupsService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IProductService private readonly productService: IProductService,
@ILifecycleService private readonly lifecycleService: ILifecycleService,
) {
super();
@ -73,6 +84,7 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
this.hasProfilesContext.set(this.userDataProfilesService.profiles.length > 1);
this._register(this.userDataProfilesService.onDidChangeProfiles(e => this.hasProfilesContext.set(this.userDataProfilesService.profiles.length > 1)));
this.registerConfiguration();
this.registerEditor();
this.registerActions();
@ -83,6 +95,29 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
this.reportWorkspaceProfileInfo();
}
private openProfilesEditor(): Promise<IUserDataProfilesEditor | undefined> {
return this.editorGroupsService.activeGroup.openEditor(new UserDataProfilesEditorInput(this.instantiationService));
}
private isNewProfilesUIEnabled(): boolean {
return this.configurationService.getValue(CONFIG_ENABLE_NEW_PROFILES_UI) === true;
}
private registerConfiguration(): void {
Registry.as<IConfigurationRegistry>(Extensions.Configuration)
.registerConfiguration({
...workbenchConfigurationNodeBase,
properties: {
[CONFIG_ENABLE_NEW_PROFILES_UI]: {
type: 'boolean',
description: localize('enable new profiles UI', "Enables the new profiles UI."),
default: this.productService.quality !== 'stable',
scope: ConfigurationScope.APPLICATION,
}
}
});
}
private registerEditor(): void {
Registry.as<IEditorPaneRegistry>(EditorExtensions.EditorPane).registerEditorPane(
EditorPaneDescriptor.create(
@ -120,6 +155,7 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
const getProfilesTitle = () => {
return localize('profiles', "Profile ({0})", this.userDataProfileService.currentProfile.name);
};
const when = ContextKeyExpr.or(CONTEXT_ENABLE_NEW_PROFILES_UI.negate(), HAS_PROFILES_CONTEXT);
MenuRegistry.appendMenuItem(MenuId.GlobalActivity, {
get title() {
return getProfilesTitle();
@ -127,7 +163,7 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
submenu: ProfilesMenu,
group: '2_configuration',
order: 1,
when: HAS_PROFILES_CONTEXT,
when,
});
MenuRegistry.appendMenuItem(MenuId.MenubarPreferencesMenu, {
get title() {
@ -136,7 +172,7 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
submenu: ProfilesMenu,
group: '2_configuration',
order: 1,
when: HAS_PROFILES_CONTEXT,
when,
});
}
@ -269,6 +305,8 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
private readonly currentprofileActionsDisposable = this._register(new MutableDisposable<DisposableStore>());
private registerCurrentProfilesActions(): void {
this.currentprofileActionsDisposable.value = new DisposableStore();
this.currentprofileActionsDisposable.value.add(this.registerEditCurrentProfileAction());
this.currentprofileActionsDisposable.value.add(this.registerShowCurrentProfileContentsAction());
this.currentprofileActionsDisposable.value.add(this.registerExportCurrentProfileAction());
this.currentprofileActionsDisposable.value.add(this.registerImportProfileAction());
}
@ -287,12 +325,14 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
{
id: MenuId.GlobalActivity,
group: '2_configuration',
order: 1
order: 1,
when: CONTEXT_ENABLE_NEW_PROFILES_UI,
},
{
id: MenuId.MenubarPreferencesMenu,
group: '2_configuration',
order: 1
order: 1,
when: CONTEXT_ENABLE_NEW_PROFILES_UI,
},
]
});
@ -308,12 +348,69 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
id: 'workbench.profiles.actions.manageProfiles',
category: Categories.Preferences,
title: localize2('open profiles', "Open Profiles (UI)"),
precondition: CONTEXT_ENABLE_NEW_PROFILES_UI,
},
}));
return disposables;
}
private registerEditCurrentProfileAction(): IDisposable {
const that = this;
return registerAction2(class RenameCurrentProfileAction extends Action2 {
constructor() {
const precondition = ContextKeyExpr.and(ContextKeyExpr.notEquals(CURRENT_PROFILE_CONTEXT.key, that.userDataProfilesService.defaultProfile.id), IS_CURRENT_PROFILE_TRANSIENT_CONTEXT.toNegated());
super({
id: `workbench.profiles.actions.editCurrentProfile`,
title: localize2('edit profile', "Edit Profile..."),
precondition,
f1: true,
menu: [
{
id: ProfilesMenu,
group: '2_manage_current',
when: ContextKeyExpr.and(precondition, CONTEXT_ENABLE_NEW_PROFILES_UI.negate()),
order: 2
}
]
});
}
run(accessor: ServicesAccessor) {
if (that.isNewProfilesUIEnabled()) {
return that.openProfilesEditor();
} else {
return that.userDataProfileImportExportService.editProfile(that.userDataProfileService.currentProfile);
}
}
});
}
private registerShowCurrentProfileContentsAction(): IDisposable {
const id = 'workbench.profiles.actions.showProfileContents';
return registerAction2(class ShowProfileContentsAction extends Action2 {
constructor() {
super({
id,
title: localize2('show profile contents', "Show Profile Contents"),
category: PROFILES_CATEGORY,
menu: [
{
id: ProfilesMenu,
group: '2_manage_current',
order: 3,
when: CONTEXT_ENABLE_NEW_PROFILES_UI.negate()
}
]
});
}
async run(accessor: ServicesAccessor) {
const userDataProfileImportExportService = accessor.get(IUserDataProfileImportExportService);
return userDataProfileImportExportService.showProfileContents();
}
});
}
private registerExportCurrentProfileAction(): IDisposable {
const that = this;
const disposables = new DisposableStore();
@ -322,22 +419,37 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
constructor() {
super({
id,
title: localize2('export profile', "Export Profile ({0})...", that.userDataProfileService.currentProfile.name),
title: localize2('export profile', "Export Profile..."),
category: PROFILES_CATEGORY,
precondition: IS_PROFILE_EXPORT_IN_PROGRESS_CONTEXT.toNegated(),
f1: true,
menu: {
id: MenuId.MenubarShare
}
menu: [
{
id: ProfilesMenu,
group: '4_import_export_profiles',
order: 1,
when: CONTEXT_ENABLE_NEW_PROFILES_UI.negate(),
}, {
id: MenuId.CommandPalette
}
]
});
}
async run(accessor: ServicesAccessor) {
const editorGroupsService = accessor.get(IEditorGroupsService);
const instantiationService = accessor.get(IInstantiationService);
return editorGroupsService.activeGroup.openEditor(new UserDataProfilesEditorInput(instantiationService));
if (that.isNewProfilesUIEnabled()) {
return that.openProfilesEditor();
} else {
return that.userDataProfileImportExportService.exportProfile2();
}
}
}));
disposables.add(MenuRegistry.appendMenuItem(MenuId.MenubarShare, {
command: {
id,
title: localize2('export profile in share', "Export Profile ({0})...", that.userDataProfileService.currentProfile.name),
precondition: PROFILES_ENABLEMENT_CONTEXT,
},
}));
return disposables;
}
@ -352,7 +464,17 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
title: localize2('import profile', "Import Profile..."),
category: PROFILES_CATEGORY,
precondition: IS_PROFILE_IMPORT_IN_PROGRESS_CONTEXT.toNegated(),
f1: true,
menu: [
{
id: ProfilesMenu,
group: '4_import_export_profiles',
when: ContextKeyExpr.and(PROFILES_ENABLEMENT_CONTEXT, CONTEXT_ENABLE_NEW_PROFILES_UI.negate()),
order: 2
}, {
id: MenuId.CommandPalette,
when: PROFILES_ENABLEMENT_CONTEXT,
}
]
});
}
@ -454,6 +576,7 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
}
private registerCreateProfileAction(): void {
const that = this;
this._register(registerAction2(class CreateProfileAction extends Action2 {
constructor() {
super({
@ -462,13 +585,23 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
category: PROFILES_CATEGORY,
precondition: PROFILES_ENABLEMENT_CONTEXT,
f1: true,
menu: [
{
id: ProfilesMenu,
group: '3_manage_profiles',
when: ContextKeyExpr.and(PROFILES_ENABLEMENT_CONTEXT, CONTEXT_ENABLE_NEW_PROFILES_UI.negate()),
order: 1
}
]
});
}
async run(accessor: ServicesAccessor) {
const editorGroupsService = accessor.get(IEditorGroupsService);
const instantiationService = accessor.get(IInstantiationService);
return editorGroupsService.activeGroup.openEditor(new UserDataProfilesEditorInput(instantiationService));
if (that.isNewProfilesUIEnabled()) {
return that.openProfilesEditor();
} else {
return that.userDataProfileImportExportService.createProfile();
}
}
}));
}
@ -482,6 +615,14 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
category: PROFILES_CATEGORY,
f1: true,
precondition: ContextKeyExpr.and(PROFILES_ENABLEMENT_CONTEXT, HAS_PROFILES_CONTEXT),
menu: [
{
id: ProfilesMenu,
group: '3_manage_profiles',
when: ContextKeyExpr.and(PROFILES_ENABLEMENT_CONTEXT, CONTEXT_ENABLE_NEW_PROFILES_UI.negate()),
order: 2
}
]
});
}

View file

@ -80,6 +80,7 @@ import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { KeyCode } from 'vs/base/common/keyCodes';
import type { IHoverWidget } from 'vs/base/browser/ui/hover/hover';
import { IAccessibleViewInformationService } from 'vs/workbench/services/accessibility/common/accessibleViewInformationService';
import { ILogService } from 'vs/platform/log/common/log';
interface IUserDataProfileTemplate {
readonly name: string;
@ -103,6 +104,7 @@ function isUserDataProfileTemplate(thing: unknown): thing is IUserDataProfileTem
&& (isUndefined(candidate.extensions) || typeof candidate.extensions === 'string'));
}
const EXPORT_PROFILE_PREVIEW_VIEW = 'workbench.views.profiles.export.preview';
const IMPORT_PROFILE_PREVIEW_VIEW = 'workbench.views.profiles.import.preview';
export class UserDataProfileImportExportService extends Disposable implements IUserDataProfileImportExportService, IURLHandler {
@ -141,6 +143,7 @@ export class UserDataProfileImportExportService extends Disposable implements IU
@ITelemetryService private readonly telemetryService: ITelemetryService,
@IContextViewService private readonly contextViewService: IContextViewService,
@IHoverService private readonly hoverService: IHoverService,
@ILogService private readonly logService: ILogService,
) {
super();
this.registerProfileContentHandler(Schemas.file, this.fileUserDataProfileContentHandler = instantiationService.createInstance(FileUserDataProfileContentHandler));
@ -190,6 +193,15 @@ export class UserDataProfileImportExportService extends Disposable implements IU
this.profileContentHandlers.delete(id);
}
async exportProfile2(): Promise<void> {
if (this.isProfileExportInProgressContextKey.get()) {
this.logService.warn('Profile export already in progress.');
return;
}
return this.showProfileContents();
}
async importProfile(uri: URI, options?: IProfileImportOptions): Promise<void> {
if (this.isProfileImportInProgressContextKey.get()) {
this.notificationService.warn('Profile import already in progress.');
@ -226,6 +238,10 @@ export class UserDataProfileImportExportService extends Disposable implements IU
return this.saveProfile(undefined, from);
}
editProfile(profile: IUserDataProfile): Promise<void> {
return this.saveProfile(profile);
}
async createFromProfile(from: IUserDataProfile, options: IUserDataProfileCreateOptions, token: CancellationToken): Promise<IUserDataProfile | undefined> {
const disposables = new DisposableStore();
let creationPromise: CancelablePromise<void>;
@ -643,6 +659,36 @@ export class UserDataProfileImportExportService extends Disposable implements IU
}
}
async showProfileContents(): Promise<void> {
const view = this.viewsService.getViewWithId(EXPORT_PROFILE_PREVIEW_VIEW);
if (view) {
this.viewsService.openView(view.id, true);
return;
}
const disposables = new DisposableStore();
try {
const userDataProfilesExportState = disposables.add(this.instantiationService.createInstance(UserDataProfileExportState, this.userDataProfileService.currentProfile, undefined));
const barrier = new Barrier();
const exportAction = new BarrierAction(barrier, new Action('export', localize('export', "Export"), undefined, true, async () => {
exportAction.enabled = false;
try {
await this.doExportProfile(userDataProfilesExportState, EXPORT_PROFILE_PREVIEW_VIEW);
} catch (error) {
exportAction.enabled = true;
this.notificationService.error(error);
throw error;
}
}), this.notificationService);
const closeAction = new BarrierAction(barrier, new Action('close', localize('close', "Close")), this.notificationService);
await this.showProfilePreviewView(EXPORT_PROFILE_PREVIEW_VIEW, userDataProfilesExportState.profile.name, exportAction, closeAction, true, userDataProfilesExportState);
disposables.add(this.userDataProfileService.onDidChangeCurrentProfile(e => barrier.open()));
await barrier.wait();
await this.hideProfilePreviewView(EXPORT_PROFILE_PREVIEW_VIEW);
} finally {
disposables.dispose();
}
}
async exportProfile(profile: IUserDataProfile): Promise<void> {
const disposables = new DisposableStore();
try {

View file

@ -101,8 +101,11 @@ export interface IUserDataProfileImportExportService {
resolveProfileTemplate(uri: URI): Promise<IUserDataProfileTemplate | null>;
exportProfile(profile: IUserDataProfile): Promise<void>;
exportProfile2(): Promise<void>;
importProfile(uri: URI, options?: IProfileImportOptions): Promise<void>;
showProfileContents(): Promise<void>;
createProfile(from?: IUserDataProfile | URI): Promise<void>;
editProfile(profile: IUserDataProfile): Promise<void>;
createFromProfile(from: IUserDataProfile, options: IUserDataProfileCreateOptions, token: CancellationToken): Promise<IUserDataProfile | undefined>;
createProfileFromTemplate(profileTemplate: IUserDataProfileTemplate, options: IUserDataProfileCreateOptions, token: CancellationToken): Promise<IUserDataProfile | undefined>;
createTroubleshootProfile(): Promise<void>;