diff --git a/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.contribution.ts b/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.contribution.ts index c19d471fdc8..eee76405345 100644 --- a/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.contribution.ts +++ b/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.contribution.ts @@ -11,7 +11,6 @@ import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuratio import { IWorkbenchContributionsRegistry, Extensions } from 'vs/workbench/common/contributions'; import { UserDataProfilesWorkbenchContribution } from 'vs/workbench/contrib/userDataProfile/browser/userDataProfile'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; -import '../common/profileActions'; import '../common/userDataProfileActions'; if (!isWeb) { diff --git a/src/vs/workbench/contrib/userDataProfile/common/profileActions.ts b/src/vs/workbench/contrib/userDataProfile/common/profileActions.ts deleted file mode 100644 index 698833c1aa8..00000000000 --- a/src/vs/workbench/contrib/userDataProfile/common/profileActions.ts +++ /dev/null @@ -1,136 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { CancellationToken } from 'vs/base/common/cancellation'; -import { DisposableStore } from 'vs/base/common/lifecycle'; -import { joinPath } from 'vs/base/common/resources'; -import { localize } from 'vs/nls'; -import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; -import { IDialogService, IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { IFileService } from 'vs/platform/files/common/files'; -import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; -import { INotificationService } from 'vs/platform/notification/common/notification'; -import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; -import { asJson, asText, IRequestService } from 'vs/platform/request/common/request'; -import { IUserDataProfileTemplate, isUserDataProfileTemplate, IUserDataProfileWorkbenchService, PROFILES_CATEGORY, PROFILE_EXTENSION, PROFILE_FILTER } from 'vs/workbench/services/userDataProfile/common/userDataProfile'; -import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; - -registerAction2(class ExportProfileAction extends Action2 { - constructor() { - super({ - id: 'workbench.profiles.actions.exportProfile', - title: { - value: localize('export profile', "Export Settings as a Profile..."), - original: 'Export Settings as a Profile...' - }, - category: PROFILES_CATEGORY, - f1: true - }); - } - - async run(accessor: ServicesAccessor) { - const textFileService = accessor.get(ITextFileService); - const fileDialogService = accessor.get(IFileDialogService); - const profileService = accessor.get(IUserDataProfileWorkbenchService); - const notificationService = accessor.get(INotificationService); - - const profileLocation = await fileDialogService.showSaveDialog({ - title: localize('export profile dialog', "Save Profile"), - filters: PROFILE_FILTER, - defaultUri: joinPath(await fileDialogService.defaultFilePath(), `profile.${PROFILE_EXTENSION}`), - }); - - if (!profileLocation) { - return; - } - - const profile = await profileService.createProfile({ skipComments: true }); - await textFileService.create([{ resource: profileLocation, value: JSON.stringify(profile), options: { overwrite: true } }]); - - notificationService.info(localize('export success', "{0}: Exported successfully.", PROFILES_CATEGORY)); - } -}); - -registerAction2(class ImportProfileAction extends Action2 { - constructor() { - super({ - id: 'workbench.profiles.actions.importProfile', - title: { - value: localize('import profile', "Import Settings from a Profile..."), - original: 'Import Settings from a Profile...' - }, - category: PROFILES_CATEGORY, - f1: true - }); - } - - async run(accessor: ServicesAccessor) { - const fileDialogService = accessor.get(IFileDialogService); - const quickInputService = accessor.get(IQuickInputService); - const fileService = accessor.get(IFileService); - const requestService = accessor.get(IRequestService); - const profileService = accessor.get(IUserDataProfileWorkbenchService); - const dialogService = accessor.get(IDialogService); - - if (!(await dialogService.confirm({ - title: localize('import profile title', "Import Settings from a Profile"), - message: localize('confiirmation message', "This will replace your current settings. Are you sure you want to continue?"), - })).confirmed) { - return; - } - - const disposables = new DisposableStore(); - const quickPick = disposables.add(quickInputService.createQuickPick()); - const updateQuickPickItems = (value?: string) => { - const selectFromFileItem: IQuickPickItem = { label: localize('select from file', "Import from profile file") }; - quickPick.items = value ? [{ label: localize('select from url', "Import from URL"), description: quickPick.value }, selectFromFileItem] : [selectFromFileItem]; - }; - quickPick.title = localize('import profile quick pick title', "Import Settings from a Profile"); - quickPick.placeholder = localize('import profile placeholder', "Provide profile URL or select profile file to import"); - quickPick.ignoreFocusOut = true; - disposables.add(quickPick.onDidChangeValue(updateQuickPickItems)); - updateQuickPickItems(); - quickPick.matchOnLabel = false; - quickPick.matchOnDescription = false; - disposables.add(quickPick.onDidAccept(async () => { - quickPick.hide(); - const profile = quickPick.selectedItems[0].description ? await this.getProfileFromURL(quickPick.value, requestService) : await this.getProfileFromFileSystem(fileDialogService, fileService); - if (profile) { - await profileService.setProfile(profile); - } - })); - disposables.add(quickPick.onDidHide(() => disposables.dispose())); - quickPick.show(); - } - - private async getProfileFromFileSystem(fileDialogService: IFileDialogService, fileService: IFileService): Promise { - const profileLocation = await fileDialogService.showOpenDialog({ - canSelectFolders: false, - canSelectFiles: true, - canSelectMany: false, - filters: PROFILE_FILTER, - title: localize('import profile dialog', "Import Profile"), - }); - if (!profileLocation) { - return null; - } - const content = (await fileService.readFile(profileLocation[0])).value.toString(); - const parsed = JSON.parse(content); - return isUserDataProfileTemplate(parsed) ? parsed : null; - } - - private async getProfileFromURL(url: string, requestService: IRequestService): Promise { - const options = { type: 'GET', url }; - const context = await requestService.request(options, CancellationToken.None); - if (context.res.statusCode === 200) { - const result = await asJson(context); - return isUserDataProfileTemplate(result) ? result : null; - } else { - const message = await asText(context); - throw new Error(`Expected 200, got back ${context.res.statusCode} instead.\n\n${message}`); - } - } - -}); diff --git a/src/vs/workbench/contrib/userDataProfile/common/userDataProfileActions.ts b/src/vs/workbench/contrib/userDataProfile/common/userDataProfileActions.ts index 2761f24f87f..222b1f2399f 100644 --- a/src/vs/workbench/contrib/userDataProfile/common/userDataProfileActions.ts +++ b/src/vs/workbench/contrib/userDataProfile/common/userDataProfileActions.ts @@ -14,7 +14,7 @@ import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation import { INotificationService } from 'vs/platform/notification/common/notification'; import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; import { asJson, asText, IRequestService } from 'vs/platform/request/common/request'; -import { IUserDataProfileTemplate, isUserDataProfileTemplate, IUserDataProfileManagementService, IUserDataProfileWorkbenchService, PROFILES_CATEGORY, PROFILE_EXTENSION, PROFILE_FILTER, ManageProfilesSubMenu, IUserDataProfileService, PROFILES_ENABLEMENT_CONTEXT } from 'vs/workbench/services/userDataProfile/common/userDataProfile'; +import { IUserDataProfileTemplate, isUserDataProfileTemplate, IUserDataProfileManagementService, IUserDataProfileImportExportService, PROFILES_CATEGORY, PROFILE_EXTENSION, PROFILE_FILTER, ManageProfilesSubMenu, IUserDataProfileService, PROFILES_ENABLEMENT_CONTEXT } from 'vs/workbench/services/userDataProfile/common/userDataProfile'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IUserDataProfile, IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; import { CATEGORIES } from 'vs/workbench/common/actions'; @@ -25,7 +25,7 @@ registerAction2(class CreateFromCurrentProfileAction extends Action2 { super({ id: 'workbench.profiles.actions.createFromCurrentProfile', title: { - value: localize('save profile as', "Create from Current Profile..."), + value: localize('save profile as', "Create from Current Settings Profile..."), original: 'Create from Current Profile...' }, category: PROFILES_CATEGORY, @@ -47,7 +47,7 @@ registerAction2(class CreateFromCurrentProfileAction extends Action2 { const userDataProfileManagementService = accessor.get(IUserDataProfileManagementService); const name = await quickInputService.input({ placeHolder: localize('name', "Profile name"), - title: localize('save profile as', "Create from Current Profile..."), + title: localize('save profile as', "Create from Current Settings Profile..."), }); if (name) { await userDataProfileManagementService.createAndEnterProfile(name, undefined, true); @@ -60,7 +60,7 @@ registerAction2(class CreateEmptyProfileAction extends Action2 { super({ id: 'workbench.profiles.actions.createProfile', title: { - value: localize('create profile', "Create an Empty Profile..."), + value: localize('create profile', "Create an Empty Settings Profile..."), original: 'Create an Empty Profile...' }, category: PROFILES_CATEGORY, @@ -95,7 +95,7 @@ registerAction2(class RemoveProfileAction extends Action2 { super({ id: 'workbench.profiles.actions.removeProfile', title: { - value: localize('remove profile', "Remove Profile..."), + value: localize('remove profile', "Remove Settings Profile..."), original: 'Remove Profile...' }, category: PROFILES_CATEGORY, @@ -132,8 +132,8 @@ registerAction2(class SwitchProfileAction extends Action2 { super({ id: 'workbench.profiles.actions.switchProfile', title: { - value: localize('switch profile', "Switch Settings Profile"), - original: 'Switch Settings Profile' + value: localize('switch profile', "Switch Settings Profile..."), + original: 'Switch Settings Profile...' }, category: PROFILES_CATEGORY, f1: true, @@ -167,7 +167,7 @@ registerAction2(class CleanupProfilesAction extends Action2 { super({ id: 'workbench.profiles.actions.cleanupProfiles', title: { - value: localize('cleanup profile', "Cleanup Profiles"), + value: localize('cleanup profile', "Cleanup Settings Profiles"), original: 'Cleanup Profiles' }, category: CATEGORIES.Developer, @@ -190,21 +190,29 @@ registerAction2(class CleanupProfilesAction extends Action2 { registerAction2(class ExportProfileAction extends Action2 { constructor() { super({ - id: 'workbench.profiles.actions.exportProfile2', + id: 'workbench.profiles.actions.exportProfile', title: { - value: localize('export profile', "Export Settings as a Profile (2)..."), - original: 'Export Settings as a Profile as a Profile (2)...' + value: localize('export profile', "Export Settings Profile..."), + original: 'Export Settings Profile...' }, category: PROFILES_CATEGORY, f1: true, precondition: PROFILES_ENABLEMENT_CONTEXT, + menu: [ + { + id: ManageProfilesSubMenu, + group: '3_import_export_profiles', + when: PROFILES_ENABLEMENT_CONTEXT, + order: 1 + } + ] }); } async run(accessor: ServicesAccessor) { const textFileService = accessor.get(ITextFileService); const fileDialogService = accessor.get(IFileDialogService); - const profileService = accessor.get(IUserDataProfileWorkbenchService); + const userDataProfileImportExportService = accessor.get(IUserDataProfileImportExportService); const notificationService = accessor.get(INotificationService); const profileLocation = await fileDialogService.showSaveDialog({ @@ -217,7 +225,7 @@ registerAction2(class ExportProfileAction extends Action2 { return; } - const profile = await profileService.createProfile({ skipComments: true }); + const profile = await userDataProfileImportExportService.exportProfile({ skipComments: true }); await textFileService.create([{ resource: profileLocation, value: JSON.stringify(profile), options: { overwrite: true } }]); notificationService.info(localize('export success', "{0}: Exported successfully.", PROFILES_CATEGORY)); @@ -227,14 +235,22 @@ registerAction2(class ExportProfileAction extends Action2 { registerAction2(class ImportProfileAction extends Action2 { constructor() { super({ - id: 'workbench.profiles.actions.importProfile2', + id: 'workbench.profiles.actions.importProfile', title: { - value: localize('import profile', "Import Settings from a Profile (2)..."), - original: 'Import Settings from a Profile (2)...' + value: localize('import profile', "Import Settings Profile..."), + original: 'Import Settings Profile...' }, category: PROFILES_CATEGORY, f1: true, precondition: PROFILES_ENABLEMENT_CONTEXT, + menu: [ + { + id: ManageProfilesSubMenu, + group: '3_import_export_profiles', + when: PROFILES_ENABLEMENT_CONTEXT, + order: 2 + } + ] }); } @@ -243,7 +259,7 @@ registerAction2(class ImportProfileAction extends Action2 { const quickInputService = accessor.get(IQuickInputService); const fileService = accessor.get(IFileService); const requestService = accessor.get(IRequestService); - const userDataProfileMangementService = accessor.get(IUserDataProfileManagementService); + const userDataProfileImportExportService = accessor.get(IUserDataProfileImportExportService); const disposables = new DisposableStore(); const quickPick = disposables.add(quickInputService.createQuickPick()); @@ -262,13 +278,7 @@ registerAction2(class ImportProfileAction extends Action2 { quickPick.hide(); const profile = quickPick.selectedItems[0].description ? await this.getProfileFromURL(quickPick.value, requestService) : await this.getProfileFromFileSystem(fileDialogService, fileService); if (profile) { - const name = await quickInputService.input({ - placeHolder: localize('name', "Profile name"), - title: localize('save profile as', "Create from Current Profile..."), - }); - if (name) { - await userDataProfileMangementService.createAndEnterProfileFromTemplate(name, profile); - } + await userDataProfileImportExportService.importProfile(profile); } })); disposables.add(quickPick.onDidHide(() => disposables.dispose())); diff --git a/src/vs/workbench/services/userDataProfile/browser/userDataProfileManagement.ts b/src/vs/workbench/services/userDataProfile/browser/userDataProfileManagement.ts index 614be3e2944..64fc161b5c5 100644 --- a/src/vs/workbench/services/userDataProfile/browser/userDataProfileManagement.ts +++ b/src/vs/workbench/services/userDataProfile/browser/userDataProfileManagement.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { VSBuffer } from 'vs/base/common/buffer'; import { Disposable } from 'vs/base/common/lifecycle'; import { joinPath } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; @@ -14,15 +13,13 @@ import { IExtensionsProfileScannerService } from 'vs/platform/extensionManagemen import { ExtensionType } from 'vs/platform/extensions/common/extensions'; import { IFileService } from 'vs/platform/files/common/files'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { ILogService } from 'vs/platform/log/common/log'; -import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress'; import { EXTENSIONS_RESOURCE_NAME, IUserDataProfile, IUserDataProfilesService, UseDefaultProfileFlags, WorkspaceIdentifier } from 'vs/platform/userDataProfile/common/userDataProfile'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IExtensionManagementServerService, IWorkbenchExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IHostService } from 'vs/workbench/services/host/browser/host'; -import { IUserDataProfileManagementService, IUserDataProfileService, IUserDataProfileTemplate, PROFILES_CATEGORY } from 'vs/workbench/services/userDataProfile/common/userDataProfile'; +import { IUserDataProfileManagementService, IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile'; export class UserDataProfileManagementService extends Disposable implements IUserDataProfileManagementService { readonly _serviceBrand: undefined; @@ -36,11 +33,9 @@ export class UserDataProfileManagementService extends Disposable implements IUse @IExtensionsProfileScannerService private readonly extensionsProfileScannerService: IExtensionsProfileScannerService, @IHostService private readonly hostService: IHostService, @IDialogService private readonly dialogService: IDialogService, - @IProgressService private readonly progressService: IProgressService, @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService, @IExtensionService private readonly extensionService: IExtensionService, @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, - @ILogService logService: ILogService ) { super(); } @@ -56,7 +51,7 @@ export class UserDataProfileManagementService extends Disposable implements IUse throw new Error('Invalid Profile'); } - async createAndEnterProfile(name: string, useDefaultFlags?: UseDefaultProfileFlags, fromExisting?: boolean): Promise { + async createAndEnterProfile(name: string, useDefaultFlags?: UseDefaultProfileFlags, fromExisting?: boolean): Promise { const workspaceIdentifier = this.getWorkspaceIdentifier(); const promises: Promise[] = []; const newProfile = this.userDataProfilesService.newProfile(name, useDefaultFlags); @@ -74,6 +69,7 @@ export class UserDataProfileManagementService extends Disposable implements IUse await Promise.allSettled(promises); const createdProfile = await this.userDataProfilesService.createProfile(newProfile, workspaceIdentifier); await this.enterProfile(createdProfile, !!fromExisting); + return createdProfile; } async removeProfile(profile: IUserDataProfile): Promise { @@ -105,30 +101,6 @@ export class UserDataProfileManagementService extends Disposable implements IUse await this.enterProfile(profile, false); } - async createAndEnterProfileFromTemplate(name: string, template: IUserDataProfileTemplate, useDefaultFlags: UseDefaultProfileFlags): Promise { - const workspaceIdentifier = this.getWorkspaceIdentifier(); - const profile = await this.progressService.withProgress({ - location: ProgressLocation.Notification, - title: localize('profiles.creating', "{0}: Creating...", PROFILES_CATEGORY), - }, async progress => { - const promises: Promise[] = []; - const newProfile = this.userDataProfilesService.newProfile(name, useDefaultFlags); - await this.fileService.createFolder(newProfile.location); - if (template.globalState) { - // todo: create global state - } - if (template.settings) { - promises.push(this.fileService.writeFile(newProfile.settingsResource, VSBuffer.fromString(template.settings))); - } - if (template.extensions && newProfile.extensionsResource) { - promises.push(this.fileService.writeFile(newProfile.extensionsResource, VSBuffer.fromString(template.extensions))); - } - await Promise.allSettled(promises); - return this.userDataProfilesService.createProfile(newProfile, workspaceIdentifier); - }); - await this.enterProfile(profile, false); - } - private getWorkspaceIdentifier(): WorkspaceIdentifier { const workspace = this.workspaceContextService.getWorkspace(); switch (this.workspaceContextService.getWorkbenchState()) { diff --git a/src/vs/workbench/services/userDataProfile/common/userDataProfile.ts b/src/vs/workbench/services/userDataProfile/common/userDataProfile.ts index 24d3f973e0d..d1ea95eef66 100644 --- a/src/vs/workbench/services/userDataProfile/common/userDataProfile.ts +++ b/src/vs/workbench/services/userDataProfile/common/userDataProfile.ts @@ -31,15 +31,13 @@ export const IUserDataProfileManagementService = createDecorator; - createAndEnterProfileFromTemplate(name: string, template: IUserDataProfileTemplate, useDefaultFlags?: UseDefaultProfileFlags): Promise; + createAndEnterProfile(name: string, useDefaultFlags?: UseDefaultProfileFlags, fromExisting?: boolean): Promise; removeProfile(profile: IUserDataProfile): Promise; switchProfile(profile: IUserDataProfile): Promise; } export interface IUserDataProfileTemplate { - readonly name?: string; readonly settings?: string; readonly globalState?: string; readonly extensions?: string; @@ -49,7 +47,6 @@ export function isUserDataProfileTemplate(thing: unknown): thing is IUserDataPro const candidate = thing as IUserDataProfileTemplate | undefined; return !!(candidate && typeof candidate === 'object' - && (isUndefined(candidate.name) || typeof candidate.name === 'string') && (isUndefined(candidate.settings) || typeof candidate.settings === 'string') && (isUndefined(candidate.globalState) || typeof candidate.globalState === 'string') && (isUndefined(candidate.extensions) || typeof candidate.extensions === 'string')); @@ -57,12 +54,12 @@ export function isUserDataProfileTemplate(thing: unknown): thing is IUserDataPro export type ProfileCreationOptions = { readonly skipComments: boolean }; -export const IUserDataProfileWorkbenchService = createDecorator('IUserDataProfileWorkbenchService'); -export interface IUserDataProfileWorkbenchService { +export const IUserDataProfileImportExportService = createDecorator('IUserDataProfileImportExportService'); +export interface IUserDataProfileImportExportService { readonly _serviceBrand: undefined; - createProfile(options?: ProfileCreationOptions): Promise; - setProfile(profile: IUserDataProfileTemplate): Promise; + exportProfile(options?: ProfileCreationOptions): Promise; + importProfile(profile: IUserDataProfileTemplate): Promise; } export interface IResourceProfile { diff --git a/src/vs/workbench/services/userDataProfile/common/userDataProfileWorkbenchService.ts b/src/vs/workbench/services/userDataProfile/common/userDataProfileImportExportService.ts similarity index 58% rename from src/vs/workbench/services/userDataProfile/common/userDataProfileWorkbenchService.ts rename to src/vs/workbench/services/userDataProfile/common/userDataProfileImportExportService.ts index e4aec98fb84..7403079c1ef 100644 --- a/src/vs/workbench/services/userDataProfile/common/userDataProfileWorkbenchService.ts +++ b/src/vs/workbench/services/userDataProfile/common/userDataProfileImportExportService.ts @@ -10,10 +10,11 @@ import { INotificationService } from 'vs/platform/notification/common/notificati import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress'; import { ExtensionsProfile } from 'vs/workbench/services/userDataProfile/common/extensionsProfile'; import { GlobalStateProfile } from 'vs/workbench/services/userDataProfile/common/globalStateProfile'; -import { IUserDataProfileTemplate, IUserDataProfileWorkbenchService, PROFILES_CATEGORY } from 'vs/workbench/services/userDataProfile/common/userDataProfile'; +import { IUserDataProfileTemplate, IUserDataProfileImportExportService, PROFILES_CATEGORY, IUserDataProfileManagementService } from 'vs/workbench/services/userDataProfile/common/userDataProfile'; import { SettingsProfile } from 'vs/workbench/services/userDataProfile/common/settingsProfile'; +import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; -export class UserDataProfileWorkbenchService implements IUserDataProfileWorkbenchService { +export class UserDataProfileImportExportService implements IUserDataProfileImportExportService { readonly _serviceBrand: undefined; @@ -24,14 +25,16 @@ export class UserDataProfileWorkbenchService implements IUserDataProfileWorkbenc constructor( @IInstantiationService instantiationService: IInstantiationService, @IProgressService private readonly progressService: IProgressService, - @INotificationService private readonly notificationService: INotificationService + @INotificationService private readonly notificationService: INotificationService, + @IUserDataProfileManagementService private readonly userDataProfileManagementService: IUserDataProfileManagementService, + @IQuickInputService private readonly quickInputService: IQuickInputService, ) { this.settingsProfile = instantiationService.createInstance(SettingsProfile); this.globalStateProfile = instantiationService.createInstance(GlobalStateProfile); this.extensionsProfile = instantiationService.createInstance(ExtensionsProfile); } - async createProfile(options?: { skipComments: boolean }): Promise { + async exportProfile(options?: { skipComments: boolean }): Promise { const settings = await this.settingsProfile.getProfileContent(options); const globalState = await this.globalStateProfile.getProfileContent(); const extensions = await this.extensionsProfile.getProfileContent(); @@ -42,24 +45,34 @@ export class UserDataProfileWorkbenchService implements IUserDataProfileWorkbenc }; } - async setProfile(profile: IUserDataProfileTemplate): Promise { + async importProfile(profileTemplate: IUserDataProfileTemplate): Promise { + const name = await this.quickInputService.input({ + placeHolder: localize('name', "Profile name"), + title: localize('save profile as', "Create from Current Profile..."), + }); + if (!name) { + return undefined; + } + await this.progressService.withProgress({ location: ProgressLocation.Notification, - title: localize('profiles.applying', "{0}: Applying...", PROFILES_CATEGORY), + title: localize('profiles.applying', "{0}: Importing...", PROFILES_CATEGORY), }, async progress => { - if (profile.settings) { - await this.settingsProfile.applyProfile(profile.settings); + await this.userDataProfileManagementService.createAndEnterProfile(name); + if (profileTemplate.settings) { + await this.settingsProfile.applyProfile(profileTemplate.settings); } - if (profile.globalState) { - await this.globalStateProfile.applyProfile(profile.globalState); + if (profileTemplate.globalState) { + await this.globalStateProfile.applyProfile(profileTemplate.globalState); } - if (profile.extensions) { - await this.extensionsProfile.applyProfile(profile.extensions); + if (profileTemplate.extensions) { + await this.extensionsProfile.applyProfile(profileTemplate.extensions); } }); - this.notificationService.info(localize('applied profile', "{0}: Applied successfully.", PROFILES_CATEGORY)); + + this.notificationService.info(localize('applied profile', "{0}: Imported successfully.", PROFILES_CATEGORY)); } } -registerSingleton(IUserDataProfileWorkbenchService, UserDataProfileWorkbenchService); +registerSingleton(IUserDataProfileImportExportService, UserDataProfileImportExportService); diff --git a/src/vs/workbench/workbench.common.main.ts b/src/vs/workbench/workbench.common.main.ts index 871b0fd62d3..3319bbe6143 100644 --- a/src/vs/workbench/workbench.common.main.ts +++ b/src/vs/workbench/workbench.common.main.ts @@ -83,7 +83,7 @@ import 'vs/workbench/services/extensionRecommendations/common/extensionIgnoredRe import 'vs/workbench/services/extensionRecommendations/common/workspaceExtensionsConfig'; import 'vs/workbench/services/notification/common/notificationService'; import 'vs/workbench/services/userDataSync/common/userDataSyncUtil'; -import 'vs/workbench/services/userDataProfile/common/userDataProfileWorkbenchService'; +import 'vs/workbench/services/userDataProfile/common/userDataProfileImportExportService'; import 'vs/workbench/services/userDataProfile/browser/userDataProfileManagement'; import 'vs/workbench/services/remote/common/remoteExplorerService'; import 'vs/workbench/services/workingCopy/common/workingCopyService';